summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-09-26 20:50:34 +0000
committerKarl Berry <karl@freefriends.org>2018-09-26 20:50:34 +0000
commit78334b0d4607b242273f9d0cde94f6a6fba51832 (patch)
tree5b604ee30bb611eeeae95ed4218b4e7fd6eb00b8 /Master/texmf-dist/tex/luatex
parent3a0140d05a7e481750ec23a30ed5cf3cdef61eb7 (diff)
luaotfload (26sep18)
git-svn-id: svn://tug.org/texlive/trunk@48771 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-2018-09-24.lua (renamed from Master/texmf-dist/tex/luatex/luaotfload/fontloader-2017-02-11.lua)16670
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-gen.lua187
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua251
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics.tex93
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-afk.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua1260
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cid.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua405
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-def.lua205
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua2108
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-effects.lua414
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-italics.lua147
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-ligatures.lua136
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-tex.lua144
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ini.lua29
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua216
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ocl.lua714
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua24
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-onr.lua62
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua1019
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua22
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua342
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oti.lua100
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua1181
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua193
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua174
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua1056
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua4351
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ott.lua1159
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua953
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua14
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua1233
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-vfc.lua99
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-def.lua98
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-demo-vf-1.lua52
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-enc.lua3
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-ext.lua211
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-gbn.lua (renamed from Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-gbn.lua)133
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-lig.lua2067
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-mis.lua31
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-syn.lua7
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.lua324
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.tex140
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua62
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-io.lua266
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lpeg.lua300
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua69
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-math.lua119
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-string.lua28
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua175
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-unicode.lua1361
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.lua50
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.tex19
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.lua53
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.tex1874
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.lua591
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.tex140
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-plain.tex55
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor-test.tex30
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.lua163
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.tex14
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua20247
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.lua743
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.tex11
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.lua63
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.tex20
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-test.tex173
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua243
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua510
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua6932
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua94
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua18
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua417
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua45
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua27
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua8
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua37
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua151
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty8
83 files changed, 52672 insertions, 20483 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2017-02-11.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2018-09-24.lua
index f8f6f0658a2..99e38f6399a 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2017-02-11.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2018-09-24.lua
@@ -1,9 +1,9 @@
--[[info-----------------------------------------------------------------------
Luaotfload fontloader package
- build 2017-02-11 18:16:05 by phg@phlegethon
+ build 2018-09-24 22:51:46 by fischer@troubleshooting-tex.de
-------------------------------------------------------------------------------
- © 2017 PRAGMA ADE / ConTeXt Development Team
+ © 2018 PRAGMA ADE / ConTeXt Development Team
The code in this file is provided under the GPL v2.0 license. See the
file COPYING in the Luaotfload repository for details.
@@ -22,12 +22,15 @@
· fontloader-data-con.lua
· fontloader-basics-nod.lua
· fontloader-font-ini.lua
+ · fontloader-fonts-mis.lua
· fontloader-font-con.lua
· fontloader-fonts-enc.lua
· fontloader-font-cid.lua
· fontloader-font-map.lua
- · fontloader-font-oti.lua
+ · fontloader-font-vfc.lua
· fontloader-font-otr.lua
+ · fontloader-font-oti.lua
+ · fontloader-font-ott.lua
· fontloader-font-cff.lua
· fontloader-font-ttf.lua
· fontloader-font-dsp.lua
@@ -46,13 +49,19 @@
· fontloader-font-tfm.lua
· fontloader-font-lua.lua
· fontloader-font-def.lua
+ · fontloader-fonts-def.lua
· fontloader-fonts-ext.lua
- · fontloader-font-gbn.lua
+ · fontloader-font-imp-tex.lua
+ · fontloader-font-imp-ligatures.lua
+ · fontloader-font-imp-italics.lua
+ · fontloader-font-imp-effects.lua
+ · fontloader-fonts-lig.lua
+ · fontloader-fonts-gbn.lua
--info]]-----------------------------------------------------------------------
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “data-con” d8982c834ed9acc6193eee23067b9d5d] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “data-con” d8982c834ed9acc6193eee23067b9d5d] ---
if not modules then modules={} end modules ['data-con']={
version=1.100,
@@ -164,10 +173,10 @@ function containers.cleanname(name)
return (gsub(lower(name),"[^%w\128-\255]+","-"))
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “data-con”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “data-con”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “basics-nod” 9288471b8395bfb683aba0ff3964d950] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “basics-nod” 78f56219685f3145b9393c2b688aad94] ---
if not modules then modules={} end modules ['luatex-fonts-nod']={
version=1.001,
@@ -177,7 +186,6 @@ if not modules then modules={} end modules ['luatex-fonts-nod']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
if tex.attribute[0]~=0 then
@@ -203,7 +211,6 @@ attributes.private=attributes.private or function(name)
return number
end
nodes={}
-nodes.pool={}
nodes.handlers={}
local nodecodes={}
local glyphcodes=node.subtypes("glyph")
@@ -213,21 +220,20 @@ for k,v in next,node.types() do
nodecodes[k]=v
nodecodes[v]=k
end
-for i=0,#glyphcodes do
- glyphcodes[glyphcodes[i]]=i
+for k,v in next,glyphcodes do
+ glyphcodes[v]=k
end
-for i=0,#disccodes do
- disccodes[disccodes[i]]=i
+for k,v in next,glyphcodes do
+ disccodes[v]=k
end
nodes.nodecodes=nodecodes
nodes.glyphcodes=glyphcodes
nodes.disccodes=disccodes
local flush_node=node.flush_node
local remove_node=node.remove
-local new_node=node.new
local traverse_id=node.traverse_id
-nodes.handlers.protectglyphs=node.protect_glyphs
-nodes.handlers.unprotectglyphs=node.unprotect_glyphs
+nodes.handlers.protectglyphs=node.protect_glyphs
+nodes.handlers.unprotectglyphs=node.unprotect_glyphs
local math_code=nodecodes.math
local end_of_math=node.end_of_math
function node.end_of_math(n)
@@ -253,11 +259,6 @@ end
function nodes.delete(head,current)
return nodes.remove(head,current,true)
end
-function nodes.pool.kern(k)
- local n=new_node("kern",1)
- n.kern=k
- return n
-end
local getfield=node.getfield
local setfield=node.setfield
nodes.getfield=getfield
@@ -323,16 +324,38 @@ nuts.setattr=setfield
nuts.getfont=direct.getfont
nuts.setfont=direct.setfont
nuts.getsubtype=direct.getsubtype
-nuts.setsubtype=direct.setsubtype or function(n,s) setfield(n,"subtype",s) end
+nuts.setsubtype=direct.setsubtype
nuts.getchar=direct.getchar
nuts.setchar=direct.setchar
nuts.getdisc=direct.getdisc
nuts.setdisc=direct.setdisc
nuts.setlink=direct.setlink
+nuts.setsplit=direct.setsplit
nuts.getlist=direct.getlist
-nuts.setlist=direct.setlist or function(n,l) setfield(n,"list",l) end
-nuts.getleader=direct.getleader
-nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.setlist=direct.setlist
+nuts.getoffsets=direct.getoffsets or
+ function(n)
+ return getfield(n,"xoffset"),getfield(n,"yoffset")
+ end
+nuts.setoffsets=direct.setoffsets or
+ function(n,x,y)
+ if x then setfield(n,"xoffset",x) end
+ if y then setfield(n,"xoffset",y) end
+ end
+nuts.getleader=direct.getleader or function(n) return getfield(n,"leader") end
+nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.getcomponents=direct.getcomponents or function(n) return getfield(n,"components") end
+nuts.setcomponents=direct.setcomponents or function(n,c) setfield(n,"components",c) end
+nuts.getkern=direct.getkern or function(n) return getfield(n,"kern") end
+nuts.setkern=direct.setkern or function(n,k) setfield(n,"kern",k) end
+nuts.getdir=direct.getdir or function(n) return getfield(n,"dir") end
+nuts.setdir=direct.setdir or function(n,d) setfield(n,"dir",d) end
+nuts.getwidth=direct.getwidth or function(n) return getfield(n,"width") end
+nuts.setwidth=direct.setwidth or function(n,w) return setfield(n,"width",w) end
+nuts.getheight=direct.getheight or function(n) return getfield(n,"height") end
+nuts.setheight=direct.setheight or function(n,h) return setfield(n,"height",h) end
+nuts.getdepth=direct.getdepth or function(n) return getfield(n,"depth") end
+nuts.setdepth=direct.setdepth or function(n,d) return setfield(n,"depth",d) end
if not direct.is_glyph then
local getchar=direct.getchar
local getid=direct.getid
@@ -386,18 +409,12 @@ nuts.end_of_math=direct.end_of_math
nuts.traverse=direct.traverse
nuts.traverse_id=direct.traverse_id
nuts.traverse_char=direct.traverse_char
+nuts.traverse_glyph=direct.traverse_glyph
nuts.ligaturing=direct.ligaturing
nuts.kerning=direct.kerning
+nuts.new=direct.new
nuts.getprop=nuts.getattr
nuts.setprop=nuts.setattr
-local new_nut=direct.new
-nuts.new=new_nut
-nuts.pool={}
-function nuts.pool.kern(k)
- local n=new_nut("kern",1)
- setfield(n,"kern",k)
- return n
-end
local propertydata=direct.get_properties_table()
nodes.properties={ data=propertydata }
direct.set_properties_mode(true,true)
@@ -420,11 +437,162 @@ nuts.setprop=function(n,k,v)
end
nodes.setprop=nodes.setproperty
nodes.getprop=nodes.getproperty
+local setprev=nuts.setprev
+local setnext=nuts.setnext
+local getnext=nuts.getnext
+local setlink=nuts.setlink
+local getfield=nuts.getfield
+local setfield=nuts.setfield
+local getcomponents=nuts.getcomponents
+local setcomponents=nuts.setcomponents
+local find_tail=nuts.tail
+local flush_list=nuts.flush_list
+local flush_node=nuts.flush_node
+local traverse_id=nuts.traverse_id
+local copy_node=nuts.copy_node
+local glyph_code=nodes.nodecodes.glyph
+function nuts.set_components(target,start,stop)
+ local head=getcomponents(target)
+ if head then
+ flush_list(head)
+ head=nil
+ end
+ if start then
+ setprev(start)
+ else
+ return nil
+ end
+ if stop then
+ setnext(stop)
+ end
+ local tail=nil
+ while start do
+ local c=getcomponents(start)
+ local n=getnext(start)
+ if c then
+ if head then
+ setlink(tail,c)
+ else
+ head=c
+ end
+ tail=find_tail(c)
+ setcomponents(start)
+ flush_node(start)
+ else
+ if head then
+ setlink(tail,start)
+ else
+ head=start
+ end
+ tail=start
+ end
+ start=n
+ end
+ setcomponents(target,head)
+ return head
+end
+nuts.get_components=nuts.getcomponents
+function nuts.take_components(target)
+ local c=getcomponents(target)
+ setcomponents(target)
+ return c
+end
+function nuts.count_components(n,marks)
+ local components=getcomponents(n)
+ if components then
+ if marks then
+ local i=0
+ for g in traverse_id(glyph_code,components) do
+ if not marks[getchar(g)] then
+ i=i+1
+ end
+ end
+ return i
+ else
+ return count(glyph_code,components)
+ end
+ else
+ return 0
+ end
+end
+function nuts.copy_no_components(g,copyinjection)
+ local components=getcomponents(g)
+ if components then
+ setcomponents(g)
+ local n=copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ setcomponents(g,components)
+ return n
+ else
+ local n=copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ return n
+ end
+end
+function nuts.copy_only_glyphs(current)
+ local head=nil
+ local previous=nil
+ for n in traverse_id(glyph_code,current) do
+ n=copy_node(n)
+ if head then
+ setlink(previous,n)
+ else
+ head=n
+ end
+ previous=n
+ end
+ return head
+end
+nuts.uses_font=direct.uses_font
+if not nuts.uses_font then
+ local getdisc=nuts.getdisc
+ local getfont=nuts.getfont
+ function nuts.uses_font(n,font)
+ local pre,post,replace=getdisc(n)
+ if pre then
+ for n in traverse_id(glyph_code,pre) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ if post then
+ for n in traverse_id(glyph_code,post) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ if replace then
+ for n in traverse_id(glyph_code,replace) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ return false
+ end
+end
+do
+ local dummy=tonut(node.new("glyph"))
+ nuts.traversers={
+ glyph=nuts.traverse_id(nodecodes.glyph,dummy),
+ glue=nuts.traverse_id(nodecodes.glue,dummy),
+ disc=nuts.traverse_id(nodecodes.disc,dummy),
+ boundary=nuts.traverse_id(nodecodes.boundary,dummy),
+ char=nuts.traverse_char(dummy),
+ node=nuts.traverse(dummy),
+ }
+end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “basics-nod”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “basics-nod”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ini” 10cb9a563a98e06ff79c35a8751e13dc] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ini” 6f615d3bc72fb29f409ed2b8f6364c35] ---
if not modules then modules={} end modules ['font-ini']={
version=1.001,
@@ -436,7 +604,7 @@ if not modules then modules={} end modules ['font-ini']={
local allocate=utilities.storage.allocate
fonts=fonts or {}
local fonts=fonts
-fonts.hashes={ identifiers=allocate() }
+fonts.hashes=fonts.hashes or { identifiers=allocate() }
fonts.tables=fonts.tables or {}
fonts.helpers=fonts.helpers or {}
fonts.tracers=fonts.tracers or {}
@@ -445,12 +613,46 @@ fonts.analyzers={}
fonts.readers={}
fonts.definers={ methods={} }
fonts.loggers={ register=function() end }
-fontloader.totable=fontloader.to_table
+if context then
+ fontloader=nil
+end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ini”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ini”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-con” 7575a7b4e6d04816072945e27d7d0b33] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-mis” fd0a52acf5180695d2870da654db7272] ---
+
+if not modules then modules={} end modules ['luatex-font-mis']={
+ version=1.001,
+ comment="companion to luatex-*.tex",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+if context then
+ os.exit()
+end
+local currentfont=font.current
+local hashes=fonts.hashes
+local identifiers=hashes.identifiers or {}
+local marks=hashes.marks or {}
+hashes.identifiers=identifiers
+hashes.marks=marks
+table.setmetatableindex(marks,function(t,k)
+ if k==true then
+ return marks[currentfont()]
+ else
+ local resources=identifiers[k].resources or {}
+ local marks=resources.marks or {}
+ t[k]=marks
+ return marks
+ end
+end)
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-mis”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-con” 3218bd21a24c2abb13b284085da8ced4] ---
if not modules then modules={} end modules ['font-con']={
version=1.001,
@@ -459,11 +661,14 @@ if not modules then modules={} end modules ['font-con']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local next,tostring,rawget=next,tostring,rawget
+local next,tostring,tonumber,rawget=next,tostring,tonumber,rawget
local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find
-local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
+local sort,insert,concat=table.sort,table.insert,table.concat
+local sortedkeys,sortedhash,serialize,fastcopy=table.sortedkeys,table.sortedhash,table.serialize,table.fastcopy
local derivetable=table.derive
local ioflush=io.flush
+local round=math.round
+local setmetatable,getmetatable,rawget,rawset=setmetatable,getmetatable,rawget,rawset
local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end)
local report_defining=logs.reporter("fonts","defining")
@@ -509,6 +714,28 @@ function constructors.scaled(scaledpoints,designsize)
return scaledpoints
end
end
+function constructors.getprivate(tfmdata)
+ local properties=tfmdata.properties
+ local private=properties.private
+ properties.private=private+1
+ return private
+end
+function constructors.setmathparameter(tfmdata,name,value)
+ local m=tfmdata.mathparameters
+ local c=tfmdata.MathConstants
+ if m then
+ m[name]=value
+ end
+ if c and c~=m then
+ c[name]=value
+ end
+end
+function constructors.getmathparameter(tfmdata,name)
+ local p=tfmdata.mathparameters or tfmdata.MathConstants
+ if p then
+ return p[name]
+ end
+end
function constructors.cleanuptable(tfmdata)
if constructors.autocleanup and tfmdata.properties.virtualized then
for k,v in next,tfmdata.characters do
@@ -585,27 +812,62 @@ function constructors.trytosharefont(target,tfmdata)
end
end
end
+local synonyms={
+ exheight="x_height",
+ xheight="x_height",
+ ex="x_height",
+ emwidth="quad",
+ em="quad",
+ spacestretch="space_stretch",
+ stretch="space_stretch",
+ spaceshrink="space_shrink",
+ shrink="space_shrink",
+ extraspace="extra_space",
+ xspace="extra_space",
+ slantperpoint="slant",
+}
function constructors.enhanceparameters(parameters)
- local xheight=parameters.x_height
- local quad=parameters.quad
- local space=parameters.space
- local stretch=parameters.space_stretch
- local shrink=parameters.space_shrink
- local extra=parameters.extra_space
- local slant=parameters.slant
- parameters.xheight=xheight
- parameters.spacestretch=stretch
- parameters.spaceshrink=shrink
- parameters.extraspace=extra
- parameters.em=quad
- parameters.ex=xheight
- parameters.slantperpoint=slant
- parameters.spacing={
- width=space,
- stretch=stretch,
- shrink=shrink,
- extra=extra,
- }
+ local mt=getmetatable(parameters)
+ local getter=function(t,k)
+ if not k then
+ return nil
+ end
+ local s=synonyms[k]
+ if s then
+ return rawget(t,s) or (mt and mt[s]) or nil
+ end
+ if k=="spacing" then
+ return {
+ width=t.space,
+ stretch=t.space_stretch,
+ shrink=t.space_shrink,
+ extra=t.extra_space,
+ }
+ end
+ return mt and mt[k] or nil
+ end
+ local setter=function(t,k,v)
+ if not k then
+ return 0
+ end
+ local s=synonyms[k]
+ if s then
+ rawset(t,s,v)
+ elseif k=="spacing" then
+ if type(v)=="table" then
+ rawset(t,"space",v.width or 0)
+ rawset(t,"space_stretch",v.stretch or 0)
+ rawset(t,"space_shrink",v.shrink or 0)
+ rawset(t,"extra_space",v.extra or 0)
+ end
+ else
+ rawset(t,k,v)
+ end
+ end
+ setmetatable(parameters,{
+ __index=getter,
+ __newindex=setter,
+ })
end
local function mathkerns(v,vdelta)
local k={}
@@ -624,7 +886,7 @@ local psfake=0
local function fixedpsname(psname,fallback)
local usedname=psname
if psname and psname~="" then
- if find(psname," ") then
+ if find(psname," ",1,true) then
usedname=gsub(psname,"[%s]+","-")
else
end
@@ -669,7 +931,7 @@ function constructors.scale(tfmdata,specification)
target.unscaled=tfmdata
local mathsize=tonumber(specification.mathsize) or 0
local textsize=tonumber(specification.textsize) or scaledpoints
- local forcedsize=tonumber(parameters.mathsize ) or 0
+ local forcedsize=tonumber(parameters.mathsize ) or 0
local extrafactor=tonumber(specification.factor ) or 1
if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then
scaledpoints=parameters.scriptpercentage*textsize/100
@@ -677,6 +939,7 @@ function constructors.scale(tfmdata,specification)
scaledpoints=parameters.scriptscriptpercentage*textsize/100
elseif forcedsize>1000 then
scaledpoints=forcedsize
+ else
end
targetparameters.mathsize=mathsize
targetparameters.textsize=textsize
@@ -687,9 +950,6 @@ function constructors.scale(tfmdata,specification)
local defaultheight=resources.defaultheight or 0
local defaultdepth=resources.defaultdepth or 0
local units=parameters.units or 1000
- if target.fonts then
- target.fonts=fastcopy(target.fonts)
- end
targetproperties.language=properties.language or "dflt"
targetproperties.script=properties.script or "dflt"
targetproperties.mode=properties.mode or "base"
@@ -731,24 +991,34 @@ function constructors.scale(tfmdata,specification)
target.stretch=expansion.stretch
target.shrink=expansion.shrink
target.step=expansion.step
- target.auto_expand=expansion.auto
end
- local protrusion=parameters.protrusion
- if protrusion then
- target.auto_protrude=protrusion.auto
+ local slantfactor=parameters.slantfactor or 0
+ if slantfactor~=0 then
+ target.slant=slantfactor*1000
+ else
+ target.slant=0
end
local extendfactor=parameters.extendfactor or 0
if extendfactor~=0 and extendfactor~=1 then
hdelta=hdelta*extendfactor
- target.extend=extendfactor*1000
+ target.extend=extendfactor*1000
else
target.extend=1000
end
- local slantfactor=parameters.slantfactor or 0
- if slantfactor~=0 then
- target.slant=slantfactor*1000
+ local squeezefactor=parameters.squeezefactor or 0
+ if squeezefactor~=0 and squeezefactor~=1 then
+ vdelta=vdelta*squeezefactor
+ target.squeeze=squeezefactor*1000
else
- target.slant=0
+ target.squeeze=1000
+ end
+ local mode=parameters.mode or 0
+ if mode~=0 then
+ target.mode=mode
+ end
+ local width=parameters.width or 0
+ if width~=0 then
+ target.width=width*delta*1000/655360
end
targetparameters.factor=delta
targetparameters.hfactor=hdelta
@@ -756,8 +1026,10 @@ function constructors.scale(tfmdata,specification)
targetparameters.size=scaledpoints
targetparameters.units=units
targetparameters.scaledpoints=askedscaledpoints
+ targetparameters.mode=mode
+ targetparameters.width=width
local isvirtual=properties.virtualized or tfmdata.type=="virtual"
- local hasquality=target.auto_expand or target.auto_protrude
+ local hasquality=parameters.expansion or parameters.protrusion
local hasitalics=properties.hasitalics
local autoitalicamount=properties.autoitalicamount
local stackmath=not properties.nostackmath
@@ -767,6 +1039,12 @@ function constructors.scale(tfmdata,specification)
local realdimensions=properties.realdimensions
local writingmode=properties.writingmode or "horizontal"
local identity=properties.identity or "horizontal"
+ local vfonts=target.fonts
+ if vfonts and #vfonts>0 then
+ target.fonts=fastcopy(vfonts)
+ elseif isvirtual then
+ target.fonts={ { id=0 } }
+ end
if changed and not next(changed) then
changed=false
end
@@ -842,10 +1120,15 @@ function constructors.scale(tfmdata,specification)
local chr,description,index
if changed then
local c=changed[unicode]
- if c then
- description=descriptions[c] or descriptions[unicode] or character
- character=characters[c] or character
- index=description.index or c
+ if c and c~=unicode then
+ if c then
+ description=descriptions[c] or descriptions[unicode] or character
+ character=characters[c] or character
+ index=description.index or c
+ else
+ description=descriptions[unicode] or character
+ index=description.index or unicode
+ end
else
description=descriptions[unicode] or character
index=description.index or unicode
@@ -942,10 +1225,13 @@ function constructors.scale(tfmdata,specification)
local t={}
for i=1,#vv do
local vvi=vv[i]
- t[i]={
- ["start"]=(vvi["start"] or 0)*vdelta,
- ["end"]=(vvi["end"] or 0)*vdelta,
- ["advance"]=(vvi["advance"] or 0)*vdelta,
+ local s=vvi["start"] or 0
+ local e=vvi["end"] or 0
+ local a=vvi["advance"] or 0
+ t[i]={
+ ["start"]=s==0 and 0 or s*vdelta,
+ ["end"]=e==0 and 0 or e*vdelta,
+ ["advance"]=a==0 and 0 or a*vdelta,
["extender"]=vvi["extender"],
["glyph"]=vvi["glyph"],
}
@@ -957,10 +1243,13 @@ function constructors.scale(tfmdata,specification)
local t={}
for i=1,#hv do
local hvi=hv[i]
- t[i]={
- ["start"]=(hvi["start"] or 0)*hdelta,
- ["end"]=(hvi["end"] or 0)*hdelta,
- ["advance"]=(hvi["advance"] or 0)*hdelta,
+ local s=hvi["start"] or 0
+ local e=hvi["end"] or 0
+ local a=hvi["advance"] or 0
+ t[i]={
+ ["start"]=s==0 and 0 or s*hdelta,
+ ["end"]=e==0 and 0 or e*hdelta,
+ ["advance"]=a==0 and 0 or a*hdelta,
["extender"]=hvi["extender"],
["glyph"]=hvi["glyph"],
}
@@ -1047,7 +1336,7 @@ function constructors.scale(tfmdata,specification)
local ok=false
for i=1,#vc do
local key=vc[i][1]
- if key=="right" or key=="down" then
+ if key=="right" or key=="down" or key=="rule" then
ok=true
break
end
@@ -1071,7 +1360,6 @@ function constructors.scale(tfmdata,specification)
else
chr.commands=vc
end
- chr.index=nil
end
end
targetcharacters[unicode]=chr
@@ -1079,6 +1367,20 @@ function constructors.scale(tfmdata,specification)
properties.setitalics=hasitalics
constructors.aftercopyingcharacters(target,tfmdata)
constructors.trytosharefont(target,tfmdata)
+ local vfonts=target.fonts
+if isvirtual or target.type=="virtual" or properties.virtualized then
+ properties.virtualized=true
+target.type="virtual"
+ if not vfonts or #vfonts==0 then
+ target.fonts={ { id=0 } }
+ end
+ elseif vfonts then
+ properties.virtualized=true
+ target.type="virtual"
+ if #vfonts==0 then
+ target.fonts={ { id=0 } }
+ end
+ end
return target
end
function constructors.finalize(tfmdata)
@@ -1097,26 +1399,29 @@ function constructors.finalize(tfmdata)
end
if not parameters.expansion then
parameters.expansion={
- stretch=tfmdata.stretch or 0,
- shrink=tfmdata.shrink or 0,
- step=tfmdata.step or 0,
- auto=tfmdata.auto_expand or false,
- }
- end
- if not parameters.protrusion then
- parameters.protrusion={
- auto=auto_protrude
+ stretch=tfmdata.stretch or 0,
+ shrink=tfmdata.shrink or 0,
+ step=tfmdata.step or 0,
}
end
if not parameters.size then
parameters.size=tfmdata.size
end
- if not parameters.extendfactor then
- parameters.extendfactor=tfmdata.extend or 0
+ if not parameters.mode then
+ parameters.mode=0
+ end
+ if not parameters.width then
+ parameters.width=0
end
if not parameters.slantfactor then
parameters.slantfactor=tfmdata.slant or 0
end
+ if not parameters.extendfactor then
+ parameters.extendfactor=tfmdata.extend or 0
+ end
+ if not parameters.squeezefactor then
+ parameters.squeezefactor=tfmdata.squeeze or 0
+ end
local designsize=parameters.designsize
if designsize then
parameters.minsize=tfmdata.minsize or designsize
@@ -1191,10 +1496,11 @@ function constructors.finalize(tfmdata)
tfmdata.stretch=nil
tfmdata.shrink=nil
tfmdata.step=nil
- tfmdata.auto_expand=nil
- tfmdata.auto_protrude=nil
- tfmdata.extend=nil
tfmdata.slant=nil
+ tfmdata.extend=nil
+ tfmdata.squeeze=nil
+ tfmdata.mode=nil
+ tfmdata.width=nil
tfmdata.units=nil
tfmdata.units_per_em=nil
tfmdata.cache=nil
@@ -1206,20 +1512,20 @@ constructors.hashmethods=hashmethods
function constructors.hashfeatures(specification)
local features=specification.features
if features then
- local t,tn={},0
- for category,list in next,features do
+ local t,n={},0
+ for category,list in sortedhash(features) do
if next(list) then
local hasher=hashmethods[category]
if hasher then
local hash=hasher(list)
if hash then
- tn=tn+1
- t[tn]=category..":"..hash
+ n=n+1
+ t[n]=category..":"..hash
end
end
end
end
- if tn>0 then
+ if n>0 then
return concat(t," & ")
end
end
@@ -1233,7 +1539,17 @@ hashmethods.normal=function(list)
elseif k=="number" or k=="features" then
else
n=n+1
- s[n]=k..'='..tostring(v)
+ if type(v)=="table" then
+ local t={}
+ local m=0
+ for k,v in next,v do
+ m=m+1
+ t[m]=k..'='..tostring(v)
+ end
+ s[n]=k..'={'..concat(t,",").."}"
+ else
+ s[n]=k..'='..tostring(v)
+ end
end
end
if n>0 then
@@ -1248,13 +1564,15 @@ function constructors.hashinstance(specification,force)
specification.hash=hash
end
if size<1000 and designsizes[hash] then
- size=math.round(constructors.scaled(size,designsizes[hash]))
- specification.size=size
+ size=round(constructors.scaled(size,designsizes[hash]))
+ else
+ size=round(size)
end
+ specification.size=size
if fallbacks then
- return hash..' @ '..tostring(size)..' @ '..fallbacks
+ return hash..' @ '..size..' @ '..fallbacks
else
- return hash..' @ '..tostring(size)
+ return hash..' @ '..size
end
end
function constructors.setname(tfmdata,specification)
@@ -1435,10 +1753,12 @@ do
local handler=handlers[format]
local enhancers=handler.enhancers
if not enhancers then
- local actions=allocate()
+ local actions=allocate()
local before=allocate()
local after=allocate()
local order=allocate()
+ local known={}
+ local nofsteps=0
local patches={ before=before,after=after }
local trace=false
local report=logs.reporter("fonts",format.." enhancing")
@@ -1460,7 +1780,7 @@ do
report("%s enhancing file %a","start",filename)
end
ioflush()
- for e=1,#order do
+ for e=1,nofsteps do
local enhancer=order[e]
local b=before[enhancer]
if b then
@@ -1470,7 +1790,7 @@ do
end
end
end
- enhance(enhancer,data,filename,raw)
+ enhance(enhancer,data,filename,raw)
local a=after[enhancer]
if a then
for pattern,action in next,a do
@@ -1490,7 +1810,9 @@ do
if action then
if actions[what] then
else
- order[#order+1]=what
+ nofsteps=nofsteps+1
+ order[nofsteps]=what
+ known[what]=nofsteps
end
actions[what]=action
else
@@ -1504,7 +1826,12 @@ do
if ww then
ww[pattern]=action
else
- pw[where]={ [pattern]=action}
+ pw[where]={ [pattern]=action }
+ if not known[where] then
+ nofsteps=nofsteps+1
+ order[nofsteps]=where
+ known[where]=nofsteps
+ end
end
end
end
@@ -1512,7 +1839,11 @@ do
register=register,
apply=apply,
patch=patch,
- patches={ register=patch },
+ report=report,
+ patches={
+ register=patch,
+ report=report,
+ },
}
handler.enhancers=enhancers
end
@@ -1660,10 +1991,10 @@ function constructors.addcoreunicodes(unicodes)
return unicodes
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-con”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-con”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-enc” a7ace7c1969cd64a5ca9888838f3edb6] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-enc” 5ff4ca50493d7c4ecea0e15c203099f0] ---
if not modules then modules={} end modules ['luatex-font-enc']={
version=1.001,
@@ -1673,7 +2004,6 @@ if not modules then modules={} end modules ['luatex-font-enc']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
local fonts=fonts
@@ -1683,7 +2013,7 @@ encodings.agl={}
encodings.known={}
setmetatable(encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
- texio.write(" <loading (extended) adobe glyph list>")
+ logs.report("fonts","loading (extended) adobe glyph list")
local unicodes=dofile(resolvers.findfile("font-age.lua"))
encodings.agl={ unicodes=unicodes }
return unicodes
@@ -1733,14 +2063,14 @@ function encodings.load(filename)
return containers.write(encodings.cache,name,data)
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-enc”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-enc”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cid” 52421d1fdaa07ec4b1d936c6ff5079be] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-cid” 22b0367742fb253deef84ef7ccf5e8de] ---
if not modules then modules={} end modules ['font-cid']={
version=1.001,
- comment="companion to font-otf.lua (cidmaps)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
@@ -1887,10 +2217,10 @@ function cid.getmap(specification)
return found
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cid”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-cid”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-map” 8708bde7467785c4d3b7afdaf2f9333a] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-map” 2c03dc61afabb5887ef18a88e6ec86bd] ---
if not modules then modules={} end modules ['font-map']={
version=1.001,
@@ -1902,12 +2232,12 @@ if not modules then modules={} end modules ['font-map']={
local tonumber,next,type=tonumber,next,type
local match,format,find,concat,gsub,lower=string.match,string.format,string.find,table.concat,string.gsub,string.lower
local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.match
-local floor=math.floor
local formatters=string.formatters
local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
+local rshift=bit32.rshift
local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end)
local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_mapping=v end)
-local report_fonts=logs.reporter("fonts","loading")
+local report_fonts=logs.reporter("fonts","loading")
local force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end)
local fonts=fonts or {}
local mappings=fonts.mappings or {}
@@ -1942,7 +2272,7 @@ local function tounicode16(unicode)
return f_single(unicode)
else
unicode=unicode-0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
+ return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
end
end
local function tounicode16sequence(unicodes)
@@ -1953,32 +2283,40 @@ local function tounicode16sequence(unicodes)
t[l]=f_single(u)
else
u=u-0x10000
- t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
+ t[l]=f_double(rshift(u,10)+0xD800,u%1024+0xDC00)
end
end
return concat(t)
end
-local function tounicode(unicode,name)
- if type(unicode)=="table" then
- local t={}
- for l=1,#unicode do
- local u=unicode[l]
- if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then
- t[l]=f_single(u)
- else
- u=u-0x10000
- t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
- end
- end
- return concat(t)
+local unknown=f_single(0xFFFD)
+local hash={}
+local conc={}
+table.setmetatableindex(hash,function(t,k)
+ if type(k)=="table" then
+ local n=#k
+ for l=1,n do
+ conc[l]=hash[k[l]]
+ end
+ return concat(conc,"",1,n)
+ end
+ local v
+ if k>=0x00E000 and k<=0x00F8FF then
+ v=unknown
+ elseif k>=0x0F0000 and k<=0x0FFFFF then
+ v=unknown
+ elseif k>=0x100000 and k<=0x10FFFF then
+ v=unknown
+ elseif k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then
+ v=f_single(k)
else
- if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then
- return f_single(unicode)
- else
- unicode=unicode-0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
- end
+ k=k-0x10000
+ v=f_double(rshift(k,10)+0xD800,k%1024+0xDC00)
end
+ t[k]=v
+ return v
+end)
+local function tounicode(unicode)
+ return hash[unicode]
end
local function fromunicode16(str)
if #str==4 then
@@ -1997,7 +2335,7 @@ local ligseparator=P("_")
local varseparator=P(".")
local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0)
do
- local overloads=allocate {
+ local overloads={
IJ={ name="I_J",unicode={ 0x49,0x4A },mess=0x0132 },
ij={ name="i_j",unicode={ 0x69,0x6A },mess=0x0133 },
ff={ name="f_f",unicode={ 0x66,0x66 },mess=0xFB00 },
@@ -2008,7 +2346,7 @@ do
fj={ name="f_j",unicode={ 0x66,0x6A } },
fk={ name="f_k",unicode={ 0x66,0x6B } },
}
- local o={}
+ local o=allocate {}
for k,v in next,overloads do
local name=v.name
local mess=v.mess
@@ -2022,7 +2360,7 @@ do
end
mappings.overloads=o
end
-function mappings.addtounicode(data,filename,checklookups)
+function mappings.addtounicode(data,filename,checklookups,forceligatures)
local resources=data.resources
local unicodes=resources.unicodes
if not unicodes then
@@ -2191,34 +2529,46 @@ function mappings.addtounicode(data,filename,checklookups)
if type(checklookups)=="function" then
checklookups(data,missing,nofmissing)
end
- local collected=false
local unicoded=0
- for i=1,#dlist do
- local du=dlist[i]
- local glyph=descriptions[du]
- if glyph.class=="ligature" and (force_ligatures or not glyph.unicode) then
- if not collected then
- collected=fonts.handlers.otf.readers.getcomponents(data)
- if not collected then
- break
- end
+ local collected=fonts.handlers.otf.readers.getcomponents(data)
+ local function resolve(glyph,u)
+ local n=#u
+ for i=1,n do
+ if u[i]>private then
+ n=0
+ break
end
- local u=collected[du]
- if u then
- local n=#u
- for i=1,n do
- if u[i]>private then
- n=0
- break
- end
+ end
+ if n>0 then
+ if n>1 then
+ glyph.unicode=u
+ else
+ glyph.unicode=u[1]
+ end
+ unicoded=unicoded+1
+ end
+ end
+ if not collected then
+ elseif forceligatures or force_ligatures then
+ for i=1,#dlist do
+ local du=dlist[i]
+ if du>=private or (du>=0xE000 and du<=0xF8FF) then
+ local u=collected[du]
+ if u then
+ resolve(descriptions[du],u)
end
- if n>0 then
- if n>1 then
- glyph.unicode=u
- else
- glyph.unicode=u[1]
+ end
+ end
+ else
+ for i=1,#dlist do
+ local du=dlist[i]
+ if du>=private or (du>=0xE000 and du<=0xF8FF) then
+ local glyph=descriptions[du]
+ if glyph.class=="ligature" and not glyph.unicode then
+ local u=collected[du]
+ if u then
+ resolve(glyph,u)
end
- unicoded=unicoded+1
end
end
end
@@ -2253,156 +2603,89 @@ function mappings.addtounicode(data,filename,checklookups)
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-map”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-map”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oti” 8f48c06a1d632febd7231ad5dfadfc53] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-vfc” 237aff1862009b7850653c2098473bd4] ---
-if not modules then modules={} end modules ['font-oti']={
+if not modules then modules={} end modules ['font-vfc']={
version=1.001,
- comment="companion to font-ini.mkiv",
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local lower=string.lower
+local select=select
+local insert=table.insert
local fonts=fonts
-local constructors=fonts.constructors
-local otf=constructors.handlers.otf
-local otffeatures=constructors.features.otf
-local registerotffeature=otffeatures.register
-local otftables=otf.tables or {}
-otf.tables=otftables
-local allocate=utilities.storage.allocate
-registerotffeature {
- name="features",
- description="initialization of feature handler",
- default=true,
-}
-local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode=lower(value)
- end
-end
-otf.modeinitializer=setmode
-local function setlanguage(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local languages=otftables and otftables.languages
- local properties=tfmdata.properties
- if not languages then
- properties.language=cleanvalue
- elseif languages[value] then
- properties.language=cleanvalue
- else
- properties.language="dflt"
+local helpers=fonts.helpers
+local setmetatableindex=table.setmetatableindex
+local makeweak=table.makeweak
+local push={ "push" }
+local pop={ "pop" }
+local dummy={ "comment" }
+function helpers.prependcommands(commands,...)
+ insert(commands,1,push)
+ for i=select("#",...),1,-1 do
+ local s=select(i,...)
+ if s then
+ insert(commands,1,s)
end
end
+ insert(commands,pop)
+ return commands
end
-local function setscript(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local scripts=otftables and otftables.scripts
- local properties=tfmdata.properties
- if not scripts then
- properties.script=cleanvalue
- elseif scripts[value] then
- properties.script=cleanvalue
- else
- properties.script="dflt"
+function helpers.appendcommands(commands,...)
+ insert(commands,1,push)
+ insert(commands,pop)
+ for i=1,select("#",...) do
+ local s=select(i,...)
+ if s then
+ insert(commands,s)
end
end
+ return commands
end
-registerotffeature {
- name="mode",
- description="mode",
- initializers={
- base=setmode,
- node=setmode,
- plug=setmode,
- }
-}
-registerotffeature {
- name="language",
- description="language",
- initializers={
- base=setlanguage,
- node=setlanguage,
- plug=setlanguage,
- }
-}
-registerotffeature {
- name="script",
- description="script",
- initializers={
- base=setscript,
- node=setscript,
- plug=setscript,
- }
-}
-otftables.featuretypes=allocate {
- gpos_single="position",
- gpos_pair="position",
- gpos_cursive="position",
- gpos_mark2base="position",
- gpos_mark2ligature="position",
- gpos_mark2mark="position",
- gpos_context="position",
- gpos_contextchain="position",
- gsub_single="substitution",
- gsub_multiple="substitution",
- gsub_alternate="substitution",
- gsub_ligature="substitution",
- gsub_context="substitution",
- gsub_contextchain="substitution",
- gsub_reversecontextchain="substitution",
- gsub_reversesub="substitution",
+local char=setmetatableindex(function(t,k)
+ local v={ "slot",0,k }
+ t[k]=v
+ return v
+end)
+local right=setmetatableindex(function(t,k)
+ local v={ "right",k }
+ t[k]=v
+ return v
+end)
+local left=setmetatableindex(function(t,k)
+ local v={ "right",-k }
+ t[k]=v
+ return v
+end)
+local down=setmetatableindex(function(t,k)
+ local v={ "down",k }
+ t[k]=v
+ return v
+end)
+local up=setmetatableindex(function(t,k)
+ local v={ "down",-k }
+ t[k]=v
+ return v
+end)
+helpers.commands=utilities.storage.allocate {
+ char=char,
+ right=right,
+ left=left,
+ down=down,
+ up=up,
+ push=push,
+ pop=pop,
+ dummy=dummy,
}
-function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
- if featuretype=="position" then
- local default=scripts.dflt
- if default then
- if autoscript=="position" or autoscript==true then
- return default
- else
- report_otf("script feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=scripts.dflt
- if default then
- if autoscript=="substitution" or autoscript==true then
- return default
- end
- end
- end
-end
-function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
- if featuretype=="position" then
- local default=languages.dflt
- if default then
- if autolanguage=="position" or autolanguage==true then
- return default
- else
- report_otf("language feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=languages.dflt
- if default then
- if autolanguage=="substitution" or autolanguage==true then
- return default
- end
- end
- end
-end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oti”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-vfc”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otr” 2bd0085b78027f261218d63034f43474] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otr” 4a1dae571a43d7cb8afce7e906df89c6] ---
if not modules then modules={} end modules ['font-otr']={
version=1.001,
@@ -2411,21 +2694,21 @@ if not modules then modules={} end modules ['font-otr']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local next,type,unpack=next,type,unpack
-local byte,lower,char,strip,gsub=string.byte,string.lower,string.char,string.strip,string.gsub
-local bittest=bit32.btest
-local concat,remove,unpack,fastcopy=table.concat,table.remov,table.unpack,table.fastcopy
-local floor,abs,sqrt,round=math.floor,math.abs,math.sqrt,math.round
+local next,type,tonumber=next,type,tonumber
+local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub
+local floor,round=math.floor,math.round
local 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
local lpegmatch=lpeg.match
+local rshift=bit32.rshift
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
-local stripstring=string.strip
+local stripstring=string.nospaces
local utf16_to_utf8_be=utf.utf16_to_utf8_be
local report=logs.reporter("otf reader")
local trace_cmap=false
+local trace_cmap_detail=false
fonts=fonts or {}
local handlers=fonts.handlers or {}
fonts.handlers=handlers
@@ -2450,27 +2733,50 @@ local readulong=streamreader.readcardinal4
local readshort=streamreader.readinteger2
local readlong=streamreader.readinteger4
local readfixed=streamreader.readfixed4
+local read2dot14=streamreader.read2dot14
local readfword=readshort
local readufword=readushort
local readoffset=readushort
-local read2dot14=streamreader.read2dot14
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
function streamreader.readtag(f)
- return lower(strip(readstring(f,4)))
-end
+ return lower(stripstring(readstring(f,4)))
+end
+local short=2
+local ushort=2
+local ulong=4
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ openfile=streamreader.open
+ closefile=streamreader.close
+ setposition=streamreader.setposition
+ skipshort=streamreader.skipshort
+ readbytes=streamreader.readbytes
+ readstring=streamreader.readstring
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readuint=streamreader.readcardinal3
+ readulong=streamreader.readcardinal4
+ readshort=streamreader.readinteger2
+ readlong=streamreader.readinteger4
+ readfixed=streamreader.readfixed4
+ read2dot14=streamreader.read2dot14
+ readfword=readshort
+ readufword=readushort
+ readoffset=readushort
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+ function streamreader.readtag(f)
+ return lower(stripstring(readstring(f,4)))
+ end
+end)
local function readlongdatetime(f)
local a,b,c,d,e,f,g,h=readbytes(f,8)
return 0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
end
local tableversion=0.004
readers.tableversion=tableversion
-local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
-local reportedskipped={}
-local function reportskippedtable(tag)
- if not reportedskipped[tag] then
- report("loading of table %a skipped (reported once only)",tag)
- reportedskipped[tag]=true
- end
-end
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local reservednames={ [0]="copyright",
"family",
"subfamily",
@@ -2496,6 +2802,7 @@ local reservednames={ [0]="copyright",
"wwssubfamily",
"lightbackgroundpalette",
"darkbackgroundpalette",
+ "variationspostscriptnameprefix",
}
local platforms={ [0]="unicode",
"macintosh",
@@ -2661,6 +2968,37 @@ local panosewidths={
[ 8]="verycondensed",
[ 9]="monospaced",
}
+local helpers={}
+readers.helpers=helpers
+local function gotodatatable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable=fontdata.tables[tag]
+ if datatable then
+ local tableoffset=datatable.offset
+ setposition(f,tableoffset)
+ return tableoffset
+ end
+ end
+end
+local function reportskippedtable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable=fontdata.tables[tag]
+ if datatable then
+ report("loading of table %a skipped",tag)
+ end
+ end
+end
+local function setvariabledata(fontdata,tag,data)
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ variabledata[tag]=data
+ else
+ fontdata.variabledata={ [tag]=data }
+ end
+end
+helpers.gotodatatable=gotodatatable
+helpers.setvariabledata=setvariabledata
+helpers.reportskippedtable=reportskippedtable
local platformnames={
postscriptname=true,
fullname=true,
@@ -2671,13 +3009,12 @@ local platformnames={
compatiblefullname=true,
}
function readers.name(f,fontdata,specification)
- local datatable=fontdata.tables.name
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"name",true)
+ if tableoffset then
local format=readushort(f)
local nofnames=readushort(f)
local offset=readushort(f)
- local start=datatable.offset+offset
+ local start=tableoffset+offset
local namelists={
unicode={},
windows={},
@@ -2696,19 +3033,17 @@ function readers.name(f,fontdata,specification)
local encoding=encodings[encoding]
local language=languages[language]
if encoding and language then
- local name=reservednames[readushort(f)]
- if name then
- namelist[#namelist+1]={
- platform=platform,
- encoding=encoding,
- language=language,
- name=name,
- length=readushort(f),
- offset=start+readushort(f),
- }
- else
- skipshort(f,2)
- end
+ local index=readushort(f)
+ local name=reservednames[index]
+ namelist[#namelist+1]={
+ platform=platform,
+ encoding=encoding,
+ language=language,
+ name=name,
+ index=index,
+ length=readushort(f),
+ offset=start+readushort(f),
+ }
else
skipshort(f,3)
end
@@ -2724,12 +3059,14 @@ function readers.name(f,fontdata,specification)
end
local names={}
local done={}
+ local extras={}
local function filter(platform,e,l)
local namelist=namelists[platform]
for i=1,#namelist do
local name=namelist[i]
local nametag=name.name
- if not done[nametag] then
+ local index=name.index
+ if not done[nametag or i] then
local encoding=name.encoding
local language=name.language
if (not e or encoding==e) and (not l or language==l) then
@@ -2742,13 +3079,16 @@ function readers.name(f,fontdata,specification)
if decoder then
content=decoder(content)
end
- names[nametag]={
- content=content,
- platform=platform,
- encoding=encoding,
- language=language,
- }
- done[nametag]=true
+ if nametag then
+ names[nametag]={
+ content=content,
+ platform=platform,
+ encoding=encoding,
+ language=language,
+ }
+ end
+ extras[index]=content
+ done[nametag or i]=true
end
end
end
@@ -2759,6 +3099,7 @@ function readers.name(f,fontdata,specification)
filter("macintosh")
filter("unicode")
fontdata.names=names
+ fontdata.extras=extras
if specification.platformnames then
local collected={}
for platform,namelist in next,namelists do
@@ -2806,9 +3147,8 @@ local function getname(fontdata,key)
end
end
readers["os/2"]=function(f,fontdata)
- local datatable=fontdata.tables["os/2"]
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"os/2",true)
+ if tableoffset then
local version=readushort(f)
local windowsmetrics={
version=version,
@@ -2858,9 +3198,8 @@ readers["os/2"]=function(f,fontdata)
end
end
readers.head=function(f,fontdata)
- local datatable=fontdata.tables.head
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"head",true)
+ if tableoffset then
local fontheader={
version=readfixed(f),
revision=readfixed(f),
@@ -2887,178 +3226,155 @@ readers.head=function(f,fontdata)
fontdata.nofglyphs=0
end
readers.hhea=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.hhea
- if datatable then
- setposition(f,datatable.offset)
- fontdata.horizontalheader={
- version=readfixed(f),
- ascender=readfword(f),
- descender=readfword(f),
- linegap=readfword(f),
- maxadvancewidth=readufword(f),
- minleftsidebearing=readfword(f),
- minrightsidebearing=readfword(f),
- maxextent=readfword(f),
- caretsloperise=readshort(f),
- caretsloperun=readshort(f),
- caretoffset=readshort(f),
- reserved_1=readshort(f),
- reserved_2=readshort(f),
- reserved_3=readshort(f),
- reserved_4=readshort(f),
- metricdataformat=readshort(f),
- nofmetrics=readushort(f),
- }
- else
- fontdata.horizontalheader={
- nofmetrics=0,
- }
- end
+ local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details)
+ if tableoffset then
+ fontdata.horizontalheader={
+ version=readfixed(f),
+ ascender=readfword(f),
+ descender=readfword(f),
+ linegap=readfword(f),
+ maxadvancewidth=readufword(f),
+ minleftsidebearing=readfword(f),
+ minrightsidebearing=readfword(f),
+ maxextent=readfword(f),
+ caretsloperise=readshort(f),
+ caretsloperun=readshort(f),
+ caretoffset=readshort(f),
+ reserved_1=readshort(f),
+ reserved_2=readshort(f),
+ reserved_3=readshort(f),
+ reserved_4=readshort(f),
+ metricdataformat=readshort(f),
+ nofmetrics=readushort(f),
+ }
+ else
+ fontdata.horizontalheader={
+ nofmetrics=0,
+ }
end
end
readers.vhea=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.vhea
- if datatable then
- setposition(f,datatable.offset)
- local version=readfixed(f)
- fontdata.verticalheader={
+ local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details)
+ if tableoffset then
+ fontdata.verticalheader={
+ version=readfixed(f),
+ ascender=readfword(f),
+ descender=readfword(f),
+ linegap=readfword(f),
+ maxadvanceheight=readufword(f),
+ mintopsidebearing=readfword(f),
+ minbottomsidebearing=readfword(f),
+ maxextent=readfword(f),
+ caretsloperise=readshort(f),
+ caretsloperun=readshort(f),
+ caretoffset=readshort(f),
+ reserved_1=readshort(f),
+ reserved_2=readshort(f),
+ reserved_3=readshort(f),
+ reserved_4=readshort(f),
+ metricdataformat=readshort(f),
+ nofmetrics=readushort(f),
+ }
+ else
+ fontdata.verticalheader={
+ nofmetrics=0,
+ }
+ end
+end
+readers.maxp=function(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"maxp",specification.details)
+ if tableoffset then
+ local version=readfixed(f)
+ local nofglyphs=readushort(f)
+ fontdata.nofglyphs=nofglyphs
+ if version==0.5 then
+ fontdata.maximumprofile={
version=version,
- ascender=readfword(f),
- descender=readfword(f),
- linegap=readfword(f),
- maxadvanceheight=readufword(f),
- mintopsidebearing=readfword(f),
- minbottomsidebearing=readfword(f),
- maxextent=readfword(f),
- caretsloperise=readshort(f),
- caretsloperun=readshort(f),
- caretoffset=readshort(f),
- reserved_1=readshort(f),
- reserved_2=readshort(f),
- reserved_3=readshort(f),
- reserved_4=readshort(f),
- metricdataformat=readshort(f),
- nofmetrics=readushort(f),
+ nofglyphs=nofglyphs,
+ }
+ elseif version==1.0 then
+ fontdata.maximumprofile={
+ version=version,
+ nofglyphs=nofglyphs,
+ points=readushort(f),
+ contours=readushort(f),
+ compositepoints=readushort(f),
+ compositecontours=readushort(f),
+ zones=readushort(f),
+ twilightpoints=readushort(f),
+ storage=readushort(f),
+ functiondefs=readushort(f),
+ instructiondefs=readushort(f),
+ stackelements=readushort(f),
+ sizeofinstructions=readushort(f),
+ componentelements=readushort(f),
+ componentdepth=readushort(f),
}
else
- fontdata.verticalheader={
- nofmetrics=0,
+ fontdata.maximumprofile={
+ version=version,
+ nofglyphs=0,
}
end
end
end
-readers.maxp=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.maxp
- if datatable then
- setposition(f,datatable.offset)
- local version=readfixed(f)
- local nofglyphs=readushort(f)
- fontdata.nofglyphs=nofglyphs
- if version==0.5 then
- fontdata.maximumprofile={
- version=version,
- nofglyphs=nofglyphs,
- }
- return
- elseif version==1.0 then
- fontdata.maximumprofile={
- version=version,
- nofglyphs=nofglyphs,
- points=readushort(f),
- contours=readushort(f),
- compositepoints=readushort(f),
- compositecontours=readushort(f),
- zones=readushort(f),
- twilightpoints=readushort(f),
- storage=readushort(f),
- functiondefs=readushort(f),
- instructiondefs=readushort(f),
- stackelements=readushort(f),
- sizeofinstructions=readushort(f),
- componentelements=readushort(f),
- componentdepth=readushort(f),
- }
- return
- end
- end
- fontdata.maximumprofile={
- version=version,
- nofglyphs=0,
- }
- end
-end
readers.hmtx=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.hmtx
- if datatable then
- setposition(f,datatable.offset)
- local horizontalheader=fontdata.horizontalheader
- local nofmetrics=horizontalheader.nofmetrics
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local width=0
- local leftsidebearing=0
- for i=0,nofmetrics-1 do
- local glyph=glyphs[i]
- width=readshort(f)
- leftsidebearing=readshort(f)
- if width~=0 then
- glyph.width=width
- end
+ local tableoffset=gotodatatable(f,fontdata,"hmtx",specification.glyphs)
+ if tableoffset then
+ local horizontalheader=fontdata.horizontalheader
+ local nofmetrics=horizontalheader.nofmetrics
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local width=0
+ local leftsidebearing=0
+ for i=0,nofmetrics-1 do
+ local glyph=glyphs[i]
+ width=readshort(f)
+ leftsidebearing=readshort(f)
+ if width~=0 then
+ glyph.width=width
end
- for i=nofmetrics,nofglyphs-1 do
- local glyph=glyphs[i]
- if width~=0 then
- glyph.width=width
- end
+ end
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph=glyphs[i]
+ if width~=0 then
+ glyph.width=width
end
end
end
end
readers.vmtx=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.vmtx
- if datatable then
- setposition(f,datatable.offset)
- local verticalheader=fontdata.verticalheader
- local nofmetrics=verticalheader.nofmetrics
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local vheight=0
- local vdefault=verticalheader.ascender+verticalheader.descender
- local topsidebearing=0
- for i=0,nofmetrics-1 do
- local glyph=glyphs[i]
- vheight=readshort(f)
- topsidebearing=readshort(f)
- if vheight~=0 and vheight~=vdefault then
- glyph.vheight=vheight
- end
+ local tableoffset=gotodatatable(f,fontdata,"vmtx",specification.glyphs)
+ if tableoffset then
+ local verticalheader=fontdata.verticalheader
+ local nofmetrics=verticalheader.nofmetrics
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local vheight=0
+ local vdefault=verticalheader.ascender+verticalheader.descender
+ local topsidebearing=0
+ for i=0,nofmetrics-1 do
+ local glyph=glyphs[i]
+ vheight=readshort(f)
+ topsidebearing=readshort(f)
+ if vheight~=0 and vheight~=vdefault then
+ glyph.vheight=vheight
end
- for i=nofmetrics,nofglyphs-1 do
- local glyph=glyphs[i]
- if vheight~=0 and vheight~=vdefault then
- glyph.vheight=vheight
- end
+ end
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph=glyphs[i]
+ if vheight~=0 and vheight~=vdefault then
+ glyph.vheight=vheight
end
end
end
end
readers.vorg=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.vorg
- if datatable then
- report("todo: %s","vorg")
- end
- end
+ reportskippedtable(f,fontdata,"vorg",specification.glyphs)
end
readers.post=function(f,fontdata,specification)
- local datatable=fontdata.tables.post
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"post",true)
+ if tableoffset then
local version=readfixed(f)
fontdata.postscript={
version=version,
@@ -3115,9 +3431,7 @@ readers.post=function(f,fontdata,specification)
end
end
readers.cff=function(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cff")
- end
+ reportskippedtable(f,fontdata,"cff",specification.glyphs)
end
local formatreaders={}
local duplicatestoo=true
@@ -3129,11 +3443,13 @@ local sequence={
{ 0,0,6 },
{ 3,0,6 },
{ 0,5,14 },
+{ 0,4,12 },
{ 3,10,13 },
}
local supported={}
for i=1,#sequence do
- local sp,se,sf=unpack(sequence[i])
+ local si=sequence[i]
+ local sp,se,sf=si[1],si[2],si[3]
local p=supported[sp]
if not p then
p={}
@@ -3152,32 +3468,17 @@ formatreaders[4]=function(f,fontdata,offset)
local language=readushort(f)
local nofsegments=readushort(f)/2
skipshort(f,3)
- local endchars={}
- local startchars={}
- local deltas={}
- local offsets={}
- local indices={}
local mapping=fontdata.mapping
local glyphs=fontdata.glyphs
local duplicates=fontdata.duplicates
local nofdone=0
- for i=1,nofsegments do
- endchars[i]=readushort(f)
- end
+ local endchars=readcardinaltable(f,nofsegments,ushort)
local reserved=readushort(f)
- for i=1,nofsegments do
- startchars[i]=readushort(f)
- end
- for i=1,nofsegments do
- deltas[i]=readshort(f)
- end
- for i=1,nofsegments do
- offsets[i]=readushort(f)
- end
- local size=(length-2*2-5*2-4*nofsegments*2)/2
- for i=1,size-1 do
- indices[i]=readushort(f)
- end
+ local startchars=readcardinaltable(f,nofsegments,ushort)
+ local deltas=readcardinaltable(f,nofsegments,ushort)
+ local offsets=readcardinaltable(f,nofsegments,ushort)
+ local size=(length-2*2-5*2-4*2*nofsegments)/2
+ local indices=readcardinaltable(f,size-1,ushort)
for segment=1,nofsegments do
local startchar=startchars[segment]
local endchar=endchars[segment]
@@ -3187,7 +3488,7 @@ formatreaders[4]=function(f,fontdata,offset)
elseif startchar==0xFFFF and offset==0 then
elseif offset==0xFFFF then
elseif offset==0 then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar+delta)%65536)
end
for unicode=startchar,endchar do
@@ -3219,7 +3520,7 @@ formatreaders[4]=function(f,fontdata,offset)
end
else
local shift=(segment-nofsegments+offset/2)-startchar
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536)
end
for unicode=startchar,endchar do
@@ -3267,7 +3568,7 @@ formatreaders[6]=function(f,fontdata,offset)
local count=readushort(f)
local stop=start+count-1
local nofdone=0
- if trace_cmap then
+ if trace_cmap_detail then
report("format 6 from %C to %C",2,start,stop)
end
for unicode=start,stop do
@@ -3300,7 +3601,7 @@ formatreaders[12]=function(f,fontdata,offset)
local first=readulong(f)
local last=readulong(f)
local index=readulong(f)
- if trace_cmap then
+ if trace_cmap_detail then
report("format 12 from %C to %C starts at index %i",first,last,index)
end
for unicode=first,last do
@@ -3339,7 +3640,7 @@ formatreaders[13]=function(f,fontdata,offset)
local last=readulong(f)
local index=readulong(f)
if first<privateoffset then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 13 from %C to %C get index %i",first,last,index)
end
local glyph=glyphs[index]
@@ -3429,75 +3730,81 @@ local function checkcmap(f,fontdata,records,platform,encoding,format)
local p=platforms[platform]
local e=encodings[p]
local n=reader(f,fontdata,data) or 0
- report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ if trace_cmap then
+ report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ end
return n
end
function readers.cmap(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.cmap
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- local noftables=readushort(f)
- local records={}
- local unicodecid=false
- local variantcid=false
- local variants={}
- local duplicates=fontdata.duplicates or {}
- fontdata.duplicates=duplicates
- for i=1,noftables do
- local platform=readushort(f)
- local encoding=readushort(f)
- local offset=readulong(f)
- local record=records[platform]
- if not record then
- records[platform]={
- [encoding]={
- offsets={ offset },
- formats={},
- }
+ local tableoffset=gotodatatable(f,fontdata,"cmap",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local noftables=readushort(f)
+ local records={}
+ local unicodecid=false
+ local variantcid=false
+ local variants={}
+ local duplicates=fontdata.duplicates or {}
+ fontdata.duplicates=duplicates
+ for i=1,noftables do
+ local platform=readushort(f)
+ local encoding=readushort(f)
+ local offset=readulong(f)
+ local record=records[platform]
+ if not record then
+ records[platform]={
+ [encoding]={
+ offsets={ offset },
+ formats={},
+ }
+ }
+ else
+ local subtables=record[encoding]
+ if not subtables then
+ record[encoding]={
+ offsets={ offset },
+ formats={},
}
else
- local subtables=record[encoding]
- if not subtables then
- record[encoding]={
- offsets={ offset },
- formats={},
- }
- else
- local offsets=subtables.offsets
- offsets[#offsets+1]=offset
- end
+ local offsets=subtables.offsets
+ offsets[#offsets+1]=offset
end
end
+ end
+ if trace_cmap then
report("found cmaps:")
- for platform,record in sortedhash(records) do
- local p=platforms[platform]
- local e=encodings[p]
- local sp=supported[platform]
- local ps=p or "?"
+ end
+ for platform,record in sortedhash(records) do
+ local p=platforms[platform]
+ local e=encodings[p]
+ local sp=supported[platform]
+ local ps=p or "?"
+ if trace_cmap then
if sp then
report(" platform %i: %s",platform,ps)
else
report(" platform %i: %s (unsupported)",platform,ps)
end
- for encoding,subtables in sortedhash(record) do
- local se=sp and sp[encoding]
- local es=e and e[encoding] or "?"
+ end
+ for encoding,subtables in sortedhash(record) do
+ local se=sp and sp[encoding]
+ local es=e and e[encoding] or "?"
+ if trace_cmap then
if se then
report(" encoding %i: %s",encoding,es)
else
report(" encoding %i: %s (unsupported)",encoding,es)
end
- local offsets=subtables.offsets
- local formats=subtables.formats
- for i=1,#offsets do
- local offset=tableoffset+offsets[i]
- setposition(f,offset)
- formats[readushort(f)]=offset
- end
- record[encoding]=formats
+ end
+ local offsets=subtables.offsets
+ local formats=subtables.formats
+ for i=1,#offsets do
+ local offset=tableoffset+offsets[i]
+ setposition(f,offset)
+ formats[readushort(f)]=offset
+ end
+ record[encoding]=formats
+ if trace_cmap then
local list=sortedkeys(formats)
for i=1,#list do
if not (se and se[list[i]]) then
@@ -3507,112 +3814,110 @@ function readers.cmap(f,fontdata,specification)
report(" formats: % t",list)
end
end
- local ok=false
- for i=1,#sequence do
- local sp,se,sf=unpack(sequence[i])
- if checkcmap(f,fontdata,records,sp,se,sf)>0 then
- ok=true
- end
- end
- if not ok then
- report("no useable unicode cmap found")
+ end
+ local ok=false
+ for i=1,#sequence do
+ local si=sequence[i]
+ local sp,se,sf=si[1],si[2],si[3]
+ if checkcmap(f,fontdata,records,sp,se,sf)>0 then
+ ok=true
end
- fontdata.cidmaps={
- version=version,
- noftables=noftables,
- records=records,
- }
- else
- fontdata.cidmaps={}
end
+ if not ok then
+ report("no useable unicode cmap found")
+ end
+ fontdata.cidmaps={
+ version=version,
+ noftables=noftables,
+ records=records,
+ }
+ else
+ fontdata.cidmaps={}
end
end
function readers.loca(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("loca")
- end
+ reportskippedtable(f,fontdata,"loca",specification.glyphs)
end
function readers.glyf(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("glyf")
- end
+ reportskippedtable(f,fontdata,"glyf",specification.glyphs)
end
function readers.colr(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("colr")
- end
+ reportskippedtable(f,fontdata,"colr",specification.glyphs)
end
function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cpal")
- end
+ reportskippedtable(f,fontdata,"cpal",specification.glyphs)
end
function readers.svg(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("svg")
- end
+ reportskippedtable(f,fontdata,"svg",specification.glyphs)
+end
+function readers.sbix(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"sbix",specification.glyphs)
+end
+function readers.cbdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cbdt",specification.glyphs)
+end
+function readers.cblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cblc",specification.glyphs)
+end
+function readers.ebdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebdt",specification.glyphs)
+end
+function readers.ebsc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebsc",specification.glyphs)
+end
+function readers.eblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"eblc",specification.glyphs)
end
function readers.kern(f,fontdata,specification)
- if specification.kerns then
- local datatable=fontdata.tables.kern
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"kern",specification.kerns)
+ if tableoffset then
+ local version=readushort(f)
+ local noftables=readushort(f)
+ for i=1,noftables do
local version=readushort(f)
- local noftables=readushort(f)
- for i=1,noftables do
- local version=readushort(f)
- local length=readushort(f)
- local coverage=readushort(f)
- local format=bit32.rshift(coverage,8)
- if format==0 then
- local nofpairs=readushort(f)
- local searchrange=readushort(f)
- local entryselector=readushort(f)
- local rangeshift=readushort(f)
- local kerns={}
- local glyphs=fontdata.glyphs
- for i=1,nofpairs do
- local left=readushort(f)
- local right=readushort(f)
- local kern=readfword(f)
- local glyph=glyphs[left]
- local kerns=glyph.kerns
- if kerns then
- kerns[right]=kern
- else
- glyph.kerns={ [right]=kern }
- end
+ local length=readushort(f)
+ local coverage=readushort(f)
+ local format=rshift(coverage,8)
+ if format==0 then
+ local nofpairs=readushort(f)
+ local searchrange=readushort(f)
+ local entryselector=readushort(f)
+ local rangeshift=readushort(f)
+ local kerns={}
+ local glyphs=fontdata.glyphs
+ for i=1,nofpairs do
+ local left=readushort(f)
+ local right=readushort(f)
+ local kern=readfword(f)
+ local glyph=glyphs[left]
+ local kerns=glyph.kerns
+ if kerns then
+ kerns[right]=kern
+ else
+ glyph.kerns={ [right]=kern }
end
- elseif format==2 then
- report("todo: kern classes")
- else
- report("todo: kerns")
end
+ elseif format==2 then
+ report("todo: kern classes")
+ else
+ report("todo: kerns")
end
end
end
end
function readers.gdef(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gdef")
- end
+ reportskippedtable(f,fontdata,"gdef",specification.details)
end
function readers.gsub(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gsub")
- end
+ reportskippedtable(f,fontdata,"gsub",specification.details)
end
function readers.gpos(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gpos")
- end
+ reportskippedtable(f,fontdata,"gpos",specification.details)
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("math")
- end
+ reportskippedtable(f,fontdata,"math",specification.details)
end
-local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
+local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames)
local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata
local names=fontdata.names
local info=nil
@@ -3636,6 +3941,25 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
if not familyname then familyname=family end
if not subfamilyname then subfamilyname=subfamily end
end
+ if platformnames then
+ platformnames=fontdata.platformnames
+ end
+ if instancenames then
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata and variabledata.instances
+ if instances then
+ instancenames={}
+ for i=1,#instances do
+ instancenames[i]=lower(stripstring(instances[i].subfamily))
+ end
+ else
+ instancenames=nil
+ end
+ else
+ instancenames=nil
+ end
+ end
info={
subfontindex=fontdata.subfontindex or sub or 0,
version=getname(fontdata,"version"),
@@ -3663,7 +3987,8 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
capheight=metrics.capheight,
ascender=metrics.typoascender,
descender=metrics.typodescender,
- platformnames=platformnames and fontdata.platformnames or nil,
+ platformnames=platformnames or nil,
+ instancenames=instancenames or nil,
}
if metricstoo then
local keys={
@@ -3717,6 +4042,7 @@ local function loadtables(f,specification,offset)
entryselector=readushort(f),
rangeshift=readushort(f),
tables=tables,
+ foundtables=false,
}
for i=1,fontdata.noftables do
local tag=lower(stripstring(readstring(f,4)))
@@ -3732,7 +4058,8 @@ local function loadtables(f,specification,offset)
length=length,
}
end
- if tables.cff then
+ fontdata.foundtables=sortedkeys(tables)
+ if tables.cff or tables.cff2 then
fontdata.format="opentype"
else
fontdata.format="truetype"
@@ -3750,12 +4077,25 @@ local function prepareglyps(fontdata)
fontdata.glyphs=glyphs
fontdata.mapping={}
end
+local function readtable(tag,f,fontdata,specification,...)
+ local reader=readers[tag]
+ if reader then
+ reader(f,fontdata,specification,...)
+ end
+end
+local variablefonts_supported=(context and true) or (logs and logs.application and true) or false
local function readdata(f,offset,specification)
local fontdata=loadtables(f,specification,offset)
if specification.glyphs then
prepareglyps(fontdata)
end
- readers["name"](f,fontdata,specification)
+ if not variablefonts_supported then
+ specification.instance=nil
+ specification.variable=nil
+ specification.factors=nil
+ end
+ fontdata.temporary={}
+ readtable("name",f,fontdata,specification)
local askedname=specification.askedname
if askedname then
local fullname=getname(fontdata,"fullname") or ""
@@ -3765,27 +4105,95 @@ local function readdata(f,offset,specification)
return
end
end
- readers["os/2"](f,fontdata,specification)
- readers["head"](f,fontdata,specification)
- readers["maxp"](f,fontdata,specification)
- readers["hhea"](f,fontdata,specification)
- readers["vhea"](f,fontdata,specification)
- readers["hmtx"](f,fontdata,specification)
- readers["vmtx"](f,fontdata,specification)
- readers["vorg"](f,fontdata,specification)
- readers["post"](f,fontdata,specification)
- readers["cff" ](f,fontdata,specification)
- readers["cmap"](f,fontdata,specification)
- readers["loca"](f,fontdata,specification)
- readers["glyf"](f,fontdata,specification)
- readers["colr"](f,fontdata,specification)
- readers["cpal"](f,fontdata,specification)
- readers["svg" ](f,fontdata,specification)
- readers["kern"](f,fontdata,specification)
- readers["gdef"](f,fontdata,specification)
- readers["gsub"](f,fontdata,specification)
- readers["gpos"](f,fontdata,specification)
- readers["math"](f,fontdata,specification)
+ readtable("stat",f,fontdata,specification)
+ readtable("avar",f,fontdata,specification)
+ readtable("fvar",f,fontdata,specification)
+ if variablefonts_supported then
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ if axis and (not instances or #instances==0) then
+ instances={}
+ variabledata.instances=instances
+ local function add(n,subfamily,value)
+ local values={}
+ for i=1,#axis do
+ local a=axis[i]
+ values[i]={
+ axis=a.tag,
+ value=i==n and value or a.default,
+ }
+ end
+ instances[#instances+1]={
+ subfamily=subfamily,
+ values=values,
+ }
+ end
+ for i=1,#axis do
+ local a=axis[i]
+ local tag=a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
+ end
+ end
+ end
+ if not specification.factors then
+ local instance=specification.instance
+ if type(instance)=="string" then
+ local factors=helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ fontdata.instance=instance
+ report("user instance: %s, factors: % t",instance,factors)
+ else
+ report("user instance: %s, bad factors",instance)
+ end
+ end
+ end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors=helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ end
+ else
+ end
+ end
+ end
+ readtable("os/2",f,fontdata,specification)
+ readtable("head",f,fontdata,specification)
+ readtable("maxp",f,fontdata,specification)
+ readtable("hhea",f,fontdata,specification)
+ readtable("vhea",f,fontdata,specification)
+ readtable("hmtx",f,fontdata,specification)
+ readtable("vmtx",f,fontdata,specification)
+ readtable("vorg",f,fontdata,specification)
+ readtable("post",f,fontdata,specification)
+ readtable("mvar",f,fontdata,specification)
+ readtable("hvar",f,fontdata,specification)
+ readtable("vvar",f,fontdata,specification)
+ readtable("gdef",f,fontdata,specification)
+ readtable("cff",f,fontdata,specification)
+ readtable("cff2",f,fontdata,specification)
+ readtable("cmap",f,fontdata,specification)
+ readtable("loca",f,fontdata,specification)
+ readtable("glyf",f,fontdata,specification)
+ readtable("colr",f,fontdata,specification)
+ readtable("cpal",f,fontdata,specification)
+ readtable("svg",f,fontdata,specification)
+ readtable("sbix",f,fontdata,specification)
+ readtable("cbdt",f,fontdata,specification)
+ readtable("cblc",f,fontdata,specification)
+ readtable("ebdt",f,fontdata,specification)
+ readtable("eblc",f,fontdata,specification)
+ readtable("kern",f,fontdata,specification)
+ readtable("gsub",f,fontdata,specification)
+ readtable("gpos",f,fontdata,specification)
+ readtable("math",f,fontdata,specification)
fontdata.locations=nil
fontdata.tables=nil
fontdata.cidmaps=nil
@@ -3812,12 +4220,9 @@ local function loadfontdata(specification)
fontdata=readdata(f,0,specification)
elseif version=="ttcf" then
local subfont=tonumber(specification.subfont)
- local offsets={}
local ttcversion=readulong(f)
local nofsubfonts=readulong(f)
- for i=1,nofsubfonts do
- offsets[i]=readulong(f)
- end
+ local offsets=readcardinaltable(f,nofsubfonts,ulong)
if subfont then
if subfont>=1 and subfont<=nofsubfonts then
fontdata=readdata(f,offsets[subfont],specification)
@@ -3862,7 +4267,7 @@ local function loadfontdata(specification)
return fontdata or {}
end
end
-local function loadfont(specification,n)
+local function loadfont(specification,n,instance)
if type(specification)=="string" then
specification={
filename=specification,
@@ -3871,10 +4276,12 @@ local function loadfont(specification,n)
glyphs=true,
shapes=true,
kerns=true,
+ variable=true,
globalkerns=true,
lookups=true,
subfont=n or true,
tounicode=false,
+ instance=instance
}
end
if specification.shapes or specification.lookups or specification.kerns then
@@ -3889,6 +4296,10 @@ local function loadfont(specification,n)
if specification.platformnames then
specification.platformnames=true
end
+ if specification.instance or instance then
+ specification.variable=true
+ specification.instance=specification.instance or instance
+ end
local function message(str)
report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback())
end
@@ -3897,11 +4308,14 @@ local function loadfont(specification,n)
return result
end
end
-function readers.loadshapes(filename,n)
+function readers.loadshapes(filename,n,instance,streams)
local fontdata=loadfont {
filename=filename,
shapes=true,
+ streams=streams,
+ variable=true,
subfont=n,
+ instance=instance,
}
if fontdata then
for k,v in next,fontdata.glyphs do
@@ -3922,13 +4336,15 @@ function readers.loadshapes(filename,n)
units=0,
}
end
-function readers.loadfont(filename,n)
+function readers.loadfont(filename,n,instance)
local fontdata=loadfont {
filename=filename,
glyphs=true,
shapes=false,
lookups=true,
+ variable=true,
subfont=n,
+ instance=instance,
}
if fontdata then
return {
@@ -3940,11 +4356,13 @@ function readers.loadfont(filename,n)
descriptions=fontdata.descriptions,
format=fontdata.format,
goodies={},
- metadata=getinfo(fontdata,n,false,false,true),
+ metadata=getinfo(fontdata,n,false,false,true,true),
properties={
hasitalics=fontdata.hasitalics or false,
maxcolorclass=fontdata.maxcolorclass,
hascolor=fontdata.hascolor or false,
+ instance=fontdata.instance,
+ factors=fontdata.factors,
},
resources={
filename=filename,
@@ -3962,6 +4380,9 @@ function readers.loadfont(filename,n)
mathconstants=fontdata.mathconstants,
colorpalettes=fontdata.colorpalettes,
svgshapes=fontdata.svgshapes,
+ sbixshapes=fontdata.sbixshapes,
+ variabledata=fontdata.variabledata,
+ foundtables=fontdata.foundtables,
},
}
end
@@ -3970,6 +4391,7 @@ function readers.getinfo(filename,specification)
local subfont=nil
local platformnames=false
local rawfamilynames=false
+ local instancenames=true
if type(specification)=="table" then
subfont=tonumber(specification.subfont)
platformnames=specification.platformnames
@@ -3981,19 +4403,20 @@ function readers.getinfo(filename,specification)
filename=filename,
details=true,
platformnames=platformnames,
+ instancenames=true,
}
if fontdata then
local subfonts=fontdata.subfonts
if not subfonts then
- return getinfo(fontdata,nil,platformnames,rawfamilynames)
+ return getinfo(fontdata,nil,platformnames,rawfamilynames,false,instancenames)
elseif not subfont then
local info={}
for i=1,#subfonts do
- info[i]=getinfo(fontdata,i,platformnames,rawfamilynames)
+ info[i]=getinfo(fontdata,i,platformnames,rawfamilynames,false,instancenames)
end
return info
elseif subfont>=1 and subfont<=#subfonts then
- return getinfo(fontdata,subfont,platformnames,rawfamilynames)
+ return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames)
else
return {
filename=filename,
@@ -4040,10 +4463,1205 @@ function readers.extend(fontdata)
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otr”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otr”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cff” f3fc74e8629f7a2825c34a34550c790d] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oti” 309a75f9c14b77d87e94eba827dc4e71] ---
+
+if not modules then modules={} end modules ['font-oti']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local lower=string.lower
+local fonts=fonts
+local constructors=fonts.constructors
+local otf=constructors.handlers.otf
+local otffeatures=constructors.features.otf
+local registerotffeature=otffeatures.register
+local otftables=otf.tables or {}
+otf.tables=otftables
+local allocate=utilities.storage.allocate
+registerotffeature {
+ name="features",
+ description="initialization of feature handler",
+ default=true,
+}
+local function setmode(tfmdata,value)
+ if value then
+ tfmdata.properties.mode=lower(value)
+ end
+end
+otf.modeinitializer=setmode
+local function setlanguage(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local languages=otftables and otftables.languages
+ local properties=tfmdata.properties
+ if not languages then
+ properties.language=cleanvalue
+ elseif languages[value] then
+ properties.language=cleanvalue
+ else
+ properties.language="dflt"
+ end
+ end
+end
+local function setscript(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local scripts=otftables and otftables.scripts
+ local properties=tfmdata.properties
+ if not scripts then
+ properties.script=cleanvalue
+ elseif scripts[value] then
+ properties.script=cleanvalue
+ else
+ properties.script="dflt"
+ end
+ end
+end
+registerotffeature {
+ name="mode",
+ description="mode",
+ initializers={
+ base=setmode,
+ node=setmode,
+ plug=setmode,
+ }
+}
+registerotffeature {
+ name="language",
+ description="language",
+ initializers={
+ base=setlanguage,
+ node=setlanguage,
+ plug=setlanguage,
+ }
+}
+registerotffeature {
+ name="script",
+ description="script",
+ initializers={
+ base=setscript,
+ node=setscript,
+ plug=setscript,
+ }
+}
+otftables.featuretypes=allocate {
+ gpos_single="position",
+ gpos_pair="position",
+ gpos_cursive="position",
+ gpos_mark2base="position",
+ gpos_mark2ligature="position",
+ gpos_mark2mark="position",
+ gpos_context="position",
+ gpos_contextchain="position",
+ gsub_single="substitution",
+ gsub_multiple="substitution",
+ gsub_alternate="substitution",
+ gsub_ligature="substitution",
+ gsub_context="substitution",
+ gsub_contextchain="substitution",
+ gsub_reversecontextchain="substitution",
+ gsub_reversesub="substitution",
+}
+function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
+ if featuretype=="position" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="position" or autoscript==true then
+ return default
+ else
+ report_otf("script feature %s not applied, enable default positioning")
+ end
+ else
+ end
+ elseif featuretype=="substitution" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="substitution" or autoscript==true then
+ return default
+ end
+ end
+ end
+end
+function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
+ if featuretype=="position" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="position" or autolanguage==true then
+ return default
+ else
+ report_otf("language feature %s not applied, enable default positioning")
+ end
+ else
+ end
+ elseif featuretype=="substitution" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="substitution" or autolanguage==true then
+ return default
+ end
+ end
+ end
+end
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oti”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ott” a4dd9bc516bdb7669ee61d5207f899c6] ---
+
+if not modules then modules={} end modules ["font-ott"]={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files",
+}
+local type,next,tonumber,tostring,rawget,rawset=type,next,tonumber,tostring,rawget,rawset
+local gsub,lower,format,match,gmatch,find=string.gsub,string.lower,string.format,string.match,string.gmatch,string.find
+local sequenced=table.sequenced
+local is_boolean=string.is_boolean
+local setmetatableindex=table.setmetatableindex
+local setmetatablenewindex=table.setmetatablenewindex
+local allocate=utilities.storage.allocate
+local fonts=fonts
+local otf=fonts.handlers.otf
+local otffeatures=otf.features
+local tables=otf.tables or {}
+otf.tables=tables
+local statistics=otf.statistics or {}
+otf.statistics=statistics
+local scripts=allocate {
+ ["arab"]="arabic",
+ ["armi"]="imperial aramaic",
+ ["armn"]="armenian",
+ ["avst"]="avestan",
+ ["bali"]="balinese",
+ ["bamu"]="bamum",
+ ["batk"]="batak",
+ ["beng"]="bengali",
+ ["bng2"]="bengali variant 2",
+ ["bopo"]="bopomofo",
+ ["brah"]="brahmi",
+ ["brai"]="braille",
+ ["bugi"]="buginese",
+ ["buhd"]="buhid",
+ ["byzm"]="byzantine music",
+ ["cakm"]="chakma",
+ ["cans"]="canadian syllabics",
+ ["cari"]="carian",
+ ["cham"]="cham",
+ ["cher"]="cherokee",
+ ["copt"]="coptic",
+ ["cprt"]="cypriot syllabary",
+ ["cyrl"]="cyrillic",
+ ["deva"]="devanagari",
+ ["dev2"]="devanagari variant 2",
+ ["dsrt"]="deseret",
+ ["egyp"]="egyptian heiroglyphs",
+ ["ethi"]="ethiopic",
+ ["geor"]="georgian",
+ ["glag"]="glagolitic",
+ ["goth"]="gothic",
+ ["grek"]="greek",
+ ["gujr"]="gujarati",
+ ["gjr2"]="gujarati variant 2",
+ ["guru"]="gurmukhi",
+ ["gur2"]="gurmukhi variant 2",
+ ["hang"]="hangul",
+ ["hani"]="cjk ideographic",
+ ["hano"]="hanunoo",
+ ["hebr"]="hebrew",
+ ["ital"]="old italic",
+ ["jamo"]="hangul jamo",
+ ["java"]="javanese",
+ ["kali"]="kayah li",
+ ["kana"]="hiragana and katakana",
+ ["khar"]="kharosthi",
+ ["khmr"]="khmer",
+ ["knda"]="kannada",
+ ["knd2"]="kannada variant 2",
+ ["kthi"]="kaithi",
+ ["lana"]="tai tham",
+ ["lao" ]="lao",
+ ["latn"]="latin",
+ ["lepc"]="lepcha",
+ ["limb"]="limbu",
+ ["linb"]="linear b",
+ ["lisu"]="lisu",
+ ["lyci"]="lycian",
+ ["lydi"]="lydian",
+ ["mand"]="mandaic and mandaean",
+ ["math"]="mathematical alphanumeric symbols",
+ ["merc"]="meroitic cursive",
+ ["mero"]="meroitic hieroglyphs",
+ ["mlym"]="malayalam",
+ ["mlm2"]="malayalam variant 2",
+ ["mong"]="mongolian",
+ ["mtei"]="meitei Mayek",
+ ["musc"]="musical symbols",
+ ["mym2"]="myanmar variant 2",
+ ["mymr"]="myanmar",
+ ["nko" ]='n"ko',
+ ["ogam"]="ogham",
+ ["olck"]="ol chiki",
+ ["orkh"]="old turkic and orkhon runic",
+ ["orya"]="oriya",
+ ["ory2"]="odia variant 2",
+ ["osma"]="osmanya",
+ ["phag"]="phags-pa",
+ ["phli"]="inscriptional pahlavi",
+ ["phnx"]="phoenician",
+ ["prti"]="inscriptional parthian",
+ ["rjng"]="rejang",
+ ["runr"]="runic",
+ ["samr"]="samaritan",
+ ["sarb"]="old south arabian",
+ ["saur"]="saurashtra",
+ ["shaw"]="shavian",
+ ["shrd"]="sharada",
+ ["sinh"]="sinhala",
+ ["sora"]="sora sompeng",
+ ["sund"]="sundanese",
+ ["sylo"]="syloti nagri",
+ ["syrc"]="syriac",
+ ["tagb"]="tagbanwa",
+ ["takr"]="takri",
+ ["tale"]="tai le",
+ ["talu"]="tai lu",
+ ["taml"]="tamil",
+ ["tavt"]="tai viet",
+ ["telu"]="telugu",
+ ["tel2"]="telugu variant 2",
+ ["tfng"]="tifinagh",
+ ["tglg"]="tagalog",
+ ["thaa"]="thaana",
+ ["thai"]="thai",
+ ["tibt"]="tibetan",
+ ["tml2"]="tamil variant 2",
+ ["ugar"]="ugaritic cuneiform",
+ ["vai" ]="vai",
+ ["xpeo"]="old persian cuneiform",
+ ["xsux"]="sumero-akkadian cuneiform",
+ ["yi" ]="yi",
+}
+local languages=allocate {
+ ["aba" ]="abaza",
+ ["abk" ]="abkhazian",
+ ["ach" ]="acholi",
+ ["acr" ]="achi",
+ ["ady" ]="adyghe",
+ ["afk" ]="afrikaans",
+ ["afr" ]="afar",
+ ["agw" ]="agaw",
+ ["aio" ]="aiton",
+ ["aka" ]="akan",
+ ["als" ]="alsatian",
+ ["alt" ]="altai",
+ ["amh" ]="amharic",
+ ["ang" ]="anglo-saxon",
+ ["apph"]="phonetic transcription—americanist conventions",
+ ["ara" ]="arabic",
+ ["arg" ]="aragonese",
+ ["ari" ]="aari",
+ ["ark" ]="rakhine",
+ ["asm" ]="assamese",
+ ["ast" ]="asturian",
+ ["ath" ]="athapaskan",
+ ["avr" ]="avar",
+ ["awa" ]="awadhi",
+ ["aym" ]="aymara",
+ ["azb" ]="torki",
+ ["aze" ]="azerbaijani",
+ ["bad" ]="badaga",
+ ["bad0"]="banda",
+ ["bag" ]="baghelkhandi",
+ ["bal" ]="balkar",
+ ["ban" ]="balinese",
+ ["bar" ]="bavarian",
+ ["bau" ]="baulé",
+ ["bbc" ]="batak toba",
+ ["bbr" ]="berber",
+ ["bch" ]="bench",
+ ["bcr" ]="bible cree",
+ ["bdy" ]="bandjalang",
+ ["bel" ]="belarussian",
+ ["bem" ]="bemba",
+ ["ben" ]="bengali",
+ ["bgc" ]="haryanvi",
+ ["bgq" ]="bagri",
+ ["bgr" ]="bulgarian",
+ ["bhi" ]="bhili",
+ ["bho" ]="bhojpuri",
+ ["bik" ]="bikol",
+ ["bil" ]="bilen",
+ ["bis" ]="bislama",
+ ["bjj" ]="kanauji",
+ ["bkf" ]="blackfoot",
+ ["bli" ]="baluchi",
+ ["blk" ]="pa'o karen",
+ ["bln" ]="balante",
+ ["blt" ]="balti",
+ ["bmb" ]="bambara (bamanankan)",
+ ["bml" ]="bamileke",
+ ["bos" ]="bosnian",
+ ["bpy" ]="bishnupriya manipuri",
+ ["bre" ]="breton",
+ ["brh" ]="brahui",
+ ["bri" ]="braj bhasha",
+ ["brm" ]="burmese",
+ ["brx" ]="bodo",
+ ["bsh" ]="bashkir",
+ ["bti" ]="beti",
+ ["bts" ]="batak simalungun",
+ ["bug" ]="bugis",
+ ["cak" ]="kaqchikel",
+ ["cat" ]="catalan",
+ ["cbk" ]="zamboanga chavacano",
+ ["ceb" ]="cebuano",
+ ["cgg" ]="chiga",
+ ["cha" ]="chamorro",
+ ["che" ]="chechen",
+ ["chg" ]="chaha gurage",
+ ["chh" ]="chattisgarhi",
+ ["chi" ]="chichewa (chewa, nyanja)",
+ ["chk" ]="chukchi",
+ ["chk0"]="chuukese",
+ ["cho" ]="choctaw",
+ ["chp" ]="chipewyan",
+ ["chr" ]="cherokee",
+ ["chu" ]="chuvash",
+ ["chy" ]="cheyenne",
+ ["cmr" ]="comorian",
+ ["cop" ]="coptic",
+ ["cor" ]="cornish",
+ ["cos" ]="corsican",
+ ["cpp" ]="creoles",
+ ["cre" ]="cree",
+ ["crr" ]="carrier",
+ ["crt" ]="crimean tatar",
+ ["csb" ]="kashubian",
+ ["csl" ]="church slavonic",
+ ["csy" ]="czech",
+ ["ctg" ]="chittagonian",
+ ["cuk" ]="san blas kuna",
+ ["dan" ]="danish",
+ ["dar" ]="dargwa",
+ ["dax" ]="dayi",
+ ["dcr" ]="woods cree",
+ ["deu" ]="german",
+ ["dgo" ]="dogri",
+ ["dgr" ]="dogri",
+ ["dhg" ]="dhangu",
+ ["dhv" ]="divehi (dhivehi, maldivian)",
+ ["diq" ]="dimli",
+ ["div" ]="divehi (dhivehi, maldivian)",
+ ["djr" ]="zarma",
+ ["djr0"]="djambarrpuyngu",
+ ["dng" ]="dangme",
+ ["dnj" ]="dan",
+ ["dnk" ]="dinka",
+ ["dri" ]="dari",
+ ["duj" ]="dhuwal",
+ ["dun" ]="dungan",
+ ["dzn" ]="dzongkha",
+ ["ebi" ]="ebira",
+ ["ecr" ]="eastern cree",
+ ["edo" ]="edo",
+ ["efi" ]="efik",
+ ["ell" ]="greek",
+ ["emk" ]="eastern maninkakan",
+ ["eng" ]="english",
+ ["erz" ]="erzya",
+ ["esp" ]="spanish",
+ ["esu" ]="central yupik",
+ ["eti" ]="estonian",
+ ["euq" ]="basque",
+ ["evk" ]="evenki",
+ ["evn" ]="even",
+ ["ewe" ]="ewe",
+ ["fan" ]="french antillean",
+ ["fan0"]=" fang",
+ ["far" ]="persian",
+ ["fat" ]="fanti",
+ ["fin" ]="finnish",
+ ["fji" ]="fijian",
+ ["fle" ]="dutch (flemish)",
+ ["fne" ]="forest nenets",
+ ["fon" ]="fon",
+ ["fos" ]="faroese",
+ ["fra" ]="french",
+ ["frc" ]="cajun french",
+ ["fri" ]="frisian",
+ ["frl" ]="friulian",
+ ["frp" ]="arpitan",
+ ["fta" ]="futa",
+ ["ful" ]="fulah",
+ ["fuv" ]="nigerian fulfulde",
+ ["gad" ]="ga",
+ ["gae" ]="scottish gaelic (gaelic)",
+ ["gag" ]="gagauz",
+ ["gal" ]="galician",
+ ["gar" ]="garshuni",
+ ["gaw" ]="garhwali",
+ ["gez" ]="ge'ez",
+ ["gih" ]="githabul",
+ ["gil" ]="gilyak",
+ ["gil0"]="kiribati (gilbertese)",
+ ["gkp" ]="kpelle (guinea)",
+ ["glk" ]="gilaki",
+ ["gmz" ]="gumuz",
+ ["gnn" ]="gumatj",
+ ["gog" ]="gogo",
+ ["gon" ]="gondi",
+ ["grn" ]="greenlandic",
+ ["gro" ]="garo",
+ ["gua" ]="guarani",
+ ["guc" ]="wayuu",
+ ["guf" ]="gupapuyngu",
+ ["guj" ]="gujarati",
+ ["guz" ]="gusii",
+ ["hai" ]="haitian (haitian creole)",
+ ["hal" ]="halam",
+ ["har" ]="harauti",
+ ["hau" ]="hausa",
+ ["haw" ]="hawaiian",
+ ["hay" ]="haya",
+ ["haz" ]="hazaragi",
+ ["hbn" ]="hammer-banna",
+ ["her" ]="herero",
+ ["hil" ]="hiligaynon",
+ ["hin" ]="hindi",
+ ["hma" ]="high mari",
+ ["hmn" ]="hmong",
+ ["hmo" ]="hiri motu",
+ ["hnd" ]="hindko",
+ ["ho" ]="ho",
+ ["hri" ]="harari",
+ ["hrv" ]="croatian",
+ ["hun" ]="hungarian",
+ ["hye" ]="armenian",
+ ["hye0"]="armenian east",
+ ["iba" ]="iban",
+ ["ibb" ]="ibibio",
+ ["ibo" ]="igbo",
+ ["ido" ]="ido",
+ ["ijo" ]="ijo languages",
+ ["ile" ]="interlingue",
+ ["ilo" ]="ilokano",
+ ["ina" ]="interlingua",
+ ["ind" ]="indonesian",
+ ["ing" ]="ingush",
+ ["inu" ]="inuktitut",
+ ["ipk" ]="inupiat",
+ ["ipph"]="phonetic transcription—ipa conventions",
+ ["iri" ]="irish",
+ ["irt" ]="irish traditional",
+ ["isl" ]="icelandic",
+ ["ism" ]="inari sami",
+ ["ita" ]="italian",
+ ["iwr" ]="hebrew",
+ ["jam" ]="jamaican creole",
+ ["jan" ]="japanese",
+ ["jav" ]="javanese",
+ ["jbo" ]="lojban",
+ ["jii" ]="yiddish",
+ ["jud" ]="ladino",
+ ["jul" ]="jula",
+ ["kab" ]="kabardian",
+ ["kab0"]="kabyle",
+ ["kac" ]="kachchi",
+ ["kal" ]="kalenjin",
+ ["kan" ]="kannada",
+ ["kar" ]="karachay",
+ ["kat" ]="georgian",
+ ["kaz" ]="kazakh",
+ ["kde" ]="makonde",
+ ["kea" ]="kabuverdianu (crioulo)",
+ ["keb" ]="kebena",
+ ["kek" ]="kekchi",
+ ["kge" ]="khutsuri georgian",
+ ["kha" ]="khakass",
+ ["khk" ]="khanty-kazim",
+ ["khm" ]="khmer",
+ ["khs" ]="khanty-shurishkar",
+ ["kht" ]="khamti shan",
+ ["khv" ]="khanty-vakhi",
+ ["khw" ]="khowar",
+ ["kik" ]="kikuyu (gikuyu)",
+ ["kir" ]="kirghiz (kyrgyz)",
+ ["kis" ]="kisii",
+ ["kiu" ]="kirmanjki",
+ ["kjd" ]="southern kiwai",
+ ["kjp" ]="eastern pwo karen",
+ ["kkn" ]="kokni",
+ ["klm" ]="kalmyk",
+ ["kmb" ]="kamba",
+ ["kmn" ]="kumaoni",
+ ["kmo" ]="komo",
+ ["kms" ]="komso",
+ ["knr" ]="kanuri",
+ ["kod" ]="kodagu",
+ ["koh" ]="korean old hangul",
+ ["kok" ]="konkani",
+ ["kom" ]="komi",
+ ["kon" ]="kikongo",
+ ["kon0"]="kongo",
+ ["kop" ]="komi-permyak",
+ ["kor" ]="korean",
+ ["kos" ]="kosraean",
+ ["koz" ]="komi-zyrian",
+ ["kpl" ]="kpelle",
+ ["kri" ]="krio",
+ ["krk" ]="karakalpak",
+ ["krl" ]="karelian",
+ ["krm" ]="karaim",
+ ["krn" ]="karen",
+ ["krt" ]="koorete",
+ ["ksh" ]="kashmiri",
+ ["ksh0"]="ripuarian",
+ ["ksi" ]="khasi",
+ ["ksm" ]="kildin sami",
+ ["ksw" ]="s’gaw karen",
+ ["kua" ]="kuanyama",
+ ["kui" ]="kui",
+ ["kul" ]="kulvi",
+ ["kum" ]="kumyk",
+ ["kur" ]="kurdish",
+ ["kuu" ]="kurukh",
+ ["kuy" ]="kuy",
+ ["kyk" ]="koryak",
+ ["kyu" ]="western kayah",
+ ["lad" ]="ladin",
+ ["lah" ]="lahuli",
+ ["lak" ]="lak",
+ ["lam" ]="lambani",
+ ["lao" ]="lao",
+ ["lat" ]="latin",
+ ["laz" ]="laz",
+ ["lcr" ]="l-cree",
+ ["ldk" ]="ladakhi",
+ ["lez" ]="lezgi",
+ ["lij" ]="ligurian",
+ ["lim" ]="limburgish",
+ ["lin" ]="lingala",
+ ["lis" ]="lisu",
+ ["ljp" ]="lampung",
+ ["lki" ]="laki",
+ ["lma" ]="low mari",
+ ["lmb" ]="limbu",
+ ["lmo" ]="lombard",
+ ["lmw" ]="lomwe",
+ ["lom" ]="loma",
+ ["lrc" ]="luri",
+ ["lsb" ]="lower sorbian",
+ ["lsm" ]="lule sami",
+ ["lth" ]="lithuanian",
+ ["ltz" ]="luxembourgish",
+ ["lua" ]="luba-lulua",
+ ["lub" ]="luba-katanga",
+ ["lug" ]="ganda",
+ ["luh" ]="luyia",
+ ["luo" ]="luo",
+ ["lvi" ]="latvian",
+ ["mad" ]="madura",
+ ["mag" ]="magahi",
+ ["mah" ]="marshallese",
+ ["maj" ]="majang",
+ ["mak" ]="makhuwa",
+ ["mal" ]="malayalam reformed",
+ ["mam" ]="mam",
+ ["man" ]="mansi",
+ ["map" ]="mapudungun",
+ ["mar" ]="marathi",
+ ["maw" ]="marwari",
+ ["mbn" ]="mbundu",
+ ["mch" ]="manchu",
+ ["mcr" ]="moose cree",
+ ["mde" ]="mende",
+ ["mdr" ]="mandar",
+ ["men" ]="me'en",
+ ["mer" ]="meru",
+ ["mfe" ]="morisyen",
+ ["min" ]="minangkabau",
+ ["miz" ]="mizo",
+ ["mkd" ]="macedonian",
+ ["mkr" ]="makasar",
+ ["mkw" ]="kituba",
+ ["mle" ]="male",
+ ["mlg" ]="malagasy",
+ ["mln" ]="malinke",
+ ["mly" ]="malay",
+ ["mnd" ]="mandinka",
+ ["mng" ]="mongolian",
+ ["mni" ]="manipuri",
+ ["mnk" ]="maninka",
+ ["mnx" ]="manx",
+ ["moh" ]="mohawk",
+ ["mok" ]="moksha",
+ ["mol" ]="moldavian",
+ ["mon" ]="mon",
+ ["mor" ]="moroccan",
+ ["mos" ]="mossi",
+ ["mri" ]="maori",
+ ["mth" ]="maithili",
+ ["mts" ]="maltese",
+ ["mun" ]="mundari",
+ ["mus" ]="muscogee",
+ ["mwl" ]="mirandese",
+ ["mww" ]="hmong daw",
+ ["myn" ]="mayan",
+ ["mzn" ]="mazanderani",
+ ["nag" ]="naga-assamese",
+ ["nah" ]="nahuatl",
+ ["nan" ]="nanai",
+ ["nap" ]="neapolitan",
+ ["nas" ]="naskapi",
+ ["nau" ]="nauruan",
+ ["nav" ]="navajo",
+ ["ncr" ]="n-cree",
+ ["ndb" ]="ndebele",
+ ["ndc" ]="ndau",
+ ["ndg" ]="ndonga",
+ ["nds" ]="low saxon",
+ ["nep" ]="nepali",
+ ["new" ]="newari",
+ ["nga" ]="ngbaka",
+ ["ngr" ]="nagari",
+ ["nhc" ]="norway house cree",
+ ["nis" ]="nisi",
+ ["niu" ]="niuean",
+ ["nkl" ]="nyankole",
+ ["nko" ]="n'ko",
+ ["nld" ]="dutch",
+ ["noe" ]="nimadi",
+ ["nog" ]="nogai",
+ ["nor" ]="norwegian",
+ ["nov" ]="novial",
+ ["nsm" ]="northern sami",
+ ["nso" ]="sotho, northern",
+ ["nta" ]="northern tai",
+ ["nto" ]="esperanto",
+ ["nym" ]="nyamwezi",
+ ["nyn" ]="norwegian nynorsk",
+ ["oci" ]="occitan",
+ ["ocr" ]="oji-cree",
+ ["ojb" ]="ojibway",
+ ["ori" ]="odia",
+ ["oro" ]="oromo",
+ ["oss" ]="ossetian",
+ ["paa" ]="palestinian aramaic",
+ ["pag" ]="pangasinan",
+ ["pal" ]="pali",
+ ["pam" ]="pampangan",
+ ["pan" ]="punjabi",
+ ["pap" ]="palpa",
+ ["pap0"]="papiamentu",
+ ["pas" ]="pashto",
+ ["pau" ]="palauan",
+ ["pcc" ]="bouyei",
+ ["pcd" ]="picard",
+ ["pdc" ]="pennsylvania german",
+ ["pgr" ]="polytonic greek",
+ ["phk" ]="phake",
+ ["pih" ]="norfolk",
+ ["pil" ]="filipino",
+ ["plg" ]="palaung",
+ ["plk" ]="polish",
+ ["pms" ]="piemontese",
+ ["pnb" ]="western panjabi",
+ ["poh" ]="pocomchi",
+ ["pon" ]="pohnpeian",
+ ["pro" ]="provencal",
+ ["ptg" ]="portuguese",
+ ["pwo" ]="western pwo karen",
+ ["qin" ]="chin",
+ ["quc" ]="k’iche’",
+ ["quh" ]="quechua (bolivia)",
+ ["quz" ]="quechua",
+ ["qvi" ]="quechua (ecuador)",
+ ["qwh" ]="quechua (peru)",
+ ["raj" ]="rajasthani",
+ ["rar" ]="rarotongan",
+ ["rbu" ]="russian buriat",
+ ["rcr" ]="r-cree",
+ ["rej" ]="rejang",
+ ["ria" ]="riang",
+ ["rif" ]="tarifit",
+ ["rit" ]="ritarungo",
+ ["rkw" ]="arakwal",
+ ["rms" ]="romansh",
+ ["rmy" ]="vlax romani",
+ ["rom" ]="romanian",
+ ["roy" ]="romany",
+ ["rsy" ]="rusyn",
+ ["rtm" ]="rotuman",
+ ["rua" ]="kinyarwanda",
+ ["run" ]="rundi",
+ ["rup" ]="aromanian",
+ ["rus" ]="russian",
+ ["sad" ]="sadri",
+ ["san" ]="sanskrit",
+ ["sas" ]="sasak",
+ ["sat" ]="santali",
+ ["say" ]="sayisi",
+ ["scn" ]="sicilian",
+ ["sco" ]="scots",
+ ["sek" ]="sekota",
+ ["sel" ]="selkup",
+ ["sga" ]="old irish",
+ ["sgo" ]="sango",
+ ["sgs" ]="samogitian",
+ ["shi" ]="tachelhit",
+ ["shn" ]="shan",
+ ["sib" ]="sibe",
+ ["sid" ]="sidamo",
+ ["sig" ]="silte gurage",
+ ["sks" ]="skolt sami",
+ ["sky" ]="slovak",
+ ["sla" ]="slavey",
+ ["slv" ]="slovenian",
+ ["sml" ]="somali",
+ ["smo" ]="samoan",
+ ["sna" ]="sena",
+ ["sna0"]="shona",
+ ["snd" ]="sindhi",
+ ["snh" ]="sinhala (sinhalese)",
+ ["snk" ]="soninke",
+ ["sog" ]="sodo gurage",
+ ["sop" ]="songe",
+ ["sot" ]="sotho, southern",
+ ["sqi" ]="albanian",
+ ["srb" ]="serbian",
+ ["srd" ]="sardinian",
+ ["srk" ]="saraiki",
+ ["srr" ]="serer",
+ ["ssl" ]="south slavey",
+ ["ssm" ]="southern sami",
+ ["stq" ]="saterland frisian",
+ ["suk" ]="sukuma",
+ ["sun" ]="sundanese",
+ ["sur" ]="suri",
+ ["sva" ]="svan",
+ ["sve" ]="swedish",
+ ["swa" ]="swadaya aramaic",
+ ["swk" ]="swahili",
+ ["swz" ]="swati",
+ ["sxt" ]="sutu",
+ ["sxu" ]="upper saxon",
+ ["syl" ]="sylheti",
+ ["syr" ]="syriac",
+ ["szl" ]="silesian",
+ ["tab" ]="tabasaran",
+ ["taj" ]="tajiki",
+ ["tam" ]="tamil",
+ ["tat" ]="tatar",
+ ["tcr" ]="th-cree",
+ ["tdd" ]="dehong dai",
+ ["tel" ]="telugu",
+ ["tet" ]="tetum",
+ ["tgl" ]="tagalog",
+ ["tgn" ]="tongan",
+ ["tgr" ]="tigre",
+ ["tgy" ]="tigrinya",
+ ["tha" ]="thai",
+ ["tht" ]="tahitian",
+ ["tib" ]="tibetan",
+ ["tiv" ]="tiv",
+ ["tkm" ]="turkmen",
+ ["tmh" ]="tamashek",
+ ["tmn" ]="temne",
+ ["tna" ]="tswana",
+ ["tne" ]="tundra nenets",
+ ["tng" ]="tonga",
+ ["tod" ]="todo",
+ ["tod0"]="toma",
+ ["tpi" ]="tok pisin",
+ ["trk" ]="turkish",
+ ["tsg" ]="tsonga",
+ ["tua" ]="turoyo aramaic",
+ ["tul" ]="tulu",
+ ["tuv" ]="tuvin",
+ ["tvl" ]="tuvalu",
+ ["twi" ]="twi",
+ ["tyz" ]="tày",
+ ["tzm" ]="tamazight",
+ ["tzo" ]="tzotzil",
+ ["udm" ]="udmurt",
+ ["ukr" ]="ukrainian",
+ ["umb" ]="umbundu",
+ ["urd" ]="urdu",
+ ["usb" ]="upper sorbian",
+ ["uyg" ]="uyghur",
+ ["uzb" ]="uzbek",
+ ["vec" ]="venetian",
+ ["ven" ]="venda",
+ ["vit" ]="vietnamese",
+ ["vol" ]="volapük",
+ ["vro" ]="võro",
+ ["wa" ]="wa",
+ ["wag" ]="wagdi",
+ ["war" ]="waray-waray",
+ ["wcr" ]="west-cree",
+ ["wel" ]="welsh",
+ ["wlf" ]="wolof",
+ ["wln" ]="walloon",
+ ["xbd" ]="lü",
+ ["xhs" ]="xhosa",
+ ["xjb" ]="minjangbal",
+ ["xog" ]="soga",
+ ["xpe" ]="kpelle (liberia)",
+ ["yak" ]="sakha",
+ ["yao" ]="yao",
+ ["yap" ]="yapese",
+ ["yba" ]="yoruba",
+ ["ycr" ]="y-cree",
+ ["yic" ]="yi classic",
+ ["yim" ]="yi modern",
+ ["zea" ]="zealandic",
+ ["zgh" ]="standard morrocan tamazigh",
+ ["zha" ]="zhuang",
+ ["zhh" ]="chinese, hong kong sar",
+ ["zhp" ]="chinese phonetic",
+ ["zhs" ]="chinese simplified",
+ ["zht" ]="chinese traditional",
+ ["znd" ]="zande",
+ ["zul" ]="zulu",
+ ["zza" ]="zazaki",
+}
+local features=allocate {
+ ["aalt"]="access all alternates",
+ ["abvf"]="above-base forms",
+ ["abvm"]="above-base mark positioning",
+ ["abvs"]="above-base substitutions",
+ ["afrc"]="alternative fractions",
+ ["akhn"]="akhands",
+ ["blwf"]="below-base forms",
+ ["blwm"]="below-base mark positioning",
+ ["blws"]="below-base substitutions",
+ ["c2pc"]="petite capitals from capitals",
+ ["c2sc"]="small capitals from capitals",
+ ["calt"]="contextual alternates",
+ ["case"]="case-sensitive forms",
+ ["ccmp"]="glyph composition/decomposition",
+ ["cfar"]="conjunct form after ro",
+ ["cjct"]="conjunct forms",
+ ["clig"]="contextual ligatures",
+ ["cpct"]="centered cjk punctuation",
+ ["cpsp"]="capital spacing",
+ ["cswh"]="contextual swash",
+ ["curs"]="cursive positioning",
+ ["dflt"]="default processing",
+ ["dist"]="distances",
+ ["dlig"]="discretionary ligatures",
+ ["dnom"]="denominators",
+ ["dtls"]="dotless forms",
+ ["expt"]="expert forms",
+ ["falt"]="final glyph alternates",
+ ["fin2"]="terminal forms #2",
+ ["fin3"]="terminal forms #3",
+ ["fina"]="terminal forms",
+ ["flac"]="flattened accents over capitals",
+ ["frac"]="fractions",
+ ["fwid"]="full width",
+ ["half"]="half forms",
+ ["haln"]="halant forms",
+ ["halt"]="alternate half width",
+ ["hist"]="historical forms",
+ ["hkna"]="horizontal kana alternates",
+ ["hlig"]="historical ligatures",
+ ["hngl"]="hangul",
+ ["hojo"]="hojo kanji forms",
+ ["hwid"]="half width",
+ ["init"]="initial forms",
+ ["isol"]="isolated forms",
+ ["ital"]="italics",
+ ["jalt"]="justification alternatives",
+ ["jp04"]="jis2004 forms",
+ ["jp78"]="jis78 forms",
+ ["jp83"]="jis83 forms",
+ ["jp90"]="jis90 forms",
+ ["kern"]="kerning",
+ ["lfbd"]="left bounds",
+ ["liga"]="standard ligatures",
+ ["ljmo"]="leading jamo forms",
+ ["lnum"]="lining figures",
+ ["locl"]="localized forms",
+ ["ltra"]="left-to-right alternates",
+ ["ltrm"]="left-to-right mirrored forms",
+ ["mark"]="mark positioning",
+ ["med2"]="medial forms #2",
+ ["medi"]="medial forms",
+ ["mgrk"]="mathematical greek",
+ ["mkmk"]="mark to mark positioning",
+ ["mset"]="mark positioning via substitution",
+ ["nalt"]="alternate annotation forms",
+ ["nlck"]="nlc kanji forms",
+ ["nukt"]="nukta forms",
+ ["numr"]="numerators",
+ ["onum"]="old style figures",
+ ["opbd"]="optical bounds",
+ ["ordn"]="ordinals",
+ ["ornm"]="ornaments",
+ ["palt"]="proportional alternate width",
+ ["pcap"]="petite capitals",
+ ["pkna"]="proportional kana",
+ ["pnum"]="proportional figures",
+ ["pref"]="pre-base forms",
+ ["pres"]="pre-base substitutions",
+ ["pstf"]="post-base forms",
+ ["psts"]="post-base substitutions",
+ ["pwid"]="proportional widths",
+ ["qwid"]="quarter widths",
+ ["rand"]="randomize",
+ ["rclt"]="required contextual alternates",
+ ["rkrf"]="rakar forms",
+ ["rlig"]="required ligatures",
+ ["rphf"]="reph form",
+ ["rtbd"]="right bounds",
+ ["rtla"]="right-to-left alternates",
+ ["rtlm"]="right to left mirrored forms",
+ ["rvrn"]="required variation alternates",
+ ["ruby"]="ruby notation forms",
+ ["salt"]="stylistic alternates",
+ ["sinf"]="scientific inferiors",
+ ["size"]="optical size",
+ ["smcp"]="small capitals",
+ ["smpl"]="simplified forms",
+ ["ssty"]="script style",
+ ["stch"]="stretching glyph decomposition",
+ ["subs"]="subscript",
+ ["sups"]="superscript",
+ ["swsh"]="swash",
+ ["titl"]="titling",
+ ["tjmo"]="trailing jamo forms",
+ ["tnam"]="traditional name forms",
+ ["tnum"]="tabular figures",
+ ["trad"]="traditional forms",
+ ["twid"]="third widths",
+ ["unic"]="unicase",
+ ["valt"]="alternate vertical metrics",
+ ["vatu"]="vattu variants",
+ ["vert"]="vertical writing",
+ ["vhal"]="alternate vertical half metrics",
+ ["vjmo"]="vowel jamo forms",
+ ["vkna"]="vertical kana alternates",
+ ["vkrn"]="vertical kerning",
+ ["vpal"]="proportional alternate vertical metrics",
+ ["vrt2"]="vertical rotation",
+ ["zero"]="slashed zero",
+ ["trep"]="traditional tex replacements",
+ ["tlig"]="traditional tex ligatures",
+ ["ss.."]="stylistic set ..",
+ ["cv.."]="character variant ..",
+ ["js.."]="justification ..",
+ ["dv.."]="devanagari ..",
+ ["ml.."]="malayalam ..",
+}
+local baselines=allocate {
+ ["hang"]="hanging baseline",
+ ["icfb"]="ideographic character face bottom edge baseline",
+ ["icft"]="ideographic character face tope edige baseline",
+ ["ideo"]="ideographic em-box bottom edge baseline",
+ ["idtp"]="ideographic em-box top edge baseline",
+ ["math"]="mathematical centered baseline",
+ ["romn"]="roman baseline"
+}
+tables.scripts=scripts
+tables.languages=languages
+tables.features=features
+tables.baselines=baselines
+local acceptscripts=true directives.register("otf.acceptscripts",function(v) acceptscripts=v end)
+local acceptlanguages=true directives.register("otf.acceptlanguages",function(v) acceptlanguages=v end)
+local report_checks=logs.reporter("fonts","checks")
+if otffeatures.features then
+ for k,v in next,otffeatures.features do
+ features[k]=v
+ end
+ otffeatures.features=features
+end
+local function swapped(h)
+ local r={}
+ for k,v in next,h do
+ r[gsub(v,"[^a-z0-9]","")]=k
+ end
+ return r
+end
+local verbosescripts=allocate(swapped(scripts ))
+local verboselanguages=allocate(swapped(languages))
+local verbosefeatures=allocate(swapped(features ))
+local verbosebaselines=allocate(swapped(baselines))
+local function resolve(t,k)
+ if k then
+ k=gsub(lower(k),"[^a-z0-9]","")
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ end
+end
+setmetatableindex(verbosescripts,resolve)
+setmetatableindex(verboselanguages,resolve)
+setmetatableindex(verbosefeatures,resolve)
+setmetatableindex(verbosebaselines,resolve)
+setmetatableindex(scripts,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
+ end
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptscripts then
+ report_checks("registering extra script %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+setmetatableindex(languages,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
+ end
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptlanguages then
+ report_checks("registering extra language %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+if setmetatablenewindex then
+ setmetatablenewindex(languages,"ignore")
+ setmetatablenewindex(scripts,"ignore")
+ setmetatablenewindex(baselines,"ignore")
+end
+local function resolve(t,k)
+ if k then
+ k=lower(k)
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ local tag,dd=match(k,"(..)(%d+)")
+ if tag and dd then
+ local v=rawget(t,tag)
+ if v then
+ return v
+ else
+ local v=rawget(t,tag.."..")
+ if v then
+ return (gsub(v,"%.%.",tonumber(dd)))
+ end
+ end
+ end
+ end
+ return k
+end
+setmetatableindex(features,resolve)
+local function assign(t,k,v)
+ if k and v then
+ v=lower(v)
+ rawset(t,k,v)
+ end
+end
+if setmetatablenewindex then
+ setmetatablenewindex(features,assign)
+end
+local checkers={
+ rand=function(v)
+ return v==true and "random" or v
+ end
+}
+if not storage then
+ return
+end
+local usedfeatures=statistics.usedfeatures or {}
+statistics.usedfeatures=usedfeatures
+table.setmetatableindex(usedfeatures,function(t,k) if k then local v={} t[k]=v return v end end)
+storage.register("fonts/otf/usedfeatures",usedfeatures,"fonts.handlers.otf.statistics.usedfeatures" )
+local normalizedaxis=otf.readers.helpers.normalizedaxis or function(s) return s end
+function otffeatures.normalize(features)
+ if features then
+ local h={}
+ for key,value in next,features do
+ local k=lower(key)
+ if k=="language" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.language=rawget(verboselanguages,v) or (languages[v] and v) or "dflt"
+ elseif k=="script" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt"
+ elseif k=="axis" then
+ h[k]=normalizedaxis(value)
+ if not callbacks.supported.glyph_stream_provider then
+ h.variableshapes=true
+ end
+ else
+ local uk=usedfeatures[key]
+ local uv=uk[value]
+ if uv then
+ else
+ uv=tonumber(value)
+ if uv then
+ elseif type(value)=="string" then
+ local b=is_boolean(value)
+ if type(b)=="nil" then
+ uv=lower(value)
+ else
+ uv=b
+ end
+ elseif type(value)=="table" then
+ uv=sequenced(t,",")
+ else
+ uv=value
+ end
+ if not rawget(features,k) then
+ k=rawget(verbosefeatures,k) or k
+ end
+ local c=checkers[k]
+ if c then
+ uv=c(uv) or vc
+ end
+ uk[value]=uv
+ end
+ h[k]=uv
+ end
+ end
+ return h
+ end
+end
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ott”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-cff” eefa156275ba0ac91aa651a944d35978] ---
if not modules then modules={} end modules ['font-cff']={
version=1.001,
@@ -4053,15 +5671,15 @@ if not modules then modules={} end modules ['font-cff']={
license="see context related readme files"
}
local next,type,tonumber=next,type,tonumber
-local byte=string.byte
+local byte,char,gmatch=string.byte,string.char,string.gmatch
local concat,remove=table.concat,table.remove
-local floor,abs,round,ceil=math.floor,math.abs,math.round,math.ceil
+local floor,abs,round,ceil,min,max=math.floor,math.abs,math.round,math.ceil,math.min,math.max
local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct
local lpegmatch=lpeg.match
local formatters=string.formatters
+local bytetable=string.bytetable
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
-local readbytes=streamreader.readbytes
local readstring=streamreader.readstring
local readbyte=streamreader.readcardinal1
local readushort=streamreader.readcardinal2
@@ -4069,6 +5687,18 @@ local readuint=streamreader.readcardinal3
local readulong=streamreader.readcardinal4
local setposition=streamreader.setposition
local getposition=streamreader.getposition
+local readbytetable=streamreader.readbytetable
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ readstring=streamreader.readstring
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readuint=streamreader.readcardinal3
+ readulong=streamreader.readcardinal4
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ readbytetable=streamreader.readbytetable
+end)
local setmetatableindex=table.setmetatableindex
local trace_charstrings=false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings=v end)
local report=logs.reporter("otf reader","cff")
@@ -4077,6 +5707,8 @@ local parsecharstring
local parsecharstrings
local resetcharstrings
local parseprivates
+local startparsing
+local stopparsing
local defaultstrings={ [0]=
".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
"ampersand","quoteright","parenleft","parenright","asterisk","plus",
@@ -4152,18 +5784,24 @@ local cffreaders={
}
local function readheader(f)
local offset=getposition(f)
+ local major=readbyte(f)
local header={
offset=offset,
- major=readbyte(f),
+ major=major,
minor=readbyte(f),
size=readbyte(f),
- osize=readbyte(f),
}
+ if major==1 then
+ header.dsize=readbyte(f)
+ elseif major==2 then
+ header.dsize=readushort(f)
+ else
+ end
setposition(f,offset+header.size)
return header
end
-local function readlengths(f)
- local count=readushort(f)
+local function readlengths(f,longcount)
+ local count=longcount and readulong(f) or readushort(f)
if count==0 then
return {}
end
@@ -4177,7 +5815,12 @@ local function readlengths(f)
local previous=read(f)
for i=1,count do
local offset=read(f)
- lengths[i]=offset-previous
+ local length=offset-previous
+ if length<0 then
+ report("bad offset: %i",length)
+ length=0
+ end
+ lengths[i]=length
previous=offset
end
return lengths
@@ -4242,7 +5885,7 @@ do
end+P("\16")/function()
result.encoding=stack[top]
top=0
- end+P("\17")/function()
+ end+P("\17")/function()
result.charstrings=stack[top]
top=0
end+P("\18")/function()
@@ -4253,10 +5896,20 @@ do
top=0
end+P("\19")/function()
result.subroutines=stack[top]
+ top=0
end+P("\20")/function()
result.defaultwidthx=stack[top]
+ top=0
end+P("\21")/function()
result.nominalwidthx=stack[top]
+ top=0
+ end
++P("\24")/function()
+ result.vstore=stack[top]
+ top=0
+ end+P("\25")/function()
+ result.maxstack=stack[top]
+ top=0
end
local p_double=P("\12")*(
P("\00")/function()
@@ -4280,7 +5933,7 @@ do
end+P("\06")/function()
result.charstringtype=stack[top]
top=0
- end+P("\07")/function()
+ end+P("\07")/function()
result.fontmatrix={ unpack(stack,1,6) }
top=0
end+P("\08")/function()
@@ -4318,10 +5971,10 @@ do
end+P("\35")/function()
result.cid.uidbase=stack[top]
top=0
- end+P("\36")/function()
+ end+P("\36")/function()
result.cid.fdarray=stack[top]
top=0
- end+P("\37")/function()
+ end+P("\37")/function()
result.cid.fdselect=stack[top]
top=0
end+P("\38")/function()
@@ -4386,12 +6039,12 @@ do
local p_dictionary=(
p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
)^1
- parsedictionaries=function(data,dictionaries)
+ parsedictionaries=function(data,dictionaries,what)
stack={}
strings=data.strings
for i=1,#dictionaries do
top=0
- result={
+ result=what=="cff" and {
monospaced=false,
italicangle=0,
underlineposition=-100,
@@ -4409,6 +6062,12 @@ do
fonttype=0,
count=8720,
}
+ } or {
+ charstringtype=2,
+ charset=0,
+ vstore=0,
+ cid={
+ },
}
lpegmatch(p_dictionary,dictionaries[i])
dictionaries[i]=result
@@ -4450,6 +6109,9 @@ do
local stems=0
local globalbias=0
local localbias=0
+ local nominalwidth=0
+ local defaultwidth=0
+ local charset=false
local globals=false
local locals=false
local depth=1
@@ -4460,6 +6122,12 @@ do
local checked=false
local keepcurve=false
local version=2
+ local regions=false
+ local nofregions=0
+ local region=false
+ local factors=false
+ local axis=false
+ local vsindex=0
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
end
@@ -4470,14 +6138,14 @@ do
report("%w%-10s : %s",depth*2,where,tostring(value))
end
end
- local function moveto(x,y)
+ local function xymoveto()
if keepcurve then
r=r+1
result[r]={ x,y,"m" }
end
if checked then
- if x<xmin then xmin=x elseif x>xmax then xmax=x end
- if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if x>xmax then xmax=x elseif x<xmin then xmin=x end
+ if y>ymax then ymax=y elseif y<ymin then ymin=y end
else
xmin=x
ymin=y
@@ -4486,14 +6154,55 @@ do
checked=true
end
end
- local function lineto(x,y)
+ local function xmoveto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"m" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif x>xmax then
+ xmax=x
+ elseif x<xmin then
+ xmin=x
+ end
+ end
+ local function ymoveto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"m" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif y>ymax then
+ ymax=y
+ elseif y<ymin then
+ ymin=y
+ end
+ end
+ local function moveto()
+ if trace_charstrings then
+ showstate("moveto")
+ end
+ top=0
+ xymoveto()
+ end
+ local function xylineto()
if keepcurve then
r=r+1
result[r]={ x,y,"l" }
end
if checked then
- if x<xmin then xmin=x elseif x>xmax then xmax=x end
- if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if x>xmax then xmax=x elseif x<xmin then xmin=x end
+ if y>ymax then ymax=y elseif y<ymin then ymin=y end
else
xmin=x
ymin=y
@@ -4502,14 +6211,51 @@ do
checked=true
end
end
- local function curveto(x1,y1,x2,y2,x3,y3)
+ local function xlineto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"l" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif x>xmax then
+ xmax=x
+ elseif x<xmin then
+ xmin=x
+ end
+ end
+ local function ylineto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"l" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif y>ymax then
+ ymax=y
+ elseif y<ymin then
+ ymin=y
+ end
+ end
+ local function xycurveto(x1,y1,x2,y2,x3,y3)
+ if trace_charstrings then
+ showstate("curveto")
+ end
if keepcurve then
r=r+1
result[r]={ x1,y1,x2,y2,x3,y3,"c" }
end
if checked then
- if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
- if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x1>xmax then xmax=x1 elseif x1<xmin then xmin=x1 end
+ if y1>ymax then ymax=y1 elseif y1<ymin then ymin=y1 end
else
xmin=x1
ymin=y1
@@ -4517,21 +6263,21 @@ do
ymax=y1
checked=true
end
- if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
- if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
- if x3<xmin then xmin=x3 elseif x3>xmax then xmax=x3 end
- if y3<ymin then ymin=y3 elseif y3>ymax then ymax=y3 end
+ if x2>xmax then xmax=x2 elseif x2<xmin then xmin=x2 end
+ if y2>ymax then ymax=y2 elseif y2<ymin then ymin=y2 end
+ if x3>xmax then xmax=x3 elseif x3<xmin then xmin=x3 end
+ if y3>ymax then ymax=y3 elseif y3<ymin then ymin=y3 end
end
local function rmoveto()
- if top>2 then
- if not width then
+ if not width then
+ if top>2 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("rmoveto")
@@ -4539,43 +6285,43 @@ do
x=x+stack[top-1]
y=y+stack[top]
top=0
- moveto(x,y)
+ xymoveto()
end
local function hmoveto()
- if top>1 then
- if not width then
+ if not width then
+ if top>1 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("hmoveto")
end
x=x+stack[top]
top=0
- moveto(x,y)
+ xmoveto()
end
local function vmoveto()
- if top>1 then
- if not width then
+ if not width then
+ if top>1 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("vmoveto")
end
y=y+stack[top]
top=0
- moveto(x,y)
+ ymoveto()
end
local function rlineto()
if trace_charstrings then
@@ -4584,20 +6330,7 @@ do
for i=1,top,2 do
x=x+stack[i]
y=y+stack[i+1]
- lineto(x,y)
- end
- top=0
- end
- local function xlineto(swap)
- for i=1,top do
- if swap then
- x=x+stack[i]
- swap=false
- else
- y=y+stack[i]
- swap=true
- end
- lineto(x,y)
+ xylineto()
end
top=0
end
@@ -4605,13 +6338,47 @@ do
if trace_charstrings then
showstate("hlineto")
end
- xlineto(true)
+ if top==1 then
+ x=x+stack[1]
+ xlineto()
+ else
+ local swap=true
+ for i=1,top do
+ if swap then
+ x=x+stack[i]
+ xlineto()
+ swap=false
+ else
+ y=y+stack[i]
+ ylineto()
+ swap=true
+ end
+ end
+ end
+ top=0
end
local function vlineto()
if trace_charstrings then
showstate("vlineto")
end
- xlineto(false)
+ if top==1 then
+ y=y+stack[1]
+ ylineto()
+ else
+ local swap=false
+ for i=1,top do
+ if swap then
+ x=x+stack[i]
+ xlineto()
+ swap=false
+ else
+ y=y+stack[i]
+ ylineto()
+ swap=true
+ end
+ end
+ end
+ top=0
end
local function rrcurveto()
if trace_charstrings then
@@ -4622,9 +6389,9 @@ do
local ay=y+stack[i+1]
local bx=ax+stack[i+2]
local by=ay+stack[i+3]
- x=bx+stack[i+4]
- y=by+stack[i+5]
- curveto(ax,ay,bx,by,x,y)
+ x=bx+stack[i+4]
+ y=by+stack[i+5]
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -4634,17 +6401,17 @@ do
end
local s=1
if top%2~=0 then
- y=y+stack[1]
+ y=y+stack[1]
s=2
end
for i=s,top,4 do
- local ax=x+stack[i]
+ local ax=x+stack[i]
local ay=y
local bx=ax+stack[i+1]
local by=ay+stack[i+2]
- x=bx+stack[i+3]
+ x=bx+stack[i+3]
y=by
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -4655,17 +6422,17 @@ do
local s=1
local d=0
if top%2~=0 then
- d=stack[1]
+ d=stack[1]
s=2
end
for i=s,top,4 do
local ax=x+d
- local ay=y+stack[i]
+ local ay=y+stack[i]
local bx=ax+stack[i+1]
local by=ay+stack[i+2]
x=bx
- y=by+stack[i+3]
- curveto(ax,ay,bx,by,x,y)
+ y=by+stack[i+3]
+ xycurveto(ax,ay,bx,by,x,y)
d=0
end
top=0
@@ -4675,7 +6442,6 @@ do
if last then
top=top-1
end
- local sw=swap
for i=1,top,4 do
local ax,ay,bx,by
if swap then
@@ -4703,7 +6469,7 @@ do
end
swap=true
end
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -4730,11 +6496,11 @@ do
local by=ay+stack[i+3]
x=bx+stack[i+4]
y=by+stack[i+5]
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
x=x+stack[top-1]
y=y+stack[top]
- lineto(x,y)
+ xylineto()
top=0
end
local function rlinecurve()
@@ -4745,7 +6511,7 @@ do
for i=1,top-6,2 do
x=x+stack[i]
y=y+stack[i+1]
- lineto(x,y)
+ xylineto()
end
end
local ax=x+stack[top-5]
@@ -4754,7 +6520,7 @@ do
local by=ay+stack[top-2]
x=bx+stack[top-1]
y=by+stack[top]
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
top=0
end
local function flex()
@@ -4767,33 +6533,33 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by+stack[6]
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[7]
local dy=cy+stack[8]
local ex=dx+stack[9]
local ey=dy+stack[10]
x=ex+stack[11]
y=ey+stack[12]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function hflex()
if trace_charstrings then
showstate("hflex")
end
- local ax=x+stack[1]
+ local ax=x+stack[1]
local ay=y
local bx=ax+stack[2]
local by=ay+stack[3]
local cx=bx+stack[4]
local cy=by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[5]
local dy=by
local ex=dx+stack[6]
local ey=y
x=ex+stack[7]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function hflex1()
@@ -4806,13 +6572,13 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[6]
local dy=by
local ex=dx+stack[7]
local ey=dy+stack[8]
x=ex+stack[9]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function flex1()
@@ -4825,7 +6591,7 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by+stack[6]
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[7]
local dy=cy+stack[8]
local ex=dx+stack[9]
@@ -4835,7 +6601,7 @@ do
else
y=ey+stack[11]
end
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function getstem()
@@ -4970,6 +6736,92 @@ do
end
top=0
end
+ local reginit=false
+ local function updateregions(n)
+ if regions then
+ local current=regions[n] or regions[1]
+ nofregions=#current
+ if axis and n~=reginit then
+ factors={}
+ for i=1,nofregions do
+ local region=current[i]
+ local s=1
+ for j=1,#axis do
+ local f=axis[j]
+ local r=region[j]
+ local start=r.start
+ local peak=r.peak
+ local stop=r.stop
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ factors[i]=s
+ end
+ end
+ end
+ reginit=n
+ end
+ local function setvsindex()
+ local vsindex=stack[top]
+ if trace_charstrings then
+ showstate(formatters["vsindex %i"](vsindex))
+ end
+ updateregions(vsindex)
+ top=top-1
+ end
+ local function blend()
+ local n=stack[top]
+ top=top-1
+ if axis then
+ if trace_charstrings then
+ local t=top-nofregions*n
+ local m=t-n
+ for i=1,n do
+ local k=m+i
+ local d=m+n+(i-1)*nofregions
+ local old=stack[k]
+ local new=old
+ for r=1,nofregions do
+ new=new+stack[d+r]*factors[r]
+ end
+ stack[k]=new
+ showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
+ end
+ top=t
+ elseif n==1 then
+ top=top-nofregions
+ local v=stack[top]
+ for r=1,nofregions do
+ v=v+stack[top+r]*factors[r]
+ end
+ stack[top]=v
+ else
+ top=top-nofregions*n
+ local d=top
+ local k=top-n
+ for i=1,n do
+ k=k+1
+ local v=stack[k]
+ for r=1,nofregions do
+ v=v+stack[d+r]*factors[r]
+ end
+ stack[k]=v
+ d=d+nofregions
+ end
+ end
+ else
+ end
+ end
local actions={ [0]=unsupported,
getstem,
unsupported,
@@ -4985,8 +6837,8 @@ do
unsupported,
hsbw,
unsupported,
- unsupported,
- unsupported,
+ setvsindex,
+ blend,
unsupported,
getstem,
getmask,
@@ -5018,8 +6870,80 @@ do
[036]=hflex1,
[037]=flex1,
}
- local p_bytes=Ct((P(1)/byte)^0)
- local function call(scope,list,bias,process)
+ local c_endchar=char(14)
+ local passon do
+ local rshift=bit32.rshift
+ local band=bit32.band
+ local round=math.round
+ local encode=table.setmetatableindex(function(t,i)
+ for i=-2048,-1130 do
+ t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ for i=-1131,-108 do
+ local v=0xFB00-i-108
+ t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=-107,107 do
+ t[i]=char(i+139)
+ end
+ for i=108,1131 do
+ local v=0xF700+i-108
+ t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=1132,2048 do
+ t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ return t[i]
+ end)
+ local function setvsindex()
+ local vsindex=stack[top]
+ updateregions(vsindex)
+ top=top-1
+ end
+ local function blend()
+ local n=stack[top]
+ top=top-1
+ if not axis then
+ elseif n==1 then
+ top=top-nofregions
+ local v=stack[top]
+ for r=1,nofregions do
+ v=v+stack[top+r]*factors[r]
+ end
+ stack[top]=round(v)
+ else
+ top=top-nofregions*n
+ local d=top
+ local k=top-n
+ for i=1,n do
+ k=k+1
+ local v=stack[k]
+ for r=1,nofregions do
+ v=v+stack[d+r]*factors[r]
+ end
+ stack[k]=round(v)
+ d=d+nofregions
+ end
+ end
+ end
+ passon=function(operation)
+ if operation==15 then
+ setvsindex()
+ elseif operation==16 then
+ blend()
+ else
+ for i=1,top do
+ r=r+1
+ result[r]=encode[stack[i]]
+ end
+ r=r+1
+ result[r]=char(operation)
+ top=0
+ end
+ end
+ end
+ local process
+ local function call(scope,list,bias)
depth=depth+1
if top==0 then
showstate(formatters["unknown %s call"](scope))
@@ -5032,10 +6956,6 @@ do
end
local tab=list[index]
if tab then
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- list[index]=tab
- end
process(tab)
else
showstate(formatters["unknown %s call %i"](scope,index))
@@ -5044,50 +6964,50 @@ do
end
depth=depth-1
end
- local function process(tab)
+ local justpass=false
+ process=function(tab)
local i=1
local n=#tab
while i<=n do
local t=tab[i]
- if t>=32 and t<=246 then
- top=top+1
- stack[top]=t-139
- i=i+1
- elseif t>=247 and t<=250 then
- top=top+1
- stack[top]=(t-247)*256+tab[i+1]+108
- i=i+2
- elseif t>=251 and t<=254 then
+ if t>=32 then
top=top+1
- stack[top]=-(t-251)*256-tab[i+1]-108
- i=i+2
+ if t<=246 then
+ stack[top]=t-139
+ i=i+1
+ elseif t<=250 then
+ stack[top]=t*256-63124+tab[i+1]
+ i=i+2
+ elseif t<=254 then
+ stack[top]=-t*256+64148-tab[i+1]
+ i=i+2
+ else
+ local n=0x100*tab[i+1]+tab[i+2]
+ if n>=0x8000 then
+ stack[top]=n-0x10000+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ else
+ stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ end
+ i=i+5
+ end
elseif t==28 then
top=top+1
local n=0x100*tab[i+1]+tab[i+2]
if n>=0x8000 then
- stack[top]=n-0xFFFF-1
+ stack[top]=n-0x10000
else
stack[top]=n
end
i=i+3
- elseif t==255 then
- local n=0x100*tab[i+1]+tab[i+2]
- top=top+1
- if n>=0x8000 then
- stack[top]=n-0xFFFF-1+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- else
- stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- end
- i=i+5
- elseif t==11 then
+ elseif t==11 then
if trace_charstrings then
showstate("return")
end
return
elseif t==10 then
- call("local",locals,localbias,process)
+ call("local",locals,localbias)
i=i+1
- elseif t==14 then
+ elseif t==14 then
if width then
elseif top>0 then
width=stack[1]
@@ -5102,7 +7022,7 @@ do
end
return
elseif t==29 then
- call("global",globals,globalbias,process)
+ call("global",globals,globalbias)
i=i+1
elseif t==12 then
i=i+1
@@ -5117,20 +7037,25 @@ do
top=0
end
i=i+1
+ elseif justpass then
+ passon(t)
+ i=i+1
else
local a=actions[t]
if a then
local s=a(t)
if s then
- i=i+s
+ i=i+s+1
+ else
+ i=i+1
end
else
if trace_charstrings then
showvalue("<action>",t)
end
top=0
+ i=i+1
end
- i=i+1
end
end
end
@@ -5146,96 +7071,15 @@ do
((l<1240 and 107) or (l<33900 and 1131) or 32768)+1
end
end
- parsecharstrings=function(data,glyphs,doshapes,tversion)
- local dictionary=data.dictionaries[1]
- local charstrings=dictionary.charstrings
- local charset=dictionary.charset
- local private=dictionary.private or { data={} }
- keepcurve=doshapes
- version=tversion
- stack={}
- glyphs=glyphs or {}
- strings=data.strings
- globals=data.routines or {}
- locals=dictionary.subroutines or {}
- globalbias,localbias=setbias(globals,locals)
- local nominalwidth=private.data.nominalwidthx or 0
- local defaultwidth=private.data.defaultwidthx or 0
- for i=1,#charstrings do
- local tab=charstrings[i]
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- end
- local index=i-1
- x=0
- y=0
- width=false
- r=0
- top=0
- stems=0
- result={}
- xmin=0
- xmax=0
- ymin=0
- ymax=0
- checked=false
- if trace_charstrings then
- report("glyph: %i",index)
- report("data: % t",tab)
- end
- process(tab)
- local boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
- if width==true or width==false then
- width=defaultwidth
- else
- width=nominalwidth+width
- end
- local glyph=glyphs[index]
- if not glyph then
- glyphs[index]={
- segments=doshapes~=false and result or nil,
- boundingbox=boundingbox,
- width=width,
- name=charset[index],
- }
- else
- glyph.segments=doshapes~=false and result or nil
- glyph.boundingbox=boundingbox
- if not glyph.width then
- glyph.width=width
- end
- if charset and not glyph.name then
- glyph.name=charset[index]
- end
- end
- if trace_charstrings then
- report("width: %s",tostring(width))
- report("boundingbox: % t",boundingbox)
- end
- charstrings[i]=nil
- end
- return glyphs
- end
- parsecharstring=function(data,dictionary,tab,glyphs,index,doshapes,tversion)
- local private=dictionary.private
- keepcurve=doshapes
- version=tversion
- strings=data.strings
- locals=dictionary.subroutines or {}
- globals=data.routines or {}
- globalbias,localbias=setbias(globals,locals)
- local nominalwidth=private and private.data.nominalwidthx or 0
- local defaultwidth=private and private.data.defaultwidthx or 0
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- end
+ local function processshape(tab,index)
+ tab=bytetable(tab)
x=0
y=0
width=false
r=0
top=0
stems=0
- result={}
+ result={}
xmin=0
xmax=0
ymin=0
@@ -5243,26 +7087,35 @@ do
checked=false
if trace_charstrings then
report("glyph: %i",index)
- report("data: % t",tab)
+ report("data : % t",tab)
+ end
+ if regions then
+ updateregions(vsindex)
end
process(tab)
- local boundingbox={ xmin,ymin,xmax,ymax }
+ local boundingbox={
+ round(xmin),
+ round(ymin),
+ round(xmax),
+ round(ymax),
+ }
if width==true or width==false then
width=defaultwidth
else
width=nominalwidth+width
end
- index=index-1
local glyph=glyphs[index]
- if not glyph then
- glyphs[index]={
- segments=doshapes~=false and result or nil,
- boundingbox=boundingbox,
- width=width,
- name=charset[index],
- }
- else
- glyph.segments=doshapes~=false and result or nil
+ if justpass then
+ r=r+1
+ result[r]=c_endchar
+ local stream=concat(result)
+ if glyph then
+ glyph.stream=stream
+ else
+ glyphs[index]={ stream=stream }
+ end
+ elseif glyph then
+ glyph.segments=keepcurve~=false and result or nil
glyph.boundingbox=boundingbox
if not glyph.width then
glyph.width=width
@@ -5270,22 +7123,93 @@ do
if charset and not glyph.name then
glyph.name=charset[index]
end
+ elseif keepcurve then
+ glyphs[index]={
+ segments=result,
+ boundingbox=boundingbox,
+ width=width,
+ name=charset and charset[index] or nil,
+ }
+ else
+ glyphs[index]={
+ boundingbox=boundingbox,
+ width=width,
+ name=charset and charset[index] or nil,
+ }
end
if trace_charstrings then
- report("width: %s",tostring(width))
+ report("width : %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
end
- resetcharstrings=function()
+ startparsing=function(fontdata,data,streams)
+ reginit=false
+ axis=false
+ regions=data.regions
+ justpass=streams==true
+ if regions then
+ regions={ regions }
+ axis=data.factors or false
+ end
+ end
+ stopparsing=function(fontdata,data)
+ stack={}
+ glyphs=false
result={}
top=0
- stack={}
+ locals=false
+ globals=false
+ strings=false
+ end
+ local function setwidths(private)
+ if not private then
+ return 0,0
+ end
+ local privatedata=private.data
+ if not privatedata then
+ return 0,0
+ end
+ return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0
+ end
+ parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams)
+ local dictionary=data.dictionaries[1]
+ local charstrings=dictionary.charstrings
+ keepcurve=doshapes
+ version=tversion
+ strings=data.strings
+ globals=data.routines or {}
+ locals=dictionary.subroutines or {}
+ charset=dictionary.charset
+ vsindex=dictionary.vsindex or 0
+ glyphs=glphs or {}
+ globalbias,localbias=setbias(globals,locals)
+ nominalwidth,defaultwidth=setwidths(dictionary.private)
+ startparsing(fontdata,data,streams)
+ for index=1,#charstrings do
+ processshape(charstrings[index],index-1)
+ charstrings[index]=nil
+ end
+ stopparsing(fontdata,data)
+ return glyphs
+ end
+ parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion)
+ keepcurve=doshapes
+ version=tversion
+ strings=data.strings
+ globals=data.routines or {}
+ locals=dictionary.subroutines or {}
+ charset=false
+ vsindex=dictionary.vsindex or 0
+ glyphs=glphs or {}
+ globalbias,localbias=setbias(globals,locals)
+ nominalwidth,defaultwidth=setwidths(dictionary.private)
+ processshape(tab,index-1)
end
end
local function readglobals(f,data)
local routines=readlengths(f)
for i=1,#routines do
- routines[i]=readstring(f,routines[i])
+ routines[i]=readbytetable(f,routines[i])
end
data.routines=routines
end
@@ -5297,7 +7221,7 @@ local function readcharsets(f,data,dictionary)
local strings=data.strings
local nofglyphs=data.nofglyphs
local charsetoffset=dictionary.charset
- if charsetoffset~=0 then
+ if charsetoffset and charsetoffset~=0 then
setposition(f,header.offset+charsetoffset)
local format=readbyte(f)
local charset={ [0]=".notdef" }
@@ -5323,6 +7247,9 @@ local function readcharsets(f,data,dictionary)
else
report("cff parser: unsupported charset format %a",format)
end
+ else
+ dictionary.nocharset=true
+ dictionary.charset=nil
end
end
local function readprivates(f,data)
@@ -5343,7 +7270,7 @@ local function readlocals(f,data,dictionary)
setposition(f,header.offset+private.offset+subroutineoffset)
local subroutines=readlengths(f)
for i=1,#subroutines do
- subroutines[i]=readstring(f,subroutines[i])
+ subroutines[i]=readbytetable(f,subroutines[i])
end
dictionary.subroutines=subroutines
private.data.subroutines=nil
@@ -5354,15 +7281,16 @@ local function readlocals(f,data,dictionary)
dictionary.subroutines={}
end
end
-local function readcharstrings(f,data)
+local function readcharstrings(f,data,what)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
- local type=dictionary.charstringtype
+ local stringtype=dictionary.charstringtype
local offset=dictionary.charstrings
- if type==2 then
+ if type(offset)~="number" then
+ elseif stringtype==2 then
setposition(f,header.offset+offset)
- local charstrings=readlengths(f)
+ local charstrings=readlengths(f,what=="cff2")
local nofglyphs=#charstrings
for i=1,nofglyphs do
charstrings[i]=readstring(f,charstrings[i])
@@ -5370,7 +7298,7 @@ local function readcharstrings(f,data)
data.nofglyphs=nofglyphs
dictionary.charstrings=charstrings
else
- report("unsupported charstr type %i",type)
+ report("unsupported charstr type %i",stringtype)
data.nofglyphs=0
dictionary.charstrings={}
end
@@ -5388,29 +7316,36 @@ local function readcidprivates(f,data)
end
parseprivates(data,dictionaries)
end
-local function readnoselect(f,data,glyphs,doshapes,version)
+readers.parsecharstrings=parsecharstrings
+local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
- readcharsets(f,data,dictionary)
+ readcharstrings(f,data,version)
+ if version=="cff2" then
+ dictionary.charset=nil
+ else
+ readencodings(f,data)
+ readcharsets(f,data,dictionary)
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
readlocals(f,data,dictionary)
- parsecharstrings(data,glyphs,doshapes,version)
- resetcharstrings()
+ startparsing(fontdata,data,streams)
+ parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
+ stopparsing(fontdata,data)
end
-readers.parsecharstrings=parsecharstrings
-local function readfdselect(f,data,glyphs,doshapes,version)
+local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
local cid=dictionary.cid
local cidselect=cid and cid.fdselect
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
+ readcharstrings(f,data,version)
+ if version~="cff2" then
+ readencodings(f,data)
+ end
local charstrings=dictionary.charstrings
local fdindex={}
local nofglyphs=data.nofglyphs
@@ -5459,75 +7394,140 @@ local function readfdselect(f,data,glyphs,doshapes,version)
for i=1,#dictionaries do
readlocals(f,data,dictionaries[i])
end
+ startparsing(fontdata,data,streams)
for i=1,#charstrings do
- parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ charstrings[i]=nil
end
- resetcharstrings()
+ stopparsing(fontdata,data)
end
end
+local gotodatatable=readers.helpers.gotodatatable
+local function cleanup(data,dictionaries)
+end
function readers.cff(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.cff
- if datatable then
- local offset=datatable.offset
- local glyphs=fontdata.glyphs
- if not f then
- report("invalid filehandle")
- return
- end
- if offset then
- setposition(f,offset)
- end
- local header=readheader(f)
- if header.major>1 then
- report("version mismatch")
- return
- end
- local names=readfontnames(f)
- local dictionaries=readtopdictionaries(f)
- local strings=readstrings(f)
- local data={
- header=header,
- names=names,
- dictionaries=dictionaries,
- strings=strings,
- nofglyphs=fontdata.nofglyphs,
- }
- parsedictionaries(data,data.dictionaries)
- local d=dictionaries[1]
- local c=d.cid
- fontdata.cffinfo={
- familynamename=d.familyname,
- fullname=d.fullname,
- boundingbox=d.boundingbox,
- weight=d.weight,
- italicangle=d.italicangle,
- underlineposition=d.underlineposition,
- underlinethickness=d.underlinethickness,
- monospaced=d.monospaced,
- }
- fontdata.cidinfo=c and {
- registry=c.registry,
- ordering=c.ordering,
- supplement=c.supplement,
- }
- if not specification.glyphs then
+ local tableoffset=gotodatatable(f,fontdata,"cff",specification.details)
+ if tableoffset then
+ local header=readheader(f)
+ if header.major~=1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local glyphs=fontdata.glyphs
+ local names=readfontnames(f)
+ local dictionaries=readtopdictionaries(f)
+ local strings=readstrings(f)
+ local data={
+ header=header,
+ names=names,
+ dictionaries=dictionaries,
+ strings=strings,
+ nofglyphs=fontdata.nofglyphs,
+ }
+ parsedictionaries(data,dictionaries,"cff")
+ local dic=dictionaries[1]
+ local cid=dic.cid
+ fontdata.cffinfo={
+ familynamename=dic.familyname,
+ fullname=dic.fullname,
+ boundingbox=dic.boundingbox,
+ weight=dic.weight,
+ italicangle=dic.italicangle,
+ underlineposition=dic.underlineposition,
+ underlinethickness=dic.underlinethickness,
+ monospaced=dic.monospaced,
+ }
+ fontdata.cidinfo=cid and {
+ registry=cid.registry,
+ ordering=cid.ordering,
+ supplement=cid.supplement,
+ }
+ if specification.glyphs then
+ local all=specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff")
else
- local cid=d.cid
- if cid and cid.fdselect then
- readfdselect(f,data,glyphs,specification.shapes or false)
- else
- readnoselect(f,data,glyphs,specification.shapes or false)
- end
+ readnoselect(f,fontdata,data,glyphs,all,"cff")
end
end
+ cleanup(data,dictionaries)
+ end
+end
+function readers.cff2(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"cff2",specification.glyphs)
+ if tableoffset then
+ local header=readheader(f)
+ if header.major~=2 then
+ report("only version %s is supported for table %a",2,"cff2")
+ return
+ end
+ local glyphs=fontdata.glyphs
+ local dictionaries={ readstring(f,header.dsize) }
+ local data={
+ header=header,
+ dictionaries=dictionaries,
+ nofglyphs=fontdata.nofglyphs,
+ }
+ parsedictionaries(data,dictionaries,"cff2")
+ local offset=dictionaries[1].vstore
+ if offset>0 then
+ local storeoffset=dictionaries[1].vstore+data.header.offset+2
+ local regions,deltas=readers.helpers.readvariationdata(f,storeoffset,factors)
+ data.regions=regions
+ data.deltas=deltas
+ else
+ data.regions={}
+ data.deltas={}
+ end
+ data.factors=specification.factors
+ local cid=data.dictionaries[1].cid
+ local all=specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ else
+ readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ end
+ cleanup(data,dictionaries)
+ end
+end
+function readers.cffcheck(filename)
+ local f=io.open(filename,"rb")
+ if f then
+ local fontdata={
+ glyphs={},
+ }
+ local header=readheader(f)
+ if header.major~=1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local names=readfontnames(f)
+ local dictionaries=readtopdictionaries(f)
+ local strings=readstrings(f)
+ local glyphs={}
+ local data={
+ header=header,
+ names=names,
+ dictionaries=dictionaries,
+ strings=strings,
+ glyphs=glyphs,
+ nofglyphs=4,
+ }
+ parsedictionaries(data,dictionaries,"cff")
+ local cid=data.dictionaries[1].cid
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,false)
+ else
+ readnoselect(f,fontdata,data,glyphs,false)
+ end
+ return data
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-cff”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-cff”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ttf” e0893de6d0f3f421ee4386fa90429db8] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ttf” ff587471f4297aa8ba0fa022609adc6e] ---
if not modules then modules={} end modules ['font-ttf']={
version=1.001,
@@ -5537,9 +7537,12 @@ if not modules then modules={} end modules ['font-ttf']={
license="see context related readme files"
}
local next,type,unpack=next,type,unpack
-local bittest=bit32.btest
-local sqrt=math.sqrt
+local band,rshift=bit32.band,bit32.rshift
+local sqrt,round=math.sqrt,math.round
+local char=string.char
+local concat=table.concat
local report=logs.reporter("otf reader","ttf")
+local trace_deltas=false
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
@@ -5551,22 +7554,50 @@ local readulong=streamreader.readcardinal4
local readchar=streamreader.readinteger1
local readshort=streamreader.readinteger2
local read2dot14=streamreader.read2dot14
+local readinteger=streamreader.readinteger1
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ skipbytes=streamreader.skip
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readulong=streamreader.readcardinal4
+ readchar=streamreader.readinteger1
+ readshort=streamreader.readinteger2
+ read2dot14=streamreader.read2dot14
+ readinteger=streamreader.readinteger1
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+end)
+local short=2
+local ushort=2
+local ulong=4
+local helpers=readers.helpers
+local gotodatatable=helpers.gotodatatable
local function mergecomposites(glyphs,shapes)
local function merge(index,shape,components)
local contours={}
+ local points={}
local nofcontours=0
+ local nofpoints=0
+ local offset=0
+ local deltas=shape.deltas
for i=1,#components do
local component=components[i]
local subindex=component.index
local subshape=shapes[subindex]
local subcontours=subshape.contours
+ local subpoints=subshape.points
if not subcontours then
local subcomponents=subshape.components
if subcomponents then
- subcontours=merge(subindex,subshape,subcomponents)
+ subcontours,subpoints=merge(subindex,subshape,subcomponents)
end
end
- if subcontours then
+ if subpoints then
local matrix=component.matrix
local xscale=matrix[1]
local xrotate=matrix[2]
@@ -5574,35 +7605,38 @@ local function mergecomposites(glyphs,shapes)
local yscale=matrix[4]
local xoffset=matrix[5]
local yoffset=matrix[6]
+ for i=1,#subpoints do
+ local p=subpoints[i]
+ local x=p[1]
+ local y=p[2]
+ nofpoints=nofpoints+1
+ points[nofpoints]={
+ xscale*x+xrotate*y+xoffset,
+ yscale*y+yrotate*x+yoffset,
+ p[3]
+ }
+ end
for i=1,#subcontours do
- local points=subcontours[i]
- local result={}
- for i=1,#points do
- local p=points[i]
- local x=p[1]
- local y=p[2]
- result[i]={
- xscale*x+xrotate*y+xoffset,
- yscale*y+yrotate*x+yoffset,
- p[3]
- }
- end
nofcontours=nofcontours+1
- contours[nofcontours]=result
+ contours[nofcontours]=offset+subcontours[i]
end
+ offset=offset+#subpoints
else
report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex)
end
end
+ shape.points=points
shape.contours=contours
shape.components=nil
- return contours
+ return contours,points
end
for index=1,#glyphs do
local shape=shapes[index]
- local components=shape.components
- if components then
- merge(index,shape,components)
+ if shape then
+ local components=shape.components
+ if components then
+ merge(index,shape,components)
+ end
end
end
end
@@ -5612,123 +7646,510 @@ local function readnothing(f,nofcontours)
}
end
local function curveto(m_x,m_y,l_x,l_y,r_x,r_y)
- return {
+ return
l_x+2/3*(m_x-l_x),l_y+2/3*(m_y-l_y),
r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
- r_x,r_y,"c"
- }
+ r_x,r_y,"c"
+end
+local function applyaxis(glyph,shape,deltas,dowidth)
+ local points=shape.points
+ if points then
+ local nofpoints=#points
+ local h=nofpoints+2
+ local l=nofpoints+1
+ local dw=0
+ local dl=0
+ for i=1,#deltas do
+ local deltaset=deltas[i]
+ local xvalues=deltaset.xvalues
+ local yvalues=deltaset.yvalues
+ local dpoints=deltaset.points
+ local factor=deltaset.factor
+ if dpoints then
+ local nofdpoints=#dpoints
+ for i=1,nofdpoints do
+ local d=dpoints[i]
+ local p=points[d]
+ if p then
+ if xvalues then
+ local x=xvalues[i]
+ if x and x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ end
+ if yvalues then
+ local y=yvalues[i]
+ if y and y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ end
+ elseif dowidth then
+ if d==h then
+ local x=xvalues[i]
+ if x then
+ dw=dw+factor*x
+ end
+ elseif d==l then
+ local x=xvalues[i]
+ if x then
+ dl=dl+factor*x
+ end
+ end
+ end
+ end
+ else
+ for i=1,nofpoints do
+ local p=points[i]
+ if xvalues then
+ local x=xvalues[i]
+ if x and x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ end
+ if yvalues then
+ local y=yvalues[i]
+ if y and y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ end
+ end
+ if dowidth then
+ local x=xvalues[h]
+ if x then
+ dw=dw+factor*x
+ end
+ local x=xvalues[l]
+ if x then
+ dl=dl+factor*x
+ end
+ end
+ end
+ end
+ if dowidth then
+ local width=glyph.width or 0
+ glyph.width=width+dw-dl
+ end
+ else
+ report("no points for glyph %a",glyph.name)
+ end
end
-local function contours2outlines(glyphs,shapes)
- local quadratic=true
+local quadratic=false
+local function contours2outlines_normal(glyphs,shapes)
for index=1,#glyphs do
- local glyph=glyphs[index]
local shape=shapes[index]
- local contours=shape.contours
- if contours then
- local nofcontours=#contours
- local segments={}
- local nofsegments=0
- glyph.segments=segments
- if nofcontours>0 then
- for i=1,nofcontours do
- local contour=contours[i]
- local nofcontour=#contour
- if nofcontour>0 then
- local first_pt=contour[1]
- local first_on=first_pt[3]
- if nofcontour==1 then
- first_pt[3]="m"
- nofsegments=nofsegments+1
- segments[nofsegments]=first_pt
- else
+ if shape then
+ local glyph=glyphs[index]
+ local contours=shape.contours
+ local points=shape.points
+ if contours then
+ local nofcontours=#contours
+ local segments={}
+ local nofsegments=0
+ glyph.segments=segments
+ if nofcontours>0 then
+ local px,py=0,0
+ local first=1
+ for i=1,nofcontours do
+ local last=contours[i]
+ if last>=first then
+ local first_pt=points[first]
local first_on=first_pt[3]
- local last_pt=contour[nofcontour]
- local last_on=last_pt[3]
- local start=1
- local control_pt=false
- if first_on then
- start=2
- else
- if last_on then
- first_pt=last_pt
+ if first==last then
+ first_pt[3]="m"
+ nofsegments=nofsegments+1
+ segments[nofsegments]=first_pt
+ else
+ local first_on=first_pt[3]
+ local last_pt=points[last]
+ local last_on=last_pt[3]
+ local start=1
+ local control_pt=false
+ if first_on then
+ start=2
else
- first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ if last_on then
+ first_pt=last_pt
+ else
+ first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ end
+ control_pt=first_pt
end
- control_pt=first_pt
- end
- nofsegments=nofsegments+1
- segments[nofsegments]={ first_pt[1],first_pt[2],"m" }
- local previous_pt=first_pt
- for i=start,nofcontour do
- local current_pt=contour[i]
- local current_on=current_pt[3]
- local previous_on=previous_pt[3]
- if previous_on then
- if current_on then
+ local x,y=first_pt[1],first_pt[2]
+ if not done then
+ xmin,ymin,xmax,ymax=x,y,x,y
+ done=true
+ end
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"m" }
+ if not quadratic then
+ px,py=x,y
+ end
+ local previous_pt=first_pt
+ for i=first,last do
+ local current_pt=points[i]
+ local current_on=current_pt[3]
+ local previous_on=previous_pt[3]
+ if previous_on then
+ if current_on then
+ local x,y=current_pt[1],current_pt[2]
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"l" }
+ if not quadratic then
+ px,py=x,y
+ end
+ else
+ control_pt=current_pt
+ end
+ elseif current_on then
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=current_pt[1],current_pt[2]
nofsegments=nofsegments+1
- segments[nofsegments]={ current_pt[1],current_pt[2],"l" }
+ if quadratic then
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ control_pt=false
else
+ local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2
+ local x1,y1=control_pt[1],control_pt[2]
+ nofsegments=nofsegments+1
+ if quadratic then
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
control_pt=current_pt
end
- elseif current_on then
- local ps=segments[nofsegments]
+ previous_pt=current_pt
+ end
+ if first_pt==last_pt then
+ else
nofsegments=nofsegments+1
- if quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],current_pt[1],current_pt[2],"q" }
+ local x2,y2=first_pt[1],first_pt[2]
+ if not control_pt then
+ segments[nofsegments]={ x2,y2,"l" }
+ elseif quadratic then
+ local x1,y1=control_pt[1],control_pt[2]
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
else
- local p=segments[nofsegments-1] local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],current_pt[1],current_pt[2])
+ local x1,y1=control_pt[1],control_pt[2]
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
end
- control_pt=false
+ end
+ end
+ end
+ first=last+1
+ end
+ end
+ end
+ end
+ end
+end
+local function contours2outlines_shaped(glyphs,shapes,keepcurve)
+ for index=1,#glyphs do
+ local shape=shapes[index]
+ if shape then
+ local glyph=glyphs[index]
+ local contours=shape.contours
+ local points=shape.points
+ if contours then
+ local nofcontours=#contours
+ local segments=keepcurve and {} or nil
+ local nofsegments=0
+ if keepcurve then
+ glyph.segments=segments
+ end
+ if nofcontours>0 then
+ local xmin,ymin,xmax,ymax,done=0,0,0,0,false
+ local px,py=0,0
+ local first=1
+ for i=1,nofcontours do
+ local last=contours[i]
+ if last>=first then
+ local first_pt=points[first]
+ local first_on=first_pt[3]
+ if first==last then
+ if keepcurve then
+ first_pt[3]="m"
+ nofsegments=nofsegments+1
+ segments[nofsegments]=first_pt
+ end
+ else
+ local first_on=first_pt[3]
+ local last_pt=points[last]
+ local last_on=last_pt[3]
+ local start=1
+ local control_pt=false
+ if first_on then
+ start=2
else
+ if last_on then
+ first_pt=last_pt
+ else
+ first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ end
+ control_pt=first_pt
+ end
+ local x,y=first_pt[1],first_pt[2]
+ if not done then
+ xmin,ymin,xmax,ymax=x,y,x,y
+ done=true
+ else
+ if x<xmin then xmin=x elseif x>xmax then xmax=x end
+ if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ end
+ if keepcurve then
nofsegments=nofsegments+1
- local halfway_x=(previous_pt[1]+current_pt[1])/2
- local halfway_y=(previous_pt[2]+current_pt[2])/2
+ segments[nofsegments]={ x,y,"m" }
+ end
+ if not quadratic then
+ px,py=x,y
+ end
+ local previous_pt=first_pt
+ for i=first,last do
+ local current_pt=points[i]
+ local current_on=current_pt[3]
+ local previous_on=previous_pt[3]
+ if previous_on then
+ if current_on then
+ local x,y=current_pt[1],current_pt[2]
+ if x<xmin then xmin=x elseif x>xmax then xmax=x end
+ if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"l" }
+ end
+ if not quadratic then
+ px,py=x,y
+ end
+ else
+ control_pt=current_pt
+ end
+ elseif current_on then
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=current_pt[1],current_pt[2]
+ if quadratic then
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ end
+ control_pt=false
+ else
+ local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2
+ local x1,y1=control_pt[1],control_pt[2]
+ if quadratic then
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ end
+ control_pt=current_pt
+ end
+ previous_pt=current_pt
+ end
+ if first_pt==last_pt then
+ elseif not control_pt then
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ first_pt[1],first_pt[2],"l" }
+ end
+ else
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=first_pt[1],first_pt[2]
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
if quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],halfway_x,halfway_y,"q" }
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
else
- local p=segments[nofsegments-1] local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],halfway_x,halfway_y)
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
end
- control_pt=current_pt
end
- previous_pt=current_pt
end
- if first_pt==last_pt then
+ end
+ first=last+1
+ end
+ glyph.boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
+ end
+ end
+ end
+ end
+end
+local c_zero=char(0)
+local s_zero=char(0,0)
+local function toushort(n)
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+local function toshort(n)
+ if n<0 then
+ n=n+0x10000
+ end
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+local function repackpoints(glyphs,shapes)
+ local noboundingbox={ 0,0,0,0 }
+ local result={}
+ for index=1,#glyphs do
+ local shape=shapes[index]
+ if shape then
+ local r=0
+ local glyph=glyphs[index]
+ if false then
+ else
+ local contours=shape.contours
+ local nofcontours=contours and #contours or 0
+ local boundingbox=glyph.boundingbox or noboundingbox
+ r=r+1 result[r]=toshort(nofcontours)
+ r=r+1 result[r]=toshort(boundingbox[1])
+ r=r+1 result[r]=toshort(boundingbox[2])
+ r=r+1 result[r]=toshort(boundingbox[3])
+ r=r+1 result[r]=toshort(boundingbox[4])
+ if nofcontours>0 then
+ for i=1,nofcontours do
+ r=r+1 result[r]=toshort(contours[i]-1)
+ end
+ r=r+1 result[r]=s_zero
+ local points=shape.points
+ local currentx=0
+ local currenty=0
+ local xpoints={}
+ local ypoints={}
+ local x=0
+ local y=0
+ local lastflag=nil
+ local nofflags=0
+ for i=1,#points do
+ local pt=points[i]
+ local px=pt[1]
+ local py=pt[2]
+ local fl=pt[3] and 0x01 or 0x00
+ if px==currentx then
+ fl=fl+0x10
+ else
+ local dx=round(px-currentx)
+ if dx<-255 or dx>255 then
+ x=x+1 xpoints[x]=toshort(dx)
+ elseif dx<0 then
+ fl=fl+0x02
+ x=x+1 xpoints[x]=char(-dx)
+ elseif dx>0 then
+ fl=fl+0x12
+ x=x+1 xpoints[x]=char(dx)
+ else
+ fl=fl+0x02
+ x=x+1 xpoints[x]=c_zero
+ end
+ end
+ if py==currenty then
+ fl=fl+0x20
+ else
+ local dy=round(py-currenty)
+ if dy<-255 or dy>255 then
+ y=y+1 ypoints[y]=toshort(dy)
+ elseif dy<0 then
+ fl=fl+0x04
+ y=y+1 ypoints[y]=char(-dy)
+ elseif dy>0 then
+ fl=fl+0x24
+ y=y+1 ypoints[y]=char(dy)
else
- nofsegments=nofsegments+1
- if not control_pt then
- segments[nofsegments]={ first_pt[1],first_pt[2],"l" }
- elseif quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],first_pt[1],first_pt[2],"q" }
- else
- local p=last_pt local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],first_pt[1],first_pt[2])
- end
+ fl=fl+0x04
+ y=y+1 ypoints[y]=c_zero
end
end
+ currentx=px
+ currenty=py
+ if lastflag==fl then
+ nofflags=nofflags+1
+ else
+ if nofflags==1 then
+ r=r+1 result[r]=char(lastflag)
+ elseif nofflags==2 then
+ r=r+1 result[r]=char(lastflag,lastflag)
+ elseif nofflags>2 then
+ lastflag=lastflag+0x08
+ r=r+1 result[r]=char(lastflag,nofflags-1)
+ end
+ nofflags=1
+ lastflag=fl
+ end
+ end
+ if nofflags==1 then
+ r=r+1 result[r]=char(lastflag)
+ elseif nofflags==2 then
+ r=r+1 result[r]=char(lastflag,lastflag)
+ elseif nofflags>2 then
+ lastflag=lastflag+0x08
+ r=r+1 result[r]=char(lastflag,nofflags-1)
end
+ r=r+1 result[r]=concat(xpoints)
+ r=r+1 result[r]=concat(ypoints)
end
end
+ glyph.stream=concat(result,"",1,r)
+ else
end
end
end
-local function readglyph(f,nofcontours)
+local function readglyph(f,nofcontours)
local points={}
- local endpoints={}
local instructions={}
local flags={}
+ local contours={}
for i=1,nofcontours do
- endpoints[i]=readshort(f)+1
+ contours[i]=readshort(f)+1
end
- local nofpoints=endpoints[nofcontours]
+ local nofpoints=contours[nofcontours]
local nofinstructions=readushort(f)
skipbytes(f,nofinstructions)
local i=1
while i<=nofpoints do
local flag=readbyte(f)
flags[i]=flag
- if bittest(flag,0x0008) then
+ if band(flag,0x08)~=0 then
for j=1,readbyte(f) do
i=i+1
flags[i]=flag
@@ -5739,8 +8160,8 @@ local function readglyph(f,nofcontours)
local x=0
for i=1,nofpoints do
local flag=flags[i]
- local short=bittest(flag,0x0002)
- local same=bittest(flag,0x0010)
+ local short=band(flag,0x02)~=0
+ local same=band(flag,0x10)~=0
if short then
if same then
x=x+readbyte(f)
@@ -5751,13 +8172,13 @@ local function readglyph(f,nofcontours)
else
x=x+readshort(f)
end
- points[i]={ x,y,bittest(flag,0x0001) }
+ points[i]={ x,0,band(flag,0x01)~=0 }
end
local y=0
for i=1,nofpoints do
local flag=flags[i]
- local short=bittest(flag,0x0004)
- local same=bittest(flag,0x0020)
+ local short=band(flag,0x04)~=0
+ local same=band(flag,0x20)~=0
if short then
if same then
y=y+readbyte(f)
@@ -5770,15 +8191,11 @@ local function readglyph(f,nofcontours)
end
points[i][2]=y
end
- local first=1
- for i=1,#endpoints do
- local last=endpoints[i]
- endpoints[i]={ unpack(points,first,last) }
- first=last+1
- end
return {
type="glyph",
- contours=endpoints,
+ points=points,
+ contours=contours,
+ nofpoints=nofpoints,
}
end
local function readcomposite(f)
@@ -5788,8 +8205,8 @@ local function readcomposite(f)
while true do
local flags=readushort(f)
local index=readushort(f)
- local f_xyarg=bittest(flags,0x0002)
- local f_offset=bittest(flags,0x0800)
+ local f_xyarg=band(flags,0x0002)~=0
+ local f_offset=band(flags,0x0800)~=0
local xscale=1
local xrotate=0
local yrotate=0
@@ -5799,7 +8216,7 @@ local function readcomposite(f)
local base=false
local reference=false
if f_xyarg then
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
xoffset=readshort(f)
yoffset=readshort(f)
else
@@ -5807,7 +8224,7 @@ local function readcomposite(f)
yoffset=readchar(f)
end
else
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
base=readshort(f)
reference=readshort(f)
else
@@ -5815,21 +8232,21 @@ local function readcomposite(f)
reference=readchar(f)
end
end
- if bittest(flags,0x0008) then
+ if band(flags,0x0008)~=0 then
xscale=read2dot14(f)
yscale=xscale
if f_xyarg and f_offset then
xoffset=xoffset*xscale
yoffset=yoffset*yscale
end
- elseif bittest(flags,0x0040) then
+ elseif band(flags,0x0040)~=0 then
xscale=read2dot14(f)
yscale=read2dot14(f)
if f_xyarg and f_offset then
xoffset=xoffset*xscale
yoffset=yoffset*yscale
end
- elseif bittest(flags,0x0080) then
+ elseif band(flags,0x0080)~=0 then
xscale=read2dot14(f)
xrotate=read2dot14(f)
yrotate=read2dot14(f)
@@ -5842,16 +8259,16 @@ local function readcomposite(f)
nofcomponents=nofcomponents+1
components[nofcomponents]={
index=index,
- usemine=bittest(flags,0x0200),
- round=bittest(flags,0x0006),
+ usemine=band(flags,0x0200)~=0,
+ round=band(flags,0x0006)~=0,
base=base,
reference=reference,
matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset },
}
- if bittest(flags,0x0100) then
+ if band(flags,0x0100)~=0 then
instructions=true
end
- if not bittest(flags,0x0020) then
+ if not band(flags,0x0020)~=0 then
break
end
end
@@ -5869,15 +8286,13 @@ function readers.loca(f,fontdata,specification)
local locations={}
setposition(f,datatable.offset)
if format==1 then
- local nofglyphs=datatable.length/4-1
- -1
+ local nofglyphs=datatable.length/4-2
for i=0,nofglyphs do
locations[i]=offset+readulong(f)
end
fontdata.nofglyphs=nofglyphs
else
- local nofglyphs=datatable.length/2-1
- -1
+ local nofglyphs=datatable.length/2-2
for i=0,nofglyphs do
locations[i]=offset+readushort(f)*2
end
@@ -5888,61 +8303,325 @@ function readers.loca(f,fontdata,specification)
end
end
function readers.glyf(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.glyf
- if datatable then
- local locations=fontdata.locations
- if locations then
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local filesize=fontdata.filesize
- local nothing={ 0,0,0,0 }
- local shapes={}
- local loadshapes=specification.shapes
- for index=0,nofglyphs do
- local location=locations[index]
- if location>=filesize then
- report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
- fontdata.nofglyphs=index-1
- fontdata.badfont=true
- break
- elseif location>0 then
- setposition(f,location)
- local nofcontours=readshort(f)
- glyphs[index].boundingbox={
- readshort(f),
- readshort(f),
- readshort(f),
- readshort(f),
- }
- if not loadshapes then
- elseif nofcontours==0 then
- shapes[index]=readnothing(f,nofcontours)
- elseif nofcontours>0 then
- shapes[index]=readglyph(f,nofcontours)
+ local tableoffset=gotodatatable(f,fontdata,"glyf",specification.glyphs)
+ if tableoffset then
+ local locations=fontdata.locations
+ if locations then
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local filesize=fontdata.filesize
+ local nothing={ 0,0,0,0 }
+ local shapes={}
+ local loadshapes=specification.shapes or specification.instance
+ for index=0,nofglyphs do
+ local location=locations[index]
+ if location>=filesize then
+ report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
+ fontdata.nofglyphs=index-1
+ fontdata.badfont=true
+ break
+ elseif location>0 then
+ setposition(f,location)
+ local nofcontours=readshort(f)
+ glyphs[index].boundingbox={
+ readshort(f),
+ readshort(f),
+ readshort(f),
+ readshort(f),
+ }
+ if not loadshapes then
+ elseif nofcontours==0 then
+ shapes[index]=readnothing(f,nofcontours)
+ elseif nofcontours>0 then
+ shapes[index]=readglyph(f,nofcontours)
+ else
+ shapes[index]=readcomposite(f,nofcontours)
+ end
+ else
+ if loadshapes then
+ shapes[index]={}
+ end
+ glyphs[index].boundingbox=nothing
+ end
+ end
+ if loadshapes then
+ if readers.gvar then
+ readers.gvar(f,fontdata,specification,glyphs,shapes)
+ end
+ mergecomposites(glyphs,shapes)
+ if specification.instance then
+ if specification.streams then
+ repackpoints(glyphs,shapes)
+ else
+ contours2outlines_shaped(glyphs,shapes,specification.shapes)
+ end
+ elseif specification.shapes then
+ contours2outlines_normal(glyphs,shapes)
+ end
+ end
+ end
+ end
+end
+local function readtuplerecord(f,nofaxis)
+ local record={}
+ for i=1,nofaxis do
+ record[i]=read2dot14(f)
+ end
+ return record
+end
+local function readpoints(f)
+ local count=readbyte(f)
+ if count==0 then
+ return nil,0
+ else
+ if count<128 then
+ elseif band(count,0x80)~=0 then
+ count=band(count,0x7F)*256+readbyte(f)
+ else
+ end
+ local points={}
+ local p=0
+ local n=1
+ while p<count do
+ local control=readbyte(f)
+ local runreader=band(control,0x80)~=0 and readushort or readbyte
+ local runlength=band(control,0x7F)
+ for i=1,runlength+1 do
+ n=n+runreader(f)
+ p=p+1
+ points[p]=n
+ end
+ end
+ return points,p
+ end
+end
+local function readdeltas(f,nofpoints)
+ local deltas={}
+ local p=0
+ local z=0
+ while nofpoints>0 do
+ local control=readbyte(f)
+if not control then
+ break
+end
+ local allzero=band(control,0x80)~=0
+ local runlength=band(control,0x3F)+1
+ if allzero then
+ z=z+runlength
+ else
+ local runreader=band(control,0x40)~=0 and readshort or readinteger
+ if z>0 then
+ for i=1,z do
+ p=p+1
+ deltas[p]=0
+ end
+ z=0
+ end
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=runreader(f)
+ end
+ end
+ nofpoints=nofpoints-runlength
+ end
+ if p>0 then
+ return deltas
+ else
+ end
+end
+local function readdeltas(f,nofpoints)
+ local deltas={}
+ local p=0
+ while nofpoints>0 do
+ local control=readbyte(f)
+ if control then
+ local allzero=band(control,0x80)~=0
+ local runlength=band(control,0x3F)+1
+ if allzero then
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=0
+ end
+ else
+ local runreader=band(control,0x40)~=0 and readshort or readinteger
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=runreader(f)
+ end
+ end
+ nofpoints=nofpoints-runlength
+ else
+ break
+ end
+ end
+ if p>0 then
+ return deltas
+ else
+ end
+end
+function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
+ local instance=specification.instance
+ if not instance then
+ return
+ end
+ local factors=specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset=gotodatatable(f,fontdata,"gvar",specification.variable or specification.shapes)
+ if tableoffset then
+ local version=readulong(f)
+ local nofaxis=readushort(f)
+ local noftuples=readushort(f)
+ local tupleoffset=tableoffset+readulong(f)
+ local nofglyphs=readushort(f)
+ local flags=readushort(f)
+ local dataoffset=tableoffset+readulong(f)
+ local data={}
+ local tuples={}
+ local glyphdata=fontdata.glyphs
+ local dowidth=not fontdata.variabledata.hvarwidths
+ if band(flags,0x0001)~=0 then
+ for i=1,nofglyphs+1 do
+ data[i]=dataoffset+readulong(f)
+ end
+ else
+ for i=1,nofglyphs+1 do
+ data[i]=dataoffset+2*readushort(f)
+ end
+ end
+ if noftuples>0 then
+ setposition(f,tupleoffset)
+ for i=1,noftuples do
+ tuples[i]=readtuplerecord(f,nofaxis)
+ end
+ end
+ local nextoffset=false
+ local startoffset=data[1]
+ for i=1,nofglyphs do
+ nextoffset=data[i+1]
+ local glyph=glyphdata[i-1]
+ local name=trace_deltas and glyph.name
+ if startoffset==nextoffset then
+ if name then
+ report("no deltas for glyph %a",name)
+ end
+ else
+ local shape=shapedata[i-1]
+ if not shape then
+ if name then
+ report("no shape for glyph %a",name)
+ end
+ else
+ lastoffset=startoffset
+ setposition(f,startoffset)
+ local flags=readushort(f)
+ local count=band(flags,0x0FFF)
+ local offset=startoffset+readushort(f)
+ local deltas={}
+ local allpoints=(shape.nofpoints or 0)
+ local shared=false
+ local nofshared=0
+ if band(flags,0x8000)~=0 then
+ local current=getposition(f)
+ setposition(f,offset)
+ shared,nofshared=readpoints(f)
+ offset=getposition(f)
+ setposition(f,current)
+ end
+ for j=1,count do
+ local size=readushort(f)
+ local flags=readushort(f)
+ local index=band(flags,0x0FFF)
+ local haspeak=band(flags,0x8000)~=0
+ local intermediate=band(flags,0x4000)~=0
+ local private=band(flags,0x2000)~=0
+ local peak=nil
+ local start=nil
+ local stop=nil
+ local xvalues=nil
+ local yvalues=nil
+ local points=shared
+ local nofpoints=nofshared
+ if haspeak then
+ peak=readtuplerecord(f,nofaxis)
else
- shapes[index]=readcomposite(f,nofcontours)
+ if index+1>#tuples then
+ report("error, bad tuple index",index)
+ end
+ peak=tuples[index+1]
end
- else
- if loadshapes then
- shapes[index]={}
+ if intermediate then
+ start=readtuplerecord(f,nofaxis)
+ stop=readtuplerecord(f,nofaxis)
+ end
+ if size>0 then
+ local current=getposition(f)
+ setposition(f,offset)
+ if private then
+ points,nofpoints=readpoints(f)
+ end
+ if nofpoints==0 then
+ nofpoints=allpoints+4
+ end
+ if nofpoints>0 then
+ xvalues=readdeltas(f,nofpoints)
+ yvalues=readdeltas(f,nofpoints)
+ end
+ offset=offset+size
+ setposition(f,current)
+ end
+ if not xvalues and not yvalues then
+ points=nil
+ end
+ local s=1
+ for i=1,nofaxis do
+ local f=factors[i]
+ local peak=peak and peak [i] or 0
+ local start=start and start[i] or (peak<0 and peak or 0)
+ local stop=stop and stop [i] or (peak>0 and peak or 0)
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ if s==0 then
+ if name then
+ report("no deltas applied for glyph %a",name)
+ end
+ else
+ deltas[#deltas+1]={
+ factor=s,
+ points=points,
+ xvalues=xvalues,
+ yvalues=yvalues,
+ }
end
- glyphs[index].boundingbox=nothing
end
- end
- if loadshapes then
- mergecomposites(glyphs,shapes)
- contours2outlines(glyphs,shapes)
+ if shape.type=="glyph" then
+ applyaxis(glyph,shape,deltas,dowidth)
+ else
+ shape.deltas=deltas
+ end
end
end
+ startoffset=nextoffset
end
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ttf”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ttf”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-dsp” 4a5266ada979d5c2d48867dc3ffaefea] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-dsp” 9cade9beb226c61b4323729aca1f4a80] ---
if not modules then modules={} end modules ['font-dsp']={
version=1.001,
@@ -5952,34 +8631,80 @@ if not modules then modules={} end modules ['font-dsp']={
license="see context related readme files"
}
local next,type=next,type
-local bittest=bit32.btest
+local band=bit32.band
+local extract=bit32.extract
+local bor=bit32.bor
+local lshift=bit32.lshift
local rshift=bit32.rshift
-local concat=table.concat
+local gsub=string.gsub
local lower=string.lower
-local copy=table.copy
local sub=string.sub
local strip=string.strip
local tohash=table.tohash
+local concat=table.concat
+local copy=table.copy
local reversed=table.reversed
+local sort=table.sort
+local insert=table.insert
+local round=math.round
+local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
+local sequenced=table.sequenced
local report=logs.reporter("otf reader")
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
local getposition=streamreader.getposition
-local skipshort=streamreader.skipshort
local readushort=streamreader.readcardinal2
local readulong=streamreader.readcardinal4
+local readinteger=streamreader.readinteger1
local readshort=streamreader.readinteger2
-local readfword=readshort
local readstring=streamreader.readstring
local readtag=streamreader.readtag
local readbytes=streamreader.readbytes
+local readfixed=streamreader.readfixed4
+local read2dot14=streamreader.read2dot14
+local skipshort=streamreader.skipshort
+local skipbytes=streamreader.skip
+local readbytetable=streamreader.readbytetable
+local readbyte=streamreader.readbyte
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
+local readfword=readshort
+local short=2
+local ushort=2
+local ulong=4
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ readushort=streamreader.readcardinal2
+ readulong=streamreader.readcardinal4
+ readinteger=streamreader.readinteger1
+ readshort=streamreader.readinteger2
+ readstring=streamreader.readstring
+ readtag=streamreader.readtag
+ readbytes=streamreader.readbytes
+ readfixed=streamreader.readfixed4
+ read2dot14=streamreader.read2dot14
+ skipshort=streamreader.skipshort
+ skipbytes=streamreader.skip
+ readbytetable=streamreader.readbytetable
+ readbyte=streamreader.readbyte
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+ readfword=readshort
+end)
local gsubhandlers={}
local gposhandlers={}
+readers.gsubhandlers=gsubhandlers
+readers.gposhandlers=gposhandlers
+local helpers=readers.helpers
+local gotodatatable=helpers.gotodatatable
+local setvariabledata=helpers.setvariabledata
local lookupidoffset=-1
local classes={
"base",
@@ -6013,6 +8738,51 @@ local chaindirections={
chainedcontext=1,
reversechainedcontextsingle=-1,
}
+local function setmetrics(data,where,tag,d)
+ local w=data[where]
+ if w then
+ local v=w[tag]
+ if v then
+ w[tag]=v+d
+ end
+ end
+end
+local variabletags={
+ hasc=function(data,d) setmetrics(data,"windowsmetrics","typoascender",d) end,
+ hdsc=function(data,d) setmetrics(data,"windowsmetrics","typodescender",d) end,
+ hlgp=function(data,d) setmetrics(data,"windowsmetrics","typolinegap",d) end,
+ hcla=function(data,d) setmetrics(data,"windowsmetrics","winascent",d) end,
+ hcld=function(data,d) setmetrics(data,"windowsmetrics","windescent",d) end,
+ vasc=function(data,d) setmetrics(data,"vhea not done","ascent",d) end,
+ vdsc=function(data,d) setmetrics(data,"vhea not done","descent",d) end,
+ vlgp=function(data,d) setmetrics(data,"vhea not done","linegap",d) end,
+ xhgt=function(data,d) setmetrics(data,"windowsmetrics","xheight",d) end,
+ cpht=function(data,d) setmetrics(data,"windowsmetrics","capheight",d) end,
+ sbxs=function(data,d) setmetrics(data,"windowsmetrics","subscriptxsize",d) end,
+ sbys=function(data,d) setmetrics(data,"windowsmetrics","subscriptysize",d) end,
+ sbxo=function(data,d) setmetrics(data,"windowsmetrics","subscriptxoffset",d) end,
+ sbyo=function(data,d) setmetrics(data,"windowsmetrics","subscriptyoffset",d) end,
+ spxs=function(data,d) setmetrics(data,"windowsmetrics","superscriptxsize",d) end,
+ spys=function(data,d) setmetrics(data,"windowsmetrics","superscriptysize",d) end,
+ spxo=function(data,d) setmetrics(data,"windowsmetrics","superscriptxoffset",d) end,
+ spyo=function(data,d) setmetrics(data,"windowsmetrics","superscriptyoffset",d) end,
+ strs=function(data,d) setmetrics(data,"windowsmetrics","strikeoutsize",d) end,
+ stro=function(data,d) setmetrics(data,"windowsmetrics","strikeoutpos",d) end,
+ unds=function(data,d) setmetrics(data,"postscript","underlineposition",d) end,
+ undo=function(data,d) setmetrics(data,"postscript","underlinethickness",d) end,
+}
+local read_cardinal={
+ streamreader.readcardinal1,
+ streamreader.readcardinal2,
+ streamreader.readcardinal3,
+ streamreader.readcardinal4,
+}
+local read_integer={
+ streamreader.readinteger1,
+ streamreader.readinteger2,
+ streamreader.readinteger3,
+ streamreader.readinteger4,
+}
local lookupnames={
gsub={
single="gsub_single",
@@ -6036,31 +8806,236 @@ local lookupnames={
}
local lookupflags=setmetatableindex(function(t,k)
local v={
- bittest(k,0x0008) and true or false,
- bittest(k,0x0004) and true or false,
- bittest(k,0x0002) and true or false,
- bittest(k,0x0001) and true or false,
+ band(k,0x0008)~=0 and true or false,
+ band(k,0x0004)~=0 and true or false,
+ band(k,0x0002)~=0 and true or false,
+ band(k,0x0001)~=0 and true or false,
}
t[k]=v
return v
end)
+local function axistofactors(str)
+ local t=settings_to_hash(str)
+ for k,v in next,t do
+ t[k]=tonumber(v) or v
+ end
+ return t
+end
+local hash=table.setmetatableindex(function(t,k)
+ local v=sequenced(axistofactors(k),",")
+ t[k]=v
+ return v
+end)
+helpers.normalizedaxishash=hash
+local cleanname=fonts.names and fonts.names.cleanname or function(name)
+ return name and (gsub(lower(name),"[^%a%d]","")) or nil
+end
+helpers.cleanname=cleanname
+function helpers.normalizedaxis(str)
+ return hash[str] or str
+end
+local function getaxisscale(segments,minimum,default,maximum,user)
+ if not minimum or not default or not maximum then
+ return false
+ end
+ if user<minimum then
+ user=minimum
+ elseif user>maximum then
+ user=maximum
+ end
+ if user<default then
+ default=- (default-user)/(default-minimum)
+ elseif user>default then
+ default=(user-default)/(maximum-default)
+ else
+ default=0
+ end
+ if not segments then
+ return default
+ end
+ local e
+ for i=1,#segments do
+ local s=segments[i]
+ if type(s)~="number" then
+ report("using default axis scale")
+ return default
+ elseif s[1]>=default then
+ if s[2]==default then
+ return default
+ else
+ e=i
+ break
+ end
+ end
+ end
+ if e then
+ local b=segments[e-1]
+ local e=segments[e]
+ return b[2]+(e[2]-b[2])*(default-b[1])/(e[1]-b[1])
+ else
+ return false
+ end
+end
+local function getfactors(data,instancespec)
+ if instancespec==true then
+ elseif type(instancespec)~="string" or instancespec=="" then
+ return
+ end
+ local variabledata=data.variabledata
+ if not variabledata then
+ return
+ end
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ local segments=variabledata.segments
+ if instances and axis then
+ local values
+ if instancespec==true then
+ values={}
+ for i=1,#axis do
+ values[i]={
+ value=axis[i].default,
+ }
+ end
+ else
+ for i=1,#instances do
+ local instance=instances[i]
+ if cleanname(instance.subfamily)==instancespec then
+ values=instance.values
+ break
+ end
+ end
+ end
+ if values then
+ local factors={}
+ for i=1,#axis do
+ local a=axis[i]
+ factors[i]=getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
+ end
+ return factors
+ end
+ local values=axistofactors(hash[instancespec] or instancespec)
+ if values then
+ local factors={}
+ for i=1,#axis do
+ local a=axis[i]
+ local d=a.default
+ factors[i]=getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
+ end
+ return factors
+ end
+ end
+end
+local function getscales(regions,factors)
+ local scales={}
+ for i=1,#regions do
+ local region=regions[i]
+ local s=1
+ for j=1,#region do
+ local axis=region[j]
+ local f=factors[j]
+ local start=axis.start
+ local peak=axis.peak
+ local stop=axis.stop
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ scales[i]=s
+ end
+ return scales
+end
+helpers.getaxisscale=getaxisscale
+helpers.getfactors=getfactors
+helpers.getscales=getscales
+helpers.axistofactors=axistofactors
+local function readvariationdata(f,storeoffset,factors)
+ local position=getposition(f)
+ setposition(f,storeoffset)
+ local format=readushort(f)
+ local regionoffset=storeoffset+readulong(f)
+ local nofdeltadata=readushort(f)
+ local deltadata=readcardinaltable(f,nofdeltadata,ulong)
+ setposition(f,regionoffset)
+ local nofaxis=readushort(f)
+ local nofregions=readushort(f)
+ local regions={}
+ for i=1,nofregions do
+ local t={}
+ for i=1,nofaxis do
+ t[i]={
+ start=read2dot14(f),
+ peak=read2dot14(f),
+ stop=read2dot14(f),
+ }
+ end
+ regions[i]=t
+ end
+ if factors then
+ for i=1,nofdeltadata do
+ setposition(f,storeoffset+deltadata[i])
+ local nofdeltasets=readushort(f)
+ local nofshorts=readushort(f)
+ local nofregions=readushort(f)
+ local usedregions={}
+ local deltas={}
+ for i=1,nofregions do
+ usedregions[i]=regions[readushort(f)+1]
+ end
+ for i=1,nofdeltasets do
+ local t=readintegertable(f,nofshorts,short)
+ for i=nofshorts+1,nofregions do
+ t[i]=readinteger(f)
+ end
+ deltas[i]=t
+ end
+ deltadata[i]={
+ regions=usedregions,
+ deltas=deltas,
+ scales=factors and getscales(usedregions,factors) or nil,
+ }
+ end
+ end
+ setposition(f,position)
+ return regions,deltadata
+end
+helpers.readvariationdata=readvariationdata
local function readcoverage(f,offset,simple)
setposition(f,offset)
local coverageformat=readushort(f)
- local coverage={}
if coverageformat==1 then
local nofcoverage=readushort(f)
if simple then
- for i=1,nofcoverage do
- coverage[i]=readushort(f)
+ if nofcoverage==1 then
+ return { readushort(f) }
+ elseif nofcoverage==2 then
+ return { readushort(f),readushort(f) }
+ else
+ return readcardinaltable(f,nofcoverage,ushort)
end
+ elseif nofcoverage==1 then
+ return { [readushort(f)]=0 }
+ elseif nofcoverage==2 then
+ return { [readushort(f)]=0,[readushort(f)]=1 }
else
+ local coverage={}
for i=0,nofcoverage-1 do
coverage[readushort(f)]=i
end
+ return coverage
end
elseif coverageformat==2 then
local nofranges=readushort(f)
+ local coverage={}
local n=simple and 1 or 0
for i=1,nofranges do
local firstindex=readushort(f)
@@ -6078,10 +9053,11 @@ local function readcoverage(f,offset,simple)
end
end
end
+ return coverage
else
report("unknown coverage format %a ",coverageformat)
+ return {}
end
- return coverage
end
local function readclassdef(f,offset,preset)
setposition(f,offset)
@@ -6136,34 +9112,150 @@ local function classtocoverage(defs)
return list
end
end
-local function readposition(f,format)
+local skips={ [0]=0,
+ 1,
+ 1,
+ 2,
+ 1,
+ 2,
+ 2,
+ 3,
+ 2,
+ 2,
+ 3,
+ 2,
+ 3,
+ 3,
+ 4,
+}
+local function readvariation(f,offset)
+ local p=getposition(f)
+ setposition(f,offset)
+ local outer=readushort(f)
+ local inner=readushort(f)
+ local format=readushort(f)
+ setposition(f,p)
+ if format==0x8000 then
+ return outer,inner
+ end
+end
+local function readposition(f,format,mainoffset,getdelta)
if format==0 then
- return nil
+ return false
end
- local x=bittest(format,0x0001) and readshort(f) or 0
- local y=bittest(format,0x0002) and readshort(f) or 0
- local h=bittest(format,0x0004) and readshort(f) or 0
- local v=bittest(format,0x0008) and readshort(f) or 0
- if x==0 and y==0 and h==0 and v==0 then
- return nil
+ if format==0x04 then
+ local h=readshort(f)
+ if h==0 then
+ return true
+ else
+ return { 0,0,h,0 }
+ end
+ end
+ if format==0x05 then
+ local x=readshort(f)
+ local h=readshort(f)
+ if x==0 and h==0 then
+ return true
+ else
+ return { x,0,h,0 }
+ end
+ end
+ if format==0x44 then
+ local h=readshort(f)
+ if getdelta then
+ local d=readshort(f)
+ if d>0 then
+ local outer,inner=readvariation(f,mainoffset+d)
+ if outer then
+ h=h+getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,1)
+ end
+ if h==0 then
+ return true
+ else
+ return { 0,0,h,0 }
+ end
+ end
+ local x=band(format,0x1)~=0 and readshort(f) or 0
+ local y=band(format,0x2)~=0 and readshort(f) or 0
+ local h=band(format,0x4)~=0 and readshort(f) or 0
+ local v=band(format,0x8)~=0 and readshort(f) or 0
+ if format>=0x10 then
+ local X=band(format,0x10)~=0 and skipshort(f) or 0
+ local Y=band(format,0x20)~=0 and skipshort(f) or 0
+ local H=band(format,0x40)~=0 and skipshort(f) or 0
+ local V=band(format,0x80)~=0 and skipshort(f) or 0
+ local s=skips[extract(format,4,4)]
+ if s>0 then
+ skipshort(f,s)
+ end
+ if getdelta then
+ if X>0 then
+ local outer,inner=readvariation(f,mainoffset+X)
+ if outer then
+ x=x+getdelta(outer,inner)
+ end
+ end
+ if Y>0 then
+ local outer,inner=readvariation(f,mainoffset+Y)
+ if outer then
+ y=y+getdelta(outer,inner)
+ end
+ end
+ if H>0 then
+ local outer,inner=readvariation(f,mainoffset+H)
+ if outer then
+ h=h+getdelta(outer,inner)
+ end
+ end
+ if V>0 then
+ local outer,inner=readvariation(f,mainoffset+V)
+ if outer then
+ v=v+getdelta(outer,inner)
+ end
+ end
+ end
+ return { x,y,h,v }
+ elseif x==0 and y==0 and h==0 and v==0 then
+ return true
else
return { x,y,h,v }
end
end
-local function readanchor(f,offset)
+local function readanchor(f,offset,getdelta)
if not offset or offset==0 then
return nil
end
setposition(f,offset)
- local format=readshort(f)
- if format==0 then
- report("invalid anchor format %i @ position %i",format,offset)
- return false
- elseif format>3 then
- report("unsupported anchor format %i @ position %i",format,offset)
- return false
+ local format=readshort(f)
+ local x=readshort(f)
+ local y=readshort(f)
+ if format==3 then
+ if getdelta then
+ local X=readshort(f)
+ local Y=readshort(f)
+ if X>0 then
+ local outer,inner=readvariation(f,offset+X)
+ if outer then
+ x=x+getdelta(outer,inner)
+ end
+ end
+ if Y>0 then
+ local outer,inner=readvariation(f,offset+Y)
+ if outer then
+ y=y+getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ return { x,y }
+ else
+ return { x,y }
end
- return { readshort(f),readshort(f) }
end
local function readfirst(f,offset)
if offset then
@@ -6171,23 +9263,15 @@ local function readfirst(f,offset)
end
return { readushort(f) }
end
-local function readarray(f,offset,first)
+function readarray(f,offset)
if offset then
setposition(f,offset)
end
local n=readushort(f)
- if first then
- local t={ first }
- for i=2,n do
- t[i]=readushort(f)
- end
- return t,n
+ if n==1 then
+ return { readushort(f) },1
elseif n>0 then
- local t={}
- for i=1,n do
- t[i]=readushort(f)
- end
- return t,n
+ return readcardinaltable(f,n,ushort),n
end
end
local function readcoveragearray(f,offset,t,simple)
@@ -6228,7 +9312,13 @@ local function readlookuparray(f,noflookups,nofcurrent)
if index>length then
length=index
end
- lookups[index]=readushort(f)+1
+ local lookup=readushort(f)+1
+ local list=lookups[index]
+ if list then
+ list[#list+1]=lookup
+ else
+ lookups[index]={ lookup }
+ end
end
for index=1,length do
if not lookups[index] then
@@ -6534,10 +9624,7 @@ function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
elseif subtype==2 then
local coverage=readushort(f)
local nofreplacements=readushort(f)
- local replacements={}
- for i=1,nofreplacements do
- replacements[i]=readushort(f)
- end
+ local replacements=readcardinaltable(f,nofreplacements,ushort)
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
newindex=newindex+1
@@ -6562,18 +9649,10 @@ local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
if subtype==1 then
local coverage=readushort(f)
local nofsequence=readushort(f)
- local sequences={}
- for i=1,nofsequence do
- sequences[i]=readushort(f)
- end
+ local sequences=readcardinaltable(f,nofsequence,ushort)
for i=1,nofsequence do
setposition(f,tableoffset+sequences[i])
- local n=readushort(f)
- local s={}
- for i=1,n do
- s[i]=readushort(f)
- end
- sequences[i]=s
+ sequences[i]=readcardinaltable(f,readushort(f),ushort)
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
@@ -6605,19 +9684,20 @@ function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,no
if subtype==1 then
local coverage=readushort(f)
local nofsets=readushort(f)
- local ligatures={}
- for i=1,nofsets do
- ligatures[i]=readushort(f)
- end
+ local ligatures=readcardinaltable(f,nofsets,ushort)
for i=1,nofsets do
local offset=lookupoffset+offset+ligatures[i]
setposition(f,offset)
local n=readushort(f)
- local l={}
- for i=1,n do
- l[i]=offset+readushort(f)
+ if n==1 then
+ ligatures[i]={ offset+readushort(f) }
+ else
+ local l={}
+ for i=1,n do
+ l[i]=offset+readushort(f)
+ end
+ ligatures[i]=l
end
- ligatures[i]=l
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
@@ -6671,32 +9751,35 @@ function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffs
before=readcoveragearray(f,tableoffset,before,true)
after=readcoveragearray(f,tableoffset,after,true)
return {
- coverage={
- format="reversecoverage",
- before=before,
- current=current,
- after=after,
- replacements=replacements,
+ format="reversecoverage",
+ rules={
+ {
+ before=before,
+ current=current,
+ after=after,
+ replacements=replacements,
+ }
}
},"reversechainedcontextsingle"
else
report("unsupported subtype %a in %a substitution",subtype,"reversechainedcontextsingle")
end
end
-local function readpairsets(f,tableoffset,sets,format1,format2)
+local function readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
local done={}
for i=1,#sets do
local offset=sets[i]
local reused=done[offset]
if not reused then
- setposition(f,tableoffset+offset)
+ offset=tableoffset+offset
+ setposition(f,offset)
local n=readushort(f)
reused={}
for i=1,n do
reused[i]={
readushort(f),
- readposition(f,format1),
- readposition(f,format2)
+ readposition(f,format1,offset,getdelta),
+ readposition(f,format2,offset,getdelta),
}
end
done[offset]=reused
@@ -6705,14 +9788,14 @@ local function readpairsets(f,tableoffset,sets,format1,format2)
end
return sets
end
-local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,mainoffset,getdelta)
local classlist1={}
for i=1,nofclasses1 do
local classlist2={}
classlist1[i]=classlist2
for j=1,nofclasses2 do
- local one=readposition(f,format1)
- local two=readposition(f,format2)
+ local one=readposition(f,format1,mainoffset,getdelta)
+ local two=readposition(f,format2,mainoffset,getdelta)
if one or two then
classlist2[j]={ one,two }
else
@@ -6726,33 +9809,34 @@ function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=readushort(f)
local format=readushort(f)
- local value=readposition(f,format)
+ local value=readposition(f,format,tableoffset,getdelta)
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
- coverage[index]=value
+ coverage[index]=value
end
return {
- format="pair",
- coverage=coverage
+ format="single",
+ coverage=coverage,
}
elseif subtype==2 then
local coverage=readushort(f)
local format=readushort(f)
- local values={}
local nofvalues=readushort(f)
+ local values={}
for i=1,nofvalues do
- values[i]=readposition(f,format)
+ values[i]=readposition(f,format,tableoffset,getdelta)
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
coverage[index]=values[newindex+1]
end
return {
- format="pair",
- coverage=coverage
+ format="single",
+ coverage=coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"single")
@@ -6762,12 +9846,13 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=readushort(f)
local format1=readushort(f)
local format2=readushort(f)
local sets=readarray(f)
- sets=readpairsets(f,tableoffset,sets,format1,format2)
+ sets=readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
local set=sets[newindex+1]
@@ -6779,9 +9864,9 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first=value[2]
local second=value[3]
if first or second then
- hash[other]={ first,second }
+ hash[other]={ first,second or nil }
else
- hash[other]=nil
+ hash[other]=nil
end
end
end
@@ -6789,7 +9874,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format="pair",
- coverage=coverage
+ coverage=coverage,
}
elseif subtype==2 then
local coverage=readushort(f)
@@ -6799,7 +9884,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local classdef2=readushort(f)
local nofclasses1=readushort(f)
local nofclasses2=readushort(f)
- local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+ local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
coverage=readcoverage(f,tableoffset+coverage)
classdef1=readclassdef(f,tableoffset+classdef1,coverage)
classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs)
@@ -6815,7 +9900,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first=offsets[1]
local second=offsets[2]
if first or second then
- hash[paired]={ first,second }
+ hash[paired]={ first,second or nil }
else
end
end
@@ -6826,7 +9911,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format="pair",
- coverage=usedcoverage
+ coverage=usedcoverage,
}
elseif subtype==3 then
report("yet unsupported subtype %a in %a positioning",subtype,"pair")
@@ -6838,6 +9923,7 @@ function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=tableoffset+readushort(f)
local nofrecords=readushort(f)
@@ -6846,24 +9932,27 @@ function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local entry=readushort(f)
local exit=readushort(f)
records[i]={
- entry=entry~=0 and (tableoffset+entry) or false,
- exit=exit~=0 and (tableoffset+exit ) or false,
+ entry~=0 and (tableoffset+entry) or false,
+ exit~=0 and (tableoffset+exit ) or nil,
}
end
+ local cc=(fontdata.temporary.cursivecount or 0)+1
+ fontdata.temporary.cursivecount=cc
+ cc="cc-"..cc
coverage=readcoverage(f,coverage)
for i=1,nofrecords do
local r=records[i]
records[i]={
- 1,
- readanchor(f,r.entry) or nil,
- readanchor(f,r.exit ) or nil,
+ cc,
+ readanchor(f,r[1],getdelta) or false,
+ readanchor(f,r[2],getdelta) or nil,
}
end
for index,newindex in next,coverage do
coverage[index]=records[newindex+1]
end
return {
- coverage=coverage
+ coverage=coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"cursive")
@@ -6873,6 +9962,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local markcoverage=tableoffset+readushort(f)
local basecoverage=tableoffset+readushort(f)
@@ -6899,7 +9989,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
for i=1,nofmarkclasses do
local mc=markclasses[i]
if mc then
- mc[2]=readanchor(f,mc[2])
+ mc[2]=readanchor(f,mc[2],getdelta)
end
end
setposition(f,baseoffset)
@@ -6947,7 +10037,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local classes=components[c]
if classes then
for i=1,nofclasses do
- local anchor=readanchor(f,classes[i])
+ local anchor=readanchor(f,classes[i],getdelta)
local bclass=baseclasses[i]
local bentry=bclass[b]
if bentry then
@@ -6989,7 +10079,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local r=baserecords[i]
local b=basecoverage[i]
for j=1,nofclasses do
- baseclasses[j][b]=readanchor(f,r[j])
+ baseclasses[j][b]=readanchor(f,r[j],getdelta)
end
end
for index,newindex in next,markcoverage do
@@ -7032,7 +10122,7 @@ do
setposition(f,offset)
local designsize=readushort(f)
if designsize>0 then
- local fontstyle=readushort(f)
+ local fontstyleid=readushort(f)
local guimenuid=readushort(f)
local minsize=readushort(f)
local maxsize=readushort(f)
@@ -7184,10 +10274,10 @@ do
local parameters=readushort(f)
local noflookups=readushort(f)
if noflookups>0 then
- local lookups={}
+ local lookups=readcardinaltable(f,noflookups,ushort)
feature.lookups=lookups
for j=1,noflookups do
- lookups[j]=readushort(f)+1
+ lookups[j]=lookups[j]+1
end
end
if parameters>0 then
@@ -7202,14 +10292,11 @@ do
end
local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
setposition(f,lookupoffset)
- local lookups={}
local noflookups=readushort(f)
- for i=1,noflookups do
- lookups[i]=readushort(f)
- end
+ local lookups=readcardinaltable(f,noflookups,ushort)
for lookupid=1,noflookups do
- local index=lookups[lookupid]
- setposition(f,lookupoffset+index)
+ local offset=lookups[lookupid]
+ setposition(f,lookupoffset+offset)
local subtables={}
local typebits=readushort(f)
local flagbits=readushort(f)
@@ -7217,10 +10304,9 @@ do
local lookupflags=lookupflags[flagbits]
local nofsubtables=readushort(f)
for j=1,nofsubtables do
- local offset=readushort(f)
- subtables[j]=offset+index
+ subtables[j]=offset+readushort(f)
end
- local markclass=bittest(flagbits,0x0010)
+ local markclass=band(flagbits,0x0010)~=0
if markclass then
markclass=readushort(f)
end
@@ -7240,21 +10326,9 @@ do
end
return lookups
end
- local function readscriptoffsets(f,fontdata,tableoffset)
- if not tableoffset then
- return
- end
- setposition(f,tableoffset)
- local version=readulong(f)
- if version~=0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,what,fontdata.filename)
- return
- end
- return tableoffset+readushort(f),tableoffset+readushort(f),tableoffset+readushort(f)
- end
local f_lookupname=formatters["%s_%s_%s"]
- local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
- local sequences=fontdata.sequences or {}
+ local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ local sequences=fontdata.sequences or {}
local sublookuplist=fontdata.sublookups or {}
fontdata.sequences=sequences
fontdata.sublookups=sublookuplist
@@ -7269,6 +10343,7 @@ do
local nofglyphs=fontdata.nofglyphs or #glyphs
local noflookups=#lookups
local lookupprefix=sub(what,2,2)
+ local usedlookups=false
for lookupid=1,noflookups do
local lookup=lookups[lookupid]
local lookuptype=lookup.type
@@ -7308,6 +10383,7 @@ do
local before=rule.before
local current=rule.current
local after=rule.after
+ local replacements=rule.replacements
if before then
for i=1,#before do
before[i]=tohash(before[i])
@@ -7315,15 +10391,41 @@ do
rule.before=reversed(before)
end
if current then
- for i=1,#current do
- current[i]=tohash(current[i])
+ if replacements then
+ local first=current[1]
+ local hash={}
+ local repl={}
+ for i=1,#first do
+ local c=first[i]
+ hash[c]=true
+ repl[c]=replacements[i]
+ end
+ rule.current={ hash }
+ rule.replacements=repl
+ else
+ for i=1,#current do
+ current[i]=tohash(current[i])
+ end
end
+ else
end
if after then
for i=1,#after do
after[i]=tohash(after[i])
end
end
+ if usedlookups then
+ local lookups=rule.lookups
+ if lookups then
+ for k,v in next,lookups do
+ if v then
+ for k,v in next,v do
+ usedlookups[v]=usedlookups[v]+1
+ end
+ end
+ end
+ end
+ end
end
end
end
@@ -7370,6 +10472,9 @@ do
report("no handler for lookup %a with type %a",lookupid,lookuptype)
end
end
+ if usedlookups then
+ report("used %s lookups: % t",what,sortedkeys(usedlookups))
+ end
local reported={}
local function report_issue(i,what,sequence,kind)
local name=sequence.name
@@ -7396,43 +10501,55 @@ do
else
local length=#rlookups
for index=1,length do
- local lookupid=rlookups[index]
- if lookupid then
- local h=sublookuphash[lookupid]
- if not h then
- local lookup=lookups[lookupid]
- if lookup then
- local d=lookup.done
- if d then
- nofsublookups=nofsublookups+1
- h={
- index=nofsublookups,
- name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
- derived=true,
- steps=d.steps,
- nofsteps=d.nofsteps,
- type=d.lookuptype,
- markclass=d.markclass or nil,
- flags=d.flags,
- }
- sublookuplist[nofsublookups]=copy(h)
- sublookuphash[lookupid]=nofsublookups
- sublookupcheck[lookupid]=1
- h=nofsublookups
+ local lookuplist=rlookups[index]
+ if lookuplist then
+ local length=#lookuplist
+ local found={}
+ local noffound=0
+ for index=1,length do
+ local lookupid=lookuplist[index]
+ if lookupid then
+ local h=sublookuphash[lookupid]
+ if not h then
+ local lookup=lookups[lookupid]
+ if lookup then
+ local d=lookup.done
+ if d then
+ nofsublookups=nofsublookups+1
+ local l={
+ index=nofsublookups,
+ name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
+ derived=true,
+ steps=d.steps,
+ nofsteps=d.nofsteps,
+ type=d.lookuptype or "gsub_single",
+ markclass=d.markclass or nil,
+ flags=d.flags,
+ }
+ sublookuplist[nofsublookups]=copy(l)
+ sublookuphash[lookupid]=nofsublookups
+ sublookupcheck[lookupid]=1
+ h=nofsublookups
+ else
+ report_issue(i,what,sequence,"missing")
+ rule.lookups=nil
+ break
+ end
+ else
+ report_issue(i,what,sequence,"bad")
+ rule.lookups=nil
+ break
+ end
else
- report_issue(i,what,sequence,"missing")
- rule.lookups=nil
- break
+ sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
+ end
+ if h then
+ noffound=noffound+1
+ found[noffound]=h
end
- else
- report_issue(i,what,sequence,"bad")
- rule.lookups=nil
- break
end
- else
- sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
end
- rlookups[index]=h or false
+ rlookups[index]=noffound>0 and found or false
else
rlookups[index]=false
end
@@ -7451,33 +10568,108 @@ do
end
end
end
- local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
- local datatable=fontdata.tables[what]
- if not datatable then
- return
- end
- local tableoffset=datatable.offset
- if not tableoffset then
- return
+ local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ setposition(f,variationsoffset)
+ local version=readulong(f)
+ local nofrecords=readulong(f)
+ local records={}
+ for i=1,nofrecords do
+ records[i]={
+ conditions=readulong(f),
+ substitutions=readulong(f),
+ }
end
- local scriptoffset,featureoffset,lookupoffset=readscriptoffsets(f,fontdata,tableoffset)
- if not scriptoffset then
- return
+ for i=1,nofrecords do
+ local record=records[i]
+ local offset=record.conditions
+ if offset==0 then
+ record.condition=nil
+ record.matchtype="always"
+ else
+ local offset=variationsoffset+offset
+ setposition(f,offset)
+ local nofconditions=readushort(f)
+ local conditions={}
+ for i=1,nofconditions do
+ conditions[i]=offset+readulong(f)
+ end
+ record.conditions=conditions
+ record.matchtype="condition"
+ end
end
- local scripts=readscriplan(f,fontdata,scriptoffset)
- local features=readfeatures(f,fontdata,featureoffset)
- local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
- if fontdata.features then
- fontdata.features[what]=scriptlangs
- else
- fontdata.features={ [what]=scriptlangs }
+ for i=1,nofrecords do
+ local record=records[i]
+ if record.matchtype=="condition" then
+ local conditions=record.conditions
+ for i=1,#conditions do
+ setposition(f,conditions[i])
+ conditions[i]={
+ format=readushort(f),
+ axis=readushort(f),
+ minvalue=read2dot14(f),
+ maxvalue=read2dot14(f),
+ }
+ end
+ end
end
- if not lookupstoo then
- return
+ for i=1,nofrecords do
+ local record=records[i]
+ local offset=record.substitutions
+ if offset==0 then
+ record.substitutions={}
+ else
+ setposition(f,variationsoffset+offset)
+ local version=readulong(f)
+ local nofsubstitutions=readushort(f)
+ local substitutions={}
+ for i=1,nofsubstitutions do
+ substitutions[readushort(f)]=readulong(f)
+ end
+ for index,alternates in sortedhash(substitutions) do
+ if index==0 then
+ record.substitutions=false
+ else
+ local tableoffset=variationsoffset+offset+alternates
+ setposition(f,tableoffset)
+ local parameters=readulong(f)
+ local noflookups=readushort(f)
+ local lookups=readcardinaltable(f,noflookups,ushort)
+ record.substitutions=lookups
+ end
+ end
+ end
end
- local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
- if lookups then
- resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
+ setvariabledata(fontdata,"features",records)
+ end
+ local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
+ local tableoffset=gotodatatable(f,fontdata,what,true)
+ if tableoffset then
+ local version=readulong(f)
+ local scriptoffset=tableoffset+readushort(f)
+ local featureoffset=tableoffset+readushort(f)
+ local lookupoffset=tableoffset+readushort(f)
+ local variationsoffset=version>0x00010000 and (tableoffset+readulong(f)) or 0
+ if not scriptoffset then
+ return
+ end
+ local scripts=readscriplan(f,fontdata,scriptoffset)
+ local features=readfeatures(f,fontdata,featureoffset)
+ local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
+ if fontdata.features then
+ fontdata.features[what]=scriptlangs
+ else
+ fontdata.features={ [what]=scriptlangs }
+ end
+ if not lookupstoo then
+ return
+ end
+ local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
+ if lookups then
+ resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ end
+ if variationsoffset>0 then
+ loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ end
end
end
local function checkkerns(f,fontdata,specification)
@@ -7496,57 +10688,61 @@ do
report("ignoring global kern table using gpos kern feature")
return
end
- report("adding global kern table as gpos feature %a",name)
setposition(f,datatable.offset)
local version=readushort(f)
local noftables=readushort(f)
- local kerns=setmetatableindex("table")
- for i=1,noftables do
- local version=readushort(f)
- local length=readushort(f)
- local coverage=readushort(f)
- local format=bit32.rshift(coverage,8)
- if format==0 then
- local nofpairs=readushort(f)
- local searchrange=readushort(f)
- local entryselector=readushort(f)
- local rangeshift=readushort(f)
- for i=1,nofpairs do
- kerns[readushort(f)][readushort(f)]=readfword(f)
+ if noftables>1 then
+ report("adding global kern table as gpos feature %a",name)
+ local kerns=setmetatableindex("table")
+ for i=1,noftables do
+ local version=readushort(f)
+ local length=readushort(f)
+ local coverage=readushort(f)
+ local format=rshift(coverage,8)
+ if format==0 then
+ local nofpairs=readushort(f)
+ local searchrange=readushort(f)
+ local entryselector=readushort(f)
+ local rangeshift=readushort(f)
+ for i=1,nofpairs do
+ kerns[readushort(f)][readushort(f)]=readfword(f)
+ end
+ elseif format==2 then
+ else
end
- elseif format==2 then
+ end
+ local feature={ dflt={ dflt=true } }
+ if not features then
+ fontdata.features={ gpos={ [name]=feature } }
+ elseif not gposfeatures then
+ fontdata.features.gpos={ [name]=feature }
else
+ gposfeatures[name]=feature
end
- end
- local feature={ dflt={ dflt=true } }
- if not features then
- fontdata.features={ gpos={ [name]=feature } }
- elseif not gposfeatures then
- fontdata.features.gpos={ [name]=feature }
+ local sequences=fontdata.sequences
+ if not sequences then
+ sequences={}
+ fontdata.sequences=sequences
+ end
+ local nofsequences=#sequences+1
+ sequences[nofsequences]={
+ index=nofsequences,
+ name=name,
+ steps={
+ {
+ coverage=kerns,
+ format="kern",
+ },
+ },
+ nofsteps=1,
+ type="gpos_pair",
+ flags={ false,false,false,false },
+ order={ name },
+ features={ [name]=feature },
+ }
else
- gposfeatures[name]=feature
- end
- local sequences=fontdata.sequences
- if not sequences then
- sequences={}
- fontdata.sequences=sequences
+ report("ignoring empty kern table of feature %a",name)
end
- local nofsequences=#sequences+1
- sequences[nofsequences]={
- index=nofsequences,
- name=name,
- steps={
- {
- coverage=kerns,
- format="kern",
- },
- },
- nofsteps=1,
- type="gpos_pair",
- flags={ false,false,false,false },
- order={ name },
- features={ [name]=feature },
- }
end
function readers.gsub(f,fontdata,specification)
if specification.details then
@@ -7563,25 +10759,29 @@ do
end
end
function readers.gdef(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.gdef
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readulong(f)
- local classoffset=tableoffset+readushort(f)
- local attachmentoffset=tableoffset+readushort(f)
- local ligaturecarets=tableoffset+readushort(f)
- local markclassoffset=tableoffset+readushort(f)
- local marksetsoffset=version==0x00010002 and (tableoffset+readushort(f))
- local glyphs=fontdata.glyphs
- local marks={}
- local markclasses=setmetatableindex("table")
- local marksets=setmetatableindex("table")
- fontdata.marks=marks
- fontdata.markclasses=markclasses
- fontdata.marksets=marksets
- setposition(f,classoffset)
+ if not specification.glyphs then
+ return
+ end
+ local datatable=fontdata.tables.gdef
+ if datatable then
+ local tableoffset=datatable.offset
+ setposition(f,tableoffset)
+ local version=readulong(f)
+ local classoffset=readushort(f)
+ local attachmentoffset=readushort(f)
+ local ligaturecarets=readushort(f)
+ local markclassoffset=readushort(f)
+ local marksetsoffset=version>=0x00010002 and readushort(f) or 0
+ local varsetsoffset=version>=0x00010003 and readulong(f) or 0
+ local glyphs=fontdata.glyphs
+ local marks={}
+ local markclasses=setmetatableindex("table")
+ local marksets=setmetatableindex("table")
+ fontdata.marks=marks
+ fontdata.markclasses=markclasses
+ fontdata.marksets=marksets
+ if classoffset~=0 then
+ setposition(f,tableoffset+classoffset)
local classformat=readushort(f)
if classformat==1 then
local firstindex=readushort(f)
@@ -7609,7 +10809,9 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- setposition(f,markclassoffset)
+ end
+ if markclassoffset~=0 then
+ setposition(f,tableoffset+markclassoffset)
local classformat=readushort(f)
if classformat==1 then
local firstindex=readushort(f)
@@ -7628,21 +10830,45 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- if marksetsoffset and marksetsoffset>tableoffset then
- setposition(f,marksetsoffset)
- local format=readushort(f)
- if format==1 then
- local nofsets=readushort(f)
- local sets={}
- for i=1,nofsets do
- sets[i]=readulong(f)
- end
- for i=1,nofsets do
- local offset=sets[i]
- if offset~=0 then
- marksets[i]=readcoverage(f,marksetsoffset+offset)
+ end
+ if marksetsoffset~=0 then
+ marksetsoffset=tableoffset+marksetsoffset
+ setposition(f,marksetsoffset)
+ local format=readushort(f)
+ if format==1 then
+ local nofsets=readushort(f)
+ local sets=readcardinaltable(f,nofsets,ulong)
+ for i=1,nofsets do
+ local offset=sets[i]
+ if offset~=0 then
+ marksets[i]=readcoverage(f,marksetsoffset+offset)
+ end
+ end
+ end
+ end
+ local factors=specification.factors
+ if (specification.variable or factors) and varsetsoffset~=0 then
+ local regions,deltas=readvariationdata(f,tableoffset+varsetsoffset,factors)
+ if factors then
+ fontdata.temporary.getdelta=function(outer,inner)
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local dd=0
+ for i=1,#scales do
+ local di=d[i]
+ if di then
+ dd=dd+scales[i]*di
+ else
+ break
+ end
+ end
+ return round(dd)
end
end
+ return 0
end
end
end
@@ -7833,14 +11059,8 @@ local function readmathvariants(f,fontdata,offset)
local hcoverage=readushort(f)
local vnofglyphs=readushort(f)
local hnofglyphs=readushort(f)
- local vconstruction={}
- local hconstruction={}
- for i=1,vnofglyphs do
- vconstruction[i]=readushort(f)
- end
- for i=1,hnofglyphs do
- hconstruction[i]=readushort(f)
- end
+ local vconstruction=readcardinaltable(f,vnofglyphs,ushort)
+ local hconstruction=readcardinaltable(f,hnofglyphs,ushort)
fontdata.mathconstants.MinConnectorOverlap=minoverlap
local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic)
if coverage~=0 and nofglyphs>0 then
@@ -7889,7 +11109,7 @@ local function readmathvariants(f,fontdata,offset)
advance=readushort(f),
}
local flags=readushort(f)
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
p.extender=1
end
parts[i]=p
@@ -7914,174 +11134,508 @@ local function readmathvariants(f,fontdata,offset)
get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic")
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.math
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readulong(f)
- if version~=0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
- return
- end
- local constants=readushort(f)
- local glyphinfo=readushort(f)
- local variants=readushort(f)
- if constants==0 then
- report("the math table of %a has no constants",fontdata.filename)
- else
- readmathconstants(f,fontdata,tableoffset+constants)
- end
- if glyphinfo~=0 then
- readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
- end
- if variants~=0 then
- readmathvariants(f,fontdata,tableoffset+variants)
- end
+ local tableoffset=gotodatatable(f,fontdata,"math",specification.glyphs)
+ if tableoffset then
+ local version=readulong(f)
+ local constants=readushort(f)
+ local glyphinfo=readushort(f)
+ local variants=readushort(f)
+ if constants==0 then
+ report("the math table of %a has no constants",fontdata.filename)
+ else
+ readmathconstants(f,fontdata,tableoffset+constants)
+ end
+ if glyphinfo~=0 then
+ readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
+ end
+ if variants~=0 then
+ readmathvariants(f,fontdata,tableoffset+variants)
end
end
end
function readers.colr(f,fontdata,specification)
- local datatable=fontdata.tables.colr
- if datatable then
- if specification.glyphs then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version~=0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
- return
- end
- if not fontdata.tables.cpal then
- report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
- fontdata.colorpalettes={}
- end
- local glyphs=fontdata.glyphs
- local nofglyphs=readushort(f)
- local baseoffset=readulong(f)
- local layeroffset=readulong(f)
+ local tableoffset=gotodatatable(f,fontdata,"colr",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ if version~=0 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
+ return
+ end
+ if not fontdata.tables.cpal then
+ report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
+ fontdata.colorpalettes={}
+ end
+ local glyphs=fontdata.glyphs
+ local nofglyphs=readushort(f)
+ local baseoffset=readulong(f)
+ local layeroffset=readulong(f)
+ local noflayers=readushort(f)
+ local layerrecords={}
+ local maxclass=0
+ setposition(f,tableoffset+layeroffset)
+ for i=1,noflayers do
+ local slot=readushort(f)
+ local class=readushort(f)
+ if class<0xFFFF then
+ class=class+1
+ if class>maxclass then
+ maxclass=class
+ end
+ end
+ layerrecords[i]={
+ slot=slot,
+ class=class,
+ }
+ end
+ fontdata.maxcolorclass=maxclass
+ setposition(f,tableoffset+baseoffset)
+ for i=0,nofglyphs-1 do
+ local glyphindex=readushort(f)
+ local firstlayer=readushort(f)
local noflayers=readushort(f)
- local layerrecords={}
- local maxclass=0
- setposition(f,tableoffset+layeroffset)
+ local t={}
for i=1,noflayers do
- local slot=readushort(f)
- local class=readushort(f)
- if class<0xFFFF then
- class=class+1
- if class>maxclass then
- maxclass=class
- end
- end
- layerrecords[i]={
- slot=slot,
- class=class,
- }
- end
- fontdata.maxcolorclass=maxclass
- setposition(f,tableoffset+baseoffset)
- for i=0,nofglyphs-1 do
- local glyphindex=readushort(f)
- local firstlayer=readushort(f)
- local noflayers=readushort(f)
- local t={}
- for i=1,noflayers do
- t[i]=layerrecords[firstlayer+i]
- end
- glyphs[glyphindex].colors=t
+ t[i]=layerrecords[firstlayer+i]
end
+ glyphs[glyphindex].colors=t
end
- fontdata.hascolor=true
end
+ fontdata.hascolor=true
end
function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.cpal
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version>1 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
- return
+ local tableoffset=gotodatatable(f,fontdata,"cpal",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local nofpaletteentries=readushort(f)
+ local nofpalettes=readushort(f)
+ local nofcolorrecords=readushort(f)
+ local firstcoloroffset=readulong(f)
+ local colorrecords={}
+ local palettes=readcardinaltable(f,nofpalettes,ushort)
+ if version==1 then
+ local palettettypesoffset=readulong(f)
+ local palettelabelsoffset=readulong(f)
+ local paletteentryoffset=readulong(f)
+ end
+ setposition(f,tableoffset+firstcoloroffset)
+ for i=1,nofcolorrecords do
+ local b,g,r,a=readbytes(f,4)
+ colorrecords[i]={
+ r,g,b,a~=255 and a or nil,
+ }
+ end
+ for i=1,nofpalettes do
+ local p={}
+ local o=palettes[i]
+ for j=1,nofpaletteentries do
+ p[j]=colorrecords[o+j]
end
- local nofpaletteentries=readushort(f)
- local nofpalettes=readushort(f)
- local nofcolorrecords=readushort(f)
- local firstcoloroffset=readulong(f)
- local colorrecords={}
- local palettes={}
- for i=1,nofpalettes do
- palettes[i]=readushort(f)
- end
- if version==1 then
- local palettettypesoffset=readulong(f)
- local palettelabelsoffset=readulong(f)
- local paletteentryoffset=readulong(f)
- end
- setposition(f,tableoffset+firstcoloroffset)
- for i=1,nofcolorrecords do
- local b,g,r,a=readbytes(f,4)
- colorrecords[i]={
- r,g,b,a~=255 and a or nil,
+ palettes[i]=p
+ end
+ fontdata.colorpalettes=palettes
+ end
+end
+function readers.svg(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"svg",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local glyphs=fontdata.glyphs
+ local indexoffset=tableoffset+readulong(f)
+ local reserved=readulong(f)
+ setposition(f,indexoffset)
+ local nofentries=readushort(f)
+ local entries={}
+ for i=1,nofentries do
+ entries[i]={
+ first=readushort(f),
+ last=readushort(f),
+ offset=indexoffset+readulong(f),
+ length=readulong(f),
+ }
+ end
+ for i=1,nofentries do
+ local entry=entries[i]
+ setposition(f,entry.offset)
+ entries[i]={
+ first=entry.first,
+ last=entry.last,
+ data=readstring(f,entry.length)
+ }
+ end
+ fontdata.svgshapes=entries
+ end
+ fontdata.hascolor=true
+end
+function readers.sbix(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"sbix",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local flags=readushort(f)
+ local nofstrikes=readulong(f)
+ local strikes={}
+ local nofglyphs=fontdata.nofglyphs
+ for i=1,nofstrikes do
+ strikes[i]=readulong(f)
+ end
+ local shapes={}
+ local done=0
+ for i=1,nofstrikes do
+ local strikeoffset=strikes[i]+tableoffset
+ setposition(f,strikeoffset)
+ strikes[i]={
+ ppem=readushort(f),
+ ppi=readushort(f),
+ offset=strikeoffset
}
end
- for i=1,nofpalettes do
- local p={}
- local o=palettes[i]
- for j=1,nofpaletteentries do
- p[j]=colorrecords[o+j]
+ sort(strikes,function(a,b)
+ if b.ppem==a.ppem then
+ return b.ppi<a.ppi
+ else
+ return b.ppem<a.ppem
+ end
+ end)
+ local glyphs={}
+ for i=1,nofstrikes do
+ local strike=strikes[i]
+ local strikeppem=strike.ppem
+ local strikeppi=strike.ppi
+ local strikeoffset=strike.offset
+ setposition(f,strikeoffset)
+ for i=0,nofglyphs do
+ glyphs[i]=readulong(f)
+ end
+ local glyphoffset=glyphs[0]
+ for i=0,nofglyphs-1 do
+ local nextoffset=glyphs[i+1]
+ if not shapes[i] then
+ local datasize=nextoffset-glyphoffset
+ if datasize>0 then
+ setposition(f,strikeoffset+glyphoffset)
+ shapes[i]={
+ x=readshort(f),
+ y=readshort(f),
+ tag=readtag(f),
+ data=readstring(f,datasize-8),
+ ppem=strikeppem,
+ ppi=strikeppi,
+ }
+ done=done+1
+ if done==nofglyphs then
+ break
+ end
+ end
+ end
+ glyphoffset=nextoffset
end
- palettes[i]=p
end
- fontdata.colorpalettes=palettes
- end
+ fontdata.sbixshapes=shapes
end
end
-function readers.svg(f,fontdata,specification)
- local datatable=fontdata.tables.svg
- if datatable then
- if specification.glyphs then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version~=0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
- return
- end
- local glyphs=fontdata.glyphs
- local indexoffset=tableoffset+readulong(f)
- local reserved=readulong(f)
- setposition(f,indexoffset)
- local nofentries=readushort(f)
- local entries={}
- for i=1,nofentries do
- entries[i]={
- first=readushort(f),
- last=readushort(f),
- offset=indexoffset+readulong(f),
- length=readulong(f),
+function readers.stat(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"stat",true)
+ if tableoffset then
+ local extras=fontdata.extras
+ local version=readulong(f)
+ local axissize=readushort(f)
+ local nofaxis=readushort(f)
+ local axisoffset=readulong(f)
+ local nofvalues=readushort(f)
+ local valuesoffset=readulong(f)
+ local fallbackname=extras[readushort(f)]
+ local axis={}
+ local values={}
+ setposition(f,tableoffset+axisoffset)
+ for i=1,nofaxis do
+ local tag=readtag(f)
+ axis[i]={
+ tag=tag,
+ name=lower(extras[readushort(f)] or tag),
+ ordering=readushort(f),
+ variants={}
+ }
+ end
+ setposition(f,tableoffset+valuesoffset)
+ for i=1,nofvalues do
+ values[i]=readushort(f)
+ end
+ for i=1,nofvalues do
+ setposition(f,tableoffset+valuesoffset+values[i])
+ local format=readushort(f)
+ local index=readushort(f)+1
+ local flags=readushort(f)
+ local name=lower(extras[readushort(f)] or "no name")
+ local value=readfixed(f)
+ local variant
+ if format==1 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
+ }
+ elseif format==2 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
+ minimum=readfixed(f),
+ maximum=readfixed(f),
+ }
+ elseif format==3 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
+ link=readfixed(f),
}
end
- for i=1,nofentries do
- local entry=entries[i]
- setposition(f,entry.offset)
- entries[i]={
- first=entry.first,
- last=entry.last,
- data=readstring(f,entry.length)
+ insert(axis[index].variants,variant)
+ end
+ sort(axis,function(a,b)
+ return a.ordering<b.ordering
+ end)
+ for i=1,#axis do
+ local a=axis[i]
+ sort(a.variants,function(a,b)
+ return a.name<b.name
+ end)
+ a.ordering=nil
+ end
+ setvariabledata(fontdata,"designaxis",axis)
+ setvariabledata(fontdata,"fallbackname",fallbackname)
+ end
+end
+function readers.avar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"avar",true)
+ if tableoffset then
+ local function collect()
+ local nofvalues=readushort(f)
+ local values={}
+ local lastfrom=false
+ local lastto=false
+ for i=1,nofvalues do
+ local f,t=read2dot14(f),read2dot14(f)
+ if lastfrom and f<=lastfrom then
+ elseif lastto and t>=lastto then
+ else
+ values[#values+1]={ f,t }
+ lastfrom,lastto=f,t
+ end
+ end
+ nofvalues=#values
+ if nofvalues>2 then
+ local some=values[1]
+ if some[1]==-1 and some[2]==-1 then
+ some=values[nofvalues]
+ if some[1]==1 and some[2]==1 then
+ for i=2,nofvalues-1 do
+ some=values[i]
+ if some[1]==0 and some[2]==0 then
+ return values
+ end
+ end
+ end
+ end
+ end
+ return false
+ end
+ local majorversion=readushort(f)
+ local minorversion=readushort(f)
+ local reserved=readushort(f)
+ local nofaxis=readushort(f)
+ local segments={}
+ for i=1,nofaxis do
+ segments[i]=collect()
+ end
+ setvariabledata(fontdata,"segments",segments)
+ end
+end
+function readers.fvar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"fvar",true)
+ if tableoffset then
+ local version=readulong(f)
+ local offsettoaxis=tableoffset+readushort(f)
+ local reserved=skipshort(f)
+ local nofaxis=readushort(f)
+ local sizeofaxis=readushort(f)
+ local nofinstances=readushort(f)
+ local sizeofinstances=readushort(f)
+ local extras=fontdata.extras
+ local axis={}
+ local instances={}
+ setposition(f,offsettoaxis)
+ for i=1,nofaxis do
+ axis[i]={
+ tag=readtag(f),
+ minimum=readfixed(f),
+ default=readfixed(f),
+ maximum=readfixed(f),
+ flags=readushort(f),
+ name=lower(extras[readushort(f)] or "bad name"),
+ }
+ local n=sizeofaxis-20
+ if n>0 then
+ skipbytes(f,n)
+ elseif n<0 then
+ end
+ end
+ local nofbytes=2+2+2+nofaxis*4
+ local readpsname=nofbytes<=sizeofinstances
+ local skippable=sizeofinstances-nofbytes
+ for i=1,nofinstances do
+ local subfamid=readushort(f)
+ local flags=readushort(f)
+ local values={}
+ for i=1,nofaxis do
+ values[i]={
+ axis=axis[i].tag,
+ value=readfixed(f),
}
end
- fontdata.svgshapes=entries
+ local psnameid=readpsname and readushort(f) or 0xFFFF
+ if subfamid==2 or subfamid==17 then
+ elseif subfamid==0xFFFF then
+ subfamid=nil
+ elseif subfamid<=256 or subfamid>=32768 then
+ subfamid=nil
+ end
+ if psnameid==6 then
+ elseif psnameid==0xFFFF then
+ psnameid=nil
+ elseif psnameid<=256 or psnameid>=32768 then
+ psnameid=nil
+ end
+ instances[i]={
+ subfamily=extras[subfamid],
+ psname=psnameid and extras[psnameid] or nil,
+ values=values,
+ }
+ if skippable>0 then
+ skipbytes(f,skippable)
+ end
+ end
+ setvariabledata(fontdata,"axis",axis)
+ setvariabledata(fontdata,"instances",instances)
+ end
+end
+function readers.hvar(f,fontdata,specification)
+ local factors=specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable)
+ if not tableoffset then
+ return
+ end
+ local version=readulong(f)
+ local variationoffset=tableoffset+readulong(f)
+ local advanceoffset=tableoffset+readulong(f)
+ local lsboffset=tableoffset+readulong(f)
+ local rsboffset=tableoffset+readulong(f)
+ local regions={}
+ local variations={}
+ local innerindex={}
+ local outerindex={}
+ if variationoffset>0 then
+ regions,deltas=readvariationdata(f,variationoffset,factors)
+ end
+ if not regions then
+ return
+ end
+ if advanceoffset>0 then
+ setposition(f,advanceoffset)
+ local format=readushort(f)
+ local mapcount=readushort(f)
+ local entrysize=rshift(band(format,0x0030),4)+1
+ local nofinnerbits=band(format,0x000F)+1
+ local innermask=lshift(1,nofinnerbits)-1
+ local readcardinal=read_cardinal[entrysize]
+ for i=0,mapcount-1 do
+ local mapdata=readcardinal(f)
+ outerindex[i]=rshift(mapdata,nofinnerbits)
+ innerindex[i]=band(mapdata,innermask)
+ end
+ setvariabledata(fontdata,"hvarwidths",true)
+ local glyphs=fontdata.glyphs
+ for i=0,fontdata.nofglyphs-1 do
+ local glyph=glyphs[i]
+ local width=glyph.width
+ if width then
+ local outer=outerindex[i] or 0
+ local inner=innerindex[i] or i
+ if outer and inner then
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local deltaw=0
+ for i=1,#scales do
+ local di=d[i]
+ if di then
+ deltaw=deltaw+scales[i]*di
+ else
+ break
+ end
+ end
+ glyph.width=width+round(deltaw)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+function readers.vvar(f,fontdata,specification)
+ if not specification.variable then
+ return
+ end
+end
+function readers.mvar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"mvar",specification.variable)
+ if tableoffset then
+ local version=readulong(f)
+ local reserved=skipshort(f,1)
+ local recordsize=readushort(f)
+ local nofrecords=readushort(f)
+ local offsettostore=tableoffset+readushort(f)
+ local dimensions={}
+ local factors=specification.factors
+ if factors then
+ local regions,deltas=readvariationdata(f,offsettostore,factors)
+ for i=1,nofrecords do
+ local tag=readtag(f)
+ local var=variabletags[tag]
+ if var then
+ local outer=readushort(f)
+ local inner=readushort(f)
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local dd=0
+ for i=1,#scales do
+ dd=dd+scales[i]*d[i]
+ end
+ var(fontdata,round(dd))
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ if recordsize>8 then
+ skipbytes(recordsize-8)
+ end
+ end
end
- fontdata.hascolor=true
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-dsp”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-dsp”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oup” f7237130b648a4c2b477dabedc7f90e8] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oup” 020f2630f5a18d39e209f1cbf7a334ea] ---
if not modules then modules={} end modules ['font-oup']={
version=1.001,
@@ -8098,6 +11652,7 @@ local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
local tohash=table.tohash
+local setmetatableindex=table.setmetatableindex
local report=logs.reporter("otf reader")
local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
local readers=fonts.handlers.otf.readers
@@ -8108,7 +11663,7 @@ local f_index=formatters["I%05X"]
local f_character_y=formatters["%C"]
local f_character_n=formatters["[ %C ]"]
local check_duplicates=true
-local check_soft_hyphen=false
+local check_soft_hyphen=true
directives.register("otf.checksofthyphen",function(v)
check_soft_hyphen=v
end)
@@ -8658,7 +12213,7 @@ local function checklookups(fontdata,missing,nofmissing)
end
end
if next(done) then
- report("not unicoded: % t",table.sortedkeys(done))
+ report("not unicoded: % t",sortedkeys(done))
end
end
end
@@ -8668,7 +12223,6 @@ local function unifymissing(fontdata)
require("font-agl")
end
local unicodes={}
- local private=fontdata.private
local resources=fontdata.resources
resources.unicodes=unicodes
for unicode,d in next,fontdata.descriptions do
@@ -8706,8 +12260,8 @@ local function unifyglyphs(fontdata,usenames)
end
for index=1,#glyphs do
local glyph=glyphs[index]
- local unicode=glyph.unicode
- if not unicode then
+ local unicode=glyph.unicode
+ if not unicode or unicode>=private or (unicode>=0xE000 and unicode<=0xF8FF) or unicode==0xFFFE or unicode==0xFFFF then
unicode=private
if names then
local name=glyph.name or f_private(unicode)
@@ -8830,9 +12384,9 @@ function readers.getcomponents(fontdata)
end
end
for i=1,#steps do
- local coverage=steps[i].coverage
- if coverage then
- for k,v in next,coverage do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
traverse(k,k,v)
end
end
@@ -8895,7 +12449,7 @@ function readers.rehash(fontdata,hashmethod)
copyduplicates(fontdata)
unifymissing(fontdata)
else
- fontdata.hashmethod="unicode"
+ fontdata.hashmethod="unicodes"
local indices=unifyglyphs(fontdata)
unifyresources(fontdata,indices)
copyduplicates(fontdata)
@@ -8910,10 +12464,10 @@ function readers.checkhash(fontdata)
elseif hashmethod=="names" and fontdata.names then
unifyresources(fontdata,fontdata.names)
copyduplicates(fontdata)
- fontdata.hashmethod="unicode"
+ fontdata.hashmethod="unicodes"
fontdata.names=nil
else
- readers.rehash(fontdata,"unicode")
+ readers.rehash(fontdata,"unicodes")
end
end
function readers.addunicodetable(fontdata)
@@ -9047,13 +12601,14 @@ function readers.pack(data)
return nt
end
end
- local function pack_flat(v)
- local tag=tabstr_flat(v)
+ local function pack_normal_cc(v)
+ local tag=tabstr_normal(v)
local ht=h[tag]
if ht then
c[ht]=c[ht]+1
return ht
else
+ v[1]=0
nt=nt+1
t[nt]=v
h[tag]=nt
@@ -9061,8 +12616,8 @@ function readers.pack(data)
return nt
end
end
- local function pack_boolean(v)
- local tag=tabstr_boolean(v)
+ local function pack_flat(v)
+ local tag=tabstr_flat(v)
local ht=h[tag]
if ht then
c[ht]=c[ht]+1
@@ -9103,6 +12658,20 @@ function readers.pack(data)
return nt
end
end
+ local function pack_boolean(v)
+ local tag=tabstr_boolean(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
local function pack_final(v)
if c[v]<=criterium then
return t[v]
@@ -9119,6 +12688,22 @@ function readers.pack(data)
end
end
end
+ local function pack_final_cc(v)
+ if c[v]<=criterium then
+ return t[v]
+ else
+ local hv=hh[v]
+ if hv then
+ return hv
+ else
+ ntt=ntt+1
+ tt[ntt]=t[v]
+ hh[v]=ntt
+ cc[ntt]=c[v]
+ return ntt
+ end
+ end
+ end
local function success(stage,pass)
if nt==0 then
if trace_loading or trace_packing then
@@ -9164,9 +12749,9 @@ function readers.pack(data)
end
local function packers(pass)
if pass==1 then
- return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed
+ return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc
else
- return pack_final,pack_final,pack_final,pack_final,pack_final
+ return pack_final,pack_final,pack_final,pack_final,pack_final,pack_final_cc
end
end
local resources=data.resources
@@ -9174,6 +12759,7 @@ function readers.pack(data)
local sublookups=resources.sublookups
local features=resources.features
local palettes=resources.colorpalettes
+ local variable=resources.variabledata
local chardata=characters and characters.data
local descriptions=data.descriptions or data.glyphs
if not descriptions then
@@ -9183,7 +12769,7 @@ function readers.pack(data)
if trace_packing then
report_otf("start packing: stage 1, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
for unicode,description in next,descriptions do
local boundingbox=description.boundingbox
if boundingbox then
@@ -9213,28 +12799,30 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
+ if step.format=="pair" then
for g1,d1 in next,c do
- c[g1]=pack_normal(d1)
+ for g2,d2 in next,d1 do
+ local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
+ local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
+ end
end
else
for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- local f=d2[1] if f then d2[1]=pack_indexed(f) end
- local s=d2[2] if s then d2[2]=pack_indexed(s) end
- end
+ c[g1]=pack_normal(d1)
end
end
end
elseif kind=="gpos_single" then
local c=step.coverage
if c then
- if step.format=="kern" then
- step.coverage=pack_normal(c)
- else
+ if step.format=="single" then
for g1,d1 in next,c do
- c[g1]=pack_indexed(d1)
+ if d1 and d1~=true then
+ c[g1]=pack_indexed(d1)
+ end
end
+ else
+ step.coverage=pack_normal(c)
end
end
elseif kind=="gpos_cursive" then
@@ -9285,7 +12873,6 @@ function readers.pack(data)
local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.lookups if r then rule.lookups=pack_mixed (r) end
local r=rule.replacements if r then rule.replacements=pack_flat (r) end
end
end
@@ -9325,6 +12912,45 @@ function readers.pack(data)
end
end
end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ v[j]=pack_normal(v[j])
+ end
+ end
+ end
+ local function packdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ for j=1,#d do
+ d[j]=pack_indexed(d[j])
+ end
+ di.regions=pack_indexed(di.regions)
+ end
+ end
+ local regions=main.regions
+ if regions then
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ r[j]=pack_normal(r[j])
+ end
+ end
+ end
+ end
+ end
+ packdeltas(variable.global)
+ packdeltas(variable.horizontal)
+ packdeltas(variable.vertical)
+ packdeltas(variable.metrics)
+ end
if not success(1,pass) then
return
end
@@ -9334,7 +12960,7 @@ function readers.pack(data)
if trace_packing then
report_otf("start packing: stage 2, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
for unicode,description in next,descriptions do
local math=description.math
if math then
@@ -9356,8 +12982,7 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
for g2,d2 in next,d1 do
d1[g2]=pack_normal(d2)
@@ -9365,6 +12990,15 @@ function readers.pack(data)
end
end
end
+ elseif kind=="gpos_mark2ligature" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ d1[g2]=pack_normal(d2)
+ end
+ end
+ end
end
local rules=step.rules
if rules then
@@ -9388,14 +13022,26 @@ function readers.pack(data)
if sublookups then
packthem(sublookups)
end
- if not success(2,pass) then
+ if variable then
+ local function unpackdeltas(main)
+ if main then
+ local regions=main.regions
+ if regions then
+ main.regions=pack_normal(regions)
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
end
end
for pass=1,2 do
if trace_packing then
report_otf("start packing: stage 3, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
local function packthem(sequences)
for i=1,#sequences do
local sequence=sequences[i]
@@ -9408,13 +13054,19 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
c[g1]=pack_normal(d1)
end
end
end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ c[g1]=pack_normal_cc(d1)
+ end
+ end
end
end
end
@@ -9446,6 +13098,7 @@ function readers.unpack(data)
local sublookups=resources.sublookups
local features=resources.features
local palettes=resources.colorpalettes
+ local variable=resources.variabledata
local unpacked={}
setmetatable(unpacked,unpacked_mt)
for unicode,description in next,descriptions do
@@ -9482,20 +13135,26 @@ function readers.unpack(data)
local features=sequence.features
local flags=sequence.flags
local markclass=sequence.markclass
+ if features then
+ local tv=tables[features]
+ if tv then
+ sequence.features=tv
+ features=tv
+ end
+ for script,feature in next,features do
+ local tv=tables[feature]
+ if tv then
+ features[script]=tv
+ end
+ end
+ end
if steps then
for i=1,#steps do
local step=steps[i]
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- c[g1]=tv
- end
- end
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
local tv=tables[d1]
if tv then
@@ -9512,29 +13171,41 @@ function readers.unpack(data)
local s=tables[d2[2]] if s then d2[2]=s end
end
end
+ else
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ c[g1]=tv
+ end
+ end
end
end
elseif kind=="gpos_single" then
local c=step.coverage
if c then
- if step.format=="kern" then
- local tv=tables[c]
- if tv then
- step.coverage=tv
- end
- else
+ if step.format=="single" then
for g1,d1 in next,c do
local tv=tables[d1]
if tv then
c[g1]=tv
end
end
+ else
+ local tv=tables[c]
+ if tv then
+ step.coverage=tv
+ end
end
end
elseif kind=="gpos_cursive" then
local c=step.coverage
if c then
for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ d1=tv
+ c[g1]=d1
+ end
local f=tables[d1[2]] if f then d1[2]=f end
local s=tables[d1[3]] if s then d1[3]=s end
end
@@ -9565,6 +13236,11 @@ function readers.unpack(data)
if c then
for g1,d1 in next,c do
for g2,d2 in next,d1 do
+ local tv=tables[d2]
+ if tv then
+ d2=tv
+ d1[g2]=d2
+ end
for g3,d3 in next,d2 do
local tv=tables[d2[g3]]
if tv then
@@ -9630,13 +13306,6 @@ function readers.unpack(data)
end
end
end
- local lookups=rule.lookups
- if lookups then
- local tv=tables[lookups]
- if tv then
- rule.lookups=tv
- end
- end
local replacements=rule.replacements
if replacements then
local tv=tables[replacements]
@@ -9648,19 +13317,6 @@ function readers.unpack(data)
end
end
end
- if features then
- local tv=tables[features]
- if tv then
- sequence.features=tv
- features=tv
- end
- for script,feature in next,features do
- local tv=tables[feature]
- if tv then
- features[script]=tv
- end
- end
- end
if order then
local tv=tables[order]
if tv then
@@ -9702,6 +13358,63 @@ function readers.unpack(data)
end
end
end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ local tv=tables[v[j]]
+ if tv then
+ v[j]=tv
+ end
+ end
+ end
+ end
+ local function unpackdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ local r=di.regions
+ for j=1,#d do
+ local tv=tables[d[j]]
+ if tv then
+ d[j]=tv
+ end
+ end
+ local tv=di.regions
+ if tv then
+ di.regions=tv
+ end
+ end
+ end
+ local regions=main.regions
+ if regions then
+ local tv=tables[regions]
+ if tv then
+ main.regions=tv
+ regions=tv
+ end
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ local tv=tables[r[j]]
+ if tv then
+ r[j]=tv
+ end
+ end
+ end
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
+ end
data.tables=nil
end
end
@@ -9740,9 +13453,12 @@ local function mergesteps_1(lookup,strict)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- if not target[k] then
- target[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ if not target[k] then
+ target[k]=v
+ end
end
end
end
@@ -9751,7 +13467,7 @@ local function mergesteps_1(lookup,strict)
lookup.steps={ first }
return nofsteps-1
end
-local function mergesteps_2(lookup,strict)
+local function mergesteps_2(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
local first=steps[1]
@@ -9767,69 +13483,62 @@ local function mergesteps_2(lookup,strict)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- local tk=target[k]
- if tk then
- for k,v in next,v do
- if not tk[k] then
- tk[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ for kk,vv in next,v do
+ if tk[kk]==nil then
+ tk[kk]=vv
+ end
end
+ else
+ target[k]=v
end
- else
- target[k]=v
end
end
end
lookup.nofsteps=1
+ lookup.merged=true
lookup.steps={ first }
return nofsteps-1
end
local function mergesteps_3(lookup,strict)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
- local first=steps[1]
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- local baseclasses={}
local coverage={}
- local used={}
for i=1,nofsteps do
- local offset=i*10
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=coverage[k]
+ if tk then
+ report("quitting merge due to multiple checks")
+ return nofsteps
+ else
+ coverage[k]=v
+ end
+ end
+ end
+ end
+ local first=steps[1]
+ local baseclasses={}
+ for i=1,nofsteps do
+ local offset=i*10
local step=steps[i]
for k,v in sortedhash(step.baseclasses) do
baseclasses[offset+k]=v
end
for k,v in next,step.coverage do
- local tk=coverage[k]
- if tk then
- for k,v in next,v do
- if not tk[k] then
- tk[k]=v
- local c=offset+v[1]
- v[1]=c
- if not used[c] then
- used[c]=true
- end
- end
- end
- else
- coverage[k]=v
- local c=offset+v[1]
- v[1]=c
- if not used[c] then
- used[c]=true
- end
- end
- end
- end
- for k,v in next,baseclasses do
- if not used[k] then
- baseclasses[k]=nil
- report("discarding not used baseclass %i",k)
+ v[1]=offset+v[1]
end
end
first.baseclasses=baseclasses
first.coverage=coverage
lookup.nofsteps=1
+ lookup.merged=true
lookup.steps={ first }
return nofsteps-1
end
@@ -9856,80 +13565,155 @@ local function mergesteps_4(lookup)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- local tk=target[k]
- if tk then
- nested(v,tk)
- else
- target[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ nested(v,tk)
+ else
+ target[k]=v
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.steps={ first }
+ return nofsteps-1
+end
+local function mergesteps_5(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ local target=first.coverage
+ local hash=nil
+ for k,v in next,target do
+ hash=v[1]
+ break
+ end
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ if not tk[2] then
+ tk[2]=v[2]
+ end
+ if not tk[3] then
+ tk[3]=v[3]
+ end
+ else
+ target[k]=v
+ v[1]=hash
+ end
end
end
end
lookup.nofsteps=1
+ lookup.merged=true
lookup.steps={ first }
return nofsteps-1
end
local function checkkerns(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
+ local kerned=0
for i=1,nofsteps do
local step=steps[i]
if step.format=="pair" then
local coverage=step.coverage
local kerns=true
for g1,d1 in next,coverage do
- if d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
+ if d1==true then
+ elseif not d1 then
+ elseif d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
kerns=false
break
end
end
if kerns then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
+ local c={}
for g1,d1 in next,coverage do
- coverage[g1]=d1[3]
+ if d1 and d1~=true then
+ c[g1]=d1[3]
+ end
end
- step.format="kern"
+ step.coverage=c
+ step.format="move"
+ kerned=kerned+1
end
end
end
+ return kerned
end
local function checkpairs(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
local kerned=0
- for i=1,nofsteps do
- local step=steps[i]
- if step.format=="pair" then
- local coverage=step.coverage
- local kerns=true
- for g1,d1 in next,coverage do
- for g2,d2 in next,d1 do
- if d2[2] then
- kerns=false
- break
- else
- local v=d2[1]
- if v[1]~=0 or v[2]~=0 or v[4]~=0 then
- kerns=false
- break
- end
+ local function onlykerns(step)
+ local coverage=step.coverage
+ for g1,d1 in next,coverage do
+ for g2,d2 in next,d1 do
+ if d2[2] then
+ return false
+ else
+ local v=d2[1]
+ if v==true then
+ elseif v and (v[1]~=0 or v[2]~=0 or v[4]~=0) then
+ return false
end
end
end
- if kerns then
+ end
+ return coverage
+ end
+ for i=1,nofsteps do
+ local step=steps[i]
+ if step.format=="pair" then
+ local coverage=onlykerns(step)
+ if coverage then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
for g1,d1 in next,coverage do
+ local d={}
for g2,d2 in next,d1 do
- d1[g2]=d2[1][3]
+ local v=d2[1]
+ if v==true then
+ elseif v then
+ d[g2]=v[3]
+ end
end
+ coverage[g1]=d
end
- step.format="kern"
+ step.format="move"
kerned=kerned+1
end
end
end
return kerned
end
+local compact_pairs=true
+local compact_singles=true
+local merge_pairs=true
+local merge_singles=true
+local merge_substitutions=true
+local merge_alternates=true
+local merge_multiples=true
+local merge_ligatures=true
+local merge_cursives=true
+local merge_marks=true
+directives.register("otf.compact.pairs",function(v) compact_pairs=v end)
+directives.register("otf.compact.singles",function(v) compact_singles=v end)
+directives.register("otf.merge.pairs",function(v) merge_pairs=v end)
+directives.register("otf.merge.singles",function(v) merge_singles=v end)
+directives.register("otf.merge.substitutions",function(v) merge_substitutions=v end)
+directives.register("otf.merge.alternates",function(v) merge_alternates=v end)
+directives.register("otf.merge.multiples",function(v) merge_multiples=v end)
+directives.register("otf.merge.ligatures",function(v) merge_ligatures=v end)
+directives.register("otf.merge.cursives",function(v) merge_cursives=v end)
+directives.register("otf.merge.marks",function(v) merge_marks=v end)
function readers.compact(data)
if not data or data.compacted then
return
@@ -9946,23 +13730,64 @@ function readers.compact(data)
for i=1,#lookups do
local lookup=lookups[i]
local nofsteps=lookup.nofsteps
+ local kind=lookup.type
allsteps=allsteps+nofsteps
if nofsteps>1 then
- local kind=lookup.type
- if kind=="gsub_single" or kind=="gsub_alternate" or kind=="gsub_multiple" then
- merged=merged+mergesteps_1(lookup)
+ local merg=merged
+ if kind=="gsub_single" then
+ if merge_substitutions then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_alternate" then
+ if merge_alternates then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_multiple" then
+ if merge_multiples then
+ merged=merged+mergesteps_1(lookup)
+ end
elseif kind=="gsub_ligature" then
- merged=merged+mergesteps_4(lookup)
+ if merge_ligatures then
+ merged=merged+mergesteps_4(lookup)
+ end
elseif kind=="gpos_single" then
- merged=merged+mergesteps_1(lookup,true)
- checkkerns(lookup)
+ if merge_singles then
+ merged=merged+mergesteps_1(lookup,true)
+ end
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
elseif kind=="gpos_pair" then
- merged=merged+mergesteps_2(lookup,true)
- kerned=kerned+checkpairs(lookup)
+ if merge_pairs then
+ merged=merged+mergesteps_2(lookup)
+ end
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
elseif kind=="gpos_cursive" then
- merged=merged+mergesteps_2(lookup)
+ if merge_cursives then
+ merged=merged+mergesteps_5(lookup)
+ end
elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
- merged=merged+mergesteps_3(lookup)
+ if merge_marks then
+ merged=merged+mergesteps_3(lookup)
+ end
+ end
+ if merg~=merged then
+ lookup.merged=true
+ end
+ elseif nofsteps==1 then
+ local kern=kerned
+ if kind=="gpos_single" then
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
+ elseif kind=="gpos_pair" then
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
+ end
+ if kern~=kerned then
end
end
end
@@ -9979,6 +13804,72 @@ function readers.compact(data)
report("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
end
end
+local function mergesteps(t,k)
+ if k=="merged" then
+ local merged={}
+ for i=1,#t do
+ local step=t[i]
+ local coverage=step.coverage
+ for k in next,coverage do
+ local m=merged[k]
+ if m then
+ m[2]=i
+ else
+ merged[k]={ i,i }
+ end
+ end
+ end
+ t.merged=merged
+ return merged
+ end
+end
+local function checkmerge(sequence)
+ local steps=sequence.steps
+ if steps then
+ setmetatableindex(steps,mergesteps)
+ end
+end
+local function checkflags(sequence,resources)
+ if not sequence.skiphash then
+ local flags=sequence.flags
+ if flags then
+ local skipmark=flags[1]
+ local skipligature=flags[2]
+ local skipbase=flags[3]
+ local markclass=sequence.markclass
+ local skipsome=skipmark or skipligature or skipbase or markclass or false
+ if skipsome then
+ sequence.skiphash=setmetatableindex(function(t,k)
+ local c=resources.classes[k]
+ local v=c==skipmark
+ or (markclass and c=="mark" and not markclass[k])
+ or c==skipligature
+ or c==skipbase
+ or false
+ t[k]=v
+ return v
+ end)
+ else
+ sequence.skiphash=false
+ end
+ else
+ sequence.skiphash=false
+ end
+ end
+end
+local function checksteps(sequence)
+ local steps=sequence.steps
+ if steps then
+ for i=1,#steps do
+ steps[i].index=i
+ end
+ end
+end
+if fonts.helpers then
+ fonts.helpers.checkmerge=checkmerge
+ fonts.helpers.checkflags=checkflags
+ fonts.helpers.checksteps=checksteps
+end
function readers.expand(data)
if not data or data.expanded then
return
@@ -10023,6 +13914,7 @@ function readers.expand(data)
local sequence=sequences[i]
local steps=sequence.steps
if steps then
+ local nofsteps=sequence.nofsteps
local kind=sequence.type
local markclass=sequence.markclass
if markclass then
@@ -10033,7 +13925,7 @@ function readers.expand(data)
sequence.markclass=markclasses[markclass]
end
end
- for i=1,sequence.nofsteps do
+ for i=1,nofsteps do
local step=steps[i]
local baseclasses=step.baseclasses
if baseclasses then
@@ -10049,13 +13941,14 @@ function readers.expand(data)
end
local rules=step.rules
if rules then
- local rulehash={}
+ local rulehash={ n=0 }
local rulesize=0
local coverage={}
local lookuptype=sequence.type
+ local nofrules=#rules
step.coverage=coverage
- for nofrules=1,#rules do
- local rule=rules[nofrules]
+ for currentrule=1,nofrules do
+ local rule=rules[currentrule]
local current=rule.current
local before=rule.before
local after=rule.after
@@ -10083,21 +13976,26 @@ function readers.expand(data)
local lookups=rule.lookups or false
local subtype=nil
if lookups then
- for k,v in next,lookups do
- local lookup=sublookups[v]
- if lookup then
- lookups[k]=lookup
- if not subtype then
- subtype=lookup.type
+ for i=1,#lookups do
+ local lookups=lookups[i]
+ if lookups then
+ for k,v in next,lookups do
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]=lookup
+ if not subtype then
+ subtype=lookup.type
+ end
+ else
+ end
end
- else
end
end
end
if sequence[1] then
- rulesize=rulesize+1
- rulehash[rulesize]={
- nofrules,
+ sequence.n=#sequence
+ local ruledata={
+ currentrule,
lookuptype,
sequence,
start,
@@ -10106,16 +14004,36 @@ function readers.expand(data)
replacements,
subtype,
}
- for unic in next,sequence[start] do
- local cu=coverage[unic]
- if not cu then
- coverage[unic]=rulehash
+ rulesize=rulesize+1
+ rulehash[rulesize]=ruledata
+ rulehash.n=rulesize
+ if true then
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ local n=#cu+1
+ cu[n]=ruledata
+ cu.n=n
+ else
+ coverage[unic]={ ruledata,n=1 }
+ end
+ end
+ else
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ else
+ coverage[unic]=rulehash
+ end
end
end
end
end
end
end
+ checkmerge(sequence)
+ checkflags(sequence,resources)
+ checksteps(sequence)
end
end
end
@@ -10124,10 +14042,10 @@ function readers.expand(data)
expandlookups(sublookups)
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oup”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oup”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otl” 2e7c8d9a331c46826211bd507f8e488a] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otl” fcc55ae6cff5fd55b5054f923c21cafa] ---
if not modules then modules={} end modules ['font-otl']={
version=1.001,
@@ -10136,7 +14054,7 @@ if not modules then modules={} end modules ['font-otl']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
}
-local gmatch,find,match,lower,strip=string.gmatch,string.find,string.match,string.lower,string.strip
+local lower=string.lower
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
local derivetable=table.derive
@@ -10155,11 +14073,13 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.027
+otf.version=3.104
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
+otf.sbixcache=containers.define("fonts","sbix",otf.version,true)
otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
otf.svgenabled=false
+otf.sbixenabled=false
local otfreaders=otf.readers
local hashes=fonts.hashes
local definers=fonts.definers
@@ -10173,6 +14093,7 @@ local forceload=false
local cleanup=0
local syncspace=true
local forcenotdef=false
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
local wildcard="*"
local default="dflt"
@@ -10184,17 +14105,31 @@ registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or
registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
-registerotfenhancer("check extra features",function() end)
-function otf.load(filename,sub,featurefile)
- local featurefile=nil
+registerotfenhancer("check extra features",function() end)
+local checkmemory=utilities.lua and utilities.lua.checkmemory
+local threshold=100
+local tracememory=false
+registertracker("fonts.otf.loader.memory",function(v) tracememory=v end)
+if not checkmemory then
+ local collectgarbage=collectgarbage
+ checkmemory=function(previous,threshold)
+ local current=collectgarbage("count")
+ if previous then
+ local checked=(threshold or 64)*1024
+ if current-previous>checked then
+ collectgarbage("collect")
+ current=collectgarbage("count")
+ end
+ end
+ return current
+ end
+end
+function otf.load(filename,sub,instance)
local base=file.basename(file.removesuffix(filename))
- local name=file.removesuffix(base)
+ local name=file.removesuffix(base)
local attr=lfs.attributes(filename)
local size=attr and attr.size or 0
local time=attr and attr.modification or 0
- if featurefile then
- name=name.."@"..file.removesuffix(file.basename(featurefile))
- end
if sub=="" then
sub=false
end
@@ -10202,27 +14137,10 @@ function otf.load(filename,sub,featurefile)
if sub then
hash=hash.."-"..sub
end
- hash=containers.cleanname(hash)
- local featurefiles
- if featurefile then
- featurefiles={}
- for s in gmatch(featurefile,"[^,]+") do
- local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or ""
- if name=="" then
- report_otf("loading error, no featurefile %a",s)
- else
- local attr=lfs.attributes(name)
- featurefiles[#featurefiles+1]={
- name=name,
- size=attr and attr.size or 0,
- time=attr and attr.modification or 0,
- }
- end
- end
- if #featurefiles==0 then
- featurefiles=nil
- end
+ if instance then
+ hash=hash.."-"..instance
end
+ hash=containers.cleanname(hash)
local data=containers.read(otf.cache,hash)
local reload=not data or data.size~=size or data.time~=time or data.tableversion~=otfreaders.tableversion
if forceload then
@@ -10232,10 +14150,15 @@ function otf.load(filename,sub,featurefile)
if reload then
report_otf("loading %a, hash %a",filename,hash)
starttiming(otfreaders)
- data=otfreaders.loadfont(filename,sub or 1)
+ data=otfreaders.loadfont(filename,sub or 1,instance)
if data then
+ local used=checkmemory()
local resources=data.resources
local svgshapes=resources.svgshapes
+ local sbixshapes=resources.sbixshapes
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
if svgshapes then
resources.svgshapes=nil
if otf.svgenabled then
@@ -10249,17 +14172,49 @@ function otf.load(filename,sub,featurefile)
timestamp=timestamp,
}
end
+ if cleanup>1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
+ end
+ if sbixshapes then
+ resources.sbixshapes=nil
+ if otf.sbixenabled then
+ local timestamp=os.date()
+ containers.write(otf.sbixcache,hash,{
+ sbixshapes=sbixshapes,
+ timestamp=timestamp,
+ })
+ data.properties.sbix={
+ hash=hash,
+ timestamp=timestamp,
+ }
+ end
+ if cleanup>1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
end
otfreaders.compact(data)
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.rehash(data,"unicodes")
otfreaders.addunicodetable(data)
otfreaders.extend(data)
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
data=containers.write(otf.cache,hash,data)
if cleanup>1 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
stoptiming(otfreaders)
if elapsedtime then
@@ -10267,10 +14222,14 @@ function otf.load(filename,sub,featurefile)
end
if cleanup>3 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
data=containers.read(otf.cache,hash)
if cleanup>2 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
else
data=nil
@@ -10286,9 +14245,20 @@ function otf.load(filename,sub,featurefile)
otfreaders.addunicodetable(data)
otfenhancers.apply(data,filename,data)
if applyruntimefixes then
- applyruntimefixes(filename,data)
+ applyruntimefixes(filename,data)
end
data.metadata.math=data.resources.mathconstants
+ local classes=data.resources.classes
+ if not classes then
+ local descriptions=data.descriptions
+ classes=setmetatableindex(function(t,k)
+ local d=descriptions[k]
+ local v=(d and d.class or "base") or false
+ t[k]=v
+ return v
+ end)
+ data.resources.classes=classes
+ end
end
return data
end
@@ -10332,7 +14302,7 @@ local function copytotfm(data,cache_id)
end
if mathspecs then
for unicode,character in next,characters do
- local d=descriptions[unicode]
+ local d=descriptions[unicode]
local m=d.math
if m then
local italic=m.italic
@@ -10385,6 +14355,7 @@ local function copytotfm(data,cache_id)
local fontname=metadata.fontname
local fullname=metadata.fullname or fontname
local psname=fontname or fullname
+ local subfont=metadata.subfontindex
local units=metadata.units or 1000
if units==0 then
units=1000
@@ -10472,6 +14443,8 @@ local function copytotfm(data,cache_id)
properties.fullname=fullname
properties.psname=psname
properties.name=filename or fullname
+ properties.subfont=subfont
+ properties.private=properties.private or data.private or privateoffset
return {
characters=characters,
descriptions=descriptions,
@@ -10520,7 +14493,8 @@ local function otftotfm(specification)
local subindex=specification.subindex
local filename=specification.filename
local features=specification.features.normal
- local rawdata=otf.load(filename,sub,features and features.featurefile)
+ local instance=specification.instance or (features and features.axis)
+ local rawdata=otf.load(filename,sub,instance)
if rawdata and next(rawdata) then
local descriptions=rawdata.descriptions
rawdata.lookuphash={}
@@ -10563,7 +14537,7 @@ local function checkmathsize(tfmdata,mathsize)
local parameters=tfmdata.parameters
parameters.scriptpercentage=mathdata.ScriptPercentScaleDown
parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown
- parameters.mathsize=mathsize
+ parameters.mathsize=mathsize
end
end
registerotffeature {
@@ -10745,6 +14719,7 @@ otf.coverup={
multiple=justset,
kern=justset,
pair=justset,
+ single=justset,
ligature=function(coverage,unicode,ligature)
local first=ligature[1]
local tree=coverage[first]
@@ -10772,10 +14747,10 @@ otf.coverup={
end
}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otl”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otl”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oto” 5fbdd899624d4eef639f81b580afe9aa] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oto” d78a6165b7ff6c21f4c3c4c3c0553648] ---
if not modules then modules={} end modules ['font-oto']={
version=1.001,
@@ -10801,6 +14776,7 @@ local otf=fonts.handlers.otf
local otffeatures=otf.features
local registerotffeature=otffeatures.register
otf.defaultbasealternate="none"
+local getprivate=fonts.constructors.getprivate
local wildcard="*"
local default="dflt"
local formatters=string.formatters
@@ -10834,19 +14810,31 @@ end
local function cref(feature,sequence)
return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
end
-local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
- report_prepare("%s: base alternate %s => %s (%S => %S)",
- cref(feature,sequence),
- gref(descriptions,unicode),
- replacement and gref(descriptions,replacement),
- value,
- comment)
-end
local function report_substitution(feature,sequence,descriptions,unicode,substitution)
- report_prepare("%s: base substitution %s => %S",
- cref(feature,sequence),
- gref(descriptions,unicode),
- gref(descriptions,substitution))
+ if unicode==substitution then
+ report_prepare("%s: base substitution %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base substitution %s => %S",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ gref(descriptions,substitution))
+ end
+end
+local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
+ if unicode==replacement then
+ report_prepare("%s: base alternate %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base alternate %s => %s (%S => %S)",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ replacement and gref(descriptions,replacement),
+ value,
+ comment)
+ end
end
local function report_ligature(feature,sequence,descriptions,unicode,ligature)
report_prepare("%s: base ligature %s => %S",
@@ -10879,13 +14867,11 @@ local function registerbasefeature(feature,value)
applied[#applied+1]=feature.."="..tostring(value)
end
local function makefake(tfmdata,name,present)
- local resources=tfmdata.resources
- local private=resources.private
+ local private=getprivate(tfmdata)
local character={ intermediate=true,ligatures={} }
resources.unicodes[name]=private
tfmdata.characters[private]=character
tfmdata.descriptions[private]={ name=name }
- resources.private=private+1
present[name]=private
return character
end
@@ -10951,37 +14937,44 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
if kind=="gsub_single" then
for i=1,#steps do
for unicode,data in next,steps[i].coverage do
- if trace_singles then
- report_substitution(feature,sequence,descriptions,unicode,data)
- end
+ if unicode~=data then
changed[unicode]=data
+ end
+ if trace_singles then
+ report_substitution(feature,sequence,descriptions,unicode,data)
+ end
end
end
elseif kind=="gsub_alternate" then
for i=1,#steps do
for unicode,data in next,steps[i].coverage do
- if not changed[unicode] then
- local replacement=data[alternate]
- if replacement then
+ local replacement=data[alternate]
+ if replacement then
+ if unicode~=replacement then
changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
- end
- elseif defaultalt=="first" then
- replacement=data[1]
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
+ end
+ elseif defaultalt=="first" then
+ replacement=data[1]
+ if unicode~=replacement then
changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- elseif defaultalt=="last" then
- replacement=data[#data]
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- else
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
- end
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ elseif defaultalt=="last" then
+ replacement=data[#data]
+ if unicode~=replacement then
+ changed[unicode]=replacement
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ else
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
end
end
end
@@ -11028,7 +15021,8 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
if kind=="gpos_pair" then
for i=1,#steps do
local step=steps[i]
- if step.format=="kern" then
+ local format=step.format
+ if format=="kern" or format=="move" then
for unicode,data in next,steps[i].coverage do
local character=characters[unicode]
local kerns=character.kerns
@@ -11056,9 +15050,11 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
local character=characters[unicode]
local kerns=character.kerns
for otherunicode,kern in next,data do
- if not kern[2] and not (kerns and kerns[otherunicode]) then
+ local other=kern[2]
+ if other==true or (not other and not (kerns and kerns[otherunicode])) then
local kern=kern[1]
- if kern[1]~=0 or kern[2]~=0 or kern[4]~=0 then
+ if kern==true then
+ elseif kern[1]~=0 or kern[2]~=0 or kern[4]~=0 then
else
kern=kern[3]
if kern~=0 then
@@ -11083,6 +15079,51 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
end
local function initializehashes(tfmdata)
end
+local function checkmathreplacements(tfmdata,fullname,fixitalics)
+ if tfmdata.mathparameters then
+ local characters=tfmdata.characters
+ local changed=tfmdata.changed
+ if next(changed) then
+ if trace_preparing or trace_baseinit then
+ report_prepare("checking math replacements for %a",fullname)
+ end
+ for unicode,replacement in next,changed do
+ local u=characters[unicode]
+ local r=characters[replacement]
+ local n=u.next
+ local v=u.vert_variants
+ local h=u.horiz_variants
+ if fixitalics then
+ local ui=u.italic
+ if ui and not r.italic then
+ if trace_preparing then
+ report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+ end
+ r.italic=ui
+ end
+ end
+ if n and not r.next then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
+ end
+ r.next=n
+ end
+ if v and not r.vert_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+ end
+ r.vert_variants=v
+ end
+ if h and not r.horiz_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+ end
+ r.horiz_variants=h
+ end
+ end
+ end
+ end
+end
local function featuresinitializer(tfmdata,value)
if true then
local starttime=trace_preparing and os.clock()
@@ -11099,6 +15140,8 @@ local function featuresinitializer(tfmdata,value)
local rawfeatures=rawresources and rawresources.features
local basesubstitutions=rawfeatures and rawfeatures.gsub
local basepositionings=rawfeatures and rawfeatures.gpos
+ local substitutionsdone=false
+ local positioningsdone=false
if basesubstitutions or basepositionings then
local sequences=tfmdata.resources.sequences
for s=1,#sequences do
@@ -11119,12 +15162,14 @@ local function featuresinitializer(tfmdata,value)
end
preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ substitutionsdone=true
elseif basepositionings and basepositionings[feature] then
if trace_preparing then
report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value)
end
preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ positioningsdone=true
end
end
end
@@ -11132,6 +15177,9 @@ local function featuresinitializer(tfmdata,value)
end
end
end
+ if substitutionsdone then
+ checkmathreplacements(tfmdata,fullname,features.fixitalics)
+ end
registerbasehash(tfmdata)
end
if trace_preparing then
@@ -11149,10 +15197,10 @@ registerotffeature {
}
otf.basemodeinitializer=featuresinitializer
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-oto”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-oto”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otj” 5ea70db9f1990dc1459425853c79f663] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otj” 578448ae37a167319dbccd5af04738da] ---
if not modules then modules={} end modules ['font-otj']={
version=1.001,
@@ -11162,20 +15210,21 @@ if not modules then modules={} end modules ['font-otj']={
license="see context related readme files",
}
if not nodes.properties then return end
-local next,rawget=next,rawget
+local next,rawget,tonumber=next,rawget,tonumber
local fastcopy=table.fastcopy
local registertracker=trackers.register
+local registerdirective=directives.register
local trace_injections=false registertracker("fonts.injections",function(v) trace_injections=v end)
local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end)
local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end)
local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end)
-local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end)
local report_injections=logs.reporter("fonts","injections")
local report_spaces=logs.reporter("fonts","spaces")
local attributes,nodes,node=attributes,nodes,node
fonts=fonts
local hashes=fonts.hashes
local fontdata=hashes.identifiers
+local fontmarks=hashes.marks
nodes.injections=nodes.injections or {}
local injections=nodes.injections
local tracers=nodes.tracers
@@ -11188,31 +15237,62 @@ local kern_code=nodecodes.kern
local glue_code=nodecodes.glue
local nuts=nodes.nuts
local nodepool=nuts.pool
-local newkern=nodepool.kern
local tonode=nuts.tonode
local tonut=nuts.tonut
-local getfield=nuts.getfield
local setfield=nuts.setfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getid=nuts.getid
local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
+local getoffsets=nuts.getoffsets
local getboth=nuts.getboth
-local ischar=nuts.is_char
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
-local traverse_id=nuts.traverse_id
-local traverse_char=nuts.traverse_char
+local setoffsets=nuts.setoffsets
+local ischar=nuts.is_char
+local getkern=nuts.getkern
+local setkern=nuts.setkern
+local setlink=nuts.setlink
+local setwidth=nuts.setwidth
+local getwidth=nuts.getwidth
+local nextchar=nuts.traversers.char
+local nextglue=nuts.traversers.glue
local insert_node_before=nuts.insert_before
local insert_node_after=nuts.insert_after
local properties=nodes.properties.data
-function injections.installnewkern(nk)
- newkern=nk or newkern
-end
+local fontkern=nuts.pool and nuts.pool.fontkern
+local italickern=nuts.pool and nuts.pool.italickern
+local useitalickerns=false
+directives.register("fonts.injections.useitalics",function(v)
+ if v then
+ report_injections("using italics for space kerns (tracing only)")
+ end
+ useitalickerns=v
+end)
+do if not fontkern then
+ local thekern=nuts.new("kern",0)
+ local setkern=nuts.setkern
+ local copy_node=nuts.copy_node
+ fontkern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
+do if not italickern then
+ local thekern=nuts.new("kern",3)
+ local setkern=nuts.setkern
+ local copy_node=nuts.copy_node
+ italickern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
+function injections.installnewkern() end
local nofregisteredkerns=0
-local nofregisteredpairs=0
+local nofregisteredpositions=0
local nofregisteredmarks=0
local nofregisteredcursives=0
local keepregisteredcounts=false
@@ -11221,7 +15301,7 @@ function injections.keepcounts()
end
function injections.resetcounts()
nofregisteredkerns=0
- nofregisteredpairs=0
+ nofregisteredpositions=0
nofregisteredmarks=0
nofregisteredcursives=0
keepregisteredcounts=false
@@ -11244,7 +15324,7 @@ function injections.copy(target,source)
if tp then
tp.injections=si
else
- propertydata[target]={
+ properties[target]={
injections=si,
}
end
@@ -11262,7 +15342,7 @@ function injections.copy(target,source)
end
end
end
-function injections.setligaindex(n,index)
+function injections.setligaindex(n,index)
local p=rawget(properties,n)
if p then
local i=p.injections
@@ -11291,7 +15371,7 @@ function injections.getligaindex(n,default)
end
return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
local dx=factor*(exit[1]-entry[1])
local dy=-factor*(exit[2]-entry[2])
local ws=tfmstart.width
@@ -11344,17 +15424,17 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
end
return dx,dy,nofregisteredcursives
end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
- local x=factor*spec[1]
- local y=factor*spec[2]
- local w=factor*spec[3]
- local h=factor*spec[4]
+function injections.setposition(kind,current,factor,rlmode,spec,injection)
+ local x=factor*(spec[1] or 0)
+ local y=factor*(spec[2] or 0)
+ local w=factor*(spec[3] or 0)
+ local h=factor*(spec[4] or 0)
if x~=0 or w~=0 or y~=0 or h~=0 then
local yoffset=y-h
local leftkern=x
local rightkern=w-x
if leftkern~=0 or rightkern~=0 or yoffset~=0 then
- nofregisteredpairs=nofregisteredpairs+1
+ nofregisteredpositions=nofregisteredpositions+1
if rlmode and rlmode<0 then
leftkern,rightkern=rightkern,leftkern
end
@@ -11363,7 +15443,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
end
local p=rawget(properties,current)
if p then
- local i=rawget(p,injection)
+ local i=p[injection]
if i then
if leftkern~=0 then
i.leftkern=(i.leftkern or 0)+leftkern
@@ -11400,7 +15480,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
},
}
end
- return x,y,w,h,nofregisteredpairs
+ return x,y,w,h,nofregisteredpositions
end
end
return x,y,w,h
@@ -11414,7 +15494,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
injection="injections"
end
if p then
- local i=rawget(p,injection)
+ local i=p[injection]
if i then
i.leftkern=dx+(i.leftkern or 0)
else
@@ -11434,6 +15514,54 @@ function injections.setkern(current,factor,rlmode,x,injection)
return 0,0
end
end
+function injections.setmove(current,factor,rlmode,x,injection)
+ local dx=factor*x
+ if dx~=0 then
+ nofregisteredkerns=nofregisteredkerns+1
+ local p=rawget(properties,current)
+ if not injection then
+ injection="injections"
+ end
+ if rlmode and rlmode<0 then
+ if p then
+ local i=p[injection]
+ if i then
+ i.rightkern=dx+(i.rightkern or 0)
+ else
+ p[injection]={
+ rightkern=dx,
+ }
+ end
+ else
+ properties[current]={
+ [injection]={
+ rightkern=dx,
+ },
+ }
+ end
+ else
+ if p then
+ local i=p[injection]
+ if i then
+ i.leftkern=dx+(i.leftkern or 0)
+ else
+ p[injection]={
+ leftkern=dx,
+ }
+ end
+ else
+ properties[current]={
+ [injection]={
+ leftkern=dx,
+ },
+ }
+ end
+ end
+ return dx,nofregisteredkerns
+ else
+ return 0,0
+ end
+end
function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
nofregisteredmarks=nofregisteredmarks+1
@@ -11446,9 +15574,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmar
if i then
if i.markmark then
else
- i.markx=dx
- i.marky=dy
- i.markdir=rlmode or 0
+ if dx~=0 then
+ i.markx=dx
+ end
+ if y~=0 then
+ i.marky=dy
+ end
+ if rlmode then
+ i.markdir=rlmode
+ end
i.markbase=nofregisteredmarks
i.markbasenode=base
i.markmark=mkmk
@@ -11491,7 +15625,7 @@ local function show(n,what,nested,symbol)
if n then
local p=rawget(properties,n)
if p then
- local i=rawget(p,what)
+ local i=p[what]
if i then
local leftkern=i.leftkern or 0
local rightkern=i.rightkern or 0
@@ -11531,15 +15665,16 @@ local function show(n,what,nested,symbol)
end
local function showsub(n,what,where)
report_injections("begin subrun: %s",where)
- for n in traverse_id(glyph_code,n) do
+ for n in nextchar,n do
showchar(n,where)
show(n,what,where," ")
end
report_injections("end subrun")
end
local function trace(head,where)
- report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered",
- where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
+ report_injections()
+ report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
+ where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
local n=head
while n do
local id=getid(n)
@@ -11573,11 +15708,12 @@ local function show_result(head)
while current do
local id=getid(current)
if id==glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",
- getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+ local w=getwidth(current)
+ local x,y=getoffsets(current)
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
skipping=false
elseif id==kern_code then
- report_injections("kern: %p",getfield(current,"kern"))
+ report_injections("kern: %p",getkern(current))
skipping=false
elseif not skipping then
report_injections()
@@ -11585,9 +15721,9 @@ local function show_result(head)
end
current=getnext(current)
end
+ report_injections()
end
local function inject_kerns_only(head,where)
- head=tonut(head)
if trace_injections then
trace(head,"kerns")
end
@@ -11595,7 +15731,6 @@ local function inject_kerns_only(head,where)
local prev=nil
local next=nil
local prevdisc=nil
- local prevglyph=nil
local pre=nil
local post=nil
local replace=nil
@@ -11603,128 +15738,99 @@ local function inject_kerns_only(head,where)
local posttail=nil
local replacetail=nil
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(current,"xoffset",leftkern)
- setfield(current,"xadvance",leftkern)
- else
- insert_node_before(head,current,newkern(leftkern))
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ head=insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ if prevdisc then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
end
- if prevdisc then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(post,"xadvance",leftkern)
- else
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
- end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(replace,"xadvance",leftkern)
- else
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
- end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
end
end
prevdisc=nil
- prevglyph=current
+ elseif char==false then
+ prevdisc=nil
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(pre,"xoffset",leftkern)
- setfield(pre,"xadvance",leftkern)
- else
- pre=insert_node_before(pre,n,newkern(leftkern))
- done=true
- end
+ pre=insert_node_before(pre,n,fontkern(leftkern))
+ done=true
end
end
end
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(post,"xoffset",leftkern)
- setfield(post,"xadvance",leftkern)
- else
- post=insert_node_before(post,n,newkern(leftkern))
- done=true
- end
+ post=insert_node_before(post,n,fontkern(leftkern))
+ done=true
end
end
end
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(replace,"xoffset",leftkern)
- setfield(replace,"xadvance",leftkern)
- else
- replace=insert_node_before(replace,n,newkern(leftkern))
- done=true
- end
+ replace=insert_node_before(replace,n,fontkern(leftkern))
+ done=true
end
end
end
@@ -11733,10 +15839,8 @@ local function inject_kerns_only(head,where)
if done then
setdisc(current,pre,post,replace)
end
- prevglyph=nil
prevdisc=current
else
- prevglyph=nil
prevdisc=nil
end
prev=current
@@ -11747,12 +15851,14 @@ local function inject_kerns_only(head,where)
else
nofregisteredkerns=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
-local function inject_pairs_only(head,where)
- head=tonut(head)
+local function inject_positions_only(head,where)
if trace_injections then
- trace(head,"pairs")
+ trace(head,"positions")
end
local current=head
local prev=nil
@@ -11766,99 +15872,105 @@ local function inject_pairs_only(head,where)
local posttail=nil
local replacetail=nil
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local yoffset=i.yoffset
- if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
- end
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- head=insert_node_before(head,current,newkern(leftkern))
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local yoffset=i.yoffset
+ if yoffset and yoffset~=0 then
+ setoffsets(current,false,yoffset)
+ end
+ local leftkern=i.leftkern
+ local rightkern=i.rightkern
+ if leftkern and leftkern~=0 then
+ if rightkern and leftkern==-rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern=0
+ else
+ head=insert_node_before(head,current,fontkern(leftkern))
end
+ end
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ else
+ local i=p.emptyinjections
+ if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(head,current,newkern(rightkern))
- end
- else
- local i=p.emptyinjections
- if i then
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- if next and getid(next)==disc_code then
- if replace then
- else
- setfield(next,"replace",newkern(rightkern))
- end
+ if next and getid(next)==disc_code then
+ if replace then
+ else
+ setfield(next,"replace",fontkern(rightkern))
end
end
end
end
- if prevdisc then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
+ end
+ if prevdisc then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
+ end
end
end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
end
end
prevdisc=nil
prevglyph=current
+ elseif char==false then
+ prevdisc=nil
+ prevglyph=current
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- pre=insert_node_before(pre,n,newkern(leftkern))
+ pre=insert_node_before(pre,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done=true
end
end
@@ -11866,23 +15978,23 @@ local function inject_pairs_only(head,where)
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- post=insert_node_before(post,n,newkern(leftkern))
+ post=insert_node_before(post,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done=true
end
end
@@ -11890,23 +16002,23 @@ local function inject_pairs_only(head,where)
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- replace=insert_node_before(replace,n,newkern(leftkern))
+ replace=insert_node_before(replace,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done=true
end
end
@@ -11921,7 +16033,7 @@ local function inject_pairs_only(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- pre=insert_node_before(pre,pre,newkern(rightkern))
+ pre=insert_node_before(pre,pre,fontkern(rightkern))
done=true
end
end
@@ -11934,7 +16046,7 @@ local function inject_pairs_only(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- replace=insert_node_before(replace,replace,newkern(rightkern))
+ replace=insert_node_before(replace,replace,fontkern(rightkern))
done=true
end
end
@@ -11956,23 +16068,20 @@ local function inject_pairs_only(head,where)
if keepregisteredcounts then
keepregisteredcounts=false
else
- nofregisteredkerns=0
+ nofregisteredpositions=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
local function showoffset(n,flag)
- local o=getfield(n,"xoffset")
- if o==0 then
- o=getfield(n,"yoffset")
- end
- if o~=0 then
- setcolor(n,flag and "darkred" or "darkgreen")
- else
- resetcolor(n)
+ local x,y=getoffsets(n)
+ if x~=0 or y~=0 then
+ setcolor(n,"darkgray")
end
end
local function inject_everything(head,where)
- head=tonut(head)
if trace_injections then
trace(head,"everything")
end
@@ -11980,8 +16089,6 @@ local function inject_everything(head,where)
local hasmarks=nofregisteredmarks>0
local current=head
local last=nil
- local font=font
- local markdata=nil
local prev=nil
local next=nil
local prevdisc=nil
@@ -11999,7 +16106,8 @@ local function inject_everything(head,where)
local marks={}
local nofmarks=0
local function processmark(p,n,pn)
- local px=getfield(p,"xoffset")
+ local px,py=getoffsets(p)
+ local nx,ny=getoffsets(n)
local ox=0
local rightkern=nil
local pp=rawget(properties,p)
@@ -12009,212 +16117,232 @@ local function inject_everything(head,where)
rightkern=pp.rightkern
end
end
+ local markdir=pn.markdir
if rightkern then
- if pn.markdir<0 then
- ox=px-pn.markx-rightkern
+ ox=px-(pn.markx or 0)-rightkern
+ if markdir and markdir<0 then
+ if not pn.markmark then
+ ox=ox+(pn.leftkern or 0)
+ end
else
if false then
local leftkern=pp.leftkern
if leftkern then
- ox=px-pn.markx-leftkern
- else
- ox=px-pn.markx
+ ox=ox-leftkern
end
- else
- ox=px-pn.markx
end
end
else
- ox=px-pn.markx
+ ox=px-(pn.markx or 0)
+ if markdir and markdir<0 then
+ if not pn.markmark then
+ local leftkern=pn.leftkern
+ if leftkern then
+ ox=ox+leftkern
+ end
+ end
+ end
if pn.checkmark then
- local wn=getfield(n,"width")
- if wn~=0 then
+ local wn=getwidth(n)
+ if wn and wn~=0 then
wn=wn/2
if trace_injections then
report_injections("correcting non zero width mark %C",getchar(n))
end
- insert_node_before(n,n,newkern(-wn))
- insert_node_after(n,n,newkern(-wn))
+ insert_node_before(n,n,fontkern(-wn))
+ insert_node_after(n,n,fontkern(-wn))
end
end
end
- local oy=getfield(n,"yoffset")+getfield(p,"yoffset")+pn.marky
- setfield(n,"xoffset",ox)
- setfield(n,"yoffset",oy)
+ local oy=ny+py+(pn.marky or 0)
+ if not pn.markmark then
+ local yoffset=pn.yoffset
+ if yoffset then
+ oy=oy+yoffset
+ end
+ end
+ setoffsets(n,ox,oy)
if trace_marks then
showoffset(n,true)
end
end
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local pm=i.markbasenode
- if pm then
- nofmarks=nofmarks+1
- marks[nofmarks]=current
- else
- local yoffset=i.yoffset
- if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
- end
- if hascursives then
- local cursivex=i.cursivex
- if cursivex then
- if cursiveanchor then
- if cursivex~=0 then
- i.leftkern=(i.leftkern or 0)+cursivex
- end
- if maxc==0 then
- minc=1
- maxc=1
- glyphs[1]=cursiveanchor
- else
- maxc=maxc+1
- glyphs[maxc]=cursiveanchor
- end
- properties[cursiveanchor].cursivedy=i.cursivey
- last=current
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local pm=i.markbasenode
+ if pm then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=current
+ else
+ local yoffset=i.yoffset
+ if yoffset and yoffset~=0 then
+ setoffsets(current,false,yoffset)
+ end
+ if hascursives then
+ local cursivex=i.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex~=0 then
+ i.leftkern=(i.leftkern or 0)+cursivex
+ end
+ if maxc==0 then
+ minc=1
+ maxc=1
+ glyphs[1]=cursiveanchor
else
- maxc=0
+ maxc=maxc+1
+ glyphs[maxc]=cursiveanchor
+ end
+ properties[cursiveanchor].cursivedy=i.cursivey
+ last=current
+ else
+ maxc=0
+ end
+ elseif maxc>0 then
+ local nx,ny=getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setoffsets(ti,false,ny)
+ if trace_cursive then
+ showoffset(ti)
end
- elseif maxc>0 then
- local ny=getfield(current,"yoffset")
+ end
+ maxc=0
+ cursiveanchor=nil
+ end
+ if i.cursiveanchor then
+ cursiveanchor=current
+ else
+ if maxc>0 then
+ local nx,ny=getoffsets(current)
for i=maxc,minc,-1 do
local ti=glyphs[i]
ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
+ setoffsets(ti,false,ny)
if trace_cursive then
showoffset(ti)
end
end
maxc=0
- cursiveanchor=nil
- end
- if i.cursiveanchor then
- cursiveanchor=current
- else
- if maxc>0 then
- local ny=getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti=glyphs[i]
- ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
- if trace_cursive then
- showoffset(ti)
- end
- end
- maxc=0
- end
- cursiveanchor=nil
end
+ cursiveanchor=nil
end
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_before(head,current,newkern(leftkern))
- end
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- insert_node_after(head,current,newkern(rightkern))
+ end
+ local leftkern=i.leftkern
+ local rightkern=i.rightkern
+ if leftkern and leftkern~=0 then
+ if rightkern and leftkern==-rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern=0
+ else
+ head=insert_node_before(head,current,fontkern(leftkern))
end
end
- else
- local i=p.emptyinjections
- if i then
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- if next and getid(next)==disc_code then
- if replace then
- else
- setfield(next,"replace",newkern(rightkern))
- end
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ end
+ else
+ local i=p.emptyinjections
+ if i then
+ local rightkern=i.rightkern
+ if rightkern and rightkern~=0 then
+ if next and getid(next)==disc_code then
+ if replace then
+ else
+ setfield(next,"replace",fontkern(rightkern))
end
end
end
end
- if prevdisc then
- if p then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
+ end
+ if prevdisc then
+ if p then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
+ end
end
end
- end
- else
- if hascursives and maxc>0 then
- local ny=getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti=glyphs[i]
- ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
- maxc=0
- cursiveanchor=nil
end
end
+ else
+ if hascursives and maxc>0 then
+ local nx,ny=getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ local xi,yi=getoffsets(ti)
+ setoffsets(ti,xi,yi+ny)
+ end
+ maxc=0
+ cursiveanchor=nil
+ end
end
prevdisc=nil
prevglyph=current
+ elseif char==false then
+ prevdisc=nil
+ prevglyph=current
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- pre=insert_node_before(pre,n,newkern(leftkern))
+ pre=insert_node_before(pre,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -12222,29 +16350,29 @@ local function inject_everything(head,where)
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- post=insert_node_before(post,n,newkern(leftkern))
+ post=insert_node_before(post,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -12252,29 +16380,29 @@ local function inject_everything(head,where)
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- replace=insert_node_before(replace,n,newkern(leftkern))
+ replace=insert_node_before(replace,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -12289,7 +16417,7 @@ local function inject_everything(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- pre=insert_node_before(pre,pre,newkern(rightkern))
+ pre=insert_node_before(pre,pre,fontkern(rightkern))
done=true
end
end
@@ -12302,7 +16430,7 @@ local function inject_everything(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- replace=insert_node_before(replace,replace,newkern(rightkern))
+ replace=insert_node_before(replace,replace,fontkern(rightkern))
done=true
end
end
@@ -12322,11 +16450,11 @@ local function inject_everything(head,where)
current=next
end
if hascursives and maxc>0 then
- local ny=getfield(last,"yoffset")
+ local nx,ny=getoffsets(last)
for i=maxc,minc,-1 do
local ti=glyphs[i]
ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
+ setoffsets(ti,false,ny)
if trace_cursive then
showoffset(ti)
end
@@ -12346,11 +16474,14 @@ local function inject_everything(head,where)
keepregisteredcounts=false
else
nofregisteredkerns=0
- nofregisteredpairs=0
+ nofregisteredpositions=0
nofregisteredmarks=0
nofregisteredcursives=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
local triggers=false
function nodes.injections.setspacekerns(font,sequence)
@@ -12383,17 +16514,21 @@ else
end
end
injections.getthreshold=getthreshold
-function injections.isspace(n,threshold)
- if getid(n)==glue_code then
- local w=getfield(n,"width")
+function injections.isspace(n,threshold,id)
+ if (id or getid(n))==glue_code then
+ local w=getwidth(n)
if threshold and w>threshold then
return 32
end
end
end
+local getspaceboth=getboth
+function injections.installgetspaceboth(gb)
+ getspaceboth=gb or getboth
+end
local function injectspaces(head)
if not triggers then
- return head,false
+ return head
end
local lastfont=nil
local spacekerns=nil
@@ -12410,10 +16545,10 @@ local function injectspaces(head)
threshold,
factor=getthreshold(font)
end
- for n in traverse_id(glue_code,tonut(head)) do
- local prev,next=getboth(n)
- local prevchar=ischar(prev)
- local nextchar=ischar(next)
+ for n in nextglue,head do
+ local prev,next=getspaceboth(n)
+ local prevchar=prev and ischar(prev)
+ local nextchar=next and ischar(next)
if nextchar then
local font=getfont(next)
local trig=triggers[font]
@@ -12439,38 +16574,64 @@ local function injectspaces(head)
end
end
if leftkern then
- local old=getfield(n,"width")
+ local old=getwidth(n)
if old>threshold then
if rightkern then
- local new=old+(leftkern+rightkern)*factor
- if trace_spaces then
- report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ if useitalickerns then
+ local lnew=leftkern*factor
+ local rnew=rightkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
+ end
+ head=insert_node_before(head,n,italickern(lnew))
+ insert_node_after(head,n,italickern(rnew))
+ else
+ local new=old+(leftkern+rightkern)*factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
- leftkern=false
+ rightkern=false
else
- local new=old+leftkern*factor
- if trace_spaces then
- report_spaces("%C [%p -> %p]",prevchar,old,new)
+ if useitalickerns then
+ local new=leftkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",prevchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ local new=old+leftkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p]",prevchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
end
leftkern=false
elseif rightkern then
- local old=getfield(n,"width")
+ local old=getwidth(n)
if old>threshold then
- local new=old+rightkern*factor
- if trace_spaces then
- report_spaces("[%p -> %p] %C",nextchar,old,new)
+ if useitalickerns then
+ local new=rightkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",nextchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ local new=old+rightkern*factor
+ if trace_spaces then
+ report_spaces("[%p -> %p] %C",nextchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
rightkern=false
end
end
triggers=false
- return head,true
+ return head
end
function injections.handler(head,where)
if triggers then
@@ -12481,29 +16642,29 @@ function injections.handler(head,where)
report_injections("injection variant %a","everything")
end
return inject_everything(head,where)
- elseif nofregisteredpairs>0 then
+ elseif nofregisteredpositions>0 then
if trace_injections then
- report_injections("injection variant %a","pairs")
+ report_injections("injection variant %a","positions")
end
- return inject_pairs_only(head,where)
+ return inject_positions_only(head,where)
elseif nofregisteredkerns>0 then
if trace_injections then
report_injections("injection variant %a","kerns")
end
return inject_kerns_only(head,where)
else
- return head,false
+ return head
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otj”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otj”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ota” c281d18dfc89a8ca18af64f55e9fa92b] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ota” d883cf661bb8c27bfa9b7cc66420c1ed] ---
if not modules then modules={} end modules ['font-ota']={
version=1.001,
- comment="companion to font-otf.lua (analysing)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
@@ -12521,7 +16682,6 @@ analyzers.methods=methods
local a_state=attributes.private('state')
local nuts=nodes.nuts
local tonut=nuts.tonut
-local getfield=nuts.getfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getprev=nuts.getprev
@@ -12531,7 +16691,6 @@ local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
local ischar=nuts.is_char
-local traverse_id=nuts.traverse_id
local end_of_math=nuts.end_of_math
local nodecodes=nodes.nodecodes
local disc_code=nodecodes.disc
@@ -12547,7 +16706,7 @@ local s_fina=3 local s_pref=9
local s_isol=4 local s_blwf=10
local s_mark=5 local s_pstf=11
local s_rest=6
-local states={
+local states=allocate {
init=s_init,
medi=s_medi,
med2=s_medi,
@@ -12563,7 +16722,7 @@ local states={
blwf=s_blwf,
pstf=s_pstf,
}
-local features={
+local features=allocate {
init=s_init,
medi=s_medi,
med2=s_medi,
@@ -12695,7 +16854,7 @@ local function warning(current,what)
arab_warned[char]=true
end
end
-local mappers={
+local mappers=allocate {
l=s_init,
d=s_medi,
c=s_medi,
@@ -12879,10 +17038,10 @@ directives.register("otf.analyze.useunicodemarks",function(v)
analyzers.useunicodemarks=v
end)
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ota”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ota”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ots” 7e1e55f9f728474372665e4a64a43f5a] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ots” 624f23e63b7430a51212c8824d09924f] ---
if not modules then modules={} end modules ['font-ots']={
version=1.001,
@@ -12895,12 +17054,14 @@ local type,next,tonumber=type,next,tonumber
local random=math.random
local formatters=string.formatters
local insert=table.insert
-local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes
local registertracker=trackers.register
-local registerdirective=directives.register
+local logs=logs
+local trackers=trackers
+local nodes=nodes
+local attributes=attributes
local fonts=fonts
local otf=fonts.handlers.otf
-local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end)
+local tracers=nodes.tracers
local trace_singles=false registertracker("otf.singles",function(v) trace_singles=v end)
local trace_multiples=false registertracker("otf.multiples",function(v) trace_multiples=v end)
local trace_alternatives=false registertracker("otf.alternatives",function(v) trace_alternatives=v end)
@@ -12914,30 +17075,32 @@ local trace_bugs=false registertracker("otf.bugs",function(v) trace_bugs=v end)
local trace_details=false registertracker("otf.details",function(v) trace_details=v end)
local trace_steps=false registertracker("otf.steps",function(v) trace_steps=v end)
local trace_skips=false registertracker("otf.skips",function(v) trace_skips=v end)
-local trace_directions=false registertracker("otf.directions",function(v) trace_directions=v end)
local trace_plugins=false registertracker("otf.plugins",function(v) trace_plugins=v end)
+local trace_chains=false registertracker("otf.chains",function(v) trace_chains=v end)
local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kernruns=v end)
-local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end)
local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end)
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
-local optimizekerns=true
-local alwaysdisc=true registerdirective("otf.alwaysdisc",function(v) alwaysdisc=v end)
+local forcediscretionaries=false
+local forcepairadvance=false
+directives.register("otf.forcediscretionaries",function(v)
+ forcediscretionaries=v
+end)
+directives.register("otf.forcepairadvance",function(v)
+ forcepairadvance=v
+end)
local report_direct=logs.reporter("fonts","otf direct")
local report_subchain=logs.reporter("fonts","otf subchain")
local report_chain=logs.reporter("fonts","otf chain")
local report_process=logs.reporter("fonts","otf process")
local report_warning=logs.reporter("fonts","otf warning")
local report_run=logs.reporter("fonts","otf run")
-registertracker("otf.replacements","otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
-registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
-registertracker("otf.actions","otf.replacements,otf.positions")
-registertracker("otf.injections","nodes.injections")
-registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+registertracker("otf.substitutions","otf.singles","otf.multiples","otf.alternatives","otf.ligatures")
+registertracker("otf.positions","otf.marks","otf.kerns","otf.cursive")
+registertracker("otf.actions","otf.substitutions","otf.positions")
+registertracker("otf.sample","otf.steps","otf.substitutions","otf.positions","otf.analyzing")
+registertracker("otf.sample.silent","otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing")
local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
local getfield=nuts.getfield
-local setfield=nuts.setfield
local getnext=nuts.getnext
local setnext=nuts.setnext
local getprev=nuts.getprev
@@ -12957,22 +17120,28 @@ local setchar=nuts.setchar
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
local setlink=nuts.setlink
+local getcomponents=nuts.getcomponents
+local setcomponents=nuts.setcomponents
+local getdir=nuts.getdir
+local getwidth=nuts.getwidth
local ischar=nuts.is_char
+local usesfont=nuts.uses_font
local insert_node_after=nuts.insert_after
local copy_node=nuts.copy
local copy_node_list=nuts.copy_list
+local remove_node=nuts.remove
local find_node_tail=nuts.tail
local flush_node_list=nuts.flush_list
local flush_node=nuts.flush_node
local end_of_math=nuts.end_of_math
-local traverse_nodes=nuts.traverse
-local traverse_id=nuts.traverse_id
-local remove_node=nuts.remove
+local set_components=nuts.set_components
+local take_components=nuts.take_components
+local count_components=nuts.count_components
+local copy_no_components=nuts.copy_no_components
+local copy_only_glyphs=nuts.copy_only_glyphs
+local setmetatable=setmetatable
local setmetatableindex=table.setmetatableindex
-local zwnj=0x200C
-local zwj=0x200D
-local wildcard="*"
-local default="dflt"
+local nextnode=nuts.traversers.node
local nodecodes=nodes.nodecodes
local glyphcodes=nodes.glyphcodes
local disccodes=nodes.disccodes
@@ -12984,21 +17153,20 @@ local dir_code=nodecodes.dir
local localpar_code=nodecodes.localpar
local discretionary_code=disccodes.discretionary
local ligature_code=glyphcodes.ligature
-local privateattribute=attributes.private
-local a_state=privateattribute('state')
+local a_state=attributes.private('state')
+local a_noligature=attributes.private("noligature")
local injections=nodes.injections
local setmark=injections.setmark
local setcursive=injections.setcursive
local setkern=injections.setkern
-local setpair=injections.setpair
+local setmove=injections.setmove
+local setposition=injections.setposition
local resetinjection=injections.reset
local copyinjection=injections.copy
local setligaindex=injections.setligaindex
local getligaindex=injections.getligaindex
-local cursonce=true
-local fonthashes=fonts.hashes
-local fontdata=fonthashes.identifiers
-local fontfeatures=fonthashes.features
+local fontdata=fonts.hashes.identifiers
+local fontfeatures=fonts.hashes.features
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local onetimemessage=fonts.loggers.onetimemessage or function() end
@@ -13008,98 +17176,91 @@ local tfmdata=false
local characters=false
local descriptions=false
local marks=false
+local classes=false
local currentfont=false
local factor=0
local threshold=0
local checkmarks=false
+local discs=false
+local spaces=false
local sweepnode=nil
-local sweepprev=nil
-local sweepnext=nil
-local sweephead={}
-local notmatchpre={}
-local notmatchpost={}
-local notmatchreplace={}
+local sweephead={}
+local notmatchpre={}
+local notmatchpost={}
+local notmatchreplace={}
local handlers={}
local isspace=injections.isspace
local getthreshold=injections.getthreshold
-local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
-local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
-local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
-local function checkdisccontent(d)
- local pre,post,replace=getdisc(d)
- if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end
- if post then for n in traverse_id(glue_code,post) do print("pos",nodes.idstostring(post)) break end end
- if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
-end
+local checkstep=(tracers and tracers.steppers.check) or function() end
+local registerstep=(tracers and tracers.steppers.register) or function() end
+local registermessage=(tracers and tracers.steppers.message) or function() end
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_direct(...)
end
local function logwarning(...)
report_direct(...)
end
-local f_unicode=formatters["%U"]
-local f_uniname=formatters["%U (%s)"]
-local f_unilist=formatters["% t (% t)"]
-local function gref(n)
- if type(n)=="number" then
- local description=descriptions[n]
- local name=description and description.name
- if name then
- return f_uniname(n,name)
- else
- return f_unicode(n)
- end
- elseif n then
- local num,nam={},{}
- for i=1,#n do
- local ni=n[i]
- if tonumber(ni) then
- local di=descriptions[ni]
- num[i]=f_unicode(ni)
- nam[i]=di and di.name or "-"
+local gref do
+ local f_unicode=formatters["U+%X"]
+ local f_uniname=formatters["U+%X (%s)"]
+ local f_unilist=formatters["% t"]
+ gref=function(n)
+ if type(n)=="number" then
+ local description=descriptions[n]
+ local name=description and description.name
+ if name then
+ return f_uniname(n,name)
+ else
+ return f_unicode(n)
+ end
+ elseif n then
+ local t={}
+ for i=1,#n do
+ local ni=n[i]
+ if tonumber(ni) then
+ local di=descriptions[ni]
+ local nn=di and di.name
+ if nn then
+ t[#t+1]=f_uniname(ni,nn)
+ else
+ t[#t+1]=f_unicode(ni)
+ end
+ end
end
+ return f_unilist(t)
+ else
+ return "<error in node mode tracing>"
end
- return f_unilist(num,nam)
- else
- return "<error in node mode tracing>"
end
end
local function cref(dataset,sequence,index)
if not dataset then
return "no valid dataset"
- elseif index then
- return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index)
+ end
+ local merged=sequence.merged and "merged " or ""
+ if index then
+ return formatters["feature %a, type %a, %schain lookup %a, index %a"](
+ dataset[4],sequence.type,merged,sequence.name,index)
else
- return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %schain lookup %a"](
+ dataset[4],sequence.type,merged,sequence.name)
end
end
local function pref(dataset,sequence)
- return formatters["feature %a, type %a, lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %slookup %a"](
+ dataset[4],sequence.type,sequence.merged and "merged " or "",sequence.name)
end
local function mref(rlmode)
- if not rlmode or rlmode==0 then
- return "---"
- elseif rlmode==-1 or rlmode=="+TRT" then
- return "r2l"
- else
+ if not rlmode or rlmode>=0 then
return "l2r"
- end
-end
-local function copy_glyph(g)
- local components=getfield(g,"components")
- if components then
- setfield(g,"components")
- local n=copy_node(g)
- copyinjection(n,g)
- setfield(g,"components",components)
- return n
else
- local n=copy_node(g)
- copyinjection(n,g)
- return n
+ return "r2l"
end
end
local function flattendisk(head,disc)
@@ -13123,7 +17284,6 @@ local function flattendisk(head,disc)
elseif next then
return next,next
else
- return
end
else
if replace then
@@ -13145,15 +17305,34 @@ local function appenddisc(disc,list)
if post then
setlink(posttail,posthead)
else
- post=phead
+ post=posthead
end
if replace then
setlink(replacetail,replacehead)
else
- replace=rhead
+ replace=replacehead
end
setdisc(disc,pre,post,replace)
end
+local take_components=getcomponents
+local set_components=setcomponents
+local function count_components(start,marks)
+ if getid(start)~=glyph_code then
+ return 0
+ elseif getsubtype(start)==ligature_code then
+ local i=0
+ local components=getcomponents(start)
+ while components do
+ i=i+count_components(components,marks)
+ components=getnext(components)
+ end
+ return i
+ elseif not marks[getchar(start)] then
+ return 1
+ else
+ return 0
+ end
+end
local function markstoligature(head,start,stop,char)
if start==stop and getchar(start)==char then
return head,start
@@ -13162,38 +17341,19 @@ local function markstoligature(head,start,stop,char)
local next=getnext(stop)
setprev(start)
setnext(stop)
- local base=copy_glyph(start)
+ local base=copy_no_components(start,copyinjection)
if head==start then
head=base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",start)
- setlink(prev,base)
- setlink(base,next)
+ set_components(base,start)
+ setlink(prev,base,next)
return head,base
end
end
-local function getcomponentindex(start)
- if getid(start)~=glyph_code then
- return 0
- elseif getsubtype(start)==ligature_code then
- local i=0
- local components=getfield(start,"components")
- while components do
- i=i+getcomponentindex(components)
- components=getnext(components)
- end
- return i
- elseif not marks[getchar(start)] then
- return 1
- else
- return 0
- end
-end
-local a_noligature=attributes.private("noligature")
-local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound)
+local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks)
if getattr(start,a_noligature)==1 then
return head,start
end
@@ -13202,31 +17362,22 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setchar(start,char)
return head,start
end
- local components=getfield(start,"components")
- if components then
- end
local prev=getprev(start)
local next=getnext(stop)
local comp=start
setprev(start)
setnext(stop)
- local base=copy_glyph(start)
+ local base=copy_no_components(start,copyinjection)
if start==head then
head=base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",comp)
- if prev then
- setnext(prev,base)
- end
- if next then
- setprev(next,base)
- end
- setboth(base,prev,next)
+ set_components(base,comp)
+ setlink(prev,base,next)
if not discfound then
- local deletemarks=markflag~="mark"
+ local deletemarks=not skiphash or hasmarks
local components=start
local baseindex=0
local componentindex=0
@@ -13236,14 +17387,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local char=getchar(start)
if not marks[char] then
baseindex=baseindex+componentindex
- componentindex=getcomponentindex(start)
- elseif not deletemarks then
+ componentindex=count_components(start,marks)
+ elseif not deletemarks then
setligaindex(start,baseindex+getligaindex(start,componentindex))
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
end
local n=copy_node(start)
- copyinjection(n,start)
+ copyinjection(n,start)
head,current=insert_node_after(head,current,n)
elseif trace_marks then
logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -13271,27 +17422,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local discprev,discnext=getboth(discfound)
if discprev and discnext then
local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true)
- if not replace then
+ if not replace then
local prev=getprev(base)
- local current=comp
- local previous=nil
- local copied=nil
- while current do
- if getid(current)==glyph_code then
- local n=copy_node(current)
- if copied then
- setlink(previous,n)
- else
- copied=n
- end
- previous=n
- end
- current=getnext(current)
- end
- setprev(discnext)
- setnext(discprev)
+ local comp=take_components(base)
+ local copied=copy_only_glyphs(comp)
if pre then
setlink(discprev,pre)
+ else
+ setnext(discprev)
end
pre=comp
if post then
@@ -13299,19 +17437,24 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setprev(post)
else
post=discnext
+ setprev(discnext)
end
- setlink(prev,discfound)
- setlink(discfound,next)
+ setlink(prev,discfound,next)
setboth(base)
- setfield(base,"components",copied)
- setdisc(discfound,pre,post,base)
- base=prev
+ set_components(base,copied)
+ replace=base
+ if forcediscretionaries then
+ setdisc(discfound,pre,post,replace,discretionary_code)
+ else
+ setdisc(discfound,pre,post,replace)
+ end
+ base=prev
end
end
end
return head,base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks,what)
+local function multiple_glyphs(head,start,multiple,skiphash,what,stop)
local nofmultiples=#multiple
if nofmultiples>0 then
resetinjection(start)
@@ -13347,7 +17490,9 @@ local function multiple_glyphs(head,start,multiple,ignoremarks,what)
end
local function get_alternative_glyph(start,alternatives,value)
local n=#alternatives
- if value=="random" then
+ if n==1 then
+ return alternatives[1],trace_alternatives and "1 (only one present)"
+ elseif value=="random" then
local r=getrandom and getrandom("glyph",1,n) or random(1,n)
return alternatives[r],trace_alternatives and formatters["value %a, taking %a"](value,r)
elseif value=="first" then
@@ -13402,20 +17547,20 @@ function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
end
return head,start,true
end
-function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
+function handlers.gsub_multiple(head,start,dataset,sequence,multiple,rlmode,skiphash)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
+ return multiple_glyphs(head,start,multiple,skiphash,dataset[1])
end
-function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
+function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skiphash)
local current=getnext(start)
if not current then
return head,start,false,nil
end
local stop=nil
local startchar=getchar(start)
- if marks[startchar] then
+ if skiphash and skiphash[startchar] then
while current do
local char=ischar(current,currentfont)
if char then
@@ -13445,14 +17590,14 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
else
end
end
- else
- local skipmark=sequence.flags[1]
+ else
local discfound=false
local lastdisc=nil
+ local hasmarks=marks[startchar]
while current do
local char,id=ischar(current,currentfont)
if char then
- if skipmark and marks[char] then
+ if skiphash and skiphash[char] then
current=getnext(current)
else
local lg=ligature[char]
@@ -13461,6 +17606,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
discfound=lastdisc
lastdisc=nil
end
+ if marks[char] then
+ hasmarks=true
+ end
stop=current
ligature=lg
current=getnext(current)
@@ -13471,13 +17619,16 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
elseif char==false then
break
elseif id==disc_code then
- local replace=getfield(current,"replace")
+ local replace=getfield(current,"replace")
if replace then
while replace do
local char,id=ischar(replace,currentfont)
if char then
local lg=ligature[char]
if lg then
+ if marks[char] then
+ hasmarks=true
+ end
ligature=lg
replace=getnext(replace)
else
@@ -13500,10 +17651,10 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
if stop then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
else
- head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
end
else
resetinjection(start)
@@ -13518,83 +17669,81 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
end
return head,start,false,discfound
end
-function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local startchar=getchar(start)
- if step.format=="pair" then
- local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns,injection)
+ local format=step.format
+ if format=="single" or type(kerns)=="table" then
+ local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
end
else
- local k=setkern(start,factor,rlmode,kerns,injection)
+ local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k)
end
end
- return head,start,false
+ return head,start,true
end
-function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local snext=getnext(start)
if not snext then
return head,start,false
else
local prev=start
- local done=false
while snext do
local nextchar=ischar(snext,currentfont)
if nextchar then
- local krn=kerns[nextchar]
- if not krn and marks[nextchar] then
+ if skiphash and skiphash[nextchar] then
prev=snext
snext=getnext(snext)
- elseif not krn then
- break
- elseif step.format=="pair" then
- local a,b=krn[1],krn[2]
- if optimizekerns then
- if not b and a[1]==0 and a[2]==0 and a[4]==0 then
- local k=setkern(snext,factor,rlmode,a[3],injection)
+ else
+ local krn=kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format=step.format
+ if format=="pair" then
+ local a,b=krn[1],krn[2]
+ if a==true then
+ elseif a then
+ local x,y,w,h=setposition(1,start,factor,rlmode,a,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
+ local startchar=getchar(start)
+ 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")
end
- done=true
- break
end
- end
- if a and #a>0 then
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,injection)
- if trace_kerns then
- local startchar=getchar(start)
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ if b==true then
+ start=snext
+ elseif b then
+ local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection)
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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")
+ end
+ start=snext
+ elseif forcepairadvance then
+ start=snext
end
- end
- if b and #b>0 then
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
+ return head,start,true
+ elseif krn~=0 then
+ local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection)
if trace_kerns then
- local startchar=getchar(snext)
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections")
end
+ return head,start,true
+ else
+ break
end
- done=true
- break
- elseif krn~=0 then
- local k=setkern(snext,factor,rlmode,krn,injection)
- if trace_kerns then
- logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections")
- end
- done=true
- break
- else
- break
end
else
break
end
end
- return head,start,done
+ return head,start,false
end
end
-function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -13629,10 +17778,12 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
local ma=markanchors[2]
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head,start,true
+ elseif trace_bugs then
+ logwarning("%s: mark %s is not anchored to %s",pref(dataset,sequence),gref(markchar),gref(basechar))
end
elseif trace_bugs then
logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1)
@@ -13645,7 +17796,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
end
return head,start,false
end
-function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -13684,8 +17835,8 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
if ba then
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ logprocess("%s, index %s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ pref(dataset,sequence),index,bound,gref(markchar),gref(basechar),index,dx,dy)
end
return head,start,true
else
@@ -13708,7 +17859,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
end
return head,start,false
end
-function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -13731,8 +17882,8 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
local ma=markanchors[2]
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head,start,true
end
@@ -13743,8 +17894,7 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
end
return head,start,false
end
-function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i)
- local done=false
+function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step)
local startchar=getchar(start)
if marks[startchar] then
if trace_cursive then
@@ -13752,11 +17902,11 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
else
local nxt=getnext(start)
- while not done and nxt do
+ while nxt do
local nextchar=ischar(nxt,currentfont)
if not nextchar then
break
- elseif marks[nextchar] then
+ elseif marks[nextchar] then
nxt=getnext(nxt)
else
local exit=exitanchors[3]
@@ -13765,11 +17915,12 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
if entry then
entry=entry[2]
if entry then
- local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local r2lflag=sequence.flags[4]
+ local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ 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))
end
- done=true
+ return head,start,true
end
end
end
@@ -13777,12 +17928,15 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
end
end
- return head,start,done
+ return head,start,false
end
local chainprocs={}
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_subchain(...)
end
@@ -13790,11 +17944,14 @@ local logwarning=report_subchain
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_chain(...)
end
local logwarning=report_chain
-local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
+local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode,skiphash)
local char=getchar(start)
local replacement=replacements[char]
if replacement then
@@ -13809,509 +17966,551 @@ local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
end
end
chainprocs.reversesub=reversesub
+local function reportzerosteps(dataset,sequence)
+ logwarning("%s: no steps",cref(dataset,sequence))
+end
local function reportmoresteps(dataset,sequence)
logwarning("%s: more than 1 step",cref(dataset,sequence))
end
-function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,chainindex)
+local function getmapping(dataset,sequence,currentlookup)
local steps=currentlookup.steps
local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+ if nofsteps==0 then
+ reportzerosteps(dataset,sequence)
+ currentlookup.mapping=false
+ return false
+ else
+ if nofsteps>1 then
+ reportmoresteps(dataset,sequence)
+ end
+ local mapping=steps[1].coverage
+ currentlookup.mapping=mapping
+ currentlookup.format=steps[1].format
+ return mapping
end
- local current=start
- while current do
- local currentchar=ischar(current)
- if currentchar then
- local replacement=steps[1].coverage[currentchar]
- if not replacement or replacement=="" then
- if trace_bugs then
- logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
+end
+function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ if trace_chains then
+ logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start)))
+ end
+ head,start=remove_node(head,start,true)
+ return head,getprev(start),true
+end
+function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local current=start
+ while current do
+ local currentchar=ischar(current)
+ if currentchar then
+ local replacement=mapping[currentchar]
+ if not replacement or replacement=="" then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
+ end
+ resetinjection(current)
+ setchar(current,replacement)
end
+ return head,start,true
+ elseif currentchar==false then
+ break
+ elseif current==stop then
+ break
else
- if trace_singles then
- logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
- end
- resetinjection(current)
- setchar(current,replacement)
+ current=getnext(current)
end
- return head,start,true
- elseif currentchar==false then
- break
- elseif current==stop then
- break
- else
- current=getnext(current)
end
end
return head,start,false
end
-function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local replacement=steps[1].coverage[startchar]
- if not replacement or replacement=="" then
- if trace_bugs then
- logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
- end
- else
- if trace_multiples then
- logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ if mapping then
+ local kind=dataset[4]
+ local what=dataset[1]
+ local value=what==true and tfmdata.shared.features[kind] or what
+ local current=start
+ while current do
+ local currentchar=ischar(current)
+ if currentchar then
+ local alternatives=mapping[currentchar]
+ if alternatives then
+ local choice,comment=get_alternative_glyph(current,alternatives,value)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(currentchar),choice,gref(choice),comment)
+ end
+ resetinjection(start)
+ setchar(start,choice)
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(currentchar),comment)
+ end
+ end
+ end
+ return head,start,true
+ elseif currentchar==false then
+ break
+ elseif current==stop then
+ break
+ else
+ current=getnext(current)
+ end
end
- return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
end
return head,start,false
end
-function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local kind=dataset[4]
- local what=dataset[1]
- local value=what==true and tfmdata.shared.features[kind] or what
- local current=start
- while current do
- local currentchar=ischar(current)
- if currentchar then
- local alternatives=steps[1].coverage[currentchar]
- if alternatives then
- local choice,comment=get_alternative_glyph(current,alternatives,value)
- if choice then
- if trace_alternatives then
- logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment)
- end
- resetinjection(start)
- setchar(start,choice)
- else
- if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment)
- end
- end
+ if mapping then
+ local startchar=getchar(start)
+ local replacement=mapping[startchar]
+ if not replacement or replacement=="" then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
end
- return head,start,true
- elseif currentchar==false then
- break
- elseif current==stop then
- break
else
- current=getnext(current)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ end
+ return multiple_glyphs(head,start,replacement,skiphash,dataset[1],stop)
end
end
return head,start,false
end
-function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local ligatures=steps[1].coverage[startchar]
- if not ligatures then
- if trace_bugs then
- logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
- end
- else
- local current=getnext(start)
- local discfound=false
- local last=stop
- local nofreplacements=1
- local skipmark=currentlookup.flags[1]
- while current do
- local id=getid(current)
- if id==disc_code then
- if not discfound then
- discfound=current
- end
- if current==stop then
- break
- else
- current=getnext(current)
- end
- else
- local schar=getchar(current)
- if skipmark and marks[schar] then
+ if mapping then
+ local startchar=getchar(start)
+ local ligatures=mapping[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
+ end
+ else
+ local hasmarks=marks[startchar]
+ local current=getnext(start)
+ local discfound=false
+ local last=stop
+ local nofreplacements=1
+ while current do
+ local id=getid(current)
+ if id==disc_code then
+ if not discfound then
+ discfound=current
+ end
+ if current==stop then
+ break
+ else
current=getnext(current)
+ end
else
- local lg=ligatures[schar]
- if lg then
- ligatures=lg
- last=current
- nofreplacements=nofreplacements+1
- if current==stop then
- break
- else
+ local schar=getchar(current)
+ if skiphash and skiphash[schar] then
current=getnext(current)
- end
else
- break
+ local lg=ligatures[schar]
+ if lg then
+ ligatures=lg
+ last=current
+ nofreplacements=nofreplacements+1
+ if marks[char] then
+ hasmarks=true
+ end
+ if current==stop then
+ break
+ else
+ current=getnext(current)
+ end
+ else
+ break
+ end
end
end
end
- end
- local ligature=ligatures.ligature
- if ligature then
- if chainindex then
- stop=last
- end
- if trace_ligatures then
+ local ligature=ligatures.ligature
+ if ligature then
+ if chainindex then
+ stop=last
+ end
+ if trace_ligatures then
+ if start==stop then
+ logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ end
+ end
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
+ return head,start,true,nofreplacements,discfound
+ elseif trace_bugs then
if start==stop then
- logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
else
- logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
end
end
- head,start=toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound)
- return head,start,true,nofreplacements,discfound
- elseif trace_bugs then
- if start==stop then
- logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
- else
- logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
- end
end
end
return head,start,false,0,false
end
-function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local step=steps[1]
- local kerns=step.coverage[startchar]
- if not kerns then
- elseif step.format=="pair" then
- local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns)
- if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h)
- end
- else
- local k=setkern(start,factor,rlmode,kerns,injection)
- if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ if mapping then
+ local startchar=getchar(start)
+ local kerns=mapping[startchar]
+ if kerns then
+ local format=currentlookup.format
+ if format=="single" then
+ local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
+ end
+ else
+ local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k)
+ end
+ end
+ return head,start,true
end
end
return head,start,false
end
-function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local snext=getnext(start)
- if snext then
- local startchar=getchar(start)
- local step=steps[1]
- local kerns=step.coverage[startchar]
- if kerns then
- local prev=start
- local done=false
- while snext do
- local nextchar=ischar(snext,currentfont)
- if not nextchar then
- break
- end
- local krn=kerns[nextchar]
- if not krn and marks[nextchar] then
- prev=snext
- snext=getnext(snext)
- elseif not krn then
- break
- elseif step.format=="pair" then
- local a,b=krn[1],krn[2]
- if optimizekerns then
- if not b and a[1]==0 and a[2]==0 and a[4]==0 then
- local k=setkern(snext,factor,rlmode,a[3],"injections")
+ if mapping then
+ local snext=getnext(start)
+ if snext then
+ local startchar=getchar(start)
+ local kerns=mapping[startchar]
+ if kerns then
+ local prev=start
+ while snext do
+ local nextchar=ischar(snext,currentfont)
+ if not nextchar then
+ break
+ end
+ if skiphash and skiphash[nextchar] then
+ prev=snext
+ snext=getnext(snext)
+ else
+ local krn=kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format=currentlookup.format
+ if format=="pair" then
+ local a,b=krn[1],krn[2]
+ if a==true then
+ elseif a then
+ local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections")
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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)
+ end
+ end
+ if b==true then
+ start=snext
+ elseif b then
+ local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections")
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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)
+ end
+ start=snext
+ elseif forcepairadvance then
+ start=snext
+ end
+ return head,start,true
+ elseif krn~=0 then
+ local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar))
end
- done=true
+ return head,start,true
+ else
break
end
end
- if a and #a>0 then
- local startchar=getchar(start)
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,"injections")
- if trace_kerns then
- 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)
- end
- end
- if b and #b>0 then
- local startchar=getchar(start)
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
- if trace_kerns then
- 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)
- end
- end
- done=true
- break
- elseif krn~=0 then
- local k=setkern(snext,factor,rlmode,krn)
- if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar))
- end
- done=true
- break
- else
- break
end
end
- return head,start,done
end
end
return head,start,false
end
-function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base=getprev(base)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base=getprev(base)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ end
+ return head,start,false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
end
return head,start,false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
- end
- return head,start,false
end
end
- end
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base=getprev(base)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base=getprev(base)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ end
+ return head,start,false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
end
return head,start,false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
- end
- return head,start,false
end
end
- end
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local index=getligaindex(start)
- ba=ba[index]
- if ba then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local index=getligaindex(start)
+ ba=ba[index]
+ if ba then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ cref(dataset,sequence),a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
end
+ elseif trace_bugs then
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- local slc=getligaindex(start)
- if slc then
- while base do
- local blc=getligaindex(base)
- if blc and blc~=slc then
- base=getprev(base)
- else
- break
+function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ local slc=getligaindex(start)
+ if slc then
+ while base do
+ local blc=getligaindex(base)
+ if blc and blc~=slc then
+ base=getprev(base)
+ else
+ break
+ end
end
end
- end
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local exitanchors=steps[1].coverage[startchar]
- if exitanchors then
- local done=false
- if marks[startchar] then
- if trace_cursive then
- logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
- end
- else
- local nxt=getnext(start)
- while not done and nxt do
- local nextchar=ischar(nxt,currentfont)
- if not nextchar then
- break
- elseif marks[nextchar] then
- nxt=getnext(nxt)
- else
- local exit=exitanchors[3]
- if exit then
- local entry=exitanchors[1][nextchar]
- if entry then
- entry=entry[2]
+ if mapping then
+ local startchar=getchar(start)
+ local exitanchors=mapping[startchar]
+ if exitanchors then
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
+ end
+ else
+ local nxt=getnext(start)
+ while nxt do
+ local nextchar=ischar(nxt,currentfont)
+ if not nextchar then
+ break
+ elseif marks[nextchar] then
+ nxt=getnext(nxt)
+ else
+ local exit=exitanchors[3]
+ if exit then
+ local entry=exitanchors[1][nextchar]
if entry then
- local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
- if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ entry=entry[2]
+ if entry then
+ local r2lflag=sequence.flags[4]
+ local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
+ if trace_cursive then
+ 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))
+ end
+ return head,start,true
end
- done=true
- break
end
+ elseif trace_bugs then
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
- elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ break
end
- break
end
end
- end
- return head,start,done
- else
- if trace_cursive and trace_details then
+ elseif trace_cursive and trace_details then
logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone)
end
- return head,start,false
end
+ return head,start,false
end
local function show_skip(dataset,sequence,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2])
end
-local new_kern=nuts.pool.kern
+local userkern=nuts.pool and nuts.pool.newkern
+do if not userkern then
+ local thekern=nuts.new("kern",1)
+ local setkern=nuts.setkern
+ userkern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
local function checked(head)
local current=head
while current do
if getid(current)==glue_code then
- local kern=new_kern(getfield(current,"width"))
+ local kern=userkern(getwidth(current))
if head==current then
local next=getnext(current)
if next then
@@ -14322,8 +18521,7 @@ local function checked(head)
current=next
else
local prev,next=getboth(current)
- setlink(prev,kern)
- setlink(kern,next)
+ setlink(prev,kern,next)
flush_node(current)
current=next
end
@@ -14339,7 +18537,95 @@ local function setdiscchecked(d,pre,post,replace)
if replace then replace=checked(replace) end
setdisc(d,pre,post,replace)
end
-local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
+local noflags={ false,false,false,false }
+local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+ local size=ck[5]-ck[4]+1
+ local chainlookups=ck[6]
+ local done=false
+ if chainlookups then
+ if size==1 then
+ local chainlookup=chainlookups[1]
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local chainkind=chainstep.type
+ local chainproc=chainprocs[chainkind]
+ if chainproc then
+ local ok
+ head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ if ok then
+ done=true
+ end
+ else
+ logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
+ end
+ end
+ else
+ local i=1
+ local laststart=start
+ local nofchainlookups=#chainlookups
+ while start do
+ if skiphash then
+ while start do
+ local char=ischar(start,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ start=getnext(start)
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ end
+ local chainlookup=chainlookups[i]
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local chainkind=chainstep.type
+ local chainproc=chainprocs[chainkind]
+ if chainproc then
+ local ok,n
+ head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i)
+ if ok then
+ done=true
+ if n and n>1 and i+n>nofchainlookups then
+ i=size
+ break
+ end
+ end
+ else
+ logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
+ end
+ end
+ else
+ end
+ i=i+1
+ if i>size or not start then
+ break
+ elseif start then
+ laststart=start
+ start=getnext(start)
+ end
+ end
+ if not start then
+ start=laststart
+ end
+ end
+ else
+ local replacements=ck[7]
+ if replacements then
+ head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode,skiphash)
+ else
+ done=true
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(dataset,sequence))
+ end
+ end
+ end
+ return head,start,done
+end
+local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
if not start then
return head,start,false
end
@@ -14352,7 +18638,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local sweepnode=sweepnode
local sweeptype=sweeptype
local sweepoverflow=false
- local checkdisc=getprev(head)
local keepdisc=not sweepnode
local lookaheaddisc=nil
local backtrackdisc=nil
@@ -14375,18 +18660,22 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
elseif id==disc_code then
if keepdisc then
keepdisc=false
- if notmatchpre[current]~=notmatchreplace[current] then
- lookaheaddisc=current
- end
+ lookaheaddisc=current
local replace=getfield(current,"replace")
- while replace and i<=l do
- if getid(replace)==glyph_code then
- i=i+1
+ if not replace then
+ sweepoverflow=true
+ sweepnode=current
+ current=getnext(current)
+ else
+ while replace and i<=l do
+ if getid(replace)==glyph_code then
+ i=i+1
+ end
+ replace=getnext(replace)
end
- replace=getnext(replace)
+ current=getnext(replace)
end
last=current
- current=getnext(c)
else
head,current=flattendisk(head,current)
end
@@ -14444,7 +18733,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if notmatchpre[current]~=notmatchreplace[current] then
lookaheaddisc=current
end
- local replace=getfield(c,"replace")
+ local replace=getfield(current,"replace")
while replace and i<s do
if getid(replace)==glyph_code then
i=i+1
@@ -14505,7 +18794,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
end
end
end
- local ok=false
+ local done=false
if lookaheaddisc then
local cf=start
local cl=getprev(lookaheaddisc)
@@ -14522,37 +18811,44 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
- setprev(lookaheaddisc,cprev)
- if cprev then
- setnext(cprev,lookaheaddisc)
- end
+ setlink(cprev,lookaheaddisc)
setprev(cf)
setnext(cl)
if startishead then
head=lookaheaddisc
end
local pre,post,replace=getdisc(lookaheaddisc)
- local new=copy_node_list(cf)
+ local new=copy_node_list(cf)
local cnew=new
+ if pre then
+ setlink(find_node_tail(cf),pre)
+ end
+ if replace then
+ local tail=find_node_tail(new)
+ setlink(tail,replace)
+ end
for i=1,insertedmarks do
cnew=getnext(cnew)
end
+ cl=start
local clast=cnew
for i=f,l do
+ cl=getnext(cl)
clast=getnext(clast)
end
if not notmatchpre[lookaheaddisc] then
- cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if not notmatchreplace[lookaheaddisc] then
- new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
- end
- if pre then
- setlink(cl,pre)
- end
- if replace then
- local tail=find_node_tail(new)
- setlink(tail,replace)
+ local ok=false
+ new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if hasglue then
setdiscchecked(lookaheaddisc,cf,post,new)
@@ -14560,8 +18856,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(lookaheaddisc,cf,post,new)
end
start=getprev(lookaheaddisc)
- sweephead[cf]=getnext(clast)
- sweephead[new]=getnext(last)
+ sweephead[cf]=getnext(clast) or false
+ sweephead[new]=getnext(cl) or false
elseif backtrackdisc then
local cf=getnext(backtrackdisc)
local cl=start
@@ -14577,10 +18873,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
- if cnext then
- setprev(cnext,backtrackdisc)
- end
- setnext(backtrackdisc,cnext)
+ setlink(backtrackdisc,cnext)
setprev(cf)
setnext(cl)
local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true)
@@ -14594,10 +18887,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
clast=getnext(clast)
end
if not notmatchpost[backtrackdisc] then
- cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if not notmatchreplace[backtrackdisc] then
- new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if post then
setlink(posttail,cf)
@@ -14615,492 +18916,413 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(backtrackdisc,pre,post,replace)
end
start=getprev(backtrackdisc)
- sweephead[post]=getnext(clast)
- sweephead[replace]=getnext(last)
+ sweephead[post]=getnext(clast) or false
+ sweephead[replace]=getnext(last) or false
else
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
- return head,start,ok
+ return head,start,done
end
-local noflags={ false,false,false,false }
-local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
+local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode)
+ local rule=ck[1]
+ local lookuptype=ck[8] or ck[2]
+ local nofseq=#ck[3]
+ local first=ck[4]
+ local last=ck[5]
+ local char=getchar(start)
+ logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping",
+ cref(dataset,sequence),rule,match and "matches" or "nomatch",
+ gref(char),first-1,last-first+1,nofseq-last,lookuptype,
+ discseen and "" or "no ",sweepnode and "" or "not ")
+end
+local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
local sweepnode=sweepnode
local sweeptype=sweeptype
+ local postreplace
+ local prereplace
+ local checkdisc
+ local discseen
+ if sweeptype then
+ if sweeptype=="replace" then
+ postreplace=true
+ prereplace=true
+ else
+ postreplace=sweeptype=="post"
+ prereplace=sweeptype=="pre"
+ end
+ checkdisc=getprev(head)
+ end
local currentfont=currentfont
- local diskseen=false
- local checkdisc=getprev(head)
- local flags=sequence.flags or noflags
- local done=false
- local skipmark=flags[1]
- local skipligature=flags[2]
- local skipbase=flags[3]
- local markclass=sequence.markclass
- local skipped=false
- for k=1,#contexts do
- local match=true
- local current=start
- local last=start
+ local skipped
+ local startprev,
+ startnext=getboth(start)
+ local done
+ local nofcontexts=contexts.n
+ local startchar=nofcontext==1 or ischar(start,currentfont)
+ for k=1,nofcontexts do
local ck=contexts[k]
local seq=ck[3]
- local s=#seq
- local size=1
- if s==1 then
- local char=ischar(current,currentfont)
- if char then
- match=seq[1][char]
- end
- else
- local f=ck[4]
- local l=ck[5]
- size=l-f+1
- if size>1 then
- local discfound=nil
- local n=f+1
- last=getnext(last)
- while n<=l do
- if not last and (sweeptype=="post" or sweeptype=="replace") then
- last=getnext(sweepnode)
- sweeptype=nil
- end
- if last then
- local char,id=ischar(last,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class or "base"
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- last=getnext(last)
- elseif seq[n][char] then
- if n<l then
- last=getnext(last)
- end
- n=n+1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
- break
- end
+ local f=ck[4]
+ if not startchar or not seq[f][startchar] then
+ goto next
+ end
+ local s=seq.n
+ local l=ck[5]
+ local current=start
+ local last=start
+ if l>f then
+ local discfound
+ local n=f+1
+ last=startnext
+ while n<=l do
+ if postreplace and not last then
+ last=getnext(sweepnode)
+ sweeptype=nil
+ end
+ if last then
+ local char,id=ischar(last,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ last=getnext(last)
+ elseif seq[n][char] then
+ if n<l then
+ last=getnext(last)
+ end
+ n=n+1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- match=false
+ break
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=last
- notmatchpre[last]=nil
- notmatchpost[last]=true
- notmatchreplace[last]=nil
- local pre,post,replace=getdisc(last)
- if pre then
- local n=n
- while pre do
- if seq[n][getchar(pre)] then
- n=n+1
- pre=getnext(pre)
- if n>l then
- break
- end
- else
- notmatchpre[last]=true
+ else
+ goto next
+ end
+ elseif id==disc_code then
+ discseen=true
+ discfound=last
+ notmatchpre[last]=nil
+ notmatchpost[last]=true
+ notmatchreplace[last]=nil
+ local pre,post,replace=getdisc(last)
+ if pre then
+ local n=n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n=n+1
+ if n>l then
break
end
- end
- if n<=l then
+ pre=getnext(pre)
+ else
notmatchpre[last]=true
+ break
end
- else
- notmatchpre[last]=true
end
- if replace then
- while replace do
- if seq[n][getchar(replace)] then
- n=n+1
- replace=getnext(replace)
- if n>l then
- break
- end
+ else
+ notmatchpre[last]=true
+ end
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ if n>l then
+ break
+ end
+ replace=getnext(replace)
+ else
+ notmatchreplace[last]=true
+ if notmatchpre[last] then
+ goto next
else
- notmatchreplace[last]=true
- match=not notmatchpre[last]
break
end
end
- match=not notmatchpre[last]
end
- last=getnext(last)
- else
- match=false
- break
+ if notmatchpre[last] then
+ goto next
+ end
end
+ last=getnext(last)
else
- match=false
- break
+ goto next
end
+ else
+ goto next
end
end
- if match and f>1 then
- local prev=getprev(start)
+ end
+ if f>1 then
+ if startprev then
+ local prev=startprev
+ if prereplace and prev==checkdisc then
+ prev=getprev(sweepnode)
+ end
if prev then
- if prev==checkdisc and (sweeptype=="pre" or sweeptype=="replace") then
- prev=getprev(sweepnode)
- end
- if prev then
- local discfound=nil
- local n=f-1
- while n>=1 do
- if prev then
- local char,id=ischar(prev,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- prev=getprev(prev)
- elseif seq[n][char] then
- if n>1 then
- prev=getprev(prev)
- end
- n=n-1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
- end
- break
- end
+ local discfound
+ local n=f-1
+ while n>=1 do
+ if prev then
+ local char,id=ischar(prev,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ prev=getprev(prev)
+ elseif seq[n][char] then
+ if n>1 then
+ prev=getprev(prev)
+ end
+ n=n-1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpost[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpost[discfound] then
+ goto next
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=prev
- notmatchpre[prev]=true
- notmatchpost[prev]=nil
- notmatchreplace[prev]=nil
- local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
- if pre~=start and post~=start and replace~=start then
- if post then
- local n=n
- while posttail do
- if seq[n][getchar(posttail)] then
- n=n-1
- if posttail==post then
- break
- else
- posttail=getprev(posttail)
- if n<1 then
- break
- end
- end
- else
- notmatchpost[prev]=true
+ else
+ goto next
+ end
+ break
+ elseif id==disc_code then
+ discseen=true
+ discfound=prev
+ notmatchpre[prev]=true
+ notmatchpost[prev]=nil
+ notmatchreplace[prev]=nil
+ local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
+ if pre~=start and post~=start and replace~=start then
+ if post then
+ local n=n
+ while posttail do
+ if seq[n][getchar(posttail)] then
+ n=n-1
+ if posttail==post or n<1 then
break
+ else
+ posttail=getprev(posttail)
end
- end
- if n>=1 then
+ else
notmatchpost[prev]=true
+ break
end
- else
+ end
+ if n>=1 then
notmatchpost[prev]=true
end
- if replace then
- while replacetail do
- if seq[n][getchar(replacetail)] then
- n=n-1
- if replacetail==replace then
- break
- else
- replacetail=getprev(replacetail)
- if n<1 then
- break
- end
- end
+ else
+ notmatchpost[prev]=true
+ end
+ if replace then
+ while replacetail do
+ if seq[n][getchar(replacetail)] then
+ n=n-1
+ if replacetail==replace or n<1 then
+ break
+ else
+ replacetail=getprev(replacetail)
+ end
+ else
+ notmatchreplace[prev]=true
+ if notmatchpost[prev] then
+ goto next
else
- notmatchreplace[prev]=true
- match=not notmatchpost[prev]
break
end
end
- if not match then
- break
- end
end
+ else
+ notmatchreplace[prev]=true
end
- prev=getprev(prev)
- elseif seq[n][32] and isspace(prev,threshold) then
+ end
+ prev=getprev(prev)
+ elseif id==glue_code then
+ local sn=seq[n]
+ if (sn[32] and spaces[prev]) or sn[0xFFFC] then
n=n-1
prev=getprev(prev)
else
- match=false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n=n-1
+ prev=getprev(prev)
else
- match=false
- break
+ goto next
end
+ else
+ goto next
end
- else
- match=false
end
else
- match=false
+ goto next
end
+ else
+ goto next
end
- if match and s>l then
- local current=last and getnext(last)
- if not current then
- if sweeptype=="post" or sweeptype=="replace" then
- current=getnext(sweepnode)
- end
- end
- if current then
- local discfound=nil
- local n=l+1
- while n<=s do
- if current then
- local char,id=ischar(current,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- current=getnext(current)
- elseif seq[n][char] then
- if n<s then
- current=getnext(current)
- end
- n=n+1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
- break
- end
+ end
+ if s>l then
+ local current=last and getnext(last)
+ if not current and postreplace then
+ current=getnext(sweepnode)
+ end
+ if current then
+ local discfound
+ local n=l+1
+ while n<=s do
+ if current then
+ local char,id=ischar(current,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ current=getnext(current)
+ elseif seq[n][char] then
+ if n<s then
+ current=getnext(current)
+ end
+ n=n+1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- match=false
+ break
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=current
- notmatchpre[current]=nil
- notmatchpost[current]=true
- notmatchreplace[current]=nil
- local pre,post,replace=getdisc(current)
- if pre then
- local n=n
- while pre do
- if seq[n][getchar(pre)] then
- n=n+1
- pre=getnext(pre)
- if n>s then
- break
- end
- else
- notmatchpre[current]=true
+ else
+ goto next
+ end
+ elseif id==disc_code then
+ discseen=true
+ discfound=current
+ notmatchpre[current]=nil
+ notmatchpost[current]=true
+ notmatchreplace[current]=nil
+ local pre,post,replace=getdisc(current)
+ if pre then
+ local n=n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n=n+1
+ if n>s then
break
+ else
+ pre=getnext(pre)
end
- end
- if n<=s then
+ else
notmatchpre[current]=true
+ break
end
- else
+ end
+ if n<=s then
notmatchpre[current]=true
end
- if replace then
- while replace do
- if seq[n][getchar(replace)] then
- n=n+1
+ else
+ notmatchpre[current]=true
+ end
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ if n>s then
+ break
+ else
replace=getnext(replace)
- if n>s then
- break
- end
+ end
+ else
+ notmatchreplace[current]=true
+ if notmatchpre[current] then
+ goto next
else
- notmatchreplace[current]=true
- match=notmatchpre[current]
break
end
end
- if not match then
- break
- end
- else
end
- current=getnext(current)
- elseif seq[n][32] and isspace(current,threshold) then
+ else
+ notmatchreplace[current]=true
+ end
+ current=getnext(current)
+ elseif id==glue_code then
+ local sn=seq[n]
+ if (sn[32] and spaces[current]) or sn[0xFFFC] then
n=n+1
current=getnext(current)
else
- match=false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n=n+1
+ current=getnext(current)
else
- match=false
- break
- end
- end
- else
- match=false
- end
- end
- end
- if match then
- local diskchain=diskseen or sweepnode
- if trace_contexts then
- local rule=ck[1]
- local lookuptype=ck[8] or ck[2]
- local first=ck[4]
- local last=ck[5]
- local char=getchar(start)
- logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
- cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype)
- end
- local chainlookups=ck[6]
- if chainlookups then
- local nofchainlookups=#chainlookups
- if size==1 then
- local chainlookup=chainlookups[1]
- local chainkind=chainlookup.type
- local chainproc=chainprocs[chainkind]
- if chainproc then
- local ok
- if diskchain then
- head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc)
- else
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
- end
- if ok then
- done=true
+ goto next
end
else
- logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
- end
- else
- local i=1
- while start do
- if skipped then
- while start do
- local char=getchar(start)
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class or "base"
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- start=getnext(start)
- else
- break
- end
- else
- break
- end
- end
- end
- local chainlookup=chainlookups[i]
- if chainlookup then
- local chainkind=chainlookup.type
- local chainproc=chainprocs[chainkind]
- if chainproc then
- local ok,n
- if diskchain then
- head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc)
- else
- head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
- end
- if ok then
- done=true
- if n and n>1 and i+n>nofchainlookups then
- break
- end
- end
- else
- logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
- end
- end
- i=i+1
- if i>size or not start then
- break
- elseif start then
- start=getnext(start)
- end
+ goto next
end
end
else
- local replacements=ck[7]
- if replacements then
- head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode)
- else
- done=true
- if trace_contexts then
- logprocess("%s: skipping match",cref(dataset,sequence))
- end
- end
- end
- if done then
- break
+ goto next
end
end
+ if trace_contexts then
+ chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true,discseen,sweepnode)
+ end
+ if discseen or sweepnode then
+ head,start,done=chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck)
+ else
+ head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck)
+ end
+ if done then
+ break
+ end
+ ::next::
end
- if diskseen then
+ if discseen then
notmatchpre={}
notmatchpost={}
notmatchreplace={}
@@ -15112,13 +19334,18 @@ handlers.gsub_contextchain=handle_contextchain
handlers.gsub_reversecontextchain=handle_contextchain
handlers.gpos_contextchain=handle_contextchain
handlers.gpos_context=handle_contextchain
-local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode)
+local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
local steps=currentlookup.steps
local nofsteps=currentlookup.nofsteps
if nofsteps>1 then
reportmoresteps(dataset,sequence)
end
- return handle_contextchain(head,start,dataset,sequence,currentlookup,rlmode)
+ local l=steps[1].coverage[getchar(start)]
+ if l then
+ return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash)
+ else
+ return head,start,false
+ end
end
chainprocs.gsub_context=chained_contextchain
chainprocs.gsub_contextchain=chained_contextchain
@@ -15126,22 +19353,17 @@ chainprocs.gsub_reversecontextchain=chained_contextchain
chainprocs.gpos_contextchain=chained_contextchain
chainprocs.gpos_context=chained_contextchain
local missing=setmetatableindex("table")
+local logwarning=report_process
+local resolved={}
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_process(...)
end
-local logwarning=report_process
-local function report_missing_coverage(dataset,sequence)
- local t=missing[currentfont]
- if not t[sequence] then
- t[sequence]=true
- logwarning("missing coverage for feature %a, lookup %a, type %a, font %a, name %a",
- dataset[4],sequence.name,sequence.type,currentfont,tfmdata.properties.fullname)
- end
-end
-local resolved={}
local sequencelists=setmetatableindex(function(t,font)
local sequences=fontdata[font].resources.sequences
if not sequences or not next(sequences) then
@@ -15150,75 +19372,79 @@ local sequencelists=setmetatableindex(function(t,font)
t[font]=sequences
return sequences
end)
-local autofeatures=fonts.analyzers.features
-local featuretypes=otf.tables.featuretypes
-local defaultscript=otf.features.checkeddefaultscript
-local defaultlanguage=otf.features.checkeddefaultlanguage
-local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
- local features=sequence.features
- if features then
- local order=sequence.order
- if order then
- local featuretype=featuretypes[sequence.type or "unknown"]
- for i=1,#order do
- local kind=order[i]
- local valid=enabled[kind]
- if valid then
- local scripts=features[kind]
- local languages=scripts and (
- scripts[script] or
- scripts[wildcard] or
- (autoscript and defaultscript(featuretype,autoscript,scripts))
- )
- local enabled=languages and (
- languages[language] or
- languages[wildcard] or
- (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
- )
- if enabled then
- return { valid,autofeatures[kind] or false,sequence,kind }
+do
+ local autofeatures=fonts.analyzers.features
+ local featuretypes=otf.tables.featuretypes
+ local defaultscript=otf.features.checkeddefaultscript
+ local defaultlanguage=otf.features.checkeddefaultlanguage
+ local wildcard="*"
+ local default="dflt"
+ local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
+ local features=sequence.features
+ if features then
+ local order=sequence.order
+ if order then
+ local featuretype=featuretypes[sequence.type or "unknown"]
+ for i=1,#order do
+ local kind=order[i]
+ local valid=enabled[kind]
+ if valid then
+ local scripts=features[kind]
+ local languages=scripts and (
+ scripts[script] or
+ scripts[wildcard] or
+ (autoscript and defaultscript(featuretype,autoscript,scripts))
+ )
+ local enabled=languages and (
+ languages[language] or
+ languages[wildcard] or
+ (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
+ )
+ if enabled then
+ return { valid,autofeatures[kind] or false,sequence,kind }
+ end
end
end
+ else
end
- else
end
+ return false
end
- return false
-end
-function otf.dataset(tfmdata,font)
- local shared=tfmdata.shared
- local properties=tfmdata.properties
- local language=properties.language or "dflt"
- local script=properties.script or "dflt"
- local enabled=shared.features
- local autoscript=enabled and enabled.autoscript
- local autolanguage=enabled and enabled.autolanguage
- local res=resolved[font]
- if not res then
- res={}
- resolved[font]=res
- end
- local rs=res[script]
- if not rs then
- rs={}
- res[script]=rs
- end
- local rl=rs[language]
- if not rl then
- rl={
- }
- rs[language]=rl
- local sequences=tfmdata.resources.sequences
- if sequences then
- for s=1,#sequences do
- local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
- if v then
- rl[#rl+1]=v
+ function otf.dataset(tfmdata,font)
+ local shared=tfmdata.shared
+ local properties=tfmdata.properties
+ local language=properties.language or "dflt"
+ local script=properties.script or "dflt"
+ local enabled=shared.features
+ local autoscript=enabled and enabled.autoscript
+ local autolanguage=enabled and enabled.autolanguage
+ local res=resolved[font]
+ if not res then
+ res={}
+ resolved[font]=res
+ end
+ local rs=res[script]
+ if not rs then
+ rs={}
+ res[script]=rs
+ end
+ local rl=rs[language]
+ if not rl then
+ rl={
+ }
+ rs[language]=rl
+ local sequences=tfmdata.resources.sequences
+ if sequences then
+ for s=1,#sequences do
+ local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
+ if v then
+ rl[#rl+1]=v
+ end
end
end
end
+ return rl
end
- return rl
end
local function report_disc(what,n)
report_run("%s: %s > %s",what,n,languages.serializediscretionary(n))
@@ -15251,13 +19477,12 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
if prev then
- local nest=getprev(pre)
setlink(prev,pre)
if k_run(prevmarks,"preinjections",pre,font,attr,...) then
done=true
end
- setprev(pre,nest)
- setnext(prev,disc)
+ setprev(pre)
+ setlink(prev,disc)
end
end
if post then
@@ -15270,7 +19495,7 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
setnext(posttail)
- setprev(next,disc)
+ setlink(disc,next)
end
end
if replace then
@@ -15278,13 +19503,12 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
if prev then
- local nest=getprev(replace)
setlink(prev,replace)
if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then
done=true
end
- setprev(replace,nest)
- setnext(prev,disc)
+ setprev(replace)
+ setlink(prev,disc)
end
if next then
setlink(replacetail,next)
@@ -15292,19 +19516,21 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
setnext(replacetail)
- setprev(next,disc)
+ setlink(disc,next)
end
elseif prev and next then
setlink(prev,next)
if k_run(prevmarks,"emptyinjections",next,font,attr,...) then
done=true
end
- setlink(prev,disc)
- setlink(disc,next)
+ setlink(prev,disc,next)
+ end
+ if done and trace_testruns then
+ report_disc("done",disc)
end
return nextstart,done
end
-local function comprun(disc,c_run,...)
+local function comprun(disc,c_run,...)
if trace_compruns then
report_disc("comp",disc)
end
@@ -15340,6 +19566,9 @@ local function comprun(disc,c_run,...)
sweepnode=nil
sweeptype=nil
if renewed then
+ if trace_testruns then
+ report_disc("done",disc)
+ end
setdisc(disc,pre,post,replace)
end
return getnext(disc),renewed
@@ -15353,22 +19582,66 @@ local function testrun(disc,t_run,c_run,...)
return
end
local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
- local done=false
- if replace and prev then
- setlink(replacetail,next)
- local ok,overflow=t_run(replace,next,...)
- if ok and overflow then
- setfield(disc,"replace")
- setlink(prev,replace)
- setboth(disc)
- flush_node_list(disc)
- return replace,true
+ local renewed=false
+ if (post or replace) and prev then
+ if post then
+ setlink(posttail,next)
else
- setnext(replacetail)
- setprev(next,disc)
+ post=next
end
+ if replace then
+ setlink(replacetail,next)
+ else
+ replace=next
+ end
+ local d_post=t_run(post,next,...)
+ local d_replace=t_run(replace,next,...)
+ if d_post>0 or d_replace>0 then
+ local d=d_replace>d_post and d_replace or d_post
+ local head=getnext(disc)
+ local tail=head
+ for i=1,d do
+ local nx=getnext(tail)
+ local id=getid(nx)
+ if id==disc_code then
+ head,tail=flattendisk(head,nx)
+ elseif id==glyph_code then
+ tail=nx
+ else
+ break
+ end
+ end
+ next=getnext(tail)
+ setnext(tail)
+ setprev(head)
+ local new=copy_node_list(head)
+ if posttail then
+ setlink(posttail,head)
+ else
+ post=head
+ end
+ if replacetail then
+ setlink(replacetail,new)
+ else
+ replace=new
+ end
+ else
+ if posttail then
+ setnext(posttail)
+ else
+ post=nil
+ end
+ if replacetail then
+ setnext(replacetail)
+ else
+ replace=nil
+ end
+ end
+ setlink(disc,next)
+ end
+ if trace_testruns then
+ report_disc("more",disc)
end
- local renewed=false
if pre then
sweepnode=disc
sweeptype="pre"
@@ -15400,30 +19673,34 @@ local function testrun(disc,t_run,c_run,...)
sweeptype=nil
if renewed then
setdisc(disc,pre,post,replace)
- return next,true
- else
- return next,done
+ if trace_testruns then
+ report_disc("done",disc)
+ end
end
+ return getnext(disc),renewed
end
local nesting=0
-local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
local done=false
local sweep=sweephead[head]
if sweep then
start=sweep
- sweephead[head]=nil
+ sweephead[head]=false
else
start=head
end
while start do
- local char=ischar(start,font)
+ local char,id=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
if not a or (a==attr) then
local lookupmatch=lookupcache[char]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
if ok then
done=true
end
@@ -15445,46 +19722,91 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm
return head,done
end
local function t_run_single(start,stop,font,attr,lookupcache)
+ local lastd=nil
while start~=stop do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ local startnext=getnext(start)
if not a or (a==attr) then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local s=getnext(start)
+ local s=startnext
+ local ss=nil
+ local sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
local l=nil
local d=0
while s do
- if s==stop then
- d=1
- elseif d>0 then
- d=d+1
- end
- local lg=lookupmatch[getchar(s)]
- if lg then
- l=lg
- s=getnext(s)
+ local char=ischar(s,font)
+ if char then
+ local lg=lookupmatch[char]
+ if lg then
+ if sstop then
+ d=1
+ elseif d>0 then
+ d=d+1
+ end
+ l=lg
+ s=getnext(s)
+ sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
+ else
+ break
+ end
else
break
end
end
- if l and l.ligature then
- return true,d>1
+ if l and l.ligature then
+ lastd=d
end
+ else
end
else
end
- start=getnext(start)
+ if lastd then
+ return lastd
+ end
+ start=startnext
else
break
end
end
+ return 0
end
-local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- local a=attr and getattr(sub,0)
+local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ local a
+ if attr then
+ a=getattr(sub,0)
+ end
if not a or (a==attr) then
- for n in traverse_nodes(sub) do
+ for n in nextnode,sub do
if n==last then
break
end
@@ -15492,7 +19814,7 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
if char then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection)
+ local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
if ok then
return true
end
@@ -15501,37 +19823,36 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
end
end
end
-local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
+local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
local done=false
local sweep=sweephead[head]
if sweep then
start=sweep
- sweephead[head]=nil
+ sweephead[head]=false
else
start=head
end
while start do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
if not a or (a==attr) then
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done=true
- break
- elseif not start then
- break
- end
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ done=true
+ break
+ elseif not start then
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -15551,54 +19872,94 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
return head,done
end
local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
+ local lastd=nil
while start~=stop do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ local startnext=getnext(start)
if not a or (a==attr) then
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local s=getnext(start)
- local l=nil
- local d=0
- while s do
- if s==stop then
- d=1
- elseif d>0 then
- d=d+1
- end
- local lg=lookupmatch[getchar(s)]
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local s=startnext
+ local ss=nil
+ local sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
+ local l=nil
+ local d=0
+ while s do
+ local char=ischar(s)
+ if char then
+ local lg=lookupmatch[char]
if lg then
+ if sstop then
+ d=1
+ elseif d>0 then
+ d=d+1
+ end
l=lg
s=getnext(s)
+ sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
else
break
end
- end
- if l and l.ligature then
- return true,d>1
+ else
+ break
end
end
- else
- report_missing_coverage(dataset,sequence)
+ if l and l.ligature then
+ lastd=d
+ end
end
end
else
end
- start=getnext(start)
+ if lastd then
+ return lastd
+ end
+ start=startnext
else
break
end
end
+ return 0
end
-local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- local a=attr and getattr(sub,0)
+local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ local a
+ if attr then
+ a=getattr(sub,0)
+ end
if not a or (a==attr) then
- for n in traverse_nodes(sub) do
+ for n in nextnode,sub do
if n==last then
break
end
@@ -15607,16 +19968,12 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local h,d,ok=handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection)
- if ok then
- return true
- end
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
+ if ok then
+ return true
end
- else
- report_missing_coverage(dataset,sequence)
end
end
end
@@ -15624,176 +19981,194 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
end
end
local function txtdirstate(start,stack,top,rlparmode)
- local dir=getfield(start,"dir")
- local new=1
+ local nxt=getnext(start)
+ local dir=getdir(start)
if dir=="+TRT" then
top=top+1
stack[top]=dir
- new=-1
+ return nxt,top,-1
elseif dir=="+TLT" then
top=top+1
stack[top]=dir
+ return nxt,top,1
elseif dir=="-TRT" or dir=="-TLT" then
- top=top-1
- if stack[top]=="+TRT" then
- new=-1
+ if top==1 then
+ return nxt,0,rlparmode
+ else
+ top=top-1
+ if stack[top]=="+TRT" then
+ return nxt,top,-1
+ else
+ return nxt,top,1
+ end
end
else
- new=rlparmode
- end
- if trace_directions then
- report_process("directions after txtdir %a: parmode %a, txtmode %a, level %a",dir,mref(rlparmode),mref(new),top)
+ return nxt,top,rlparmode
end
- return getnext(start),top,new
end
local function pardirstate(start)
- local dir=getfield(start,"dir")
- local new=0
+ local nxt=getnext(start)
+ local dir=getdir(start)
if dir=="TLT" then
- new=1
+ return nxt,1,1
elseif dir=="TRT" then
- new=-1
- end
- if trace_directions then
- report_process("directions after pardir %a: parmode %a",dir,mref(new))
+ return nxt,-1,-1
+ else
+ return nxt,0,0
end
- return getnext(start),new,new
end
otf.helpers=otf.helpers or {}
otf.helpers.txtdirstate=txtdirstate
otf.helpers.pardirstate=pardirstate
-local function featuresprocessor(head,font,attr)
- local sequences=sequencelists[font]
- if not sequencelists then
- return head,false
- end
- nesting=nesting+1
- if nesting==1 then
- currentfont=font
- tfmdata=fontdata[font]
- descriptions=tfmdata.descriptions
- characters=tfmdata.characters
- marks=tfmdata.resources.marks
- threshold,
- factor=getthreshold(font)
- checkmarks=tfmdata.properties.checkmarks
- elseif currentfont~=font then
- report_warning("nested call with a different font, level %s, quitting",nesting)
- nesting=nesting-1
- return head,false
- end
- head=tonut(head)
- if trace_steps then
- checkstep(head)
- end
- local rlmode=0
- local done=false
- local datasets=otf.dataset(tfmdata,font,attr)
- local forcedisc=alwaysdisc or not attr
- local dirstack={}
- sweephead={}
- for s=1,#datasets do
- local dataset=datasets[s]
- local attribute=dataset[2]
- local sequence=dataset[3]
- local rlparmode=0
- local topstack=0
- local success=false
- local typ=sequence.type
- local gpossing=typ=="gpos_single" or typ=="gpos_pair"
- local handler=handlers[typ]
- local steps=sequence.steps
- local nofsteps=sequence.nofsteps
- if not steps then
- local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
- if ok then
- success=true
- if h then
+do
+ local fastdisc=true
+ local testdics=false
+ directives.register("otf.fastdisc",function(v) fastdisc=v end)
+ local otfdataset=nil
+ local getfastdisc={ __index=function(t,k)
+ local v=usesfont(k,currentfont)
+ t[k]=v
+ return v
+ end }
+ local getfastspace={ __index=function(t,k)
+ local v=isspace(k,threshold) or false
+ t[k]=v
+ return v
+ end }
+ function otf.featuresprocessor(head,font,attr,direction,n)
+ local sequences=sequencelists[font]
+ nesting=nesting+1
+ if nesting==1 then
+ currentfont=font
+ tfmdata=fontdata[font]
+ descriptions=tfmdata.descriptions
+ characters=tfmdata.characters
+ local resources=tfmdata.resources
+ marks=resources.marks
+ classes=resources.classes
+ threshold,
+ factor=getthreshold(font)
+ checkmarks=tfmdata.properties.checkmarks
+ if not otfdataset then
+ otfdataset=otf.dataset
+ end
+ discs=fastdisc and n and n>1 and setmetatable({},getfastdisc)
+ spaces=setmetatable({},getfastspace)
+ elseif currentfont~=font then
+ report_warning("nested call with a different font, level %s, quitting",nesting)
+ nesting=nesting-1
+ return head,false
+ end
+ if trace_steps then
+ checkstep(head)
+ end
+ local initialrl=direction=="TRT" and -1 or 0
+ local datasets=otfdataset(tfmdata,font,attr)
+ local dirstack={ nil }
+ sweephead={}
+ for s=1,#datasets do
+ local dataset=datasets[s]
+ local attribute=dataset[2]
+ local sequence=dataset[3]
+ local rlparmode=initialrl
+ local topstack=0
+ local typ=sequence.type
+ local gpossing=typ=="gpos_single" or typ=="gpos_pair"
+ local forcetestrun=typ=="gsub_ligature"
+ local handler=handlers[typ]
+ local steps=sequence.steps
+ local nofsteps=sequence.nofsteps
+ local skiphash=sequence.skiphash
+ if not steps then
+ local h,ok=handler(head,dataset,sequence,initialrl,font,attr)
+ if h and h~=head then
head=h
end
- end
- elseif typ=="gsub_reversecontextchain" then
- local start=find_node_tail(head)
- while start do
- local char=ischar(start,font)
- if char then
- local a=attr and getattr(start,0)
- if not a or (a==attr) then
- for i=1,nofsteps do
- local step=steps[i]
- local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success=true
- break
+ elseif typ=="gsub_reversecontextchain" then
+ local start=find_node_tail(head)
+ local rlmode=0
+ local merged=steps.merged
+ while start do
+ local char=ischar(start,font)
+ if char then
+ local m=merged[char]
+ if m then
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ if not a or (a==attr) then
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ end
end
end
+ if start then
+ start=getprev(start)
+ end
else
- report_missing_coverage(dataset,sequence)
+ start=getprev(start)
end
- end
- if start then
+ else
start=getprev(start)
end
else
start=getprev(start)
end
- else
- start=getprev(start)
end
- end
- else
- local start=head
- rlmode=0
- if nofsteps==1 then
- local step=steps[1]
- local lookupcache=step.coverage
- if not lookupcache then
- report_missing_coverage(dataset,sequence)
- else
+ else
+ local start=head
+ local rlmode=initialrl
+ if nofsteps==1 then
+ local step=steps[1]
+ local lookupcache=step.coverage
while start do
local char,id=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
- if a then
- a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
+ if skiphash and skiphash[char] then
+ start=getnext(start)
else
- a=not attribute or getprop(start,a_state)==attribute
- end
- if a then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
- if ok then
- success=true
+ local a
+ if attr then
+ if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then
+ a=true
+ end
+ elseif not attribute or getprop(start,a_state)==attribute then
+ a=true
end
- end
- if start then
+ if a then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if start then
+ start=getnext(start)
+ end
+ else
+ start=getnext(start)
+ end
+ else
start=getnext(start)
end
- else
- start=getnext(start)
end
- elseif char==false then
+ elseif char==false or id==glue_code then
start=getnext(start)
elseif id==disc_code then
- local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
- if a then
+ if not discs or discs[start]==true then
local ok
if gpossing then
- start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- elseif typ=="gsub_ligature" then
- start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
else
- start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- end
- if ok then
- success=true
+ start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
end
else
start=getnext(start)
@@ -15808,110 +20183,197 @@ local function featuresprocessor(head,font,attr)
start=getnext(start)
end
end
- end
- else
- while start do
- local char,id=ischar(start,font)
- if char then
- local a=attr and getattr(start,0)
- if a then
- a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
- else
- a=not attribute or getprop(start,a_state)==attribute
- end
- if a then
- for i=1,nofsteps do
- local step=steps[i]
- local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success=true
- break
- elseif not start then
- break
+ else
+ local merged=steps.merged
+ while start do
+ local char,id=ischar(start,font)
+ if char then
+ if skiphash and skiphash[char] then
+ start=getnext(start)
+ else
+ local m=merged[char]
+ if m then
+ local a
+ if attr then
+ if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then
+ a=true
end
+ elseif not attribute or getprop(start,a_state)==attribute then
+ a=true
+ end
+ if a then
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ elseif not start then
+ break
+ end
+ end
+ end
+ if start then
+ start=getnext(start)
+ end
+ else
+ start=getnext(start)
end
else
- report_missing_coverage(dataset,sequence)
+ start=getnext(start)
end
end
- if start then
+ elseif char==false or id==glue_code then
+ start=getnext(start)
+ elseif id==disc_code then
+ if not discs or discs[start]==true then
+ local ok
+ if gpossing then
+ start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ else
+ start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ end
+ else
start=getnext(start)
end
+ elseif id==math_code then
+ start=getnext(end_of_math(start))
+ elseif id==dir_code then
+ start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id==localpar_code then
+ start,rlparmode,rlmode=pardirstate(start)
else
start=getnext(start)
end
- elseif char==false then
+ end
+ end
+ end
+ if trace_steps then
+ registerstep(head)
+ end
+ end
+ nesting=nesting-1
+ return head
+ end
+ function otf.datasetpositionprocessor(head,font,direction,dataset)
+ currentfont=font
+ tfmdata=fontdata[font]
+ descriptions=tfmdata.descriptions
+ characters=tfmdata.characters
+ local resources=tfmdata.resources
+ marks=resources.marks
+ classes=resources.classes
+ threshold,
+ factor=getthreshold(font)
+ checkmarks=tfmdata.properties.checkmarks
+ if type(dataset)=="number" then
+ dataset=otfdataset(tfmdata,font,0)[dataset]
+ end
+ local sequence=dataset[3]
+ local typ=sequence.type
+ local handler=handlers[typ]
+ local steps=sequence.steps
+ local nofsteps=sequence.nofsteps
+ local done=false
+ local dirstack={ nil }
+ local start=head
+ local initialrl=direction=="TRT" and -1 or 0
+ local rlmode=initialrl
+ local rlparmode=initialrl
+ local topstack=0
+ local merged=steps.merged
+ local position=0
+ while start do
+ local char,id=ischar(start,font)
+ if char then
+ position=position+1
+ local m=merged[char]
+ if m then
+ if skiphash and skiphash[char] then
start=getnext(start)
- elseif id==disc_code then
- local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
- if a then
- local ok
- if gpossing then
- start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- elseif typ=="gsub_ligature" then
- start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- else
- start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- end
- if ok then
- success=true
+ else
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ elseif not start then
+ break
+ end
end
- else
+ end
+ if start then
start=getnext(start)
end
- elseif id==math_code then
- start=getnext(end_of_math(start))
- elseif id==dir_code then
- start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
- elseif id==localpar_code then
- start,rlparmode,rlmode=pardirstate(start)
- else
- start=getnext(start)
end
+ else
+ start=getnext(start)
end
+ elseif char==false or id==glue_code then
+ start=getnext(start)
+ elseif id==math_code then
+ start=getnext(end_of_math(start))
+ elseif id==dir_code then
+ start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id==localpar_code then
+ start,rlparmode,rlmode=pardirstate(start)
+ else
+ start=getnext(start)
end
end
- if success then
- done=true
- end
- if trace_steps then
- registerstep(head)
- end
+ return head
end
- nesting=nesting-1
- head=tonode(head)
- return head,done
end
local plugins={}
otf.plugins=plugins
+local report=logs.reporter("fonts")
function otf.registerplugin(name,f)
if type(name)=="string" and type(f)=="function" then
plugins[name]={ name,f }
+ report()
+ report("plugin %a has been loaded, please be aware of possible side effects",name)
+ report()
+ if logs.pushtarget then
+ logs.pushtarget("log")
+ end
+ report("Plugins are not officially supported unless stated otherwise. This is because")
+ report("they bypass the regular font handling and therefore some features in ConTeXt")
+ report("(especially those related to fonts) might not work as expected or might not work")
+ report("at all. Some plugins are for testing and development only and might change")
+ report("whenever we feel the need for it.")
+ report()
+ if logs.poptarget then
+ logs.poptarget()
+ end
end
end
-local function plugininitializer(tfmdata,value)
+function otf.plugininitializer(tfmdata,value)
if type(value)=="string" then
tfmdata.shared.plugin=plugins[value]
end
end
-local function pluginprocessor(head,font)
+function otf.pluginprocessor(head,font,attr,direction)
local s=fontdata[font].shared
local p=s and s.plugin
if p then
if trace_plugins then
report_process("applying plugin %a",p[1])
end
- return p[2](head,font)
+ return p[2](head,font,attr,direction)
else
return head,false
end
end
-local function featuresinitializer(tfmdata,value)
+function otf.featuresinitializer(tfmdata,value)
end
registerotffeature {
name="features",
@@ -15919,53 +20381,87 @@ registerotffeature {
default=true,
initializers={
position=1,
- node=featuresinitializer,
- plug=plugininitializer,
+ node=otf.featuresinitializer,
+ plug=otf.plugininitializer,
},
processors={
- node=featuresprocessor,
- plug=pluginprocessor,
+ node=otf.featuresprocessor,
+ plug=otf.pluginprocessor,
}
}
-otf.nodemodeinitializer=featuresinitializer
-otf.featuresprocessor=featuresprocessor
otf.handlers=handlers
local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end
+local tag="kern"
if fontfeatures then
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local features=fontfeatures[font]
- local enabled=features and features.spacekern and features.kern
+ local enabled=features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head,start,enabled
+ return head,enabled
end
else
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local shared=fontdata[font].shared
local features=shared and shared.features
- local enabled=features and features.spacekern and features.kern
+ local enabled=features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head,start,enabled
+ return head,enabled
end
end
local function hasspacekerns(data)
- local sequences=data.resources.sequences
- for i=1,#sequences do
- local sequence=sequences[i]
- local steps=sequence.steps
- if steps and sequence.features.kern then
- for i=1,#steps do
- local coverage=steps[i].coverage
- if not coverage then
- elseif coverage[32] then
- return true
- else
- for k,v in next,coverage do
- if v[32] then
- return true
+ local resources=data.resources
+ local sequences=resources.sequences
+ local validgpos=resources.features.gpos
+ if validgpos and sequences then
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local steps=sequence.steps
+ if steps and sequence.features[tag] then
+ local kind=sequence.type
+ if kind=="gpos_pair" or kind=="gpos_single" then
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ local rules=step.rules
+ if rules then
+ elseif not coverage then
+ elseif kind=="gpos_single" then
+ elseif kind=="gpos_pair" then
+ local format=step.format
+ if format=="move" or format=="kern" then
+ local kerns=coverage[32]
+ if kerns then
+ return true
+ end
+ for k,v in next,coverage do
+ if v[32] then
+ return true
+ end
+ end
+ elseif format=="pair" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ local one=v[1]
+ if one and one~=true then
+ return true
+ end
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ local one=kern[1]
+ if one and one~=true then
+ return true
+ end
+ end
+ end
+ end
end
end
end
@@ -15983,103 +20479,110 @@ otf.readers.registerextender {
local function spaceinitializer(tfmdata,value)
local resources=tfmdata.resources
local spacekerns=resources and resources.spacekerns
- local properties=tfmdata.properties
if value and spacekerns==nil then
+ local rawdata=tfmdata.shared and tfmdata.shared.rawdata
+ local properties=rawdata.properties
if properties and properties.hasspacekerns then
local sequences=resources.sequences
- local left={}
- local right={}
- local last=0
- local feat=nil
- for i=1,#sequences do
- local sequence=sequences[i]
- local steps=sequence.steps
- if steps then
- local kern=sequence.features.kern
- if kern then
- if feat then
- for script,languages in next,kern do
- local f=feat[script]
- if f then
- for l in next,languages do
- f[l]=true
- end
- else
- feat[script]=languages
- end
- end
- else
- feat=kern
- end
- for i=1,#steps do
- local step=steps[i]
- local coverage=step.coverage
- local rules=step.rules
- local format=step.format
- if rules then
- elseif coverage then
- local single=format==gpos_single
- local kerns=coverage[32]
- if kerns then
- for k,v in next,kerns do
- if type(v)~="table" then
- right[k]=v
- elseif single then
- right[k]=v[3]
- else
- local one=v[1]
- if one then
- right[k]=one[3]
+ local validgpos=resources.features.gpos
+ if validgpos and sequences then
+ local left={}
+ local right={}
+ local last=0
+ local feat=nil
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local steps=sequence.steps
+ if steps then
+ local kern=sequence.features[tag]
+ if kern then
+ local kind=sequence.type
+ if kind=="gpos_pair" or kind=="gpos_single" then
+ if feat then
+ for script,languages in next,kern do
+ local f=feat[script]
+ if f then
+ for l in next,languages do
+ f[l]=true
end
+ else
+ feat[script]=languages
end
end
+ else
+ feat=kern
end
- for k,v in next,coverage do
- local kern=v[32]
- if kern then
- if type(kern)~="table" then
- left[k]=kern
- elseif single then
- left[k]=v[3]
- else
- local one=v[1]
- if one then
- left[k]=one[3]
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ local rules=step.rules
+ if rules then
+ elseif not coverage then
+ elseif kind=="gpos_single" then
+ elseif kind=="gpos_pair" then
+ local format=step.format
+ if format=="move" or format=="kern" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ right[k]=v
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ left[k]=kern
+ end
+ end
+ elseif format=="pair" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ local one=v[1]
+ if one and one~=true then
+ right[k]=one[3]
+ end
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ local one=kern[1]
+ if one and one~=true then
+ left[k]=one[3]
+ end
+ end
end
end
end
end
+ last=i
end
+ else
end
- last=i
end
- else
end
- end
- left=next(left) and left or false
- right=next(right) and right or false
- if left or right then
- spacekerns={
- left=left,
- right=right,
- }
- if last>0 then
- local triggersequence={
- features={ kern=feat or { dflt={ dflt=true,} } },
- flags=noflags,
- name="trigger_space_kerns",
- order={ "kern" },
- type="trigger_space_kerns",
+ left=next(left) and left or false
+ right=next(right) and right or false
+ if left or right then
+ spacekerns={
left=left,
right=right,
}
- insert(sequences,last,triggersequence)
+ if last>0 then
+ local triggersequence={
+ features={ [tag]=feat or { dflt={ dflt=true,} } },
+ flags=noflags,
+ name="trigger_space_kerns",
+ order={ tag },
+ type="trigger_space_kerns",
+ left=left,
+ right=right,
+ }
+ insert(sequences,last,triggersequence)
+ end
end
- else
- spacekerns=false
end
- else
- spacekerns=false
end
resources.spacekerns=spacekerns
end
@@ -16106,10 +20609,10 @@ registerotffeature {
},
}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ots”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ots”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-osd” 10ecd4b375680b011e7c6a25e5ad74f7] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-osd” d2b542031aa693bb423b6d3272820c9a] ---
if not modules then modules={} end modules ['font-osd']={
version=1.001,
@@ -16120,7 +20623,7 @@ if not modules then modules={} end modules ['font-osd']={
}
local insert,imerge,copy=table.insert,table.imerge,table.copy
local next,type=next,type
-local report_devanagari=logs.reporter("otf","devanagari")
+local report=logs.reporter("otf","devanagari")
fonts=fonts or {}
fonts.analyzers=fonts.analyzers or {}
fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } }
@@ -16130,8 +20633,6 @@ local methods=fonts.analyzers.methods
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
local getnext=nuts.getnext
local getprev=nuts.getprev
local getboth=nuts.getboth
@@ -16157,6 +20658,9 @@ local fontdata=fonts.hashes.identifiers
local a_state=attributes.private('state')
local a_syllabe=attributes.private('syllabe')
local dotted_circle=0x25CC
+local c_nbsp=0x00A0
+local c_zwnj=0x200C
+local c_zwj=0x200D
local states=fonts.analyzers.states
local s_rphf=states.rphf
local s_half=states.half
@@ -16170,214 +20674,161 @@ replace_all_nbsp=function(head)
end
return replace_all_nbsp(head)
end
-local xprocesscharacters=nil
+local processcharacters=nil
if context then
- xprocesscharacters=function(head,font)
- xprocesscharacters=nodes.handlers.characters
- return xprocesscharacters(head,font)
+ local fontprocesses=fonts.hashes.processes
+ function processcharacters(head,font)
+ local processors=fontprocesses[font]
+ for i=1,#processors do
+ head=processors[i](head,font,0)
+ end
+ return head
end
else
- xprocesscharacters=function(head,font)
- xprocesscharacters=nodes.handlers.nodepass
- return xprocesscharacters(head,font)
- end
-end
-local function processcharacters(head,font)
- return tonut(xprocesscharacters(tonode(head)))
-end
-local consonant={
- [0x0915]=true,[0x0916]=true,[0x0917]=true,[0x0918]=true,
- [0x0919]=true,[0x091A]=true,[0x091B]=true,[0x091C]=true,
- [0x091D]=true,[0x091E]=true,[0x091F]=true,[0x0920]=true,
- [0x0921]=true,[0x0922]=true,[0x0923]=true,[0x0924]=true,
- [0x0925]=true,[0x0926]=true,[0x0927]=true,[0x0928]=true,
- [0x0929]=true,[0x092A]=true,[0x092B]=true,[0x092C]=true,
- [0x092D]=true,[0x092E]=true,[0x092F]=true,[0x0930]=true,
- [0x0931]=true,[0x0932]=true,[0x0933]=true,[0x0934]=true,
- [0x0935]=true,[0x0936]=true,[0x0937]=true,[0x0938]=true,
- [0x0939]=true,[0x0958]=true,[0x0959]=true,[0x095A]=true,
- [0x095B]=true,[0x095C]=true,[0x095D]=true,[0x095E]=true,
- [0x095F]=true,[0x0979]=true,[0x097A]=true,
- [0x0C95]=true,[0x0C96]=true,[0x0C97]=true,[0x0C98]=true,
- [0x0C99]=true,[0x0C9A]=true,[0x0C9B]=true,[0x0C9C]=true,
- [0x0C9D]=true,[0x0C9E]=true,[0x0C9F]=true,[0x0CA0]=true,
- [0x0CA1]=true,[0x0CA2]=true,[0x0CA3]=true,[0x0CA4]=true,
- [0x0CA5]=true,[0x0CA6]=true,[0x0CA7]=true,[0x0CA8]=true,
- [0x0CA9]=true,[0x0CAA]=true,[0x0CAB]=true,[0x0CAC]=true,
- [0x0CAD]=true,[0x0CAE]=true,[0x0CAF]=true,[0x0CB0]=true,
- [0x0CB1]=true,[0x0CB2]=true,[0x0CB3]=true,[0x0CB4]=true,
- [0x0CB5]=true,[0x0CB6]=true,[0x0CB7]=true,[0x0CB8]=true,
- [0x0CB9]=true,
- [0x0CDE]=true,
- [0x0D15]=true,[0x0D16]=true,[0x0D17]=true,[0x0D18]=true,
- [0x0D19]=true,[0x0D1A]=true,[0x0D1B]=true,[0x0D1C]=true,
- [0x0D1D]=true,[0x0D1E]=true,[0x0D1F]=true,[0x0D20]=true,
- [0x0D21]=true,[0x0D22]=true,[0x0D23]=true,[0x0D24]=true,
- [0x0D25]=true,[0x0D26]=true,[0x0D27]=true,[0x0D28]=true,
- [0x0D29]=true,[0x0D2A]=true,[0x0D2B]=true,[0x0D2C]=true,
- [0x0D2D]=true,[0x0D2E]=true,[0x0D2F]=true,[0x0D30]=true,
- [0x0D31]=true,[0x0D32]=true,[0x0D33]=true,[0x0D34]=true,
- [0x0D35]=true,[0x0D36]=true,[0x0D37]=true,[0x0D38]=true,
- [0x0D39]=true,[0x0D3A]=true,
-}
-local independent_vowel={
- [0x0904]=true,[0x0905]=true,[0x0906]=true,[0x0907]=true,
- [0x0908]=true,[0x0909]=true,[0x090A]=true,[0x090B]=true,
- [0x090C]=true,[0x090D]=true,[0x090E]=true,[0x090F]=true,
- [0x0910]=true,[0x0911]=true,[0x0912]=true,[0x0913]=true,
- [0x0914]=true,[0x0960]=true,[0x0961]=true,[0x0972]=true,
- [0x0973]=true,[0x0974]=true,[0x0975]=true,[0x0976]=true,
- [0x0977]=true,
- [0x0C85]=true,[0x0C86]=true,[0x0C87]=true,[0x0C88]=true,
- [0x0C89]=true,[0x0C8A]=true,[0x0C8B]=true,[0x0C8C]=true,
- [0x0C8D]=true,[0x0C8E]=true,[0x0C8F]=true,[0x0C90]=true,
- [0x0C91]=true,[0x0C92]=true,[0x0C93]=true,[0x0C94]=true,
- [0x0D05]=true,[0x0D06]=true,[0x0D07]=true,[0x0D08]=true,
- [0x0D09]=true,[0x0D0A]=true,[0x0D0B]=true,[0x0D0C]=true,
- [0x0D0E]=true,[0x0D0F]=true,[0x0D10]=true,[0x0D12]=true,
- [0x0D13]=true,[0x0D14]=true,
-}
-local dependent_vowel={
- [0x093A]=true,[0x093B]=true,[0x093E]=true,[0x093F]=true,
- [0x0940]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
- [0x0944]=true,[0x0945]=true,[0x0946]=true,[0x0947]=true,
- [0x0948]=true,[0x0949]=true,[0x094A]=true,[0x094B]=true,
- [0x094C]=true,[0x094E]=true,[0x094F]=true,[0x0955]=true,
- [0x0956]=true,[0x0957]=true,[0x0962]=true,[0x0963]=true,
- [0x0CBE]=true,[0x0CBF]=true,[0x0CC0]=true,[0x0CC1]=true,
- [0x0CC2]=true,[0x0CC3]=true,[0x0CC4]=true,[0x0CC5]=true,
- [0x0CC6]=true,[0x0CC7]=true,[0x0CC8]=true,[0x0CC9]=true,
- [0x0CCA]=true,[0x0CCB]=true,[0x0CCC]=true,
- [0x0D3E]=true,[0x0D3F]=true,[0x0D40]=true,[0x0D41]=true,
- [0x0D42]=true,[0x0D43]=true,[0x0D44]=true,[0x0D46]=true,
- [0x0D47]=true,[0x0D48]=true,[0x0D4A]=true,[0x0D4B]=true,
- [0x0D4C]=true,[0x0D57]=true,
-}
-local vowel_modifier={
- [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x0903]=true,
- [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
- [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
- [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
- [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
- [0xA8F0]=true,[0xA8F1]=true,
- [0x0D02]=true,[0x0D03]=true,
-}
-local stress_tone_mark={
- [0x0951]=true,[0x0952]=true,[0x0953]=true,[0x0954]=true,
- [0x0CCD]=true,
- [0x0D4D]=true,
-}
-local nukta={
- [0x093C]=true,
- [0x0CBC]=true,
-}
-local halant={
- [0x094D]=true,
- [0x0CCD]=true,
- [0x0D4D]=true,
-}
-local ra={
- [0x0930]=true,
- [0x0CB0]=true,
- [0x0D30]=true,
-}
-local c_anudatta=0x0952
-local c_nbsp=0x00A0
-local c_zwnj=0x200C
-local c_zwj=0x200D
+ function processcharacters(head,font)
+ local processors=fontdata[font].shared.processes
+ for i=1,#processors do
+ head=processors[i](head,font,0)
+ end
+ return head
+ end
+end
+local indicgroups=characters and characters.indicgroups
+if not indicgroups and characters then
+ local indic={
+ c={},
+ i={},
+ d={},
+ m={},
+ s={},
+ o={},
+ }
+ local indicmarks={
+ l={},
+ t={},
+ b={},
+ r={},
+ s={},
+ }
+ local indicclasses={
+ nukta={},
+ halant={},
+ ra={},
+ anudatta={},
+ }
+ local indicorders={
+ bp={},
+ ap={},
+ bs={},
+ as={},
+ bh={},
+ ah={},
+ bm={},
+ am={},
+ }
+ for k,v in next,characters.data do
+ local i=v.indic
+ if i then
+ indic[i][k]=true
+ i=v.indicmark
+ if i then
+ if i=="s" then
+ local s=v.specials
+ indicmarks[i][k]={ s[2],s[3] }
+ else
+ indicmarks[i][k]=true
+ end
+ end
+ i=v.indicclass
+ if i then
+ indicclasses[i][k]=true
+ end
+ i=v.indicorder
+ if i then
+ indicorders[i][k]=true
+ end
+ end
+ end
+ indicgroups={
+ consonant=indic.c,
+ independent_vowel=indic.i,
+ dependent_vowel=indic.d,
+ vowel_modifier=indic.m,
+ stress_tone_mark=indic.s,
+ pre_mark=indicmarks.l,
+ above_mark=indicmarks.t,
+ below_mark=indicmarks.b,
+ post_mark=indicmarks.r,
+ twopart_mark=indicmarks.s,
+ nukta=indicclasses.nukta,
+ halant=indicclasses.halant,
+ ra=indicclasses.ra,
+ anudatta=indicclasses.anudatta,
+ before_postscript=indicorders.bp,
+ after_postscript=indicorders.ap,
+ before_half=indicorders.bh,
+ after_half=indicorders.ah,
+ before_subscript=indicorders.bs,
+ after_subscript=indicorders.as,
+ before_main=indicorders.bm,
+ after_main=indicorders.am,
+ }
+ indic=nil
+ indicmarks=nil
+ indicclasses=nil
+ indicorders=nil
+ characters.indicgroups=indicgroups
+end
+local consonant=indicgroups.consonant
+local independent_vowel=indicgroups.independent_vowel
+local dependent_vowel=indicgroups.dependent_vowel
+local vowel_modifier=indicgroups.vowel_modifier
+local stress_tone_mark=indicgroups.stress_tone_mark
+local pre_mark=indicgroups.pre_mark
+local above_mark=indicgroups.above_mark
+local below_mark=indicgroups.below_mark
+local post_mark=indicgroups.post_mark
+local twopart_mark=indicgroups.twopart_mark
+local nukta=indicgroups.nukta
+local halant=indicgroups.halant
+local ra=indicgroups.ra
+local anudatta=indicgroups.anudatta
+local before_postscript=indicgroups.before_postscript
+local after_postscript=indicgroups.after_postscript
+local before_half=indicgroups.before_half
+local after_half=indicgroups.after_half
+local before_subscript=indicgroups.before_subscript
+local after_subscript=indicgroups.after_subscript
+local before_main=indicgroups.before_main
+local after_main=indicgroups.after_main
+local mark_four=table.merged (
+ pre_mark,
+ above_mark,
+ below_mark,
+ post_mark
+)
+local mark_above_below_post=table.merged (
+ above_mark,
+ below_mark,
+ post_mark
+)
local zw_char={
- [0x200C]=true,
- [0x200D]=true,
-}
-local pre_mark={
- [0x093F]=true,[0x094E]=true,
- [0x0D46]=true,[0x0D47]=true,[0x0D48]=true,
-}
-local above_mark={
- [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x093A]=true,
- [0x0945]=true,[0x0946]=true,[0x0947]=true,[0x0948]=true,
- [0x0951]=true,[0x0953]=true,[0x0954]=true,[0x0955]=true,
- [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
- [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
- [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
- [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
- [0xA8F0]=true,[0xA8F1]=true,
- [0x0D4E]=true,
-}
-local below_mark={
- [0x093C]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
- [0x0944]=true,[0x094D]=true,[0x0952]=true,[0x0956]=true,
- [0x0957]=true,[0x0962]=true,[0x0963]=true,
-}
-local post_mark={
- [0x0903]=true,[0x093B]=true,[0x093E]=true,[0x0940]=true,
- [0x0949]=true,[0x094A]=true,[0x094B]=true,[0x094C]=true,
- [0x094F]=true,
-}
-local twopart_mark={
- [0x0D4A]={ 0x0D46,0x0D3E,},
- [0x0D4B]={ 0x0D47,0x0D3E,},
- [0x0D4C]={ 0x0D46,0x0D57,},
-}
-local mark_four={}
-for k,v in next,pre_mark do mark_four[k]=pre_mark end
-for k,v in next,above_mark do mark_four[k]=above_mark end
-for k,v in next,below_mark do mark_four[k]=below_mark end
-for k,v in next,post_mark do mark_four[k]=post_mark end
-local mark_above_below_post={}
-for k,v in next,above_mark do mark_above_below_post[k]=above_mark end
-for k,v in next,below_mark do mark_above_below_post[k]=below_mark end
-for k,v in next,post_mark do mark_above_below_post[k]=post_mark end
-local reorder_class={
- [0x0930]="before postscript",
- [0x093F]="before half",
- [0x0940]="after subscript",
- [0x0941]="after subscript",
- [0x0942]="after subscript",
- [0x0943]="after subscript",
- [0x0944]="after subscript",
- [0x0945]="after subscript",
- [0x0946]="after subscript",
- [0x0947]="after subscript",
- [0x0948]="after subscript",
- [0x0949]="after subscript",
- [0x094A]="after subscript",
- [0x094B]="after subscript",
- [0x094C]="after subscript",
- [0x0962]="after subscript",
- [0x0963]="after subscript",
- [0x093E]="after subscript",
- [0x0CB0]="after postscript",
- [0x0CBF]="before subscript",
- [0x0CC6]="before subscript",
- [0x0CCC]="before subscript",
- [0x0CBE]="before subscript",
- [0x0CE2]="before subscript",
- [0x0CE3]="before subscript",
- [0x0CC1]="before subscript",
- [0x0CC2]="before subscript",
- [0x0CC3]="after subscript",
- [0x0CC4]="after subscript",
- [0x0CD5]="after subscript",
- [0x0CD6]="after subscript",
+ [c_zwnj]=true,
+ [c_zwj ]=true,
}
local dflt_true={
dflt=true
}
-local dev2_defaults={
+local two_defaults={
dev2=dflt_true,
}
-local deva_defaults={
+local one_defaults={
dev2=dflt_true,
deva=dflt_true,
}
local false_flags={ false,false,false,false }
-local both_joiners_true={
- [0x200C]=true,
- [0x200D]=true,
-}
local sequence_reorder_matras={
- features={ dv01=dev2_defaults },
+ features={ dv01=two_defaults },
flags=false_flags,
name="dv01_reorder_matras",
order={ "dv01" },
@@ -16385,13 +20836,12 @@ local sequence_reorder_matras={
nofsteps=1,
steps={
{
- osdstep=true,
coverage=pre_mark,
}
}
}
local sequence_reorder_reph={
- features={ dv02=dev2_defaults },
+ features={ dv02=two_defaults },
flags=false_flags,
name="dv02_reorder_reph",
order={ "dv02" },
@@ -16399,13 +20849,12 @@ local sequence_reorder_reph={
nofsteps=1,
steps={
{
- osdstep=true,
coverage={},
}
}
}
local sequence_reorder_pre_base_reordering_consonants={
- features={ dv03=dev2_defaults },
+ features={ dv03=two_defaults },
flags=false_flags,
name="dv03_reorder_pre_base_reordering_consonants",
order={ "dv03" },
@@ -16413,54 +20862,80 @@ local sequence_reorder_pre_base_reordering_consonants={
nofsteps=1,
steps={
{
- osdstep=true,
coverage={},
}
}
}
local sequence_remove_joiners={
- features={ dv04=deva_defaults },
+ features={ dv04=one_defaults },
flags=false_flags,
name="dv04_remove_joiners",
order={ "dv04" },
type="devanagari_remove_joiners",
nofsteps=1,
steps={
- { osdstep=true,
- coverage=both_joiners_true,
+ {
+ coverage=zw_char,
},
}
}
local basic_shaping_forms={
- nukt=true,
akhn=true,
- rphf=true,
- pref=true,
- rkrf=true,
blwf=true,
+ cjct=true,
half=true,
+ nukt=true,
+ pref=true,
pstf=true,
+ rkrf=true,
+ rphf=true,
vatu=true,
- cjct=true,
}
local valid={
+ abvs=true,
akhn=true,
- rphf=true,
- pref=true,
- half=true,
blwf=true,
+ calt=true,
+ cjct=true,
+ half=true,
+ haln=true,
+ nukt=true,
+ pref=true,
+ pres=true,
pstf=true,
+ psts=true,
+ rkrf=true,
+ rphf=true,
+ vatu=true,
pres=true,
+ abvs=true,
blws=true,
psts=true,
+ haln=true,
+ calt=true,
}
+local scripts={}
+local scripts_one={ "deva","mlym","beng","gujr","guru","knda","orya","taml","telu" }
+local scripts_two={ "dev2","mlm2","bng2","gjr2","gur2","knd2","ory2","tml2","tel2" }
+local nofscripts=#scripts_one
+for i=1,nofscripts do
+ local one=scripts_one[i]
+ local two=scripts_two[i]
+ scripts[one]=true
+ scripts[two]=true
+ two_defaults[one]=dflt_true
+ one_defaults[one]=dflt_true
+ one_defaults[two]=dflt_true
+end
+local function valid_one(s) for i=1,nofscripts do if s[scripts_one[i]] then return true end end end
+local function valid_two(s) for i=1,nofscripts do if s[scripts_two[i]] then return true end end end
local function initializedevanagi(tfmdata)
local script,language=otf.scriptandlanguage(tfmdata,attr)
- if script=="deva" or script=="dev2" or script=="mlym" or script=="mlm2" then
+ if scripts[script] then
local resources=tfmdata.resources
local devanagari=resources.devanagari
if not devanagari then
- report_devanagari("adding devanagari features to font")
+ report("adding devanagari features to font")
local gsubfeatures=resources.features.gsub
local sequences=resources.sequences
local sharedfeatures=tfmdata.shared.features
@@ -16476,10 +20951,10 @@ local function initializedevanagi(tfmdata)
end
end
local insertindex=lastmatch+1
- gsubfeatures["dv01"]=dev2_defaults
- gsubfeatures["dv02"]=dev2_defaults
- gsubfeatures["dv03"]=dev2_defaults
- gsubfeatures["dv04"]=deva_defaults
+ gsubfeatures["dv01"]=two_defaults
+ gsubfeatures["dv02"]=two_defaults
+ gsubfeatures["dv03"]=two_defaults
+ gsubfeatures["dv04"]=one_defaults
local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants)
local reorder_reph=copy(sequence_reorder_reph)
local reorder_matras=copy(sequence_reorder_matras)
@@ -16527,32 +21002,29 @@ local function initializedevanagi(tfmdata)
end
end
end
- for kind,spec in next,features do
- if spec.dev2 and valid[kind] then
+ for kind,spec in next,features do
+ if valid[kind] and valid_two(spec)then
for i=1,nofsteps do
local step=steps[i]
local coverage=step.coverage
if coverage then
local reph=false
if kind=="rphf" then
- if true then
- for k,v in next,ra do
- local r=coverage[k]
- if r then
- local h=false
- for k,v in next,halant do
- local h=r[k]
- if h then
- reph=h.ligature or false
- break
- end
- end
- if reph then
+ for k,v in next,ra do
+ local r=coverage[k]
+ if r then
+ local h=false
+ for k,v in next,halant do
+ local h=r[k]
+ if h then
+ reph=h.ligature or false
break
end
end
+ if reph then
+ break
+ end
end
- else
end
end
seqsubset[#seqsubset+1]={ kind,coverage,reph }
@@ -16600,8 +21072,14 @@ local function initializedevanagi(tfmdata)
sharedfeatures["pstf"]=true
sharedfeatures["pref"]=true
sharedfeatures["dv03"]=true
- gsubfeatures ["dv03"]=dev2_defaults
+ gsubfeatures ["dv03"]=two_defaults
insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants)
+ elseif script=="taml" then
+ sharedfeatures["dv04"]=true
+sharedfeatures["pstf"]=true
+ elseif script=="tml2" then
+ else
+ report("todo: enable the right features for script %a",script)
end
end
end
@@ -16614,7 +21092,18 @@ registerotffeature {
node=initializedevanagi,
},
}
-local function deva_initialize(font,attr)
+local show_syntax_errors=false
+local function inject_syntax_error(head,current,char)
+ local signal=copy_node(current)
+ copyinjection(signal,current)
+ if pre_mark[char] then
+ setchar(signal,dotted_circle)
+ else
+ setchar(current,dotted_circle)
+ end
+ return insert_node_after(head,current,signal)
+end
+local function initialize_one(font,attr)
local tfmdata=fontdata[font]
local datasets=otf.dataset(tfmdata,font,attr)
local devanagaridata=datasets.devanagari
@@ -16642,8 +21131,8 @@ local function deva_initialize(font,attr)
end
return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache
end
-local function deva_reorder(head,start,stop,font,attr,nbspaces)
- local reph,vattu,blwfcache=deva_initialize(font,attr)
+local function reorder_one(head,start,stop,font,attr,nbspaces)
+ local reph,vattu,blwfcache=initialize_one(font,attr)
local current=start
local n=getnext(start)
local base=nil
@@ -16674,40 +21163,39 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
lastcons=current
current=getnext(current)
if current~=stop then
- if nukta[getchar(current)] then
+ local char=getchar(current)
+ if nukta[char] then
current=getnext(current)
+ char=getchar(current)
end
- if getchar(current)==c_zwj then
- if current~=stop then
- local next=getnext(current)
- if next~=stop and halant[getchar(next)] then
- current=next
- next=getnext(current)
- local tmp=next and getnext(next) or nil
- local changestop=next==stop
- local tempcurrent=copy_node(next)
- copyinjection(tempcurrent,next)
- local nextcurrent=copy_node(current)
- copyinjection(nextcurrent,current)
- setlink(tempcurrent,nextcurrent)
- setprop(tempcurrent,a_state,s_blwf)
- tempcurrent=processcharacters(tempcurrent,font)
- setprop(tempcurrent,a_state,unsetvalue)
- if getchar(next)==getchar(tempcurrent) then
- flush_list(tempcurrent)
- local n=copy_node(current)
- copyinjection(n,current)
- setchar(current,dotted_circle)
- head=insert_node_after(head,current,n)
- else
- setchar(current,getchar(tempcurrent))
- local freenode=getnext(current)
- setlink(current,tmp)
- flush_node(freenode)
- flush_list(tempcurrent)
- if changestop then
- stop=current
- end
+ if char==c_zwj and current~=stop then
+ local next=getnext(current)
+ if next~=stop and halant[getchar(next)] then
+ current=next
+ next=getnext(current)
+ local tmp=next and getnext(next) or nil
+ local changestop=next==stop
+ local tempcurrent=copy_node(next)
+ copyinjection(tempcurrent,next)
+ local nextcurrent=copy_node(current)
+ copyinjection(nextcurrent,current)
+ setlink(tempcurrent,nextcurrent)
+ setprop(tempcurrent,a_state,s_blwf)
+ tempcurrent=processcharacters(tempcurrent,font)
+ setprop(tempcurrent,a_state,unsetvalue)
+ if getchar(next)==getchar(tempcurrent) then
+ flush_list(tempcurrent)
+ if show_syntax_errors then
+ head,current=inject_syntax_error(head,current,char)
+ end
+ else
+ setchar(current,getchar(tempcurrent))
+ local freenode=getnext(current)
+ setlink(current,tmp)
+ flush_node(freenode)
+ flush_list(tempcurrent)
+ if changestop then
+ stop=current
end
end
end
@@ -16980,9 +21468,11 @@ function handlers.devanagari_reorder_reph(head,start)
local startprev=nil
local startfont=getfont(start)
local startattr=getprop(start,a_syllabe)
+ ::step_1::
+ ::step_2::
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
+ if char and getprop(current,a_syllabe)==startattr then
if halant[char] and not getprop(current,a_state) then
local next=getnext(current)
if next then
@@ -17005,16 +21495,17 @@ function handlers.devanagari_reorder_reph(head,start)
break
end
end
+ ::step_3::
+ ::step_4::
if not startnext then
current=getnext(start)
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
+ if char and getprop(current,a_syllabe)==startattr then
if getprop(current,a_state)==s_pstf then
startnext=getnext(start)
head=remove_node(head,start)
- local prev=getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
start=startnext
startattr=getprop(start,a_syllabe)
@@ -17026,13 +21517,14 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
end
+ ::step_5::
if not startnext then
current=getnext(start)
local c=nil
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
- if not c and mark_above_below_post[char] and reorder_class[char]~="after subscript" then
+ if char and getprop(current,a_syllabe)==startattr then
+ if not c and mark_above_below_post[char] and not after_subscript[char] then
c=current
end
current=getnext(current)
@@ -17043,19 +21535,19 @@ function handlers.devanagari_reorder_reph(head,start)
if c then
startnext=getnext(start)
head=remove_node(head,start)
- local prev=getprev(c)
- setlink(prev,start)
+ setlink(getprev(c),start)
setlink(start,c)
start=startnext
startattr=getprop(start,a_syllabe)
end
end
+ ::step_6::
if not startnext then
current=start
local next=getnext(current)
while next do
local nextchar=ischar(next,startfont)
- if nextchar and getprop(next,a_syllabe)==startattr then
+ if nextchar and getprop(next,a_syllabe)==startattr then
current=next
next=getnext(current)
else
@@ -17065,8 +21557,7 @@ function handlers.devanagari_reorder_reph(head,start)
if start~=current then
startnext=getnext(start)
head=remove_node(head,start)
- local next=getnext(current)
- setlink(start,next)
+ setlink(start,getnext(current))
setlink(current,start)
start=startnext
end
@@ -17114,8 +21605,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
if not consonant[char] and getprop(current,a_state) then
startnext=getnext(start)
removenode(start,start)
- local prev=getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
start=startnext
break
@@ -17149,12 +21639,12 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
setnext(prev)
end
if head==start then
- head=stop
+ head=stop
end
flush_list(start)
return head,stop,true
end
-local function dev2_initialize(font,attr)
+local function initialize_two(font,attr)
local devanagari=fontdata[font].resources.devanagari
if devanagari then
return devanagari.seqsubset or {},devanagari.reorderreph or {}
@@ -17162,8 +21652,8 @@ local function dev2_initialize(font,attr)
return {},{}
end
end
-local function dev2_reorder(head,start,stop,font,attr,nbspaces)
- local seqsubset,reorderreph=dev2_initialize(font,attr)
+local function reorder_two(head,start,stop,font,attr,nbspaces)
+ local seqsubset,reorderreph=initialize_two(font,attr)
local reph=false
local halfpos=nil
local basepos=nil
@@ -17188,8 +21678,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if found[n] then
local afternext=next~=stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then
- current=next
- current=getnext(current)
+ current=afternext
elseif current==start then
setprop(current,a_state,s_rphf)
current=next
@@ -17315,7 +21804,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
next=getnext(current)
local tmp=getnext(next)
local changestop=next==stop
- setnext(next,nil)
+ setnext(next)
setprop(current,a_state,s_pref)
current=processcharacters(current,font)
setprop(current,a_state,s_blwf)
@@ -17325,10 +21814,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
setprop(current,a_state,unsetvalue)
if halant[getchar(current)] then
setnext(getnext(current),tmp)
- local nc=copy_node(current)
- copyinjection(nc,current)
- setchar(current,dotted_circle)
- head=insert_node_after(head,current,nc)
+ if show_syntax_errors then
+ head,current=inject_syntax_error(head,current,char)
+ end
else
setnext(current,tmp)
if changestop then
@@ -17408,8 +21896,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
end
start=current
end
- local prev=getprev(halfpos)
- setlink(prev,current)
+ setlink(getprev(halfpos),current)
setlink(current,halfpos)
halfpos=current
elseif above_mark[char] then
@@ -17439,8 +21926,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if current==stop then
stop=prev
end
- local next=getnext(target)
- setlink(current,next)
+ setlink(current,getnext(target))
setlink(target,current)
end
end
@@ -17465,8 +21951,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if stop==next then
stop=current
end
- local prev=getprev(c)
- setlink(prev,next)
+ setlink(getprev(c),next)
local nextnext=getnext(next)
setnext(current,nextnext)
local nextnextnext=getnext(nextnext)
@@ -17700,7 +22185,7 @@ local function analyze_next_chars_two(c,font)
if not v then
return c
end
- if v==c_anudatta then
+ if anudatta[v] then
c=n
n=getnext(c)
if not n then
@@ -17795,31 +22280,20 @@ local function analyze_next_chars_two(c,font)
return c
end
end
-local function inject_syntax_error(head,current,mark)
- local signal=copy_node(current)
- copyinjection(signal,current)
- if mark==pre_mark then
- setchar(signal,dotted_circle)
- else
- setchar(current,dotted_circle)
- end
- return insert_node_after(head,current,signal)
-end
-function methods.deva(head,font,attr)
- head=tonut(head)
+local function method_one(head,font,attr)
local current=head
local start=true
local done=false
local nbspaces=0
while current do
- local char=ischar(current,font)
+ local char=ischar(current,font)
if char then
done=true
local syllablestart=current
local syllableend=nil
local c=current
local n=getnext(c)
- local first=char
+ local first=char
if n and ra[first] then
local second=ischar(n,font)
if second and halant[second] then
@@ -17847,10 +22321,10 @@ function methods.deva(head,font,attr)
end
end
if standalone then
- local syllableend=analyze_next_chars_one(c,font,2)
- current=getnext(syllableend)
+ local syllableend=analyze_next_chars_one(c,font,2)
+ current=getnext(syllableend)
if syllablestart~=syllableend then
- head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current=getnext(current)
end
else
@@ -17947,7 +22421,7 @@ function methods.deva(head,font,attr)
end
end
if syllablestart~=syllableend then
- head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current=getnext(current)
end
elseif independent_vowel[char] then
@@ -17968,9 +22442,11 @@ function methods.deva(head,font,attr)
end
end
else
- local mark=mark_four[char]
- if mark then
- head,current=inject_syntax_error(head,current,mark)
+ if show_syntax_errors then
+ local mark=mark_four[char]
+ if mark then
+ head,current=inject_syntax_error(head,current,char)
+ end
end
current=getnext(current)
end
@@ -17983,11 +22459,9 @@ function methods.deva(head,font,attr)
if nbspaces>0 then
head=replace_all_nbsp(head)
end
- head=tonode(head)
return head,done
end
-function methods.dev2(head,font,attr)
- head=tonut(head)
+local function method_two(head,font,attr)
local current=head
local start=true
local done=false
@@ -18010,7 +22484,7 @@ function methods.dev2(head,font,attr)
local nextnextchar=ischar(n,font)
if nextnextchar then
c=n
- char=nextnextchar
+ char=nextnextchar
end
end
end
@@ -18049,14 +22523,14 @@ function methods.dev2(head,font,attr)
end
end
if syllableend and syllablestart~=syllableend then
- head,current,nbspaces=dev2_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_two(head,syllablestart,syllableend,font,attr,nbspaces)
end
- if not syllableend then
+ if not syllableend and show_syntax_errors then
local char=ischar(current,font)
if char and not getprop(current,a_state) then
local mark=mark_four[char]
if mark then
- head,current=inject_syntax_error(head,current,mark)
+ head,current=inject_syntax_error(head,current,char)
end
end
end
@@ -18066,32 +22540,39 @@ function methods.dev2(head,font,attr)
if nbspaces>0 then
head=replace_all_nbsp(head)
end
- head=tonode(head)
return head,done
end
-methods.mlym=methods.deva
-methods.mlm2=methods.dev2
+for i=1,nofscripts do
+ methods[scripts_one[i]]=method_one
+ methods[scripts_two[i]]=method_two
+end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-osd”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-osd”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ocl” fbc00782e4efb24a7569f99cd1574ffb] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ocl” 49cf3230228aa7f2d19cd491f55f5395] ---
if not modules then modules={} end modules ['font-ocl']={
version=1.001,
- comment="companion to font-otf.lua (context)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local tostring,next,format=tostring,next,string.format
+local tostring,tonumber,next=tostring,tonumber,next
local round,max=math.round,math.round
+local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash
+local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local tounicode=fonts.mappings.tounicode
+local helpers=fonts.helpers
+local charcommand=helpers.commands.char
+local rightcommand=helpers.commands.right
+local leftcommand=helpers.commands.left
+local downcommand=helpers.commands.down
local otf=fonts.handlers.otf
-local f_color=formatters["pdf:direct:%f %f %f rg"]
-local f_gray=formatters["pdf:direct:%f g"]
-local s_black="pdf:direct:0 g"
+local f_color=formatters["%.3f %.3f %.3f rg"]
+local f_gray=formatters["%.3f g"]
if context then
local startactualtext=nil
local stopactualtext=nil
@@ -18106,35 +22587,42 @@ else
local tounicode=fonts.mappings.tounicode16
function otf.getactualtext(s)
return
- "/Span << /ActualText <feff"..n.."> >> BDC",
+ "/Span << /ActualText <feff"..s.."> >> BDC",
"EMC"
end
end
local sharedpalettes={}
+local hash=setmetatableindex(function(t,k)
+ local v={ "pdf","direct",k }
+ t[k]=v
+ return v
+end)
if context then
- local graytorgb=attributes.colors.graytorgb
- local cmyktorgb=attributes.colors.cmyktorgb
+ local colors=attributes.list[attributes.private('color')] or {}
+ local transparencies=attributes.list[attributes.private('transparency')] or {}
function otf.registerpalette(name,values)
sharedpalettes[name]=values
for i=1,#values do
local v=values[i]
- local r,g,b
- local s=v.s
- if s then
- r,g,b=graytorgb(s)
+ local c=nil
+ local t=nil
+ if type(v)=="table" then
+ c=colors.register(name,"rgb",
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )
else
- local c,m,y,k=v.c,v.m,v.y,v.k
- if c or m or y or k then
- r,g,b=cmyktorgb(c or 0,m or 0,y or 0,k or 0)
- else
- r,g,b=v.r,v.g,v.b
- end
+ c=colors[v]
+ t=transparencies[v]
+ end
+ if c and t then
+ values[i]=hash[lpdf.color(1,c).." "..lpdf.transparency(t)]
+ elseif c then
+ values[i]=hash[lpdf.color(1,c)]
+ elseif t then
+ values[i]=hash[lpdf.color(1,t)]
end
- values[i]={
- max(r and round(r*255) or 0,255),
- max(g and round(g*255) or 0,255),
- max(b and round(b*255) or 0,255)
- }
end
end
else
@@ -18142,64 +22630,98 @@ else
sharedpalettes[name]=values
for i=1,#values do
local v=values[i]
- values[i]={
- max(round((v.r or 0)*255),255),
- max(round((v.g or 0)*255),255),
- max(round((v.b or 0)*255),255)
- }
+ values[i]=hash[f_color(
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )]
end
end
end
-local function initializecolr(tfmdata,kind,value)
+local function convert(t,k)
+ local v={}
+ for i=1,#k do
+ local p=k[i]
+ local r,g,b=p[1],p[2],p[3]
+ if r==g and g==b then
+ v[i]=hash[f_gray(r/255)]
+ else
+ v[i]=hash[f_color(r/255,g/255,b/255)]
+ end
+ end
+ t[k]=v
+ return v
+end
+local start={ "pdf","mode","font" }
+local push={ "pdf","page","q" }
+local pop={ "pdf","page","Q" }
+if not LUATEXFUNCTIONALITY or LUATEXFUNCTIONALITY<6472 then
+ start={ "nop" }
+end
+local function initialize(tfmdata,kind,value)
if value then
- local palettes=tfmdata.resources.colorpalettes
+ local resources=tfmdata.resources
+ local palettes=resources.colorpalettes
if palettes then
- local palette=sharedpalettes[value] or palettes[tonumber(value) or 1] or palettes[1] or {}
- local classes=#palette
+ local converted=resources.converted
+ if not converted then
+ converted=setmetatableindex(convert)
+ resources.converted=converted
+ end
+ local colorvalues=sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or {}
+ local classes=#colorvalues
if classes==0 then
return
end
local characters=tfmdata.characters
local descriptions=tfmdata.descriptions
local properties=tfmdata.properties
- local colorvalues={}
properties.virtualized=true
tfmdata.fonts={
{ id=0 }
}
- for i=1,classes do
- local p=palette[i]
- local r,g,b=p[1],p[2],p[3]
- if r==g and g==b then
- colorvalues[i]={ "special",f_gray(r/255) }
- else
- colorvalues[i]={ "special",f_color(r/255,g/255,b/255) }
- end
- end
local getactualtext=otf.getactualtext
+ local default=colorvalues[#colorvalues]
+ local b,e=getactualtext(tounicode(0xFFFD))
+ local actualb={ "pdf","page",b }
+ local actuale={ "pdf","page",e }
for unicode,character in next,characters do
local description=descriptions[unicode]
if description then
local colorlist=description.colors
if colorlist then
- local b,e=getactualtext(tounicode(characters[unicode].unicode or 0xFFFD))
+ local u=description.unicode or characters[unicode].unicode
local w=character.width or 0
local s=#colorlist
+ local goback=w~=0 and leftcommand[w] or nil
local t={
- { "special","pdf:page:q" },
- { "special","pdf:raw:"..b }
+ start,
+ not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) }
}
- local n=#t
+ local n=2
+ local l=nil
+ local f=false
for i=1,s do
local entry=colorlist[i]
- n=n+1 t[n]=colorvalues[entry.class] or s_black
- n=n+1 t[n]={ "char",entry.slot }
- if s>1 and i<s and w~=0 then
- n=n+1 t[n]={ "right",-w }
+ local v=colorvalues[entry.class] or default
+ if v and l~=v then
+ if f then
+ n=n+1 t[n]=pop
+ end
+ n=n+1 t[n]=push
+ f=true
+ n=n+1 t[n]=v
+ l=v
+ end
+ n=n+1 t[n]=charcommand[entry.slot]
+ if s>1 and i<s and goback then
+ n=n+1 t[n]=goback
end
end
- n=n+1 t[n]={ "special","pdf:page:"..e }
- n=n+1 t[n]={ "special","pdf:raw:Q" }
+ if f then
+ n=n+1 t[n]=pop
+ end
+ n=n+1 t[n]=actuale
character.commands=t
end
end
@@ -18211,48 +22733,101 @@ fonts.handlers.otf.features.register {
name="colr",
description="color glyphs",
manipulators={
- base=initializecolr,
- node=initializecolr,
+ base=initialize,
+ node=initialize,
}
}
-local otfsvg=otf.svg or {}
-otf.svg=otfsvg
-otf.svgenabled=true
do
local nofstreams=0
- local f_name=formatters[ [[svg-glyph-%05i]] ]
+ local f_name=formatters[ [[pdf-glyph-%05i]] ]
local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local hashed={}
local cache={}
- function otfsvg.storepdfdata(pdf)
- nofstreams=nofstreams+1
- local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
- cache[n]=o
- return nil,f_used(n),nil
+ if epdf then
+ local openpdf=epdf.openMemStream
+ function otf.storepdfdata(pdf)
+ local done=hashed[pdf]
+ if not done then
+ nofstreams=nofstreams+1
+ local o,n=openpdf(pdf,#pdf,f_name(nofstreams))
+ cache[n]=o
+ done=f_used(n)
+ hashed[pdf]=done
+ end
+ return nil,done,nil
+ end
+ else
+ local openpdf=pdfe.new
+ function otf.storepdfdata(pdf)
+ local done=hashed[pdf]
+ if not done then
+ nofstreams=nofstreams+1
+ local f=f_name(nofstreams)
+ local n=openpdf(pdf,#pdf,f)
+ done=f_used(n)
+ hashed[pdf]=done
+ end
+ return nil,done,nil
+ end
end
- if context then
- local storepdfdata=otfsvg.storepdfdata
- local initialized=false
- function otfsvg.storepdfdata(pdf)
- if not initialized then
- if resolvers.setmemstream then
- local f_setstream=formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
- local f_getstream=formatters[ [[memstream:///svg-glyph-%05i]] ]
- local f_nilstream=formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
- storepdfdata=function(pdf)
- nofstreams=nofstreams+1
- return
- f_setstream(nofstreams,pdf),
- f_getstream(nofstreams),
- f_nilstream(nofstreams)
- end
- otfsvg.storepdfdata=storepdfdata
+end
+local function pdftovirtual(tfmdata,pdfshapes,kind)
+ if not tfmdata or not pdfshapes or not kind then
+ return
+ end
+ local characters=tfmdata.characters
+ local properties=tfmdata.properties
+ local parameters=tfmdata.parameters
+ local hfactor=parameters.hfactor
+ properties.virtualized=true
+ tfmdata.fonts={
+ { id=0 }
+ }
+ local getactualtext=otf.getactualtext
+ local storepdfdata=otf.storepdfdata
+ local b,e=getactualtext(tounicode(0xFFFD))
+ local actualb={ "pdf","page",b }
+ local actuale={ "pdf","page",e }
+ for unicode,character in sortedhash(characters) do
+ local index=character.index
+ if index then
+ local pdf=pdfshapes[index]
+ local typ=type(pdf)
+ local data=nil
+ local dx=nil
+ local dy=nil
+ if typ=="table" then
+ data=pdf.data
+ dx=pdf.dx or 0
+ dy=pdf.dy or 0
+ elseif typ=="string" then
+ data=pdf
+ dx=0
+ dy=0
+ end
+ if data then
+ local setcode,name,nilcode=storepdfdata(data)
+ if name then
+ local bt=unicode and getactualtext(unicode)
+ local wd=character.width or 0
+ local ht=character.height or 0
+ local dp=character.depth or 0
+ character.commands={
+ not unicode and actualb or { "pdf","page",(getactualtext(unicode)) },
+ downcommand[dp+dy*hfactor],
+ rightcommand[dx*hfactor],
+ { "image",{ filename=name,width=wd,height=ht,depth=dp } },
+ actuale,
+ }
+ character[kind]=true
end
- initialized=true
end
- return storepdfdata(pdf)
end
end
end
+local otfsvg=otf.svg or {}
+otf.svg=otfsvg
+otf.svgenabled=true
do
local report_svg=logs.reporter("fonts","svg conversion")
local loaddata=io.loaddata
@@ -18272,52 +22847,68 @@ do
return entry.data
end
end
+ local runner=sandbox and sandbox.registerrunner {
+ name="otfsvg",
+ program="inkscape",
+ method="pipeto",
+ template="--shell > temp-otf-svg-shape.log",
+ reporter=report_svg,
+ }
+ if not runner then
+ runner=function()
+ return io.open("inkscape --shell > temp-otf-svg-shape.log","w")
+ end
+ end
function otfsvg.topdf(svgshapes)
- local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
local pdfshapes={}
- local nofshapes=#svgshapes
- local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
- local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert=formatters["%s --export-pdf=%s\n"]
- local filterglyph=otfsvg.filterglyph
- report_svg("processing %i svg containers",nofshapes)
- statistics.starttiming()
- for i=1,nofshapes do
- local entry=svgshapes[i]
- for index=entry.first,entry.last do
- local data=filterglyph(entry,index)
- if data and data~="" then
- local svgfile=f_svgfile(index)
- local pdffile=f_pdffile(index)
- savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[index]=true
- end
- end
- end
- inkscape:write("quit\n")
- inkscape:close()
- report_svg("processing %i pdf results",nofshapes)
- for index in next,pdfshapes do
- local svgfile=f_svgfile(index)
- local pdffile=f_pdffile(index)
- pdfshapes[index]=loaddata(pdffile)
- remove(svgfile)
- remove(pdffile)
- end
- statistics.stoptiming()
- if statistics.elapsedseconds then
- report_svg("svg conversion time %s",statistics.elapsedseconds())
+ local inkscape=runner()
+ if inkscape then
+ local nofshapes=#svgshapes
+ local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert=formatters["%s --export-pdf=%s\n"]
+ local filterglyph=otfsvg.filterglyph
+ local nofdone=0
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming()
+ for i=1,nofshapes do
+ local entry=svgshapes[i]
+ for index=entry.first,entry.last do
+ local data=filterglyph(entry,index)
+ if data and data~="" then
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
+ savedata(svgfile,data)
+ inkscape:write(f_convert(svgfile,pdffile))
+ pdfshapes[index]=true
+ nofdone=nofdone+1
+ if nofdone%100==0 then
+ report_svg("%i shapes processed",nofdone)
+ end
+ end
+ end
+ end
+ inkscape:write("quit\n")
+ inkscape:close()
+ report_svg("processing %i pdf results",nofshapes)
+ for index in next,pdfshapes do
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
+ pdfshapes[index]=loaddata(pdffile)
+ remove(svgfile)
+ remove(pdffile)
+ end
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
+ end
end
return pdfshapes
end
end
local function initializesvg(tfmdata,kind,value)
if value and otf.svgenabled then
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local properties=tfmdata.properties
- local svg=properties.svg
+ local svg=tfmdata.properties.svg
local hash=svg and svg.hash
local timestamp=svg and svg.timestamp
if not hash then
@@ -18334,40 +22925,7 @@ local function initializesvg(tfmdata,kind,value)
timestamp=timestamp,
})
end
- if not pdfshapes or not next(pdfshapes) then
- return
- end
- properties.virtualized=true
- tfmdata.fonts={
- { id=0 }
- }
- local getactualtext=otf.getactualtext
- local storepdfdata=otfsvg.storepdfdata
- local nop={ "nop" }
- for unicode,character in next,characters do
- local index=character.index
- if index then
- local pdf=pdfshapes[index]
- if pdf then
- local setcode,name,nilcode=storepdfdata(pdf)
- if name then
- local bt,et=getactualtext(unicode)
- local wd=character.width or 0
- local ht=character.height or 0
- local dp=character.depth or 0
- character.commands={
- { "special","pdf:direct:"..bt },
- { "down",dp },
- setcode and { "lua",setcode } or nop,
- { "image",{ filename=name,width=wd,height=ht,depth=dp } },
- nilcode and { "lua",nilcode } or nop,
- { "special","pdf:direct:"..et },
- }
- character.svg=true
- end
- end
- end
- end
+ pdftovirtual(tfmdata,pdfshapes,"svg")
end
end
fonts.handlers.otf.features.register {
@@ -18378,29 +22936,118 @@ fonts.handlers.otf.features.register {
node=initializesvg,
}
}
+local otfsbix=otf.sbix or {}
+otf.sbix=otfsbix
+otf.sbixenabled=true
+do
+ local report_sbix=logs.reporter("fonts","sbix conversion")
+ local loaddata=io.loaddata
+ local savedata=io.savedata
+ local remove=os.remove
+ local runner=sandbox and sandbox.registerrunner {
+ name="otfsbix",
+ program="gm",
+ template="convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log",
+ }
+ if not runner then
+ runner=function()
+ return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log")
+ end
+ end
+ function otfsbix.topdf(sbixshapes)
+ local pdfshapes={}
+ local sbixfile="temp-otf-sbix-shape.sbix"
+ local pdffile="temp-otf-sbix-shape.pdf"
+ local nofdone=0
+ local indices=sortedkeys(sbixshapes)
+ local nofindices=#indices
+ report_sbix("processing %i sbix containers",nofindices)
+ statistics.starttiming()
+ for i=1,nofindices do
+ local index=indices[i]
+ local entry=sbixshapes[index]
+ local data=entry.data
+ local x=entry.x
+ local y=entry.y
+ savedata(sbixfile,data)
+ runner()
+ pdfshapes[index]={
+ x=x~=0 and x or nil,
+ y=y~=0 and y or nil,
+ data=loaddata(pdffile),
+ }
+ nofdone=nofdone+1
+ if nofdone%100==0 then
+ report_sbix("%i shapes processed",nofdone)
+ end
+ end
+ report_sbix("processing %i pdf results",nofindices)
+ remove(sbixfile)
+ remove(pdffile)
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ return pdfshapes
+ end
+end
+local function initializesbix(tfmdata,kind,value)
+ if value and otf.sbixenabled then
+ local sbix=tfmdata.properties.sbix
+ local hash=sbix and sbix.hash
+ local timestamp=sbix and sbix.timestamp
+ if not hash then
+ return
+ end
+ local pdffile=containers.read(otf.pdfcache,hash)
+ local pdfshapes=pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp~=timestamp then
+ local sbixfile=containers.read(otf.sbixcache,hash)
+ local sbixshapes=sbixfile and sbixfile.sbixshapes
+ pdfshapes=sbixshapes and otfsbix.topdf(sbixshapes) or {}
+ containers.write(otf.pdfcache,hash,{
+ pdfshapes=pdfshapes,
+ timestamp=timestamp,
+ })
+ end
+ pdftovirtual(tfmdata,pdfshapes,"sbix")
+ end
+end
+fonts.handlers.otf.features.register {
+ name="sbix",
+ description="sbix glyphs",
+ manipulators={
+ base=initializesbix,
+ node=initializesbix,
+ }
+}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-ocl”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-ocl”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otc” 85d63e257c748c624768aa7c8ec7f0bc] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otc” 9dcd93d83bc61c90f0fb6161a1911a55] ---
if not modules then modules={} end modules ['font-otc']={
version=1.001,
- comment="companion to font-otf.lua (context)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkeys,table.tohash
+local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
local type,next=type,next
local lpegmatch=lpeg.match
local utfbyte,utflen=utf.byte,utf.len
+local sortedhash=table.sortedhash
local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
local registerotffeature=otf.features.register
local setmetatableindex=table.setmetatableindex
+local checkmerge=fonts.helpers.checkmerge
+local checkflags=fonts.helpers.checkflags
+local checksteps=fonts.helpers.checksteps
local normalized={
substitution="substitution",
single="substitution",
@@ -18409,6 +23056,7 @@ local normalized={
multiple="multiple",
kern="kern",
pair="pair",
+ single="single",
chainsubstitution="chainsubstitution",
chainposition="chainposition",
}
@@ -18419,6 +23067,7 @@ local types={
multiple="gsub_multiple",
kern="gpos_pair",
pair="gpos_pair",
+ single="gpos_single",
chainsubstitution="gsub_contextchain",
chainposition="gpos_contextchain",
}
@@ -18550,13 +23199,15 @@ local function addfeature(data,feature,specifications)
local coveractions=coverup.actions
local stepkey=coverup.stepkey
local register=coverup.register
- local function prepare_substitution(list,featuretype)
+ local function prepare_substitution(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip=skip+1
+ else
if type(replacement)=="table" then
replacement=replacement[1]
end
@@ -18567,25 +23218,23 @@ local function addfeature(data,feature,specifications)
else
skip=skip+1
end
- else
- skip=skip+1
end
end
return coverage
end
- local function prepare_alternate(list,featuretype)
+ local function prepare_alternate(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip=skip+1
elseif type(replacement)=="table" then
local r={}
for i=1,#replacement do
local u=tounicode(replacement[i])
- r[i]=descriptions[u] and u or unicode
+ r[i]=(nocheck or descriptions[u]) and u or unicode
end
cover(coverage,unicode,r)
done=done+1
@@ -18601,19 +23250,19 @@ local function addfeature(data,feature,specifications)
end
return coverage
end
- local function prepare_multiple(list,featuretype)
+ local function prepare_multiple(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip=skip+1
elseif type(replacement)=="table" then
local r,n={},0
for i=1,#replacement do
local u=tounicode(replacement[i])
- if descriptions[u] then
+ if nocheck or descriptions[u] then
n=n+1
r[n]=u
end
@@ -18636,13 +23285,15 @@ local function addfeature(data,feature,specifications)
end
return coverage
end
- local function prepare_ligature(list,featuretype)
+ local function prepare_ligature(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,ligature in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip=skip+1
+ else
if type(ligature)=="string" then
ligature={ lpegmatch(splitter,ligature) }
end
@@ -18650,7 +23301,7 @@ local function addfeature(data,feature,specifications)
for i=1,#ligature do
local l=ligature[i]
local u=tounicode(l)
- if descriptions[u] then
+ if nocheck or descriptions[u] then
ligature[i]=u
else
present=false
@@ -18663,15 +23314,18 @@ local function addfeature(data,feature,specifications)
else
skip=skip+1
end
- else
- skip=skip+1
end
end
return coverage
end
+ local function resetspacekerns()
+ data.properties.hasspacekerns=true
+ data.resources .spacekerns=nil
+ end
local function prepare_kern(list,featuretype)
local coverage={}
local cover=coveractions[featuretype]
+ local isspace=false
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
@@ -18681,11 +23335,17 @@ local function addfeature(data,feature,specifications)
local u=tounicode(k)
if u then
r[u]=v
+ if u==32 then
+ isspace=true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done=done+1
+ if unicode==32 then
+ isspace=true
+ end
else
skip=skip+1
end
@@ -18693,6 +23353,9 @@ local function addfeature(data,feature,specifications)
skip=skip+1
end
end
+ if isspace then
+ resetspacekerns()
+ end
return coverage
end
local function prepare_pair(list,featuretype)
@@ -18708,11 +23371,17 @@ local function addfeature(data,feature,specifications)
local u=tounicode(k)
if u then
r[u]=v
+ if u==32 then
+ isspace=true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done=done+1
+ if unicode==32 then
+ isspace=true
+ end
else
skip=skip+1
end
@@ -18720,19 +23389,21 @@ local function addfeature(data,feature,specifications)
skip=skip+1
end
end
+ if isspace then
+ resetspacekerns()
+ end
else
report_otf("unknown cover type %a",featuretype)
end
return coverage
end
+ local prepare_single=prepare_pair
local function prepare_chain(list,featuretype,sublookups)
local rules=list.rules
local coverage={}
if rules then
local rulehash={}
local rulesize=0
- local sequence={}
- local nofsequences=0
local lookuptype=types[featuretype]
for nofrules=1,#rules do
local rule=rules[nofrules]
@@ -18763,14 +23434,29 @@ local function addfeature(data,feature,specifications)
local lookups=rule.lookups or false
local subtype=nil
if lookups and sublookups then
- for k,v in next,lookups do
- local lookup=sublookups[v]
- if lookup then
- lookups[k]=lookup
- if not subtype then
- subtype=lookup.type
+ for k,v in sortedhash(lookups) do
+ local t=type(v)
+ if t=="table" then
+ for i=1,#v do
+ local vi=v[i]
+ if type(vi)~="table" then
+ v[i]={ vi }
+ end
+ end
+ elseif t=="number" then
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]={ lookup }
+ if not subtype then
+ subtype=lookup.type
+ end
+ elseif v==0 then
+ lookups[k]={ { type="gsub_remove" } }
+ else
+ lookups[k]=false
end
else
+ lookups[k]=false
end
end
end
@@ -18799,14 +23485,16 @@ local function addfeature(data,feature,specifications)
replacements,
subtype,
}
- for unic in next,sequence[start] do
+ for unic in sortedhash(sequence[start]) do
local cu=coverage[unic]
if not cu then
coverage[unic]=rulehash
end
end
+ sequence.n=nofsequences
end
end
+ rulehash.n=rulesize
end
return coverage
end
@@ -18844,7 +23532,7 @@ local function addfeature(data,feature,specifications)
local s=sequences[i]
local f=s.features
if f then
- for k in next,f do
+ for k in sortedhash(f) do
if k==position then
index=i
break
@@ -18892,12 +23580,15 @@ local function addfeature(data,feature,specifications)
local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
local featuretype=normalized[specification.type or "substitution"] or "substitution"
local featureflags=specification.flags or noflags
+ local nocheck=specification.nocheck
+ local futuresteps=specification.futuresteps
local featureorder=specification.order or { feature }
local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
local nofsteps=0
local steps={}
local sublookups=specification.lookups
local category=nil
+ checkflags(specification,resources)
if sublookups then
local s={}
for i=1,#sublookups do
@@ -18912,28 +23603,34 @@ local function addfeature(data,feature,specifications)
local coverage=nil
local format=nil
if featuretype=="substitution" then
- coverage=prepare_substitution(list,featuretype)
+ coverage=prepare_substitution(list,featuretype,nocheck)
elseif featuretype=="ligature" then
- coverage=prepare_ligature(list,featuretype)
+ coverage=prepare_ligature(list,featuretype,nocheck)
elseif featuretype=="alternate" then
- coverage=prepare_alternate(list,featuretype)
+ coverage=prepare_alternate(list,featuretype,nocheck)
elseif featuretype=="multiple" then
- coverage=prepare_multiple(list,featuretype)
- elseif featuretype=="kern" then
- format="kern"
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
+ format=featuretype
coverage=prepare_kern(list,featuretype)
elseif featuretype=="pair" then
format="pair"
coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ format="single"
+ coverage=prepare_single(list,featuretype)
end
if coverage and next(coverage) then
nofsteps=nofsteps+1
steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
end
end
+ checkmerge(specification)
+ checksteps(specification)
s[i]={
[stepkey]=steps,
nofsteps=nofsteps,
+ flags=featureflags,
type=types[featuretype],
}
end
@@ -18945,24 +23642,28 @@ local function addfeature(data,feature,specifications)
local format=nil
if featuretype=="substitution" then
category="gsub"
- coverage=prepare_substitution(list,featuretype)
+ coverage=prepare_substitution(list,featuretype,nocheck)
elseif featuretype=="ligature" then
category="gsub"
- coverage=prepare_ligature(list,featuretype)
+ coverage=prepare_ligature(list,featuretype,nocheck)
elseif featuretype=="alternate" then
category="gsub"
- coverage=prepare_alternate(list,featuretype)
+ coverage=prepare_alternate(list,featuretype,nocheck)
elseif featuretype=="multiple" then
category="gsub"
- coverage=prepare_multiple(list,featuretype)
- elseif featuretype=="kern" then
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
category="gpos"
- format="kern"
+ format=featuretype
coverage=prepare_kern(list,featuretype)
elseif featuretype=="pair" then
category="gpos"
format="pair"
coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ category="gpos"
+ format="single"
+ coverage=prepare_single(list,featuretype)
elseif featuretype=="chainsubstitution" then
category="gsub"
coverage=prepare_chain(list,featuretype,sublookups)
@@ -18998,6 +23699,9 @@ local function addfeature(data,feature,specifications)
nofsteps=nofsteps,
type=steptype,
}
+ checkflags(sequence,resources)
+ checkmerge(sequence)
+ checksteps(sequence)
local first,last=getrange(sequences,category)
inject(specification,sequences,sequence,first,last,category,feature)
local features=fontfeatures[category]
@@ -19041,10 +23745,13 @@ function otf.addfeature(name,specification)
specification,name=validspecification(specification,name)
if name and specification then
local slot=knownfeatures[name]
- if slot then
- else
+ if not slot then
slot=#extrafeatures+1
knownfeatures[name]=slot
+ elseif specification.overload==false then
+ slot=#extrafeatures+1
+ knownfeatures[name]=slot
+ else
end
specification.name=name
extrafeatures[slot]=specification
@@ -19058,103 +23765,11 @@ local function enhance(data,filename,raw)
end
otf.enhancers.enhance=enhance
otf.enhancers.register("check extra features",enhance)
-local tlig={
- [0x2013]={ 0x002D,0x002D },
- [0x2014]={ 0x002D,0x002D,0x002D },
-}
-local tlig_specification={
- type="ligature",
- features=everywhere,
- data=tlig,
- order={ "tlig" },
- flags=noflags,
- prepend=true,
-}
-otf.addfeature("tlig",tlig_specification)
-registerotffeature {
- name='tlig',
- description='tex ligatures',
-}
-local trep={
- [0x0027]=0x2019,
-}
-local trep_specification={
- type="substitution",
- features=everywhere,
- data=trep,
- order={ "trep" },
- flags=noflags,
- prepend=true,
-}
-otf.addfeature("trep",trep_specification)
-registerotffeature {
- name='trep',
- description='tex replacements',
-}
-local anum_arabic={
- [0x0030]=0x0660,
- [0x0031]=0x0661,
- [0x0032]=0x0662,
- [0x0033]=0x0663,
- [0x0034]=0x0664,
- [0x0035]=0x0665,
- [0x0036]=0x0666,
- [0x0037]=0x0667,
- [0x0038]=0x0668,
- [0x0039]=0x0669,
-}
-local anum_persian={
- [0x0030]=0x06F0,
- [0x0031]=0x06F1,
- [0x0032]=0x06F2,
- [0x0033]=0x06F3,
- [0x0034]=0x06F4,
- [0x0035]=0x06F5,
- [0x0036]=0x06F6,
- [0x0037]=0x06F7,
- [0x0038]=0x06F8,
- [0x0039]=0x06F9,
-}
-local function valid(data)
- local features=data.resources.features
- if features then
- for k,v in next,features do
- for k,v in next,v do
- if v.arab then
- return true
- end
- end
- end
- end
-end
-local anum_specification={
- {
- type="substitution",
- features={ arab={ urd=true,dflt=true } },
- order={ "anum" },
- data=anum_arabic,
- flags=noflags,
- valid=valid,
- },
- {
- type="substitution",
- features={ arab={ urd=true } },
- order={ "anum" },
- data=anum_persian,
- flags=noflags,
- valid=valid,
- },
-}
-otf.addfeature("anum",anum_specification)
-registerotffeature {
- name='anum',
- description='arabic digits',
-}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-otc”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-otc”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-onr” 205c8bc640715aecf3538a33b842f450] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-onr” cf93eb4ab34461d2b3797792dbdb035f] ---
if not modules then modules={} end modules ['font-onr']={
version=1.001,
@@ -19180,7 +23795,7 @@ local afm=handlers.afm or {}
handlers.afm=afm
local readers=afm.readers or {}
afm.readers=readers
-afm.version=1.512
+afm.version=1.513
local get_indexes,get_shapes
do
local decrypt
@@ -19204,7 +23819,7 @@ do
local dup=P("dup")
local put=P("put")
local array=P("array")
- local name=P("/")*C((R("az")+R("AZ")+R("09")+S("-_."))^1)
+ local name=P("/")*C((R("az","AZ","09")+S("-_."))^1)
local digits=R("09")^1
local cardinal=digits/tonumber
local spaces=P(" ")^1
@@ -19215,30 +23830,38 @@ do
m=size
return position+1
end
- local setroutine=function(str,position,index,size)
+ local setroutine=function(str,position,index,size,filename)
local forward=position+tonumber(size)
- local stream=sub(str,position+1,forward)
- routines[index]=decrypt(stream,4330,4)
+ local stream=decrypt(sub(str,position+1,forward),4330,4)
+ routines[index]={ byte(stream,1,#stream) }
return forward
end
- local setvector=function(str,position,name,size)
+ local setvector=function(str,position,name,size,filename)
local forward=position+tonumber(size)
if n>=m then
return #str
elseif forward<#str then
+ if n==0 and name~=".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename)
+ n=n+1
+ end
vector[n]=name
- n=n+1
+ n=n+1
return forward
else
return #str
end
end
- local setshapes=function(str,position,name,size)
+ local setshapes=function(str,position,name,size,filename)
local forward=position+tonumber(size)
local stream=sub(str,position+1,forward)
if n>m then
return #str
elseif forward<#str then
+ if n==0 and name~=".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename)
+ n=n+1
+ end
vector[n]=name
n=n+1
chars [n]=decrypt(stream,4330,4)
@@ -19251,11 +23874,11 @@ do
local p_np=spacing*(P("NP")+P("|"))
local p_nd=spacing*(P("ND")+P("|"))
local p_filterroutines=
- (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd,setroutine)*p_np+P(1))^1
+ (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd*Carg(1),setroutine)*p_np+P(1))^1
local p_filtershapes=
- (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd,setshapes)*p_nd+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd*Carg(1),setshapes)*p_nd+P(1))^1
local p_filternames=Ct (
- (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,setvector)+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*Carg(1),setvector)+P(1))^1
)
local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
@@ -19266,7 +23889,7 @@ do
report_pfb("no data in %a",filename)
return
end
- if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then
+ if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then
report_pfb("no font in %a",filename)
return
end
@@ -19281,8 +23904,8 @@ do
local glyphs={}
routines,vector,chars={},{},{}
if shapestoo then
- lpegmatch(p_filterroutines,binary)
- lpegmatch(p_filtershapes,binary)
+ lpegmatch(p_filterroutines,binary,1,filename)
+ lpegmatch(p_filtershapes,binary,1,filename)
local data={
dictionaries={
{
@@ -19292,9 +23915,9 @@ do
}
},
}
- fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
+ fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,true)
else
- lpegmatch(p_filternames,binary)
+ lpegmatch(p_filternames,binary,1,filename)
end
names=vector
routines,vector,chars=nil,nil,nil
@@ -19310,7 +23933,7 @@ do
if trace_loading then
report_afm("getting index data from %a",pfbname)
end
- for index=1,#vector do
+ for index=0,#vector do
local name=vector[index]
local char=characters[name]
if char then
@@ -19318,6 +23941,10 @@ do
report_afm("glyph %a has index %a",name,index)
end
char.index=index
+ else
+ if trace_indexing then
+ report_afm("glyph %a has index %a but no data",name,index)
+ end
end
end
end
@@ -19423,7 +24050,6 @@ local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName
+(fontdata*C("AXISHEIGHT")*number*rest)/set_1
)
local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
-local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local infoparser=(P("StartFontMetrics")*fontdata*name/start )*(p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local function read(filename,parser)
local afmblob=io.loaddata(filename)
@@ -19462,16 +24088,15 @@ function readers.loadfont(afmname,pfbname)
local data=read(resolvers.findfile(afmname),fullparser)
if data then
if not pfbname or pfbname=="" then
- pfbname=file.replacesuffix(file.nameonly(afmname),"pfb")
- pfbname=resolvers.findfile(pfbname)
+ pfbname=resolvers.findfile(file.replacesuffix(file.nameonly(afmname),"pfb"))
end
if pfbname and pfbname~="" then
data.resources.filename=resolvers.unresolve(pfbname)
get_indexes(data,pfbname)
- elseif trace_loading then
+ return data
+ else
report_afm("no pfb file for %a",afmname)
end
- return data
end
end
function readers.loadshapes(filename)
@@ -19497,10 +24122,10 @@ function readers.getinfo(filename)
end
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-onr”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-onr”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-one” 6fbf6b9e219a944cd1ad5933d77cc488] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-one” 52588c7c3aab714d95d03e91ee86e1ad] ---
if not modules then modules={} end modules ['font-one']={
version=1.001,
@@ -19511,12 +24136,11 @@ if not modules then modules={} end modules ['font-one']={
}
local fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers
local next,type,tonumber,rawget=next,type,tonumber,rawget
-local match,gmatch,lower,gsub,strip,find=string.match,string.gmatch,string.lower,string.gsub,string.strip,string.find
-local char,byte,sub=string.char,string.byte,string.sub
+local match,gsub=string.match,string.gsub
local abs=math.abs
-local bxor,rshift=bit32.bxor,bit32.rshift
local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg
local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local sortedhash=table.sortedhash
local trace_features=false trackers.register("afm.features",function(v) trace_features=v end)
local trace_indexing=false trackers.register("afm.indexing",function(v) trace_indexing=v end)
local trace_loading=false trackers.register("afm.loading",function(v) trace_loading=v end)
@@ -19525,6 +24149,7 @@ local report_afm=logs.reporter("fonts","afm loading")
local setmetatableindex=table.setmetatableindex
local derivetable=table.derive
local findbinfile=resolvers.findbinfile
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local definers=fonts.definers
local readers=fonts.readers
local constructors=fonts.constructors
@@ -19537,7 +24162,7 @@ local afmfeatures=constructors.features.afm
local registerafmfeature=afmfeatures.register
local afmenhancers=constructors.enhancers.afm
local registerafmenhancer=afmenhancers.register
-afm.version=1.512
+afm.version=1.513
afm.cache=containers.define("fonts","one",afm.version,true)
afm.autoprefixed=true
afm.helpdata={}
@@ -19550,7 +24175,7 @@ function afm.load(filename)
local name=file.removesuffix(file.basename(filename))
local data=containers.read(afm.cache,name)
local attr=lfs.attributes(filename)
- local size,time=attr.size or 0,attr.modification or 0
+ local size,time=attr and attr.size or 0,attr and attr.modification or 0
local pfbfile=file.replacesuffix(name,"pfb")
local pfbname=resolvers.findfile(pfbfile,"pfb") or ""
if pfbname=="" then
@@ -19595,9 +24220,9 @@ local function enhance_unify_names(data,filename)
local unicodevector=fonts.encodings.agl.unicodes
local unicodes={}
local names={}
- local private=constructors.privateoffset
+ local private=data.private or privateoffset
local descriptions=data.descriptions
- for name,blob in next,data.characters do
+ for name,blob in sortedhash(data.characters) do
local code=unicodevector[name]
if not code then
code=lpegmatch(uparser,name)
@@ -19634,12 +24259,12 @@ local function enhance_unify_names(data,filename)
end
end
data.characters=nil
+ data.private=private
local resources=data.resources
local filename=resources.filename or file.removesuffix(file.basename(filename))
resources.filename=resolvers.unresolve(filename)
resources.unicodes=unicodes
resources.marks={}
- resources.private=private
end
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
@@ -19993,6 +24618,7 @@ local function copytotfm(data)
properties.fullname=fullname
properties.psname=fullname
properties.name=filename or fullname or fontname
+ properties.private=properties.private or data.private or privateoffset
if next(characters) then
return {
characters=characters,
@@ -20198,14 +24824,14 @@ registerafmenhancer("normalize features",enhance_normalize_features)
registerafmenhancer("check extra features",otfenhancers.enhance)
registerafmenhancer("fix names",enhance_fix_names)
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-one”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-one”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-afk” b36a76ceb835f41f8c05b471000ddc14] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-afk” 9da14e0fb22129c053acc599d1312544] ---
if not modules then modules={} end modules ['font-afk']={
version=1.001,
- comment="companion to font-afm.lua",
+ comment="companion to font-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
@@ -20368,10 +24994,10 @@ fonts.handlers.afm.helpdata={
}
}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-afk”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-afk”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-tfm” 3d813578dbf6c447e4b859c2bf0618f7] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-tfm” c9797c1b4ccb8fdb7f041e19207109a2] ---
if not modules then modules={} end modules ['font-tfm']={
version=1.001,
@@ -20391,6 +25017,7 @@ local findbinfile=resolvers.findbinfile
local setmetatableindex=table.setmetatableindex
local fonts=fonts
local handlers=fonts.handlers
+local helpers=fonts.helpers
local readers=fonts.readers
local constructors=fonts.constructors
local encodings=fonts.encodings
@@ -20404,6 +25031,7 @@ local tfmfeatures=constructors.features.tfm
local registertfmfeature=tfmfeatures.register
local tfmenhancers=constructors.enhancers.tfm
local registertfmenhancer=tfmenhancers.register
+local charcommand=helpers.commands.char
constructors.resolvevirtualtoo=false
fonts.formats.tfm="type1"
fonts.formats.ofm="type1"
@@ -20497,6 +25125,7 @@ local function read_from_tfm(specification)
parameters.quad=parameters.quad or parameters[6] or 0
parameters.extra_space=parameters.extra_space or parameters[7] or 0
constructors.enhanceparameters(parameters)
+ properties.private=properties.private or tfmdata.private or privateoffset
if newtfmdata then
elseif constructors.resolvevirtualtoo then
fonts.loggers.register(tfmdata,file.suffix(filename),specification)
@@ -20643,7 +25272,7 @@ do
local originals=tfmdata.characters
local indices={}
local parentfont={ "font",1 }
- local private=fonts.constructors.privateoffset
+ local private=tfmdata or fonts.constructors.privateoffset
local reported=encdone[tfmfile][encfile]
local backmap=vector and table.swapped(vector)
local done={}
@@ -20666,7 +25295,7 @@ do
if backmap then
original.index=backmap[name]
else
- original.commands={ parentfont,{ "char",index } }
+ original.commands={ parentfont,charcommand[index] }
original.oindex=index
end
done[name]=true
@@ -20710,6 +25339,7 @@ do
tfmdata.tounicode=1
tfmdata.embedding="subset"
tfmdata.usedbitmap=bitmap and virtualid
+ tfmdata.private=private
return tfmdata
end
end
@@ -20734,7 +25364,8 @@ end
]]
local flushstreamobject=lpdf and lpdf.flushstreamobject
local setfontattributes=pdf.setfontattributes
- if not flushstreamobject then
+ if flushstreamobject then
+ else
flushstreamobject=function(data)
return pdf.obj {
immediate=true,
@@ -20877,10 +25508,10 @@ registertfmfeature {
}
}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-tfm”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-tfm”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-lua” 1fbfdf7b689b2bdfd0e3bb9bf74ce136] ---
if not modules then modules={} end modules ['font-lua']={
version=1.001,
@@ -20920,10 +25551,10 @@ function readers.lua(specification)
return check_lua(specification,fullname)
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-lua”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-lua”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-def” 49fa2b50d8d2a1bb70b08b72f858ecd0] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-def” 8e2cb2552bf02246da2ac43334b91795] ---
if not modules then modules={} end modules ['font-def']={
version=1.001,
@@ -20935,13 +25566,13 @@ if not modules then modules={} end modules ['font-def']={
local lower,gsub=string.lower,string.gsub
local tostring,next=tostring,next
local lpegmatch=lpeg.match
-local suffixonly,removesuffix=file.suffix,file.removesuffix
+local suffixonly,removesuffix,basename=file.suffix,file.removesuffix,file.basename
local formatters=string.formatters
+local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
local allocate=utilities.storage.allocate
local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end)
trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading")
-trackers.register("fonts.all","fonts.*","otf.*","afm.*","tfm.*")
local report_defining=logs.reporter("fonts","defining")
local fonts=fonts
local fontdata=fonts.hashes.identifiers
@@ -20959,41 +25590,6 @@ local lastdefined=nil
local loadedfonts=constructors.loadedfonts
local designsizes=constructors.designsizes
local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end
-local splitter,splitspecifiers=nil,""
-local P,C,S,Cc=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc
-local left=P("(")
-local right=P(")")
-local colon=P(":")
-local space=P(" ")
-definers.defaultlookup="file"
-local prefixpattern=P(false)
-local function addspecifier(symbol)
- splitspecifiers=splitspecifiers..symbol
- local method=S(splitspecifiers)
- local lookup=C(prefixpattern)*colon
- local sub=left*C(P(1-left-right-method)^1)*right
- local specification=C(method)*C(P(1)^1)
- local name=C((1-sub-specification)^1)
- splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc("")))
-end
-local function addlookup(str,default)
- prefixpattern=prefixpattern+P(str)
-end
-definers.addlookup=addlookup
-addlookup("file")
-addlookup("name")
-addlookup("spec")
-local function getspecification(str)
- return lpegmatch(splitter,str or "")
-end
-definers.getspecification=getspecification
-function definers.registersplit(symbol,action,verbosename)
- addspecifier(symbol)
- variants[symbol]=action
- if verbosename then
- variants[verbosename]=action
- end
-end
local function makespecification(specification,lookup,name,sub,method,detail,size)
size=size or 655360
if not lookup or lookup=="" then
@@ -21018,9 +25614,48 @@ local function makespecification(specification,lookup,name,sub,method,detail,siz
return t
end
definers.makespecification=makespecification
-function definers.analyze(specification,size)
- local lookup,name,sub,method,detail=getspecification(specification or "")
- return makespecification(specification,lookup,name,sub,method,detail,size)
+if context then
+ local splitter,splitspecifiers=nil,""
+ local P,C,S,Cc,Cs=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc,lpeg.Cs
+ local left=P("(")
+ local right=P(")")
+ local colon=P(":")
+ local space=P(" ")
+ local lbrace=P("{")
+ local rbrace=P("}")
+ definers.defaultlookup="file"
+ local prefixpattern=P(false)
+ local function addspecifier(symbol)
+ splitspecifiers=splitspecifiers..symbol
+ local method=S(splitspecifiers)
+ local lookup=C(prefixpattern)*colon
+ local sub=left*C(P(1-left-right-method)^1)*right
+ local specification=C(method)*C(P(1)^1)
+ local name=Cs((lbrace/"")*(1-rbrace)^1*(rbrace/"")+(1-sub-specification)^1)
+ splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc("")))
+ end
+ local function addlookup(str)
+ prefixpattern=prefixpattern+P(str)
+ end
+ definers.addlookup=addlookup
+ addlookup("file")
+ addlookup("name")
+ addlookup("spec")
+ local function getspecification(str)
+ return lpegmatch(splitter,str or "")
+ end
+ definers.getspecification=getspecification
+ function definers.registersplit(symbol,action,verbosename)
+ addspecifier(symbol)
+ variants[symbol]=action
+ if verbosename then
+ variants[verbosename]=action
+ end
+ end
+ function definers.analyze(specification,size)
+ local lookup,name,sub,method,detail=getspecification(specification or "")
+ return makespecification(specification,lookup,name,sub,method,detail,size)
+ end
end
definers.resolvers=definers.resolvers or {}
local resolvers=definers.resolvers
@@ -21038,11 +25673,28 @@ end
function resolvers.name(specification)
local resolve=fonts.names.resolve
if resolve then
- local resolved,sub,subindex=resolve(specification.name,specification.sub,specification)
+ local resolved,sub,subindex,instance=resolve(specification.name,specification.sub,specification)
if resolved then
specification.resolved=resolved
specification.sub=sub
specification.subindex=subindex
+ if instance then
+ specification.instance=instance
+ local features=specification.features
+ if not features then
+ features={}
+ specification.features=features
+ end
+ local normal=features.normal
+ if not normal then
+ normal={}
+ features.normal=normal
+ end
+ normal.instance=instance
+ if not callbacks.supported.glyph_stream_provider then
+ normal.variableshapes=true
+ end
+ end
local suffix=lower(suffixonly(resolved))
if fonts.formats[suffix] then
specification.forced=suffix
@@ -21120,6 +25772,60 @@ local function checkembedding(tfmdata)
end
tfmdata.embedding=embedding
end
+local function checkfeatures(tfmdata)
+ local resources=tfmdata.resources
+ local shared=tfmdata.shared
+ if resources and shared then
+ local features=resources.features
+ local usedfeatures=shared.features
+ if features and usedfeatures then
+ local usedlanguage=usedfeatures.language or "dflt"
+ local usedscript=usedfeatures.script or "dflt"
+ local function check(what)
+ if what then
+ local foundlanguages={}
+ for feature,scripts in next,what do
+ if usedscript=="auto" or scripts["*"] then
+ elseif not scripts[usedscript] then
+ else
+ for script,languages in next,scripts do
+ if languages["*"] then
+ elseif not languages[usedlanguage] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,usedlanguage)
+ end
+ end
+ end
+ for script,languages in next,scripts do
+ for language in next,languages do
+ foundlanguages[language]=true
+ end
+ end
+ end
+ if false then
+ foundlanguages["*"]=nil
+ foundlanguages=sortedkeys(foundlanguages)
+ for feature,scripts in sortedhash(what) do
+ for script,languages in next,scripts do
+ if not languages["*"] then
+ for i=1,#foundlanguages do
+ local language=foundlanguages[i]
+ if not languages[language] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,language)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ check(features.gsub)
+ check(features.gpos)
+ end
+ end
+end
function definers.loadfont(specification)
local hash=constructors.hashinstance(specification)
local tfmdata=loadedfonts[hash]
@@ -21153,6 +25859,7 @@ function definers.loadfont(specification)
checkembedding(tfmdata)
loadedfonts[hash]=tfmdata
designsizes[specification.hash]=tfmdata.parameters.designsize
+ checkfeatures(tfmdata)
end
end
if not tfmdata then
@@ -21160,8 +25867,6 @@ function definers.loadfont(specification)
end
return tfmdata
end
-function constructors.checkvirtualids()
-end
function constructors.readanddefine(name,size)
local specification=definers.analyze(name,size)
local method=specification.method
@@ -21175,7 +25880,6 @@ function constructors.readanddefine(name,size)
local tfmdata=definers.loadfont(specification)
if tfmdata then
tfmdata.properties.hash=hash
- constructors.checkvirtualids(tfmdata)
id=font.define(tfmdata)
definers.register(tfmdata,id)
else
@@ -21244,8 +25948,8 @@ function definers.read(specification,size,id)
local properties=tfmdata.properties or {}
local parameters=tfmdata.parameters or {}
report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
- properties.format or "unknown",id,properties.name,parameters.size,properties.encodingbytes,
- properties.encodingname,properties.fullname,file.basename(properties.filename))
+ properties.format or "unknown",id or "-",properties.name,parameters.size,properties.encodingbytes,
+ properties.encodingname,properties.fullname,basename(properties.filename))
end
statistics.stoptiming(fonts)
return tfmdata
@@ -21255,12 +25959,12 @@ function font.getfont(id)
end
callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)")
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-def”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-def”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-ext” aff3846f4c1f15de0a9f4fd7081e0c68] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-def” f435e0875f203f343157baeff876ec9c] ---
-if not modules then modules={} end modules ['luatex-fonts-ext']={
+if not modules then modules={} end modules ['luatex-fonts-def']={
version=1.001,
comment="companion to luatex-*.tex",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -21268,72 +25972,120 @@ if not modules then modules={} end modules ['luatex-fonts-ext']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
local fonts=fonts
-local otffeatures=fonts.constructors.features.otf
-local function initializeitlc(tfmdata,value)
- if value then
- local parameters=tfmdata.parameters
- local italicangle=parameters.italicangle
- if italicangle and italicangle~=0 then
- local properties=tfmdata.properties
- local factor=tonumber(value) or 1
- properties.hasitalics=true
- properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
- end
- end
+fonts.constructors.namemode="specification"
+function fonts.definers.getspecification(str)
+ return "",str,"",":",str
+end
+local list={}
+local function issome () list.lookup='name' end
+local function isfile () list.lookup='file' end
+local function isname () list.lookup='name' end
+local function thename(s) list.name=s end
+local function issub (v) list.sub=v end
+local function iscrap (s) list.crap=string.lower(s) end
+local function iskey (k,v) list[k]=v end
+local function istrue (s) list[s]=true end
+local function isfalse(s) list[s]=false end
+local P,S,R,C,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs
+local spaces=P(" ")^0
+local namespec=Cs((P("{")/"")*(1-S("}"))^0*(P("}")/"")+(1-S("/:("))^0)
+local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces
+local filename_1=P("file:")/isfile*(namespec/thename)
+local filename_2=P("[")*P(true)/isfile*(((1-P("]"))^0)/thename)*P("]")
+local fontname_1=P("name:")/isname*(namespec/thename)
+local fontname_2=P(true)/issome*(namespec/thename)
+local sometext=R("az","AZ","09")^1
+local somekey=R("az","AZ","09")^1
+local somevalue=(P("{")/"")*(1-P("}"))^0*(P("}")/"")+(1-S(";"))^1
+local truevalue=P("+")*spaces*(sometext/istrue)
+local falsevalue=P("-")*spaces*(sometext/isfalse)
+local keyvalue=(C(somekey)*spaces*P("=")*spaces*C(somevalue))/iskey
+local somevalue=sometext/istrue
+local subvalue=P("(")*(C(P(1-S("()"))^1)/issub)*P(")")
+local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces
+local options=P(":")*spaces*(P(";")^0*option)^0
+local pattern=(filename_1+filename_2+fontname_1+fontname_2)*subvalue^0*crapspec^0*options^0
+function fonts.definers.analyze(str,size)
+ local specification=fonts.definers.makespecification(str,nil,nil,nil,":",nil,size)
+ list={}
+ lpeg.match(pattern,str)
+ list.crap=nil
+ if list.name then
+ specification.name=list.name
+ list.name=nil
+ end
+ if list.lookup then
+ specification.lookup=list.lookup
+ list.lookup=nil
+ end
+ if list.sub then
+ specification.sub=list.sub
+ list.sub=nil
+ end
+ specification.features.normal=fonts.handlers.otf.features.normalize(list)
+ list=nil
+ return specification
end
-otffeatures.register {
- name="itlc",
- description="italic correction",
- initializers={
- base=initializeitlc,
- node=initializeitlc,
- }
-}
-local function initializeslant(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>1 then
- value=1
- elseif value<-1 then
- value=-1
+function fonts.definers.applypostprocessors(tfmdata)
+ local postprocessors=tfmdata.postprocessors
+ if postprocessors then
+ for i=1,#postprocessors do
+ local extrahash=postprocessors[i](tfmdata)
+ if type(extrahash)=="string" and extrahash~="" then
+ extrahash=string.gsub(lower(extrahash),"[^a-z]","-")
+ tfmdata.properties.fullname=format("%s-%s",tfmdata.properties.fullname,extrahash)
+ end
+ end
end
- tfmdata.parameters.slantfactor=value
+ return tfmdata
end
-otffeatures.register {
- name="slant",
- description="slant glyphs",
- initializers={
- base=initializeslant,
- node=initializeslant,
- }
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-def”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-ext” 32013cbc5d5d336be8b1d1e5879d86c4] ---
+
+if not modules then modules={} end modules ['luatex-fonts-ext']={
+ version=1.001,
+ comment="companion to luatex-*.tex",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
}
-local function initializeextend(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>10 then
- value=10
- elseif value<-10 then
- value=-10
- end
- tfmdata.parameters.extendfactor=value
+if context then
+ os.exit()
end
-otffeatures.register {
- name="extend",
- description="scale glyphs horizontally",
- initializers={
- base=initializeextend,
- node=initializeextend,
- }
-}
+local byte=string.byte
+local fonts=fonts
+local handlers=fonts.handlers
+local otf=handlers.otf
+local afm=handlers.afm
+local registerotffeature=otf.features.register
+local registerafmfeature=afm.features.register
+function fonts.loggers.onetimemessage() end
fonts.protrusions=fonts.protrusions or {}
fonts.protrusions.setups=fonts.protrusions.setups or {}
local setups=fonts.protrusions.setups
+setups['default']={
+ factor=1,
+ left=1,
+ right=1,
+ [0x002C]={ 0,1 },
+ [0x002E]={ 0,1 },
+ [0x003A]={ 0,1 },
+ [0x003B]={ 0,1 },
+ [0x002D]={ 0,1 },
+ [0x2013]={ 0,0.50 },
+ [0x2014]={ 0,0.33 },
+ [0x3001]={ 0,1 },
+ [0x3002]={ 0,1 },
+ [0x060C]={ 0,1 },
+ [0x061B]={ 0,1 },
+ [0x06D4]={ 0,1 },
+}
local function initializeprotrusion(tfmdata,value)
if value then
local setup=setups[value]
@@ -21354,7 +26106,7 @@ local function initializeprotrusion(tfmdata,value)
end
end
end
-otffeatures.register {
+local specification={
name="protrusion",
description="shift characters into the left and or right margin",
initializers={
@@ -21362,9 +26114,26 @@ otffeatures.register {
node=initializeprotrusion,
}
}
+registerotffeature(specification)
+registerafmfeature(specification)
fonts.expansions=fonts.expansions or {}
fonts.expansions.setups=fonts.expansions.setups or {}
local setups=fonts.expansions.setups
+setups['default']={
+ stretch=2,
+ shrink=2,
+ step=.5,
+ factor=1,
+ [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
+ [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
+ [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
+ [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
+ [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
+ [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
+ [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
+ [byte('w')]=0.7,[byte('z')]=0.7,
+ [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
+}
local function initializeexpansion(tfmdata,value)
if value then
local setup=setups[value]
@@ -21387,7 +26156,7 @@ local function initializeexpansion(tfmdata,value)
end
end
end
-otffeatures.register {
+local specification={
name="expansion",
description="apply hz optimization",
initializers={
@@ -21395,40 +26164,15 @@ otffeatures.register {
node=initializeexpansion,
}
}
-function fonts.loggers.onetimemessage() end
-local byte=string.byte
-fonts.expansions.setups['default']={
- stretch=2,shrink=2,step=.5,factor=1,
- [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
- [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
- [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
- [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
- [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
- [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
- [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
- [byte('w')]=0.7,[byte('z')]=0.7,
- [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
-}
-fonts.protrusions.setups['default']={
- factor=1,left=1,right=1,
- [0x002C]={ 0,1 },
- [0x002E]={ 0,1 },
- [0x003A]={ 0,1 },
- [0x003B]={ 0,1 },
- [0x002D]={ 0,1 },
- [0x2013]={ 0,0.50 },
- [0x2014]={ 0,0.33 },
- [0x3001]={ 0,1 },
- [0x3002]={ 0,1 },
- [0x060C]={ 0,1 },
- [0x061B]={ 0,1 },
- [0x06D4]={ 0,1 },
-}
-fonts.handlers.otf.features.normalize=function(t)
- if t.rand then
- t.rand="random"
+registerotffeature(specification)
+registerafmfeature(specification)
+if not otf.features.normalize then
+ otf.features.normalize=function(t)
+ if t.rand then
+ t.rand="random"
+ end
+ return t
end
- return t
end
function fonts.helpers.nametoslot(name)
local t=type(name)
@@ -21458,7 +26202,7 @@ local function specialreencode(tfmdata,value)
return string.format("reencoded:%s",value)
end
end
-local function reencode(tfmdata,value)
+local function initialize(tfmdata,value)
tfmdata.postprocessors=tfmdata.postprocessors or {}
table.insert(tfmdata.postprocessors,
function(tfmdata)
@@ -21466,34 +26210,2794 @@ local function reencode(tfmdata,value)
end
)
end
-otffeatures.register {
+registerotffeature {
name="reencode",
description="reencode characters",
manipulators={
- base=reencode,
- node=reencode,
+ base=initialize,
+ node=initialize,
}
}
-local function ignore(tfmdata,key,value)
+local function initialize(tfmdata,key,value)
if value then
tfmdata.mathparameters=nil
end
end
-otffeatures.register {
+registerotffeature {
name="ignoremathconstants",
description="ignore math constants table",
initializers={
- base=ignore,
- node=ignore,
+ base=initialize,
+ node=initialize,
+ }
+}
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-ext”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-tex” ceb087ef6fa2f89aed7179f60ddf8f35] ---
+
+if not modules then modules={} end modules ['font-imp-tex']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next=next
+local fonts=fonts
+local otf=fonts.handlers.otf
+local registerotffeature=otf.features.register
+local addotffeature=otf.addfeature
+local specification={
+ type="ligature",
+ order={ "tlig" },
+ prepend=true,
+ data={
+ [0x2013]={ 0x002D,0x002D },
+ [0x2014]={ 0x002D,0x002D,0x002D },
+ },
+}
+addotffeature("tlig",specification)
+registerotffeature {
+ name="tlig",
+ description="tex ligatures",
+}
+local specification={
+ type="substitution",
+ order={ "trep" },
+ prepend=true,
+ data={
+ [0x0027]=0x2019,
+ },
+}
+addotffeature("trep",specification)
+registerotffeature {
+ name="trep",
+ description="tex replacements",
+}
+local anum_arabic={
+ [0x0030]=0x0660,
+ [0x0031]=0x0661,
+ [0x0032]=0x0662,
+ [0x0033]=0x0663,
+ [0x0034]=0x0664,
+ [0x0035]=0x0665,
+ [0x0036]=0x0666,
+ [0x0037]=0x0667,
+ [0x0038]=0x0668,
+ [0x0039]=0x0669,
+}
+local anum_persian={
+ [0x0030]=0x06F0,
+ [0x0031]=0x06F1,
+ [0x0032]=0x06F2,
+ [0x0033]=0x06F3,
+ [0x0034]=0x06F4,
+ [0x0035]=0x06F5,
+ [0x0036]=0x06F6,
+ [0x0037]=0x06F7,
+ [0x0038]=0x06F8,
+ [0x0039]=0x06F9,
+}
+local function valid(data)
+ local features=data.resources.features
+ if features then
+ for k,v in next,features do
+ for k,v in next,v do
+ if v.arab then
+ return true
+ end
+ end
+ end
+ end
+end
+local specification={
+ {
+ type="substitution",
+ features={ arab={ urd=true,dflt=true } },
+ order={ "anum" },
+ data=anum_arabic,
+ valid=valid,
+ },
+ {
+ type="substitution",
+ features={ arab={ urd=true } },
+ order={ "anum" },
+ data=anum_persian,
+ valid=valid,
+ },
+}
+addotffeature("anum",specification)
+registerotffeature {
+ name="anum",
+ description="arabic digits",
+}
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-tex”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-ligatures” 26ffcf089391445f7af59536c8814364] ---
+
+if not modules then modules={} end modules ['font-imp-ligatures']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local lpegmatch=lpeg.match
+local utfsplit=utf.split
+local settings_to_array=utilities.parsers.settings_to_array
+local fonts=fonts
+local otf=fonts.handlers.otf
+local registerotffeature=otf.features.register
+local addotffeature=otf.addfeature
+local lookups={}
+local protect={}
+local revert={}
+local zwjchar=0x200C
+local zwj={ zwjchar }
+addotffeature {
+ name="blockligatures",
+ type="chainsubstitution",
+ nocheck=true,
+ prepend=true,
+ future=true,
+ lookups={
+ {
+ type="multiple",
+ data=lookups,
+ },
+ },
+ data={
+ rules=protect,
+ }
+}
+addotffeature {
+ name="blockligatures",
+ type="chainsubstitution",
+ nocheck=true,
+ append=true,
+ overload=false,
+ lookups={
+ {
+ type="ligature",
+ data=lookups,
+ },
+ },
+ data={
+ rules=revert,
+ }
+}
+registerotffeature {
+ name='blockligatures',
+ description='block certain ligatures',
+}
+local splitter=lpeg.splitat(":")
+local function blockligatures(str)
+ local t=settings_to_array(str)
+ for i=1,#t do
+ local ti=t[i]
+ local before,current,after=lpegmatch(splitter,ti)
+ if current and after then
+ if before then
+ before=utfsplit(before)
+ for i=1,#before do
+ before[i]={ before[i] }
+ end
+ end
+ if current then
+ current=utfsplit(current)
+ end
+ if after then
+ after=utfsplit(after)
+ for i=1,#after do
+ after[i]={ after[i] }
+ end
+ end
+ else
+ before=nil
+ current=utfsplit(ti)
+ after=nil
+ end
+ if #current>1 then
+ local one=current[1]
+ local two=current[2]
+ lookups[one]={ one,zwjchar }
+ local one={ one }
+ local two={ two }
+ local new=#protect+1
+ protect[new]={
+ before=before,
+ current={ one,two },
+ after=after,
+ lookups={ 1 },
+ }
+ revert[new]={
+ current={ one,zwj },
+ after={ two },
+ lookups={ 1 },
+ }
+ end
+ end
+end
+otf.helpers.blockligatures=blockligatures
+if context then
+ interfaces.implement {
+ name="blockligatures",
+ arguments="string",
+ actions=blockligatures,
+ }
+end
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-ligatures”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-italics” c2e6d6c4096a2c30d68fbffd3d7d58a7] ---
+
+if not modules then modules={} end modules ['font-imp-italics']={
+ version=1.001,
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next=next
+local fonts=fonts
+local handlers=fonts.handlers
+local registerotffeature=handlers.otf.features.register
+local registerafmfeature=handlers.afm.features.register
+local function initialize(tfmdata,key,value)
+ for unicode,character in next,tfmdata.characters do
+ local olditalic=character.italic
+ if olditalic and olditalic~=0 then
+ character.width=character.width+olditalic
+ character.italic=0
+ end
+ end
+end
+local specification={
+ name="italicwidths",
+ description="add italic to width",
+ manipulators={
+ base=initialize,
+ node=initialize,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initialize(tfmdata,value)
+ if value then
+ local parameters=tfmdata.parameters
+ local italicangle=parameters.italicangle
+ if italicangle and italicangle~=0 then
+ local properties=tfmdata.properties
+ local factor=tonumber(value) or 1
+ properties.hasitalics=true
+ properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
+ end
+ end
+end
+local specification={
+ name="itlc",
+ description="italic correction",
+ initializers={
+ base=initialize,
+ node=initialize,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+if context then
+ local function initialize(tfmdata,value)
+ tfmdata.properties.textitalics=toboolean(value)
+ end
+ local specification={
+ name="textitalics",
+ description="use alternative text italic correction",
+ initializers={
+ base=initialize,
+ node=initialize,
+ }
+ }
+ registerotffeature(specification)
+ registerafmfeature(specification)
+end
+if context then
+ local letter=characters.is_letter
+ local always=true
+ local function collapseitalics(tfmdata,key,value)
+ local threshold=value==true and 100 or tonumber(value)
+ if threshold and threshold>0 then
+ if threshold>100 then
+ threshold=100
+ end
+ for unicode,data in next,tfmdata.characters do
+ if always or letter[unicode] or letter[data.unicode] then
+ local italic=data.italic
+ if italic and italic~=0 then
+ local width=data.width
+ if width and width~=0 then
+ local delta=threshold*italic/100
+ data.width=width+delta
+ data.italic=italic-delta
+ end
+ end
+ end
+ end
+ end
+ end
+ local dimensions_specification={
+ name="collapseitalics",
+ description="collapse italics",
+ manipulators={
+ base=collapseitalics,
+ node=collapseitalics,
+ }
+ }
+ registerotffeature(dimensions_specification)
+ registerafmfeature(dimensions_specification)
+end
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-italics”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-effects” 3327181ef3db6f44dd234ad66ccc3f38] ---
+
+if not modules then modules={} end modules ['font-imp-effects']={
+ version=1.001,
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,tonumber=next,type,tonumber
+local is_boolean=string.is_boolean
+local fonts=fonts
+local handlers=fonts.handlers
+local registerotffeature=handlers.otf.features.register
+local registerafmfeature=handlers.afm.features.register
+local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
+local helpers=fonts.helpers
+local prependcommands=helpers.prependcommands
+local charcommand=helpers.commands.char
+local leftcommand=helpers.commands.left
+local rightcommand=helpers.commands.right
+local upcommand=helpers.commands.up
+local downcommand=helpers.commands.down
+local dummycommand=helpers.commands.dummy
+local report_effect=logs.reporter("fonts","effect")
+local report_slant=logs.reporter("fonts","slant")
+local report_extend=logs.reporter("fonts","extend")
+local report_squeeze=logs.reporter("fonts","squeeze")
+local trace=false
+trackers.register("fonts.effect",function(v) trace=v end)
+trackers.register("fonts.slant",function(v) trace=v end)
+trackers.register("fonts.extend",function(v) trace=v end)
+trackers.register("fonts.squeeze",function(v) trace=v end)
+local function initializeslant(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>1 then
+ value=1
+ elseif value<-1 then
+ value=-1
+ end
+ if trace then
+ report_slant("applying %0.3f",value)
+ end
+ tfmdata.parameters.slantfactor=value
+end
+local specification={
+ name="slant",
+ description="slant glyphs",
+ initializers={
+ base=initializeslant,
+ node=initializeslant,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializeextend(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>10 then
+ value=10
+ elseif value<-10 then
+ value=-10
+ end
+ if trace then
+ report_extend("applying %0.3f",value)
+ end
+ tfmdata.parameters.extendfactor=value
+end
+local specification={
+ name="extend",
+ description="scale glyphs horizontally",
+ initializers={
+ base=initializeextend,
+ node=initializeextend,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializesqueeze(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>10 then
+ value=10
+ elseif value<-10 then
+ value=-10
+ end
+ if trace then
+ report_squeeze("applying %0.3f",value)
+ end
+ tfmdata.parameters.squeezefactor=value
+end
+local specification={
+ name="squeeze",
+ description="scale glyphs vertically",
+ initializers={
+ base=initializesqueeze,
+ node=initializesqueeze,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local effects={
+ inner=0,
+ normal=0,
+ outer=1,
+ outline=1,
+ both=2,
+ hidden=3,
+}
+local function initializeeffect(tfmdata,value)
+ local spec
+ if type(value)=="number" then
+ spec={ width=value }
+ else
+ spec=settings_to_hash(value)
+ end
+ local effect=spec.effect or "both"
+ local width=tonumber(spec.width) or 0
+ local mode=effects[effect]
+ if not mode then
+ report_effect("invalid effect %a",effect)
+ elseif width==0 and mode==0 then
+ report_effect("invalid width %a for effect %a",width,effect)
+ else
+ local parameters=tfmdata.parameters
+ local properties=tfmdata.properties
+ parameters.mode=mode
+ parameters.width=width*1000
+ if is_boolean(spec.auto)==true then
+ local squeeze=1-width/20
+ local average=(1-squeeze)*width*100
+ spec.squeeze=squeeze
+ spec.extend=1+width/2
+ spec.wdelta=average
+ spec.hdelta=average/2
+ spec.ddelta=average/2
+ spec.vshift=average/2
+ end
+ local factor=tonumber(spec.factor) or 0
+ local hfactor=tonumber(spec.hfactor) or factor
+ local vfactor=tonumber(spec.vfactor) or factor
+ local delta=tonumber(spec.delta) or 1
+ local wdelta=tonumber(spec.wdelta) or delta
+ local hdelta=tonumber(spec.hdelta) or delta
+ local ddelta=tonumber(spec.ddelta) or hdelta
+ local vshift=tonumber(spec.vshift) or 0
+ local slant=spec.slant
+ local extend=spec.extend
+ local squeeze=spec.squeeze
+ if slant then
+ initializeslant(tfmdata,slant)
+ end
+ if extend then
+ initializeextend(tfmdata,extend)
+ end
+ if squeeze then
+ initializesqueeze(tfmdata,squeeze)
+ end
+ properties.effect={
+ effect=effect,
+ width=width,
+ factor=factor,
+ hfactor=hfactor,
+ vfactor=vfactor,
+ wdelta=wdelta,
+ hdelta=hdelta,
+ ddelta=ddelta,
+ vshift=vshift,
+ slant=tfmdata.parameters.slantfactor,
+ extend=tfmdata.parameters.extendfactor,
+ squeeze=tfmdata.parameters.squeezefactor,
+ }
+ end
+end
+local rules={
+ "RadicalRuleThickness",
+ "OverbarRuleThickness",
+ "FractionRuleThickness",
+ "UnderbarRuleThickness",
+}
+local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ if delta~=0 then
+ for i=1,#rules do
+ local name=rules[i]
+ local value=mathparameters[name]
+ if value then
+ mathparameters[name]=(squeeze or 1)*(value+dx)
+ end
+ end
+ end
+end
+local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+ local function wdpatch(char)
+ if wsnap~=0 then
+ char.width=char.width+wdelta/2
+ end
+ end
+ local function htpatch(char)
+ if hsnap~=0 then
+ local height=char.height
+ if height then
+ char.height=char.height+2*dy
+ end
+ end
+ end
+ local character=characters[0x221A]
+ if character and character.next then
+ local char=character
+ local next=character.next
+ wdpatch(char)
+ htpatch(char)
+ while next do
+ char=characters[next]
+ wdpatch(char)
+ htpatch(char)
+ next=char.next
+ end
+ if char then
+ local v=char.vert_variants
+ if v then
+ local top=v[#v]
+ if top then
+ local char=characters[top.glyph]
+ htpatch(char)
+ end
+ end
+ end
+ end
+end
+local function manipulateeffect(tfmdata)
+ local effect=tfmdata.properties.effect
+ if effect then
+ local characters=tfmdata.characters
+ local parameters=tfmdata.parameters
+ local mathparameters=tfmdata.mathparameters
+ local multiplier=effect.width*100
+ local factor=parameters.factor
+ local hfactor=parameters.hfactor
+ local vfactor=parameters.vfactor
+ local wdelta=effect.wdelta*hfactor*multiplier
+ local hdelta=effect.hdelta*vfactor*multiplier
+ local ddelta=effect.ddelta*vfactor*multiplier
+ local vshift=effect.vshift*vfactor*multiplier
+ local squeeze=effect.squeeze
+ local hshift=wdelta/2
+ local dx=multiplier*vfactor
+ local dy=vshift
+ local factor=(1+effect.factor)*factor
+ local hfactor=(1+effect.hfactor)*hfactor
+ local vfactor=(1+effect.vfactor)*vfactor
+ local vshift=vshift~=0 and upcommand[vshift] or false
+ for unicode,character in next,characters do
+ local oldwidth=character.width
+ local oldheight=character.height
+ local olddepth=character.depth
+ if oldwidth and oldwidth>0 then
+ character.width=oldwidth+wdelta
+ local commands=character.commands
+ local hshift=rightcommand[hshift]
+ if vshift then
+ if commands then
+ prependcommands (commands,
+ hshift,
+ vshift
+ )
+ else
+ character.commands={
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
+ else
+ if commands then
+ prependcommands (commands,
+ hshift
+ )
+ else
+ character.commands={
+ hshift,
+ charcommand[unicode]
+ }
+ end
+ end
+ end
+ if oldheight and oldheight>0 then
+ character.height=oldheight+hdelta
+ end
+ if olddepth and olddepth>0 then
+ character.depth=olddepth+ddelta
+ end
+ end
+ if mathparameters then
+ setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+ end
+ parameters.factor=factor
+ parameters.hfactor=hfactor
+ parameters.vfactor=vfactor
+ if trace then
+ report_effect("applying")
+ report_effect(" effect : %s",effect.effect)
+ report_effect(" width : %s => %s",effect.width,multiplier)
+ report_effect(" factor : %s => %s",effect.factor,factor )
+ report_effect(" hfactor : %s => %s",effect.hfactor,hfactor)
+ report_effect(" vfactor : %s => %s",effect.vfactor,vfactor)
+ report_effect(" wdelta : %s => %s",effect.wdelta,wdelta)
+ report_effect(" hdelta : %s => %s",effect.hdelta,hdelta)
+ report_effect(" ddelta : %s => %s",effect.ddelta,ddelta)
+ end
+ end
+end
+local specification={
+ name="effect",
+ description="apply effects to glyphs",
+ initializers={
+ base=initializeeffect,
+ node=initializeeffect,
+ },
+ manipulators={
+ base=manipulateeffect,
+ node=manipulateeffect,
+ },
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializeoutline(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ else
+ value=tonumber(value) or 0
+ end
+ local parameters=tfmdata.parameters
+ local properties=tfmdata.properties
+ parameters.mode=effects.outline
+ parameters.width=value*1000
+ properties.effect={
+ effect=effect,
+ width=width,
+ }
+end
+local specification={
+ name="outline",
+ description="outline glyphs",
+ initializers={
+ base=initializeoutline,
+ node=initializeoutline,
}
}
+registerotffeature(specification)
+registerafmfeature(specification)
+
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “font-imp-effects”] ---
+
+
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-lig” fbd251eea3810a43a8d5542319361d68] ---
+
+
+fonts.handlers.otf.addfeature {
+ ["dataset"]={
+ {
+ ["data"]={
+ ["À"]={ "A","̀" },
+ ["Á"]={ "A","́" },
+ ["Â"]={ "A","̂" },
+ ["Ã"]={ "A","̃" },
+ ["Ä"]={ "A","̈" },
+ ["Å"]={ "A","̊" },
+ ["Ç"]={ "C","̧" },
+ ["È"]={ "E","̀" },
+ ["É"]={ "E","́" },
+ ["Ê"]={ "E","̂" },
+ ["Ë"]={ "E","̈" },
+ ["Ì"]={ "I","̀" },
+ ["Í"]={ "I","́" },
+ ["Î"]={ "I","̂" },
+ ["Ï"]={ "I","̈" },
+ ["Ñ"]={ "N","̃" },
+ ["Ò"]={ "O","̀" },
+ ["Ó"]={ "O","́" },
+ ["Ô"]={ "O","̂" },
+ ["Õ"]={ "O","̃" },
+ ["Ö"]={ "O","̈" },
+ ["Ù"]={ "U","̀" },
+ ["Ú"]={ "U","́" },
+ ["Û"]={ "U","̂" },
+ ["Ü"]={ "U","̈" },
+ ["Ý"]={ "Y","́" },
+ ["à"]={ "a","̀" },
+ ["á"]={ "a","́" },
+ ["â"]={ "a","̂" },
+ ["ã"]={ "a","̃" },
+ ["ä"]={ "a","̈" },
+ ["å"]={ "a","̊" },
+ ["ç"]={ "c","̧" },
+ ["è"]={ "e","̀" },
+ ["é"]={ "e","́" },
+ ["ê"]={ "e","̂" },
+ ["ë"]={ "e","̈" },
+ ["ì"]={ "i","̀" },
+ ["í"]={ "i","́" },
+ ["î"]={ "i","̂" },
+ ["ï"]={ "i","̈" },
+ ["ñ"]={ "n","̃" },
+ ["ò"]={ "o","̀" },
+ ["ó"]={ "o","́" },
+ ["ô"]={ "o","̂" },
+ ["õ"]={ "o","̃" },
+ ["ö"]={ "o","̈" },
+ ["ù"]={ "u","̀" },
+ ["ú"]={ "u","́" },
+ ["û"]={ "u","̂" },
+ ["ü"]={ "u","̈" },
+ ["ý"]={ "y","́" },
+ ["ÿ"]={ "y","̈" },
+ ["Ā"]={ "A","̄" },
+ ["ā"]={ "a","̄" },
+ ["Ă"]={ "A","̆" },
+ ["ă"]={ "a","̆" },
+ ["Ą"]={ "A","̨" },
+ ["ą"]={ "a","̨" },
+ ["Ć"]={ "C","́" },
+ ["ć"]={ "c","́" },
+ ["Ĉ"]={ "C","̂" },
+ ["ĉ"]={ "c","̂" },
+ ["Ċ"]={ "C","̇" },
+ ["ċ"]={ "c","̇" },
+ ["Č"]={ "C","̌" },
+ ["č"]={ "c","̌" },
+ ["Ď"]={ "D","̌" },
+ ["ď"]={ "d","̌" },
+ ["Ē"]={ "E","̄" },
+ ["ē"]={ "e","̄" },
+ ["Ĕ"]={ "E","̆" },
+ ["ĕ"]={ "e","̆" },
+ ["Ė"]={ "E","̇" },
+ ["ė"]={ "e","̇" },
+ ["Ę"]={ "E","̨" },
+ ["ę"]={ "e","̨" },
+ ["Ě"]={ "E","̌" },
+ ["ě"]={ "e","̌" },
+ ["Ĝ"]={ "G","̂" },
+ ["ĝ"]={ "g","̂" },
+ ["Ğ"]={ "G","̆" },
+ ["ğ"]={ "g","̆" },
+ ["Ġ"]={ "G","̇" },
+ ["ġ"]={ "g","̇" },
+ ["Ģ"]={ "G","̧" },
+ ["ģ"]={ "g","̧" },
+ ["Ĥ"]={ "H","̂" },
+ ["ĥ"]={ "h","̂" },
+ ["Ĩ"]={ "I","̃" },
+ ["ĩ"]={ "i","̃" },
+ ["Ī"]={ "I","̄" },
+ ["ī"]={ "i","̄" },
+ ["Ĭ"]={ "I","̆" },
+ ["ĭ"]={ "i","̆" },
+ ["Į"]={ "I","̨" },
+ ["į"]={ "i","̨" },
+ ["İ"]={ "I","̇" },
+ ["Ĵ"]={ "J","̂" },
+ ["ĵ"]={ "j","̂" },
+ ["Ķ"]={ "K","̧" },
+ ["ķ"]={ "k","̧" },
+ ["Ĺ"]={ "L","́" },
+ ["ĺ"]={ "l","́" },
+ ["Ļ"]={ "L","̧" },
+ ["ļ"]={ "l","̧" },
+ ["Ľ"]={ "L","̌" },
+ ["ľ"]={ "l","̌" },
+ ["Ń"]={ "N","́" },
+ ["ń"]={ "n","́" },
+ ["Ņ"]={ "N","̧" },
+ ["ņ"]={ "n","̧" },
+ ["Ň"]={ "N","̌" },
+ ["ň"]={ "n","̌" },
+ ["Ō"]={ "O","̄" },
+ ["ō"]={ "o","̄" },
+ ["Ŏ"]={ "O","̆" },
+ ["ŏ"]={ "o","̆" },
+ ["Ő"]={ "O","̋" },
+ ["ő"]={ "o","̋" },
+ ["Ŕ"]={ "R","́" },
+ ["ŕ"]={ "r","́" },
+ ["Ŗ"]={ "R","̧" },
+ ["ŗ"]={ "r","̧" },
+ ["Ř"]={ "R","̌" },
+ ["ř"]={ "r","̌" },
+ ["Ś"]={ "S","́" },
+ ["ś"]={ "s","́" },
+ ["Ŝ"]={ "S","̂" },
+ ["ŝ"]={ "s","̂" },
+ ["Ş"]={ "S","̧" },
+ ["ş"]={ "s","̧" },
+ ["Š"]={ "S","̌" },
+ ["š"]={ "s","̌" },
+ ["Ţ"]={ "T","̧" },
+ ["ţ"]={ "t","̧" },
+ ["Ť"]={ "T","̌" },
+ ["ť"]={ "t","̌" },
+ ["Ũ"]={ "U","̃" },
+ ["ũ"]={ "u","̃" },
+ ["Ū"]={ "U","̄" },
+ ["ū"]={ "u","̄" },
+ ["Ŭ"]={ "U","̆" },
+ ["ŭ"]={ "u","̆" },
+ ["Ů"]={ "U","̊" },
+ ["ů"]={ "u","̊" },
+ ["Ű"]={ "U","̋" },
+ ["ű"]={ "u","̋" },
+ ["Ų"]={ "U","̨" },
+ ["ų"]={ "u","̨" },
+ ["Ŵ"]={ "W","̂" },
+ ["ŵ"]={ "w","̂" },
+ ["Ŷ"]={ "Y","̂" },
+ ["ŷ"]={ "y","̂" },
+ ["Ÿ"]={ "Y","̈" },
+ ["Ź"]={ "Z","́" },
+ ["ź"]={ "z","́" },
+ ["Ż"]={ "Z","̇" },
+ ["ż"]={ "z","̇" },
+ ["Ž"]={ "Z","̌" },
+ ["ž"]={ "z","̌" },
+ ["Ơ"]={ "O","̛" },
+ ["ơ"]={ "o","̛" },
+ ["Ư"]={ "U","̛" },
+ ["ư"]={ "u","̛" },
+ ["Ǎ"]={ "A","̌" },
+ ["ǎ"]={ "a","̌" },
+ ["Ǐ"]={ "I","̌" },
+ ["ǐ"]={ "i","̌" },
+ ["Ǒ"]={ "O","̌" },
+ ["ǒ"]={ "o","̌" },
+ ["Ǔ"]={ "U","̌" },
+ ["ǔ"]={ "u","̌" },
+ ["Ǖ"]={ "Ü","̄" },
+ ["ǖ"]={ "ü","̄" },
+ ["Ǘ"]={ "Ü","́" },
+ ["ǘ"]={ "ü","́" },
+ ["Ǚ"]={ "Ü","̌" },
+ ["ǚ"]={ "ü","̌" },
+ ["Ǜ"]={ "Ü","̀" },
+ ["ǜ"]={ "ü","̀" },
+ ["Ǟ"]={ "Ä","̄" },
+ ["ǟ"]={ "ä","̄" },
+ ["Ǡ"]={ "Ȧ","̄" },
+ ["ǡ"]={ "ȧ","̄" },
+ ["Ǣ"]={ "Æ","̄" },
+ ["ǣ"]={ "æ","̄" },
+ ["Ǧ"]={ "G","̌" },
+ ["ǧ"]={ "g","̌" },
+ ["Ǩ"]={ "K","̌" },
+ ["ǩ"]={ "k","̌" },
+ ["Ǫ"]={ "O","̨" },
+ ["ǫ"]={ "o","̨" },
+ ["Ǭ"]={ "Ǫ","̄" },
+ ["ǭ"]={ "ǫ","̄" },
+ ["Ǯ"]={ "Ʒ","̌" },
+ ["ǯ"]={ "ʒ","̌" },
+ ["ǰ"]={ "j","̌" },
+ ["Ǵ"]={ "G","́" },
+ ["ǵ"]={ "g","́" },
+ ["Ǹ"]={ "N","̀" },
+ ["ǹ"]={ "n","̀" },
+ ["Ǻ"]={ "Å","́" },
+ ["ǻ"]={ "å","́" },
+ ["Ǽ"]={ "Æ","́" },
+ ["ǽ"]={ "æ","́" },
+ ["Ǿ"]={ "Ø","́" },
+ ["ǿ"]={ "ø","́" },
+ ["Ȁ"]={ "A","̏" },
+ ["ȁ"]={ "a","̏" },
+ ["Ȃ"]={ "A","̑" },
+ ["ȃ"]={ "a","̑" },
+ ["Ȅ"]={ "E","̏" },
+ ["ȅ"]={ "e","̏" },
+ ["Ȇ"]={ "E","̑" },
+ ["ȇ"]={ "e","̑" },
+ ["Ȉ"]={ "I","̏" },
+ ["ȉ"]={ "i","̏" },
+ ["Ȋ"]={ "I","̑" },
+ ["ȋ"]={ "i","̑" },
+ ["Ȍ"]={ "O","̏" },
+ ["ȍ"]={ "o","̏" },
+ ["Ȏ"]={ "O","̑" },
+ ["ȏ"]={ "o","̑" },
+ ["Ȑ"]={ "R","̏" },
+ ["ȑ"]={ "r","̏" },
+ ["Ȓ"]={ "R","̑" },
+ ["ȓ"]={ "r","̑" },
+ ["Ȕ"]={ "U","̏" },
+ ["ȕ"]={ "u","̏" },
+ ["Ȗ"]={ "U","̑" },
+ ["ȗ"]={ "u","̑" },
+ ["Ș"]={ "S","̦" },
+ ["ș"]={ "s","̦" },
+ ["Ț"]={ "T","̦" },
+ ["ț"]={ "t","̦" },
+ ["Ȟ"]={ "H","̌" },
+ ["ȟ"]={ "h","̌" },
+ ["Ȧ"]={ "A","̇" },
+ ["ȧ"]={ "a","̇" },
+ ["Ȩ"]={ "E","̧" },
+ ["ȩ"]={ "e","̧" },
+ ["Ȫ"]={ "Ö","̄" },
+ ["ȫ"]={ "ö","̄" },
+ ["Ȭ"]={ "Õ","̄" },
+ ["ȭ"]={ "õ","̄" },
+ ["Ȯ"]={ "O","̇" },
+ ["ȯ"]={ "o","̇" },
+ ["Ȱ"]={ "Ȯ","̄" },
+ ["ȱ"]={ "ȯ","̄" },
+ ["Ȳ"]={ "Y","̄" },
+ ["ȳ"]={ "y","̄" },
+ ["̈́"]={ "̈","́" },
+ ["΅"]={ "¨","́" },
+ ["Ά"]={ "Α","́" },
+ ["Έ"]={ "Ε","́" },
+ ["Ή"]={ "Η","́" },
+ ["Ί"]={ "Ι","́" },
+ ["Ό"]={ "Ο","́" },
+ ["Ύ"]={ "Υ","́" },
+ ["Ώ"]={ "Ω","́" },
+ ["ΐ"]={ "ϊ","́" },
+ ["Ϊ"]={ "Ι","̈" },
+ ["Ϋ"]={ "Υ","̈" },
+ ["ά"]={ "α","́" },
+ ["έ"]={ "ε","́" },
+ ["ή"]={ "η","́" },
+ ["ί"]={ "ι","́" },
+ ["ΰ"]={ "ϋ","́" },
+ ["ϊ"]={ "ι","̈" },
+ ["ϋ"]={ "υ","̈" },
+ ["ό"]={ "ο","́" },
+ ["ύ"]={ "υ","́" },
+ ["ώ"]={ "ω","́" },
+ ["ϓ"]={ "ϒ","́" },
+ ["ϔ"]={ "ϒ","̈" },
+ ["Ѐ"]={ "Е","̀" },
+ ["Ё"]={ "Е","̈" },
+ ["Ѓ"]={ "Г","́" },
+ ["Ї"]={ "І","̈" },
+ ["Ќ"]={ "К","́" },
+ ["Ѝ"]={ "И","̀" },
+ ["Ў"]={ "У","̆" },
+ ["Й"]={ "И","̆" },
+ ["й"]={ "и","̆" },
+ ["ѐ"]={ "е","̀" },
+ ["ё"]={ "е","̈" },
+ ["ѓ"]={ "г","́" },
+ ["ї"]={ "і","̈" },
+ ["ќ"]={ "к","́" },
+ ["ѝ"]={ "и","̀" },
+ ["ў"]={ "у","̆" },
+ ["Ѷ"]={ "Ѵ","̏" },
+ ["ѷ"]={ "ѵ","̏" },
+ ["Ӂ"]={ "Ж","̆" },
+ ["ӂ"]={ "ж","̆" },
+ ["Ӑ"]={ "А","̆" },
+ ["ӑ"]={ "а","̆" },
+ ["Ӓ"]={ "А","̈" },
+ ["ӓ"]={ "а","̈" },
+ ["Ӗ"]={ "Е","̆" },
+ ["ӗ"]={ "е","̆" },
+ ["Ӛ"]={ "Ә","̈" },
+ ["ӛ"]={ "ә","̈" },
+ ["Ӝ"]={ "Ж","̈" },
+ ["ӝ"]={ "ж","̈" },
+ ["Ӟ"]={ "З","̈" },
+ ["ӟ"]={ "з","̈" },
+ ["Ӣ"]={ "И","̄" },
+ ["ӣ"]={ "и","̄" },
+ ["Ӥ"]={ "И","̈" },
+ ["ӥ"]={ "и","̈" },
+ ["Ӧ"]={ "О","̈" },
+ ["ӧ"]={ "о","̈" },
+ ["Ӫ"]={ "Ө","̈" },
+ ["ӫ"]={ "ө","̈" },
+ ["Ӭ"]={ "Э","̈" },
+ ["ӭ"]={ "э","̈" },
+ ["Ӯ"]={ "У","̄" },
+ ["ӯ"]={ "у","̄" },
+ ["Ӱ"]={ "У","̈" },
+ ["ӱ"]={ "у","̈" },
+ ["Ӳ"]={ "У","̋" },
+ ["ӳ"]={ "у","̋" },
+ ["Ӵ"]={ "Ч","̈" },
+ ["ӵ"]={ "ч","̈" },
+ ["Ӹ"]={ "Ы","̈" },
+ ["ӹ"]={ "ы","̈" },
+ ["آ"]={ "ا","ٓ" },
+ ["أ"]={ "ا","ٔ" },
+ ["ؤ"]={ "و","ٔ" },
+ ["إ"]={ "ا","ٕ" },
+ ["ئ"]={ "ي","ٔ" },
+ ["ۀ"]={ "ە","ٔ" },
+ ["ۂ"]={ "ہ","ٔ" },
+ ["ۓ"]={ "ے","ٔ" },
+ ["ऩ"]={ "न","़" },
+ ["ऱ"]={ "र","़" },
+ ["ऴ"]={ "ळ","़" },
+ ["क़"]={ "क","़" },
+ ["ख़"]={ "ख","़" },
+ ["ग़"]={ "ग","़" },
+ ["ज़"]={ "ज","़" },
+ ["ड़"]={ "ड","़" },
+ ["ढ़"]={ "ढ","़" },
+ ["फ़"]={ "फ","़" },
+ ["य़"]={ "य","़" },
+ ["ো"]={ "ে","া" },
+ ["ৌ"]={ "ে","ৗ" },
+ ["ড়"]={ "ড","়" },
+ ["ঢ়"]={ "ঢ","়" },
+ ["য়"]={ "য","়" },
+ ["ਲ਼"]={ "ਲ","਼" },
+ ["ਸ਼"]={ "ਸ","਼" },
+ ["ਖ਼"]={ "ਖ","਼" },
+ ["ਗ਼"]={ "ਗ","਼" },
+ ["ਜ਼"]={ "ਜ","਼" },
+ ["ਫ਼"]={ "ਫ","਼" },
+ ["ୈ"]={ "େ","ୖ" },
+ ["ୋ"]={ "େ","ା" },
+ ["ୌ"]={ "େ","ୗ" },
+ ["ଡ଼"]={ "ଡ","଼" },
+ ["ଢ଼"]={ "ଢ","଼" },
+ ["ஔ"]={ "ஒ","ௗ" },
+ ["ொ"]={ "ெ","ா" },
+ ["ோ"]={ "ே","ா" },
+ ["ௌ"]={ "ெ","ௗ" },
+ ["ై"]={ "ె","ౖ" },
+ ["ೀ"]={ "ಿ","ೕ" },
+ ["ೇ"]={ "ೆ","ೕ" },
+ ["ೈ"]={ "ೆ","ೖ" },
+ ["ೊ"]={ "ೆ","ೂ" },
+ ["ೋ"]={ "ೊ","ೕ" },
+ ["ൊ"]={ "െ","ാ" },
+ ["ോ"]={ "േ","ാ" },
+ ["ൌ"]={ "െ","ൗ" },
+ ["ේ"]={ "ෙ","්" },
+ ["ො"]={ "ෙ","ා" },
+ ["ෝ"]={ "ො","්" },
+ ["ෞ"]={ "ෙ","ෟ" },
+ ["གྷ"]={ "ག","ྷ" },
+ ["ཌྷ"]={ "ཌ","ྷ" },
+ ["དྷ"]={ "ད","ྷ" },
+ ["བྷ"]={ "བ","ྷ" },
+ ["ཛྷ"]={ "ཛ","ྷ" },
+ ["ཀྵ"]={ "ཀ","ྵ" },
+ ["ཱི"]={ "ཱ","ི" },
+ ["ཱུ"]={ "ཱ","ུ" },
+ ["ྲྀ"]={ "ྲ","ྀ" },
+ ["ླྀ"]={ "ླ","ྀ" },
+ ["ཱྀ"]={ "ཱ","ྀ" },
+ ["ྒྷ"]={ "ྒ","ྷ" },
+ ["ྜྷ"]={ "ྜ","ྷ" },
+ ["ྡྷ"]={ "ྡ","ྷ" },
+ ["ྦྷ"]={ "ྦ","ྷ" },
+ ["ྫྷ"]={ "ྫ","ྷ" },
+ ["ྐྵ"]={ "ྐ","ྵ" },
+ ["ဦ"]={ "ဥ","ီ" },
+ ["ᬆ"]={ "ᬅ","ᬵ" },
+ ["ᬈ"]={ "ᬇ","ᬵ" },
+ ["ᬊ"]={ "ᬉ","ᬵ" },
+ ["ᬌ"]={ "ᬋ","ᬵ" },
+ ["ᬎ"]={ "ᬍ","ᬵ" },
+ ["ᬒ"]={ "ᬑ","ᬵ" },
+ ["ᬻ"]={ "ᬺ","ᬵ" },
+ ["ᬽ"]={ "ᬼ","ᬵ" },
+ ["ᭀ"]={ "ᬾ","ᬵ" },
+ ["ᭁ"]={ "ᬿ","ᬵ" },
+ ["ᭃ"]={ "ᭂ","ᬵ" },
+ ["Ḁ"]={ "A","̥" },
+ ["ḁ"]={ "a","̥" },
+ ["Ḃ"]={ "B","̇" },
+ ["ḃ"]={ "b","̇" },
+ ["Ḅ"]={ "B","̣" },
+ ["ḅ"]={ "b","̣" },
+ ["Ḇ"]={ "B","̱" },
+ ["ḇ"]={ "b","̱" },
+ ["Ḉ"]={ "Ç","́" },
+ ["ḉ"]={ "ç","́" },
+ ["Ḋ"]={ "D","̇" },
+ ["ḋ"]={ "d","̇" },
+ ["Ḍ"]={ "D","̣" },
+ ["ḍ"]={ "d","̣" },
+ ["Ḏ"]={ "D","̱" },
+ ["ḏ"]={ "d","̱" },
+ ["Ḑ"]={ "D","̧" },
+ ["ḑ"]={ "d","̧" },
+ ["Ḓ"]={ "D","̭" },
+ ["ḓ"]={ "d","̭" },
+ ["Ḕ"]={ "Ē","̀" },
+ ["ḕ"]={ "ē","̀" },
+ ["Ḗ"]={ "Ē","́" },
+ ["ḗ"]={ "ē","́" },
+ ["Ḙ"]={ "E","̭" },
+ ["ḙ"]={ "e","̭" },
+ ["Ḛ"]={ "E","̰" },
+ ["ḛ"]={ "e","̰" },
+ ["Ḝ"]={ "Ȩ","̆" },
+ ["ḝ"]={ "ȩ","̆" },
+ ["Ḟ"]={ "F","̇" },
+ ["ḟ"]={ "f","̇" },
+ ["Ḡ"]={ "G","̄" },
+ ["ḡ"]={ "g","̄" },
+ ["Ḣ"]={ "H","̇" },
+ ["ḣ"]={ "h","̇" },
+ ["Ḥ"]={ "H","̣" },
+ ["ḥ"]={ "h","̣" },
+ ["Ḧ"]={ "H","̈" },
+ ["ḧ"]={ "h","̈" },
+ ["Ḩ"]={ "H","̧" },
+ ["ḩ"]={ "h","̧" },
+ ["Ḫ"]={ "H","̮" },
+ ["ḫ"]={ "h","̮" },
+ ["Ḭ"]={ "I","̰" },
+ ["ḭ"]={ "i","̰" },
+ ["Ḯ"]={ "Ï","́" },
+ ["ḯ"]={ "ï","́" },
+ ["Ḱ"]={ "K","́" },
+ ["ḱ"]={ "k","́" },
+ ["Ḳ"]={ "K","̣" },
+ ["ḳ"]={ "k","̣" },
+ ["Ḵ"]={ "K","̱" },
+ ["ḵ"]={ "k","̱" },
+ ["Ḷ"]={ "L","̣" },
+ ["ḷ"]={ "l","̣" },
+ ["Ḹ"]={ "Ḷ","̄" },
+ ["ḹ"]={ "ḷ","̄" },
+ ["Ḻ"]={ "L","̱" },
+ ["ḻ"]={ "l","̱" },
+ ["Ḽ"]={ "L","̭" },
+ ["ḽ"]={ "l","̭" },
+ ["Ḿ"]={ "M","́" },
+ ["ḿ"]={ "m","́" },
+ ["Ṁ"]={ "M","̇" },
+ ["ṁ"]={ "m","̇" },
+ ["Ṃ"]={ "M","̣" },
+ ["ṃ"]={ "m","̣" },
+ ["Ṅ"]={ "N","̇" },
+ ["ṅ"]={ "n","̇" },
+ ["Ṇ"]={ "N","̣" },
+ ["ṇ"]={ "n","̣" },
+ ["Ṉ"]={ "N","̱" },
+ ["ṉ"]={ "n","̱" },
+ ["Ṋ"]={ "N","̭" },
+ ["ṋ"]={ "n","̭" },
+ ["Ṍ"]={ "Õ","́" },
+ ["ṍ"]={ "õ","́" },
+ ["Ṏ"]={ "Õ","̈" },
+ ["ṏ"]={ "õ","̈" },
+ ["Ṑ"]={ "Ō","̀" },
+ ["ṑ"]={ "ō","̀" },
+ ["Ṓ"]={ "Ō","́" },
+ ["ṓ"]={ "ō","́" },
+ ["Ṕ"]={ "P","́" },
+ ["ṕ"]={ "p","́" },
+ ["Ṗ"]={ "P","̇" },
+ ["ṗ"]={ "p","̇" },
+ ["Ṙ"]={ "R","̇" },
+ ["ṙ"]={ "r","̇" },
+ ["Ṛ"]={ "R","̣" },
+ ["ṛ"]={ "r","̣" },
+ ["Ṝ"]={ "Ṛ","̄" },
+ ["ṝ"]={ "ṛ","̄" },
+ ["Ṟ"]={ "R","̱" },
+ ["ṟ"]={ "r","̱" },
+ ["Ṡ"]={ "S","̇" },
+ ["ṡ"]={ "s","̇" },
+ ["Ṣ"]={ "S","̣" },
+ ["ṣ"]={ "s","̣" },
+ ["Ṥ"]={ "Ś","̇" },
+ ["ṥ"]={ "ś","̇" },
+ ["Ṧ"]={ "Š","̇" },
+ ["ṧ"]={ "š","̇" },
+ ["Ṩ"]={ "Ṣ","̇" },
+ ["ṩ"]={ "ṣ","̇" },
+ ["Ṫ"]={ "T","̇" },
+ ["ṫ"]={ "t","̇" },
+ ["Ṭ"]={ "T","̣" },
+ ["ṭ"]={ "t","̣" },
+ ["Ṯ"]={ "T","̱" },
+ ["ṯ"]={ "t","̱" },
+ ["Ṱ"]={ "T","̭" },
+ ["ṱ"]={ "t","̭" },
+ ["Ṳ"]={ "U","̤" },
+ ["ṳ"]={ "u","̤" },
+ ["Ṵ"]={ "U","̰" },
+ ["ṵ"]={ "u","̰" },
+ ["Ṷ"]={ "U","̭" },
+ ["ṷ"]={ "u","̭" },
+ ["Ṹ"]={ "Ũ","́" },
+ ["ṹ"]={ "ũ","́" },
+ ["Ṻ"]={ "Ū","̈" },
+ ["ṻ"]={ "ū","̈" },
+ ["Ṽ"]={ "V","̃" },
+ ["ṽ"]={ "v","̃" },
+ ["Ṿ"]={ "V","̣" },
+ ["ṿ"]={ "v","̣" },
+ ["Ẁ"]={ "W","̀" },
+ ["ẁ"]={ "w","̀" },
+ ["Ẃ"]={ "W","́" },
+ ["ẃ"]={ "w","́" },
+ ["Ẅ"]={ "W","̈" },
+ ["ẅ"]={ "w","̈" },
+ ["Ẇ"]={ "W","̇" },
+ ["ẇ"]={ "w","̇" },
+ ["Ẉ"]={ "W","̣" },
+ ["ẉ"]={ "w","̣" },
+ ["Ẋ"]={ "X","̇" },
+ ["ẋ"]={ "x","̇" },
+ ["Ẍ"]={ "X","̈" },
+ ["ẍ"]={ "x","̈" },
+ ["Ẏ"]={ "Y","̇" },
+ ["ẏ"]={ "y","̇" },
+ ["Ẑ"]={ "Z","̂" },
+ ["ẑ"]={ "z","̂" },
+ ["Ẓ"]={ "Z","̣" },
+ ["ẓ"]={ "z","̣" },
+ ["Ẕ"]={ "Z","̱" },
+ ["ẕ"]={ "z","̱" },
+ ["ẖ"]={ "h","̱" },
+ ["ẗ"]={ "t","̈" },
+ ["ẘ"]={ "w","̊" },
+ ["ẙ"]={ "y","̊" },
+ ["ẛ"]={ "ſ","̇" },
+ ["Ạ"]={ "A","̣" },
+ ["ạ"]={ "a","̣" },
+ ["Ả"]={ "A","̉" },
+ ["ả"]={ "a","̉" },
+ ["Ấ"]={ "Â","́" },
+ ["ấ"]={ "â","́" },
+ ["Ầ"]={ "Â","̀" },
+ ["ầ"]={ "â","̀" },
+ ["Ẩ"]={ "Â","̉" },
+ ["ẩ"]={ "â","̉" },
+ ["Ẫ"]={ "Â","̃" },
+ ["ẫ"]={ "â","̃" },
+ ["Ậ"]={ "Ạ","̂" },
+ ["ậ"]={ "ạ","̂" },
+ ["Ắ"]={ "Ă","́" },
+ ["ắ"]={ "ă","́" },
+ ["Ằ"]={ "Ă","̀" },
+ ["ằ"]={ "ă","̀" },
+ ["Ẳ"]={ "Ă","̉" },
+ ["ẳ"]={ "ă","̉" },
+ ["Ẵ"]={ "Ă","̃" },
+ ["ẵ"]={ "ă","̃" },
+ ["Ặ"]={ "Ạ","̆" },
+ ["ặ"]={ "ạ","̆" },
+ ["Ẹ"]={ "E","̣" },
+ ["ẹ"]={ "e","̣" },
+ ["Ẻ"]={ "E","̉" },
+ ["ẻ"]={ "e","̉" },
+ ["Ẽ"]={ "E","̃" },
+ ["ẽ"]={ "e","̃" },
+ ["Ế"]={ "Ê","́" },
+ ["ế"]={ "ê","́" },
+ ["Ề"]={ "Ê","̀" },
+ ["ề"]={ "ê","̀" },
+ ["Ể"]={ "Ê","̉" },
+ ["ể"]={ "ê","̉" },
+ ["Ễ"]={ "Ê","̃" },
+ ["ễ"]={ "ê","̃" },
+ ["Ệ"]={ "Ẹ","̂" },
+ ["ệ"]={ "ẹ","̂" },
+ ["Ỉ"]={ "I","̉" },
+ ["ỉ"]={ "i","̉" },
+ ["Ị"]={ "I","̣" },
+ ["ị"]={ "i","̣" },
+ ["Ọ"]={ "O","̣" },
+ ["ọ"]={ "o","̣" },
+ ["Ỏ"]={ "O","̉" },
+ ["ỏ"]={ "o","̉" },
+ ["Ố"]={ "Ô","́" },
+ ["ố"]={ "ô","́" },
+ ["Ồ"]={ "Ô","̀" },
+ ["ồ"]={ "ô","̀" },
+ ["Ổ"]={ "Ô","̉" },
+ ["ổ"]={ "ô","̉" },
+ ["Ỗ"]={ "Ô","̃" },
+ ["ỗ"]={ "ô","̃" },
+ ["Ộ"]={ "Ọ","̂" },
+ ["ộ"]={ "ọ","̂" },
+ ["Ớ"]={ "Ơ","́" },
+ ["ớ"]={ "ơ","́" },
+ ["Ờ"]={ "Ơ","̀" },
+ ["ờ"]={ "ơ","̀" },
+ ["Ở"]={ "Ơ","̉" },
+ ["ở"]={ "ơ","̉" },
+ ["Ỡ"]={ "Ơ","̃" },
+ ["ỡ"]={ "ơ","̃" },
+ ["Ợ"]={ "Ơ","̣" },
+ ["ợ"]={ "ơ","̣" },
+ ["Ụ"]={ "U","̣" },
+ ["ụ"]={ "u","̣" },
+ ["Ủ"]={ "U","̉" },
+ ["ủ"]={ "u","̉" },
+ ["Ứ"]={ "Ư","́" },
+ ["ứ"]={ "ư","́" },
+ ["Ừ"]={ "Ư","̀" },
+ ["ừ"]={ "ư","̀" },
+ ["Ử"]={ "Ư","̉" },
+ ["ử"]={ "ư","̉" },
+ ["Ữ"]={ "Ư","̃" },
+ ["ữ"]={ "ư","̃" },
+ ["Ự"]={ "Ư","̣" },
+ ["ự"]={ "ư","̣" },
+ ["Ỳ"]={ "Y","̀" },
+ ["ỳ"]={ "y","̀" },
+ ["Ỵ"]={ "Y","̣" },
+ ["ỵ"]={ "y","̣" },
+ ["Ỷ"]={ "Y","̉" },
+ ["ỷ"]={ "y","̉" },
+ ["Ỹ"]={ "Y","̃" },
+ ["ỹ"]={ "y","̃" },
+ ["ἀ"]={ "α","̓" },
+ ["ἁ"]={ "α","̔" },
+ ["ἂ"]={ "ἀ","̀" },
+ ["ἃ"]={ "ἁ","̀" },
+ ["ἄ"]={ "ἀ","́" },
+ ["ἅ"]={ "ἁ","́" },
+ ["ἆ"]={ "ἀ","͂" },
+ ["ἇ"]={ "ἁ","͂" },
+ ["Ἀ"]={ "Α","̓" },
+ ["Ἁ"]={ "Α","̔" },
+ ["Ἂ"]={ "Ἀ","̀" },
+ ["Ἃ"]={ "Ἁ","̀" },
+ ["Ἄ"]={ "Ἀ","́" },
+ ["Ἅ"]={ "Ἁ","́" },
+ ["Ἆ"]={ "Ἀ","͂" },
+ ["Ἇ"]={ "Ἁ","͂" },
+ ["ἐ"]={ "ε","̓" },
+ ["ἑ"]={ "ε","̔" },
+ ["ἒ"]={ "ἐ","̀" },
+ ["ἓ"]={ "ἑ","̀" },
+ ["ἔ"]={ "ἐ","́" },
+ ["ἕ"]={ "ἑ","́" },
+ ["Ἐ"]={ "Ε","̓" },
+ ["Ἑ"]={ "Ε","̔" },
+ ["Ἒ"]={ "Ἐ","̀" },
+ ["Ἓ"]={ "Ἑ","̀" },
+ ["Ἔ"]={ "Ἐ","́" },
+ ["Ἕ"]={ "Ἑ","́" },
+ ["ἠ"]={ "η","̓" },
+ ["ἡ"]={ "η","̔" },
+ ["ἢ"]={ "ἠ","̀" },
+ ["ἣ"]={ "ἡ","̀" },
+ ["ἤ"]={ "ἠ","́" },
+ ["ἥ"]={ "ἡ","́" },
+ ["ἦ"]={ "ἠ","͂" },
+ ["ἧ"]={ "ἡ","͂" },
+ ["Ἠ"]={ "Η","̓" },
+ ["Ἡ"]={ "Η","̔" },
+ ["Ἢ"]={ "Ἠ","̀" },
+ ["Ἣ"]={ "Ἡ","̀" },
+ ["Ἤ"]={ "Ἠ","́" },
+ ["Ἥ"]={ "Ἡ","́" },
+ ["Ἦ"]={ "Ἠ","͂" },
+ ["Ἧ"]={ "Ἡ","͂" },
+ ["ἰ"]={ "ι","̓" },
+ ["ἱ"]={ "ι","̔" },
+ ["ἲ"]={ "ἰ","̀" },
+ ["ἳ"]={ "ἱ","̀" },
+ ["ἴ"]={ "ἰ","́" },
+ ["ἵ"]={ "ἱ","́" },
+ ["ἶ"]={ "ἰ","͂" },
+ ["ἷ"]={ "ἱ","͂" },
+ ["Ἰ"]={ "Ι","̓" },
+ ["Ἱ"]={ "Ι","̔" },
+ ["Ἲ"]={ "Ἰ","̀" },
+ ["Ἳ"]={ "Ἱ","̀" },
+ ["Ἴ"]={ "Ἰ","́" },
+ ["Ἵ"]={ "Ἱ","́" },
+ ["Ἶ"]={ "Ἰ","͂" },
+ ["Ἷ"]={ "Ἱ","͂" },
+ ["ὀ"]={ "ο","̓" },
+ ["ὁ"]={ "ο","̔" },
+ ["ὂ"]={ "ὀ","̀" },
+ ["ὃ"]={ "ὁ","̀" },
+ ["ὄ"]={ "ὀ","́" },
+ ["ὅ"]={ "ὁ","́" },
+ ["Ὀ"]={ "Ο","̓" },
+ ["Ὁ"]={ "Ο","̔" },
+ ["Ὂ"]={ "Ὀ","̀" },
+ ["Ὃ"]={ "Ὁ","̀" },
+ ["Ὄ"]={ "Ὀ","́" },
+ ["Ὅ"]={ "Ὁ","́" },
+ ["ὐ"]={ "υ","̓" },
+ ["ὑ"]={ "υ","̔" },
+ ["ὒ"]={ "ὐ","̀" },
+ ["ὓ"]={ "ὑ","̀" },
+ ["ὔ"]={ "ὐ","́" },
+ ["ὕ"]={ "ὑ","́" },
+ ["ὖ"]={ "ὐ","͂" },
+ ["ὗ"]={ "ὑ","͂" },
+ ["Ὑ"]={ "Υ","̔" },
+ ["Ὓ"]={ "Ὑ","̀" },
+ ["Ὕ"]={ "Ὑ","́" },
+ ["Ὗ"]={ "Ὑ","͂" },
+ ["ὠ"]={ "ω","̓" },
+ ["ὡ"]={ "ω","̔" },
+ ["ὢ"]={ "ὠ","̀" },
+ ["ὣ"]={ "ὡ","̀" },
+ ["ὤ"]={ "ὠ","́" },
+ ["ὥ"]={ "ὡ","́" },
+ ["ὦ"]={ "ὠ","͂" },
+ ["ὧ"]={ "ὡ","͂" },
+ ["Ὠ"]={ "Ω","̓" },
+ ["Ὡ"]={ "Ω","̔" },
+ ["Ὢ"]={ "Ὠ","̀" },
+ ["Ὣ"]={ "Ὡ","̀" },
+ ["Ὤ"]={ "Ὠ","́" },
+ ["Ὥ"]={ "Ὡ","́" },
+ ["Ὦ"]={ "Ὠ","͂" },
+ ["Ὧ"]={ "Ὡ","͂" },
+ ["ὰ"]={ "α","̀" },
+ ["ὲ"]={ "ε","̀" },
+ ["ὴ"]={ "η","̀" },
+ ["ὶ"]={ "ι","̀" },
+ ["ὸ"]={ "ο","̀" },
+ ["ὺ"]={ "υ","̀" },
+ ["ὼ"]={ "ω","̀" },
+ ["ᾀ"]={ "ἀ","ͅ" },
+ ["ᾁ"]={ "ἁ","ͅ" },
+ ["ᾂ"]={ "ἂ","ͅ" },
+ ["ᾃ"]={ "ἃ","ͅ" },
+ ["ᾄ"]={ "ἄ","ͅ" },
+ ["ᾅ"]={ "ἅ","ͅ" },
+ ["ᾆ"]={ "ἆ","ͅ" },
+ ["ᾇ"]={ "ἇ","ͅ" },
+ ["ᾈ"]={ "Ἀ","ͅ" },
+ ["ᾉ"]={ "Ἁ","ͅ" },
+ ["ᾊ"]={ "Ἂ","ͅ" },
+ ["ᾋ"]={ "Ἃ","ͅ" },
+ ["ᾌ"]={ "Ἄ","ͅ" },
+ ["ᾍ"]={ "Ἅ","ͅ" },
+ ["ᾎ"]={ "Ἆ","ͅ" },
+ ["ᾏ"]={ "Ἇ","ͅ" },
+ ["ᾐ"]={ "ἠ","ͅ" },
+ ["ᾑ"]={ "ἡ","ͅ" },
+ ["ᾒ"]={ "ἢ","ͅ" },
+ ["ᾓ"]={ "ἣ","ͅ" },
+ ["ᾔ"]={ "ἤ","ͅ" },
+ ["ᾕ"]={ "ἥ","ͅ" },
+ ["ᾖ"]={ "ἦ","ͅ" },
+ ["ᾗ"]={ "ἧ","ͅ" },
+ ["ᾘ"]={ "Ἠ","ͅ" },
+ ["ᾙ"]={ "Ἡ","ͅ" },
+ ["ᾚ"]={ "Ἢ","ͅ" },
+ ["ᾛ"]={ "Ἣ","ͅ" },
+ ["ᾜ"]={ "Ἤ","ͅ" },
+ ["ᾝ"]={ "Ἥ","ͅ" },
+ ["ᾞ"]={ "Ἦ","ͅ" },
+ ["ᾟ"]={ "Ἧ","ͅ" },
+ ["ᾠ"]={ "ὠ","ͅ" },
+ ["ᾡ"]={ "ὡ","ͅ" },
+ ["ᾢ"]={ "ὢ","ͅ" },
+ ["ᾣ"]={ "ὣ","ͅ" },
+ ["ᾤ"]={ "ὤ","ͅ" },
+ ["ᾥ"]={ "ὥ","ͅ" },
+ ["ᾦ"]={ "ὦ","ͅ" },
+ ["ᾧ"]={ "ὧ","ͅ" },
+ ["ᾨ"]={ "Ὠ","ͅ" },
+ ["ᾩ"]={ "Ὡ","ͅ" },
+ ["ᾪ"]={ "Ὢ","ͅ" },
+ ["ᾫ"]={ "Ὣ","ͅ" },
+ ["ᾬ"]={ "Ὤ","ͅ" },
+ ["ᾭ"]={ "Ὥ","ͅ" },
+ ["ᾮ"]={ "Ὦ","ͅ" },
+ ["ᾯ"]={ "Ὧ","ͅ" },
+ ["ᾰ"]={ "α","̆" },
+ ["ᾱ"]={ "α","̄" },
+ ["ᾲ"]={ "ὰ","ͅ" },
+ ["ᾳ"]={ "α","ͅ" },
+ ["ᾴ"]={ "ά","ͅ" },
+ ["ᾶ"]={ "α","͂" },
+ ["ᾷ"]={ "ᾶ","ͅ" },
+ ["Ᾰ"]={ "Α","̆" },
+ ["Ᾱ"]={ "Α","̄" },
+ ["Ὰ"]={ "Α","̀" },
+ ["ᾼ"]={ "Α","ͅ" },
+ ["῁"]={ "¨","͂" },
+ ["ῂ"]={ "ὴ","ͅ" },
+ ["ῃ"]={ "η","ͅ" },
+ ["ῄ"]={ "ή","ͅ" },
+ ["ῆ"]={ "η","͂" },
+ ["ῇ"]={ "ῆ","ͅ" },
+ ["Ὲ"]={ "Ε","̀" },
+ ["Ὴ"]={ "Η","̀" },
+ ["ῌ"]={ "Η","ͅ" },
+ ["῍"]={ "᾿","̀" },
+ ["῎"]={ "᾿","́" },
+ ["῏"]={ "᾿","͂" },
+ ["ῐ"]={ "ι","̆" },
+ ["ῑ"]={ "ι","̄" },
+ ["ῒ"]={ "ϊ","̀" },
+ ["ῖ"]={ "ι","͂" },
+ ["ῗ"]={ "ϊ","͂" },
+ ["Ῐ"]={ "Ι","̆" },
+ ["Ῑ"]={ "Ι","̄" },
+ ["Ὶ"]={ "Ι","̀" },
+ ["῝"]={ "῾","̀" },
+ ["῞"]={ "῾","́" },
+ ["῟"]={ "῾","͂" },
+ ["ῠ"]={ "υ","̆" },
+ ["ῡ"]={ "υ","̄" },
+ ["ῢ"]={ "ϋ","̀" },
+ ["ῤ"]={ "ρ","̓" },
+ ["ῥ"]={ "ρ","̔" },
+ ["ῦ"]={ "υ","͂" },
+ ["ῧ"]={ "ϋ","͂" },
+ ["Ῠ"]={ "Υ","̆" },
+ ["Ῡ"]={ "Υ","̄" },
+ ["Ὺ"]={ "Υ","̀" },
+ ["Ῥ"]={ "Ρ","̔" },
+ ["῭"]={ "¨","̀" },
+ ["ῲ"]={ "ὼ","ͅ" },
+ ["ῳ"]={ "ω","ͅ" },
+ ["ῴ"]={ "ώ","ͅ" },
+ ["ῶ"]={ "ω","͂" },
+ ["ῷ"]={ "ῶ","ͅ" },
+ ["Ὸ"]={ "Ο","̀" },
+ ["Ὼ"]={ "Ω","̀" },
+ ["ῼ"]={ "Ω","ͅ" },
+ ["↚"]={ "←","̸" },
+ ["↛"]={ "→","̸" },
+ ["↮"]={ "↔","̸" },
+ ["⇍"]={ "⇐","̸" },
+ ["⇎"]={ "⇔","̸" },
+ ["⇏"]={ "⇒","̸" },
+ ["∄"]={ "∃","̸" },
+ ["∉"]={ "∈","̸" },
+ ["∌"]={ "∋","̸" },
+ ["∤"]={ "∣","̸" },
+ ["∦"]={ "∥","̸" },
+ ["≁"]={ "∼","̸" },
+ ["≄"]={ "≃","̸" },
+ ["≇"]={ "≅","̸" },
+ ["≉"]={ "≈","̸" },
+ ["≠"]={ "=","̸" },
+ ["≢"]={ "≡","̸" },
+ ["≭"]={ "≍","̸" },
+ ["≮"]={ "<","̸" },
+ ["≯"]={ ">","̸" },
+ ["≰"]={ "≤","̸" },
+ ["≱"]={ "≥","̸" },
+ ["≴"]={ "≲","̸" },
+ ["≵"]={ "≳","̸" },
+ ["≸"]={ "≶","̸" },
+ ["≹"]={ "≷","̸" },
+ ["⊀"]={ "≺","̸" },
+ ["⊁"]={ "≻","̸" },
+ ["⊄"]={ "⊂","̸" },
+ ["⊅"]={ "⊃","̸" },
+ ["⊈"]={ "⊆","̸" },
+ ["⊉"]={ "⊇","̸" },
+ ["⊬"]={ "⊢","̸" },
+ ["⊭"]={ "⊨","̸" },
+ ["⊮"]={ "⊩","̸" },
+ ["⊯"]={ "⊫","̸" },
+ ["⋠"]={ "≼","̸" },
+ ["⋡"]={ "≽","̸" },
+ ["⋢"]={ "⊑","̸" },
+ ["⋣"]={ "⊒","̸" },
+ ["⋪"]={ "⊲","̸" },
+ ["⋫"]={ "⊳","̸" },
+ ["⋬"]={ "⊴","̸" },
+ ["⋭"]={ "⊵","̸" },
+ ["⫝̸"]={ "⫝","̸" },
+ ["が"]={ "か","゙" },
+ ["ぎ"]={ "き","゙" },
+ ["ぐ"]={ "く","゙" },
+ ["げ"]={ "け","゙" },
+ ["ご"]={ "こ","゙" },
+ ["ざ"]={ "さ","゙" },
+ ["じ"]={ "し","゙" },
+ ["ず"]={ "す","゙" },
+ ["ぜ"]={ "せ","゙" },
+ ["ぞ"]={ "そ","゙" },
+ ["だ"]={ "た","゙" },
+ ["ぢ"]={ "ち","゙" },
+ ["づ"]={ "つ","゙" },
+ ["で"]={ "て","゙" },
+ ["ど"]={ "と","゙" },
+ ["ば"]={ "は","゙" },
+ ["ぱ"]={ "は","゚" },
+ ["び"]={ "ひ","゙" },
+ ["ぴ"]={ "ひ","゚" },
+ ["ぶ"]={ "ふ","゙" },
+ ["ぷ"]={ "ふ","゚" },
+ ["べ"]={ "へ","゙" },
+ ["ぺ"]={ "へ","゚" },
+ ["ぼ"]={ "ほ","゙" },
+ ["ぽ"]={ "ほ","゚" },
+ ["ゔ"]={ "う","゙" },
+ ["ゞ"]={ "ゝ","゙" },
+ ["ガ"]={ "カ","゙" },
+ ["ギ"]={ "キ","゙" },
+ ["グ"]={ "ク","゙" },
+ ["ゲ"]={ "ケ","゙" },
+ ["ゴ"]={ "コ","゙" },
+ ["ザ"]={ "サ","゙" },
+ ["ジ"]={ "シ","゙" },
+ ["ズ"]={ "ス","゙" },
+ ["ゼ"]={ "セ","゙" },
+ ["ゾ"]={ "ソ","゙" },
+ ["ダ"]={ "タ","゙" },
+ ["ヂ"]={ "チ","゙" },
+ ["ヅ"]={ "ツ","゙" },
+ ["デ"]={ "テ","゙" },
+ ["ド"]={ "ト","゙" },
+ ["バ"]={ "ハ","゙" },
+ ["パ"]={ "ハ","゚" },
+ ["ビ"]={ "ヒ","゙" },
+ ["ピ"]={ "ヒ","゚" },
+ ["ブ"]={ "フ","゙" },
+ ["プ"]={ "フ","゚" },
+ ["ベ"]={ "ヘ","゙" },
+ ["ペ"]={ "ヘ","゚" },
+ ["ボ"]={ "ホ","゙" },
+ ["ポ"]={ "ホ","゚" },
+ ["ヴ"]={ "ウ","゙" },
+ ["ヷ"]={ "ワ","゙" },
+ ["ヸ"]={ "ヰ","゙" },
+ ["ヹ"]={ "ヱ","゙" },
+ ["ヺ"]={ "ヲ","゙" },
+ ["ヾ"]={ "ヽ","゙" },
+ ["יִ"]={ "י","ִ" },
+ ["ײַ"]={ "ײ","ַ" },
+ ["שׁ"]={ "ש","ׁ" },
+ ["שׂ"]={ "ש","ׂ" },
+ ["שּׁ"]={ "שּ","ׁ" },
+ ["שּׂ"]={ "שּ","ׂ" },
+ ["אַ"]={ "א","ַ" },
+ ["אָ"]={ "א","ָ" },
+ ["אּ"]={ "א","ּ" },
+ ["בּ"]={ "ב","ּ" },
+ ["גּ"]={ "ג","ּ" },
+ ["דּ"]={ "ד","ּ" },
+ ["הּ"]={ "ה","ּ" },
+ ["וּ"]={ "ו","ּ" },
+ ["זּ"]={ "ז","ּ" },
+ ["טּ"]={ "ט","ּ" },
+ ["יּ"]={ "י","ּ" },
+ ["ךּ"]={ "ך","ּ" },
+ ["כּ"]={ "כ","ּ" },
+ ["לּ"]={ "ל","ּ" },
+ ["מּ"]={ "מ","ּ" },
+ ["נּ"]={ "נ","ּ" },
+ ["סּ"]={ "ס","ּ" },
+ ["ףּ"]={ "ף","ּ" },
+ ["פּ"]={ "פ","ּ" },
+ ["צּ"]={ "צ","ּ" },
+ ["קּ"]={ "ק","ּ" },
+ ["רּ"]={ "ר","ּ" },
+ ["שּ"]={ "ש","ּ" },
+ ["תּ"]={ "ת","ּ" },
+ ["וֹ"]={ "ו","ֹ" },
+ ["בֿ"]={ "ב","ֿ" },
+ ["כֿ"]={ "כ","ֿ" },
+ ["פֿ"]={ "פ","ֿ" },
+ ["𑂚"]={ "𑂙","𑂺" },
+ ["𑂜"]={ "𑂛","𑂺" },
+ ["𑂫"]={ "𑂥","𑂺" },
+ ["𑄮"]={ "𑄱","𑄧" },
+ ["𑄯"]={ "𑄲","𑄧" },
+ ["𑍋"]={ "𑍇","𑌾" },
+ ["𑍌"]={ "𑍇","𑍗" },
+ ["𑒻"]={ "𑒹","𑒺" },
+ ["𑒼"]={ "𑒹","𑒰" },
+ ["𑒾"]={ "𑒹","𑒽" },
+ ["𑖺"]={ "𑖸","𑖯" },
+ ["𑖻"]={ "𑖹","𑖯" },
+ ["𝅗𝅥"]={ "𝅗","𝅥" },
+ ["𝅘𝅥"]={ "𝅘","𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
+ ["𝆹𝅥"]={ "𝆹","𝅥" },
+ ["𝆺𝅥"]={ "𝆺","𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
+ },
+ },
+ {
+ ["data"]={
+ ["À"]={ "A","̀" },
+ ["Á"]={ "A","́" },
+ ["Â"]={ "A","̂" },
+ ["Ã"]={ "A","̃" },
+ ["Ä"]={ "A","̈" },
+ ["Å"]={ "A","̊" },
+ ["Ç"]={ "C","̧" },
+ ["È"]={ "E","̀" },
+ ["É"]={ "E","́" },
+ ["Ê"]={ "E","̂" },
+ ["Ë"]={ "E","̈" },
+ ["Ì"]={ "I","̀" },
+ ["Í"]={ "I","́" },
+ ["Î"]={ "I","̂" },
+ ["Ï"]={ "I","̈" },
+ ["Ñ"]={ "N","̃" },
+ ["Ò"]={ "O","̀" },
+ ["Ó"]={ "O","́" },
+ ["Ô"]={ "O","̂" },
+ ["Õ"]={ "O","̃" },
+ ["Ö"]={ "O","̈" },
+ ["Ù"]={ "U","̀" },
+ ["Ú"]={ "U","́" },
+ ["Û"]={ "U","̂" },
+ ["Ü"]={ "U","̈" },
+ ["Ý"]={ "Y","́" },
+ ["à"]={ "a","̀" },
+ ["á"]={ "a","́" },
+ ["â"]={ "a","̂" },
+ ["ã"]={ "a","̃" },
+ ["ä"]={ "a","̈" },
+ ["å"]={ "a","̊" },
+ ["ç"]={ "c","̧" },
+ ["è"]={ "e","̀" },
+ ["é"]={ "e","́" },
+ ["ê"]={ "e","̂" },
+ ["ë"]={ "e","̈" },
+ ["ì"]={ "i","̀" },
+ ["í"]={ "i","́" },
+ ["î"]={ "i","̂" },
+ ["ï"]={ "i","̈" },
+ ["ñ"]={ "n","̃" },
+ ["ò"]={ "o","̀" },
+ ["ó"]={ "o","́" },
+ ["ô"]={ "o","̂" },
+ ["õ"]={ "o","̃" },
+ ["ö"]={ "o","̈" },
+ ["ù"]={ "u","̀" },
+ ["ú"]={ "u","́" },
+ ["û"]={ "u","̂" },
+ ["ü"]={ "u","̈" },
+ ["ý"]={ "y","́" },
+ ["ÿ"]={ "y","̈" },
+ ["Ā"]={ "A","̄" },
+ ["ā"]={ "a","̄" },
+ ["Ă"]={ "A","̆" },
+ ["ă"]={ "a","̆" },
+ ["Ą"]={ "A","̨" },
+ ["ą"]={ "a","̨" },
+ ["Ć"]={ "C","́" },
+ ["ć"]={ "c","́" },
+ ["Ĉ"]={ "C","̂" },
+ ["ĉ"]={ "c","̂" },
+ ["Ċ"]={ "C","̇" },
+ ["ċ"]={ "c","̇" },
+ ["Č"]={ "C","̌" },
+ ["č"]={ "c","̌" },
+ ["Ď"]={ "D","̌" },
+ ["ď"]={ "d","̌" },
+ ["Ē"]={ "E","̄" },
+ ["ē"]={ "e","̄" },
+ ["Ĕ"]={ "E","̆" },
+ ["ĕ"]={ "e","̆" },
+ ["Ė"]={ "E","̇" },
+ ["ė"]={ "e","̇" },
+ ["Ę"]={ "E","̨" },
+ ["ę"]={ "e","̨" },
+ ["Ě"]={ "E","̌" },
+ ["ě"]={ "e","̌" },
+ ["Ĝ"]={ "G","̂" },
+ ["ĝ"]={ "g","̂" },
+ ["Ğ"]={ "G","̆" },
+ ["ğ"]={ "g","̆" },
+ ["Ġ"]={ "G","̇" },
+ ["ġ"]={ "g","̇" },
+ ["Ģ"]={ "G","̧" },
+ ["ģ"]={ "g","̧" },
+ ["Ĥ"]={ "H","̂" },
+ ["ĥ"]={ "h","̂" },
+ ["Ĩ"]={ "I","̃" },
+ ["ĩ"]={ "i","̃" },
+ ["Ī"]={ "I","̄" },
+ ["ī"]={ "i","̄" },
+ ["Ĭ"]={ "I","̆" },
+ ["ĭ"]={ "i","̆" },
+ ["Į"]={ "I","̨" },
+ ["į"]={ "i","̨" },
+ ["İ"]={ "I","̇" },
+ ["Ĵ"]={ "J","̂" },
+ ["ĵ"]={ "j","̂" },
+ ["Ķ"]={ "K","̧" },
+ ["ķ"]={ "k","̧" },
+ ["Ĺ"]={ "L","́" },
+ ["ĺ"]={ "l","́" },
+ ["Ļ"]={ "L","̧" },
+ ["ļ"]={ "l","̧" },
+ ["Ľ"]={ "L","̌" },
+ ["ľ"]={ "l","̌" },
+ ["Ń"]={ "N","́" },
+ ["ń"]={ "n","́" },
+ ["Ņ"]={ "N","̧" },
+ ["ņ"]={ "n","̧" },
+ ["Ň"]={ "N","̌" },
+ ["ň"]={ "n","̌" },
+ ["Ō"]={ "O","̄" },
+ ["ō"]={ "o","̄" },
+ ["Ŏ"]={ "O","̆" },
+ ["ŏ"]={ "o","̆" },
+ ["Ő"]={ "O","̋" },
+ ["ő"]={ "o","̋" },
+ ["Ŕ"]={ "R","́" },
+ ["ŕ"]={ "r","́" },
+ ["Ŗ"]={ "R","̧" },
+ ["ŗ"]={ "r","̧" },
+ ["Ř"]={ "R","̌" },
+ ["ř"]={ "r","̌" },
+ ["Ś"]={ "S","́" },
+ ["ś"]={ "s","́" },
+ ["Ŝ"]={ "S","̂" },
+ ["ŝ"]={ "s","̂" },
+ ["Ş"]={ "S","̧" },
+ ["ş"]={ "s","̧" },
+ ["Š"]={ "S","̌" },
+ ["š"]={ "s","̌" },
+ ["Ţ"]={ "T","̧" },
+ ["ţ"]={ "t","̧" },
+ ["Ť"]={ "T","̌" },
+ ["ť"]={ "t","̌" },
+ ["Ũ"]={ "U","̃" },
+ ["ũ"]={ "u","̃" },
+ ["Ū"]={ "U","̄" },
+ ["ū"]={ "u","̄" },
+ ["Ŭ"]={ "U","̆" },
+ ["ŭ"]={ "u","̆" },
+ ["Ů"]={ "U","̊" },
+ ["ů"]={ "u","̊" },
+ ["Ű"]={ "U","̋" },
+ ["ű"]={ "u","̋" },
+ ["Ų"]={ "U","̨" },
+ ["ų"]={ "u","̨" },
+ ["Ŵ"]={ "W","̂" },
+ ["ŵ"]={ "w","̂" },
+ ["Ŷ"]={ "Y","̂" },
+ ["ŷ"]={ "y","̂" },
+ ["Ÿ"]={ "Y","̈" },
+ ["Ź"]={ "Z","́" },
+ ["ź"]={ "z","́" },
+ ["Ż"]={ "Z","̇" },
+ ["ż"]={ "z","̇" },
+ ["Ž"]={ "Z","̌" },
+ ["ž"]={ "z","̌" },
+ ["Ơ"]={ "O","̛" },
+ ["ơ"]={ "o","̛" },
+ ["Ư"]={ "U","̛" },
+ ["ư"]={ "u","̛" },
+ ["Ǎ"]={ "A","̌" },
+ ["ǎ"]={ "a","̌" },
+ ["Ǐ"]={ "I","̌" },
+ ["ǐ"]={ "i","̌" },
+ ["Ǒ"]={ "O","̌" },
+ ["ǒ"]={ "o","̌" },
+ ["Ǔ"]={ "U","̌" },
+ ["ǔ"]={ "u","̌" },
+ ["Ǖ"]={ "Ü","̄" },
+ ["ǖ"]={ "ü","̄" },
+ ["Ǘ"]={ "Ü","́" },
+ ["ǘ"]={ "ü","́" },
+ ["Ǚ"]={ "Ü","̌" },
+ ["ǚ"]={ "ü","̌" },
+ ["Ǜ"]={ "Ü","̀" },
+ ["ǜ"]={ "ü","̀" },
+ ["Ǟ"]={ "Ä","̄" },
+ ["ǟ"]={ "ä","̄" },
+ ["Ǡ"]={ "Ȧ","̄" },
+ ["ǡ"]={ "ȧ","̄" },
+ ["Ǣ"]={ "Æ","̄" },
+ ["ǣ"]={ "æ","̄" },
+ ["Ǧ"]={ "G","̌" },
+ ["ǧ"]={ "g","̌" },
+ ["Ǩ"]={ "K","̌" },
+ ["ǩ"]={ "k","̌" },
+ ["Ǫ"]={ "O","̨" },
+ ["ǫ"]={ "o","̨" },
+ ["Ǭ"]={ "Ǫ","̄" },
+ ["ǭ"]={ "ǫ","̄" },
+ ["Ǯ"]={ "Ʒ","̌" },
+ ["ǯ"]={ "ʒ","̌" },
+ ["ǰ"]={ "j","̌" },
+ ["Ǵ"]={ "G","́" },
+ ["ǵ"]={ "g","́" },
+ ["Ǹ"]={ "N","̀" },
+ ["ǹ"]={ "n","̀" },
+ ["Ǻ"]={ "Å","́" },
+ ["ǻ"]={ "å","́" },
+ ["Ǽ"]={ "Æ","́" },
+ ["ǽ"]={ "æ","́" },
+ ["Ǿ"]={ "Ø","́" },
+ ["ǿ"]={ "ø","́" },
+ ["Ȁ"]={ "A","̏" },
+ ["ȁ"]={ "a","̏" },
+ ["Ȃ"]={ "A","̑" },
+ ["ȃ"]={ "a","̑" },
+ ["Ȅ"]={ "E","̏" },
+ ["ȅ"]={ "e","̏" },
+ ["Ȇ"]={ "E","̑" },
+ ["ȇ"]={ "e","̑" },
+ ["Ȉ"]={ "I","̏" },
+ ["ȉ"]={ "i","̏" },
+ ["Ȋ"]={ "I","̑" },
+ ["ȋ"]={ "i","̑" },
+ ["Ȍ"]={ "O","̏" },
+ ["ȍ"]={ "o","̏" },
+ ["Ȏ"]={ "O","̑" },
+ ["ȏ"]={ "o","̑" },
+ ["Ȑ"]={ "R","̏" },
+ ["ȑ"]={ "r","̏" },
+ ["Ȓ"]={ "R","̑" },
+ ["ȓ"]={ "r","̑" },
+ ["Ȕ"]={ "U","̏" },
+ ["ȕ"]={ "u","̏" },
+ ["Ȗ"]={ "U","̑" },
+ ["ȗ"]={ "u","̑" },
+ ["Ș"]={ "S","̦" },
+ ["ș"]={ "s","̦" },
+ ["Ț"]={ "T","̦" },
+ ["ț"]={ "t","̦" },
+ ["Ȟ"]={ "H","̌" },
+ ["ȟ"]={ "h","̌" },
+ ["Ȧ"]={ "A","̇" },
+ ["ȧ"]={ "a","̇" },
+ ["Ȩ"]={ "E","̧" },
+ ["ȩ"]={ "e","̧" },
+ ["Ȫ"]={ "Ö","̄" },
+ ["ȫ"]={ "ö","̄" },
+ ["Ȭ"]={ "Õ","̄" },
+ ["ȭ"]={ "õ","̄" },
+ ["Ȯ"]={ "O","̇" },
+ ["ȯ"]={ "o","̇" },
+ ["Ȱ"]={ "Ȯ","̄" },
+ ["ȱ"]={ "ȯ","̄" },
+ ["Ȳ"]={ "Y","̄" },
+ ["ȳ"]={ "y","̄" },
+ ["̈́"]={ "̈","́" },
+ ["΅"]={ "¨","́" },
+ ["Ά"]={ "Α","́" },
+ ["Έ"]={ "Ε","́" },
+ ["Ή"]={ "Η","́" },
+ ["Ί"]={ "Ι","́" },
+ ["Ό"]={ "Ο","́" },
+ ["Ύ"]={ "Υ","́" },
+ ["Ώ"]={ "Ω","́" },
+ ["ΐ"]={ "ϊ","́" },
+ ["Ϊ"]={ "Ι","̈" },
+ ["Ϋ"]={ "Υ","̈" },
+ ["ά"]={ "α","́" },
+ ["έ"]={ "ε","́" },
+ ["ή"]={ "η","́" },
+ ["ί"]={ "ι","́" },
+ ["ΰ"]={ "ϋ","́" },
+ ["ϊ"]={ "ι","̈" },
+ ["ϋ"]={ "υ","̈" },
+ ["ό"]={ "ο","́" },
+ ["ύ"]={ "υ","́" },
+ ["ώ"]={ "ω","́" },
+ ["ϓ"]={ "ϒ","́" },
+ ["ϔ"]={ "ϒ","̈" },
+ ["Ѐ"]={ "Е","̀" },
+ ["Ё"]={ "Е","̈" },
+ ["Ѓ"]={ "Г","́" },
+ ["Ї"]={ "І","̈" },
+ ["Ќ"]={ "К","́" },
+ ["Ѝ"]={ "И","̀" },
+ ["Ў"]={ "У","̆" },
+ ["Й"]={ "И","̆" },
+ ["й"]={ "и","̆" },
+ ["ѐ"]={ "е","̀" },
+ ["ё"]={ "е","̈" },
+ ["ѓ"]={ "г","́" },
+ ["ї"]={ "і","̈" },
+ ["ќ"]={ "к","́" },
+ ["ѝ"]={ "и","̀" },
+ ["ў"]={ "у","̆" },
+ ["Ѷ"]={ "Ѵ","̏" },
+ ["ѷ"]={ "ѵ","̏" },
+ ["Ӂ"]={ "Ж","̆" },
+ ["ӂ"]={ "ж","̆" },
+ ["Ӑ"]={ "А","̆" },
+ ["ӑ"]={ "а","̆" },
+ ["Ӓ"]={ "А","̈" },
+ ["ӓ"]={ "а","̈" },
+ ["Ӗ"]={ "Е","̆" },
+ ["ӗ"]={ "е","̆" },
+ ["Ӛ"]={ "Ә","̈" },
+ ["ӛ"]={ "ә","̈" },
+ ["Ӝ"]={ "Ж","̈" },
+ ["ӝ"]={ "ж","̈" },
+ ["Ӟ"]={ "З","̈" },
+ ["ӟ"]={ "з","̈" },
+ ["Ӣ"]={ "И","̄" },
+ ["ӣ"]={ "и","̄" },
+ ["Ӥ"]={ "И","̈" },
+ ["ӥ"]={ "и","̈" },
+ ["Ӧ"]={ "О","̈" },
+ ["ӧ"]={ "о","̈" },
+ ["Ӫ"]={ "Ө","̈" },
+ ["ӫ"]={ "ө","̈" },
+ ["Ӭ"]={ "Э","̈" },
+ ["ӭ"]={ "э","̈" },
+ ["Ӯ"]={ "У","̄" },
+ ["ӯ"]={ "у","̄" },
+ ["Ӱ"]={ "У","̈" },
+ ["ӱ"]={ "у","̈" },
+ ["Ӳ"]={ "У","̋" },
+ ["ӳ"]={ "у","̋" },
+ ["Ӵ"]={ "Ч","̈" },
+ ["ӵ"]={ "ч","̈" },
+ ["Ӹ"]={ "Ы","̈" },
+ ["ӹ"]={ "ы","̈" },
+ ["آ"]={ "ا","ٓ" },
+ ["أ"]={ "ا","ٔ" },
+ ["ؤ"]={ "و","ٔ" },
+ ["إ"]={ "ا","ٕ" },
+ ["ئ"]={ "ي","ٔ" },
+ ["ۀ"]={ "ە","ٔ" },
+ ["ۂ"]={ "ہ","ٔ" },
+ ["ۓ"]={ "ے","ٔ" },
+ ["ऩ"]={ "न","़" },
+ ["ऱ"]={ "र","़" },
+ ["ऴ"]={ "ळ","़" },
+ ["क़"]={ "क","़" },
+ ["ख़"]={ "ख","़" },
+ ["ग़"]={ "ग","़" },
+ ["ज़"]={ "ज","़" },
+ ["ड़"]={ "ड","़" },
+ ["ढ़"]={ "ढ","़" },
+ ["फ़"]={ "फ","़" },
+ ["य़"]={ "य","़" },
+ ["ো"]={ "ে","া" },
+ ["ৌ"]={ "ে","ৗ" },
+ ["ড়"]={ "ড","়" },
+ ["ঢ়"]={ "ঢ","়" },
+ ["য়"]={ "য","়" },
+ ["ਲ਼"]={ "ਲ","਼" },
+ ["ਸ਼"]={ "ਸ","਼" },
+ ["ਖ਼"]={ "ਖ","਼" },
+ ["ਗ਼"]={ "ਗ","਼" },
+ ["ਜ਼"]={ "ਜ","਼" },
+ ["ਫ਼"]={ "ਫ","਼" },
+ ["ୈ"]={ "େ","ୖ" },
+ ["ୋ"]={ "େ","ା" },
+ ["ୌ"]={ "େ","ୗ" },
+ ["ଡ଼"]={ "ଡ","଼" },
+ ["ଢ଼"]={ "ଢ","଼" },
+ ["ஔ"]={ "ஒ","ௗ" },
+ ["ொ"]={ "ெ","ா" },
+ ["ோ"]={ "ே","ா" },
+ ["ௌ"]={ "ெ","ௗ" },
+ ["ై"]={ "ె","ౖ" },
+ ["ೀ"]={ "ಿ","ೕ" },
+ ["ೇ"]={ "ೆ","ೕ" },
+ ["ೈ"]={ "ೆ","ೖ" },
+ ["ೊ"]={ "ೆ","ೂ" },
+ ["ೋ"]={ "ೊ","ೕ" },
+ ["ൊ"]={ "െ","ാ" },
+ ["ോ"]={ "േ","ാ" },
+ ["ൌ"]={ "െ","ൗ" },
+ ["ේ"]={ "ෙ","්" },
+ ["ො"]={ "ෙ","ා" },
+ ["ෝ"]={ "ො","්" },
+ ["ෞ"]={ "ෙ","ෟ" },
+ ["གྷ"]={ "ག","ྷ" },
+ ["ཌྷ"]={ "ཌ","ྷ" },
+ ["དྷ"]={ "ད","ྷ" },
+ ["བྷ"]={ "བ","ྷ" },
+ ["ཛྷ"]={ "ཛ","ྷ" },
+ ["ཀྵ"]={ "ཀ","ྵ" },
+ ["ཱི"]={ "ཱ","ི" },
+ ["ཱུ"]={ "ཱ","ུ" },
+ ["ྲྀ"]={ "ྲ","ྀ" },
+ ["ླྀ"]={ "ླ","ྀ" },
+ ["ཱྀ"]={ "ཱ","ྀ" },
+ ["ྒྷ"]={ "ྒ","ྷ" },
+ ["ྜྷ"]={ "ྜ","ྷ" },
+ ["ྡྷ"]={ "ྡ","ྷ" },
+ ["ྦྷ"]={ "ྦ","ྷ" },
+ ["ྫྷ"]={ "ྫ","ྷ" },
+ ["ྐྵ"]={ "ྐ","ྵ" },
+ ["ဦ"]={ "ဥ","ီ" },
+ ["ᬆ"]={ "ᬅ","ᬵ" },
+ ["ᬈ"]={ "ᬇ","ᬵ" },
+ ["ᬊ"]={ "ᬉ","ᬵ" },
+ ["ᬌ"]={ "ᬋ","ᬵ" },
+ ["ᬎ"]={ "ᬍ","ᬵ" },
+ ["ᬒ"]={ "ᬑ","ᬵ" },
+ ["ᬻ"]={ "ᬺ","ᬵ" },
+ ["ᬽ"]={ "ᬼ","ᬵ" },
+ ["ᭀ"]={ "ᬾ","ᬵ" },
+ ["ᭁ"]={ "ᬿ","ᬵ" },
+ ["ᭃ"]={ "ᭂ","ᬵ" },
+ ["Ḁ"]={ "A","̥" },
+ ["ḁ"]={ "a","̥" },
+ ["Ḃ"]={ "B","̇" },
+ ["ḃ"]={ "b","̇" },
+ ["Ḅ"]={ "B","̣" },
+ ["ḅ"]={ "b","̣" },
+ ["Ḇ"]={ "B","̱" },
+ ["ḇ"]={ "b","̱" },
+ ["Ḉ"]={ "Ç","́" },
+ ["ḉ"]={ "ç","́" },
+ ["Ḋ"]={ "D","̇" },
+ ["ḋ"]={ "d","̇" },
+ ["Ḍ"]={ "D","̣" },
+ ["ḍ"]={ "d","̣" },
+ ["Ḏ"]={ "D","̱" },
+ ["ḏ"]={ "d","̱" },
+ ["Ḑ"]={ "D","̧" },
+ ["ḑ"]={ "d","̧" },
+ ["Ḓ"]={ "D","̭" },
+ ["ḓ"]={ "d","̭" },
+ ["Ḕ"]={ "Ē","̀" },
+ ["ḕ"]={ "ē","̀" },
+ ["Ḗ"]={ "Ē","́" },
+ ["ḗ"]={ "ē","́" },
+ ["Ḙ"]={ "E","̭" },
+ ["ḙ"]={ "e","̭" },
+ ["Ḛ"]={ "E","̰" },
+ ["ḛ"]={ "e","̰" },
+ ["Ḝ"]={ "Ȩ","̆" },
+ ["ḝ"]={ "ȩ","̆" },
+ ["Ḟ"]={ "F","̇" },
+ ["ḟ"]={ "f","̇" },
+ ["Ḡ"]={ "G","̄" },
+ ["ḡ"]={ "g","̄" },
+ ["Ḣ"]={ "H","̇" },
+ ["ḣ"]={ "h","̇" },
+ ["Ḥ"]={ "H","̣" },
+ ["ḥ"]={ "h","̣" },
+ ["Ḧ"]={ "H","̈" },
+ ["ḧ"]={ "h","̈" },
+ ["Ḩ"]={ "H","̧" },
+ ["ḩ"]={ "h","̧" },
+ ["Ḫ"]={ "H","̮" },
+ ["ḫ"]={ "h","̮" },
+ ["Ḭ"]={ "I","̰" },
+ ["ḭ"]={ "i","̰" },
+ ["Ḯ"]={ "Ï","́" },
+ ["ḯ"]={ "ï","́" },
+ ["Ḱ"]={ "K","́" },
+ ["ḱ"]={ "k","́" },
+ ["Ḳ"]={ "K","̣" },
+ ["ḳ"]={ "k","̣" },
+ ["Ḵ"]={ "K","̱" },
+ ["ḵ"]={ "k","̱" },
+ ["Ḷ"]={ "L","̣" },
+ ["ḷ"]={ "l","̣" },
+ ["Ḹ"]={ "Ḷ","̄" },
+ ["ḹ"]={ "ḷ","̄" },
+ ["Ḻ"]={ "L","̱" },
+ ["ḻ"]={ "l","̱" },
+ ["Ḽ"]={ "L","̭" },
+ ["ḽ"]={ "l","̭" },
+ ["Ḿ"]={ "M","́" },
+ ["ḿ"]={ "m","́" },
+ ["Ṁ"]={ "M","̇" },
+ ["ṁ"]={ "m","̇" },
+ ["Ṃ"]={ "M","̣" },
+ ["ṃ"]={ "m","̣" },
+ ["Ṅ"]={ "N","̇" },
+ ["ṅ"]={ "n","̇" },
+ ["Ṇ"]={ "N","̣" },
+ ["ṇ"]={ "n","̣" },
+ ["Ṉ"]={ "N","̱" },
+ ["ṉ"]={ "n","̱" },
+ ["Ṋ"]={ "N","̭" },
+ ["ṋ"]={ "n","̭" },
+ ["Ṍ"]={ "Õ","́" },
+ ["ṍ"]={ "õ","́" },
+ ["Ṏ"]={ "Õ","̈" },
+ ["ṏ"]={ "õ","̈" },
+ ["Ṑ"]={ "Ō","̀" },
+ ["ṑ"]={ "ō","̀" },
+ ["Ṓ"]={ "Ō","́" },
+ ["ṓ"]={ "ō","́" },
+ ["Ṕ"]={ "P","́" },
+ ["ṕ"]={ "p","́" },
+ ["Ṗ"]={ "P","̇" },
+ ["ṗ"]={ "p","̇" },
+ ["Ṙ"]={ "R","̇" },
+ ["ṙ"]={ "r","̇" },
+ ["Ṛ"]={ "R","̣" },
+ ["ṛ"]={ "r","̣" },
+ ["Ṝ"]={ "Ṛ","̄" },
+ ["ṝ"]={ "ṛ","̄" },
+ ["Ṟ"]={ "R","̱" },
+ ["ṟ"]={ "r","̱" },
+ ["Ṡ"]={ "S","̇" },
+ ["ṡ"]={ "s","̇" },
+ ["Ṣ"]={ "S","̣" },
+ ["ṣ"]={ "s","̣" },
+ ["Ṥ"]={ "Ś","̇" },
+ ["ṥ"]={ "ś","̇" },
+ ["Ṧ"]={ "Š","̇" },
+ ["ṧ"]={ "š","̇" },
+ ["Ṩ"]={ "Ṣ","̇" },
+ ["ṩ"]={ "ṣ","̇" },
+ ["Ṫ"]={ "T","̇" },
+ ["ṫ"]={ "t","̇" },
+ ["Ṭ"]={ "T","̣" },
+ ["ṭ"]={ "t","̣" },
+ ["Ṯ"]={ "T","̱" },
+ ["ṯ"]={ "t","̱" },
+ ["Ṱ"]={ "T","̭" },
+ ["ṱ"]={ "t","̭" },
+ ["Ṳ"]={ "U","̤" },
+ ["ṳ"]={ "u","̤" },
+ ["Ṵ"]={ "U","̰" },
+ ["ṵ"]={ "u","̰" },
+ ["Ṷ"]={ "U","̭" },
+ ["ṷ"]={ "u","̭" },
+ ["Ṹ"]={ "Ũ","́" },
+ ["ṹ"]={ "ũ","́" },
+ ["Ṻ"]={ "Ū","̈" },
+ ["ṻ"]={ "ū","̈" },
+ ["Ṽ"]={ "V","̃" },
+ ["ṽ"]={ "v","̃" },
+ ["Ṿ"]={ "V","̣" },
+ ["ṿ"]={ "v","̣" },
+ ["Ẁ"]={ "W","̀" },
+ ["ẁ"]={ "w","̀" },
+ ["Ẃ"]={ "W","́" },
+ ["ẃ"]={ "w","́" },
+ ["Ẅ"]={ "W","̈" },
+ ["ẅ"]={ "w","̈" },
+ ["Ẇ"]={ "W","̇" },
+ ["ẇ"]={ "w","̇" },
+ ["Ẉ"]={ "W","̣" },
+ ["ẉ"]={ "w","̣" },
+ ["Ẋ"]={ "X","̇" },
+ ["ẋ"]={ "x","̇" },
+ ["Ẍ"]={ "X","̈" },
+ ["ẍ"]={ "x","̈" },
+ ["Ẏ"]={ "Y","̇" },
+ ["ẏ"]={ "y","̇" },
+ ["Ẑ"]={ "Z","̂" },
+ ["ẑ"]={ "z","̂" },
+ ["Ẓ"]={ "Z","̣" },
+ ["ẓ"]={ "z","̣" },
+ ["Ẕ"]={ "Z","̱" },
+ ["ẕ"]={ "z","̱" },
+ ["ẖ"]={ "h","̱" },
+ ["ẗ"]={ "t","̈" },
+ ["ẘ"]={ "w","̊" },
+ ["ẙ"]={ "y","̊" },
+ ["ẛ"]={ "ſ","̇" },
+ ["Ạ"]={ "A","̣" },
+ ["ạ"]={ "a","̣" },
+ ["Ả"]={ "A","̉" },
+ ["ả"]={ "a","̉" },
+ ["Ấ"]={ "Â","́" },
+ ["ấ"]={ "â","́" },
+ ["Ầ"]={ "Â","̀" },
+ ["ầ"]={ "â","̀" },
+ ["Ẩ"]={ "Â","̉" },
+ ["ẩ"]={ "â","̉" },
+ ["Ẫ"]={ "Â","̃" },
+ ["ẫ"]={ "â","̃" },
+ ["Ậ"]={ "Ạ","̂" },
+ ["ậ"]={ "ạ","̂" },
+ ["Ắ"]={ "Ă","́" },
+ ["ắ"]={ "ă","́" },
+ ["Ằ"]={ "Ă","̀" },
+ ["ằ"]={ "ă","̀" },
+ ["Ẳ"]={ "Ă","̉" },
+ ["ẳ"]={ "ă","̉" },
+ ["Ẵ"]={ "Ă","̃" },
+ ["ẵ"]={ "ă","̃" },
+ ["Ặ"]={ "Ạ","̆" },
+ ["ặ"]={ "ạ","̆" },
+ ["Ẹ"]={ "E","̣" },
+ ["ẹ"]={ "e","̣" },
+ ["Ẻ"]={ "E","̉" },
+ ["ẻ"]={ "e","̉" },
+ ["Ẽ"]={ "E","̃" },
+ ["ẽ"]={ "e","̃" },
+ ["Ế"]={ "Ê","́" },
+ ["ế"]={ "ê","́" },
+ ["Ề"]={ "Ê","̀" },
+ ["ề"]={ "ê","̀" },
+ ["Ể"]={ "Ê","̉" },
+ ["ể"]={ "ê","̉" },
+ ["Ễ"]={ "Ê","̃" },
+ ["ễ"]={ "ê","̃" },
+ ["Ệ"]={ "Ẹ","̂" },
+ ["ệ"]={ "ẹ","̂" },
+ ["Ỉ"]={ "I","̉" },
+ ["ỉ"]={ "i","̉" },
+ ["Ị"]={ "I","̣" },
+ ["ị"]={ "i","̣" },
+ ["Ọ"]={ "O","̣" },
+ ["ọ"]={ "o","̣" },
+ ["Ỏ"]={ "O","̉" },
+ ["ỏ"]={ "o","̉" },
+ ["Ố"]={ "Ô","́" },
+ ["ố"]={ "ô","́" },
+ ["Ồ"]={ "Ô","̀" },
+ ["ồ"]={ "ô","̀" },
+ ["Ổ"]={ "Ô","̉" },
+ ["ổ"]={ "ô","̉" },
+ ["Ỗ"]={ "Ô","̃" },
+ ["ỗ"]={ "ô","̃" },
+ ["Ộ"]={ "Ọ","̂" },
+ ["ộ"]={ "ọ","̂" },
+ ["Ớ"]={ "Ơ","́" },
+ ["ớ"]={ "ơ","́" },
+ ["Ờ"]={ "Ơ","̀" },
+ ["ờ"]={ "ơ","̀" },
+ ["Ở"]={ "Ơ","̉" },
+ ["ở"]={ "ơ","̉" },
+ ["Ỡ"]={ "Ơ","̃" },
+ ["ỡ"]={ "ơ","̃" },
+ ["Ợ"]={ "Ơ","̣" },
+ ["ợ"]={ "ơ","̣" },
+ ["Ụ"]={ "U","̣" },
+ ["ụ"]={ "u","̣" },
+ ["Ủ"]={ "U","̉" },
+ ["ủ"]={ "u","̉" },
+ ["Ứ"]={ "Ư","́" },
+ ["ứ"]={ "ư","́" },
+ ["Ừ"]={ "Ư","̀" },
+ ["ừ"]={ "ư","̀" },
+ ["Ử"]={ "Ư","̉" },
+ ["ử"]={ "ư","̉" },
+ ["Ữ"]={ "Ư","̃" },
+ ["ữ"]={ "ư","̃" },
+ ["Ự"]={ "Ư","̣" },
+ ["ự"]={ "ư","̣" },
+ ["Ỳ"]={ "Y","̀" },
+ ["ỳ"]={ "y","̀" },
+ ["Ỵ"]={ "Y","̣" },
+ ["ỵ"]={ "y","̣" },
+ ["Ỷ"]={ "Y","̉" },
+ ["ỷ"]={ "y","̉" },
+ ["Ỹ"]={ "Y","̃" },
+ ["ỹ"]={ "y","̃" },
+ ["ἀ"]={ "α","̓" },
+ ["ἁ"]={ "α","̔" },
+ ["ἂ"]={ "ἀ","̀" },
+ ["ἃ"]={ "ἁ","̀" },
+ ["ἄ"]={ "ἀ","́" },
+ ["ἅ"]={ "ἁ","́" },
+ ["ἆ"]={ "ἀ","͂" },
+ ["ἇ"]={ "ἁ","͂" },
+ ["Ἀ"]={ "Α","̓" },
+ ["Ἁ"]={ "Α","̔" },
+ ["Ἂ"]={ "Ἀ","̀" },
+ ["Ἃ"]={ "Ἁ","̀" },
+ ["Ἄ"]={ "Ἀ","́" },
+ ["Ἅ"]={ "Ἁ","́" },
+ ["Ἆ"]={ "Ἀ","͂" },
+ ["Ἇ"]={ "Ἁ","͂" },
+ ["ἐ"]={ "ε","̓" },
+ ["ἑ"]={ "ε","̔" },
+ ["ἒ"]={ "ἐ","̀" },
+ ["ἓ"]={ "ἑ","̀" },
+ ["ἔ"]={ "ἐ","́" },
+ ["ἕ"]={ "ἑ","́" },
+ ["Ἐ"]={ "Ε","̓" },
+ ["Ἑ"]={ "Ε","̔" },
+ ["Ἒ"]={ "Ἐ","̀" },
+ ["Ἓ"]={ "Ἑ","̀" },
+ ["Ἔ"]={ "Ἐ","́" },
+ ["Ἕ"]={ "Ἑ","́" },
+ ["ἠ"]={ "η","̓" },
+ ["ἡ"]={ "η","̔" },
+ ["ἢ"]={ "ἠ","̀" },
+ ["ἣ"]={ "ἡ","̀" },
+ ["ἤ"]={ "ἠ","́" },
+ ["ἥ"]={ "ἡ","́" },
+ ["ἦ"]={ "ἠ","͂" },
+ ["ἧ"]={ "ἡ","͂" },
+ ["Ἠ"]={ "Η","̓" },
+ ["Ἡ"]={ "Η","̔" },
+ ["Ἢ"]={ "Ἠ","̀" },
+ ["Ἣ"]={ "Ἡ","̀" },
+ ["Ἤ"]={ "Ἠ","́" },
+ ["Ἥ"]={ "Ἡ","́" },
+ ["Ἦ"]={ "Ἠ","͂" },
+ ["Ἧ"]={ "Ἡ","͂" },
+ ["ἰ"]={ "ι","̓" },
+ ["ἱ"]={ "ι","̔" },
+ ["ἲ"]={ "ἰ","̀" },
+ ["ἳ"]={ "ἱ","̀" },
+ ["ἴ"]={ "ἰ","́" },
+ ["ἵ"]={ "ἱ","́" },
+ ["ἶ"]={ "ἰ","͂" },
+ ["ἷ"]={ "ἱ","͂" },
+ ["Ἰ"]={ "Ι","̓" },
+ ["Ἱ"]={ "Ι","̔" },
+ ["Ἲ"]={ "Ἰ","̀" },
+ ["Ἳ"]={ "Ἱ","̀" },
+ ["Ἴ"]={ "Ἰ","́" },
+ ["Ἵ"]={ "Ἱ","́" },
+ ["Ἶ"]={ "Ἰ","͂" },
+ ["Ἷ"]={ "Ἱ","͂" },
+ ["ὀ"]={ "ο","̓" },
+ ["ὁ"]={ "ο","̔" },
+ ["ὂ"]={ "ὀ","̀" },
+ ["ὃ"]={ "ὁ","̀" },
+ ["ὄ"]={ "ὀ","́" },
+ ["ὅ"]={ "ὁ","́" },
+ ["Ὀ"]={ "Ο","̓" },
+ ["Ὁ"]={ "Ο","̔" },
+ ["Ὂ"]={ "Ὀ","̀" },
+ ["Ὃ"]={ "Ὁ","̀" },
+ ["Ὄ"]={ "Ὀ","́" },
+ ["Ὅ"]={ "Ὁ","́" },
+ ["ὐ"]={ "υ","̓" },
+ ["ὑ"]={ "υ","̔" },
+ ["ὒ"]={ "ὐ","̀" },
+ ["ὓ"]={ "ὑ","̀" },
+ ["ὔ"]={ "ὐ","́" },
+ ["ὕ"]={ "ὑ","́" },
+ ["ὖ"]={ "ὐ","͂" },
+ ["ὗ"]={ "ὑ","͂" },
+ ["Ὑ"]={ "Υ","̔" },
+ ["Ὓ"]={ "Ὑ","̀" },
+ ["Ὕ"]={ "Ὑ","́" },
+ ["Ὗ"]={ "Ὑ","͂" },
+ ["ὠ"]={ "ω","̓" },
+ ["ὡ"]={ "ω","̔" },
+ ["ὢ"]={ "ὠ","̀" },
+ ["ὣ"]={ "ὡ","̀" },
+ ["ὤ"]={ "ὠ","́" },
+ ["ὥ"]={ "ὡ","́" },
+ ["ὦ"]={ "ὠ","͂" },
+ ["ὧ"]={ "ὡ","͂" },
+ ["Ὠ"]={ "Ω","̓" },
+ ["Ὡ"]={ "Ω","̔" },
+ ["Ὢ"]={ "Ὠ","̀" },
+ ["Ὣ"]={ "Ὡ","̀" },
+ ["Ὤ"]={ "Ὠ","́" },
+ ["Ὥ"]={ "Ὡ","́" },
+ ["Ὦ"]={ "Ὠ","͂" },
+ ["Ὧ"]={ "Ὡ","͂" },
+ ["ὰ"]={ "α","̀" },
+ ["ὲ"]={ "ε","̀" },
+ ["ὴ"]={ "η","̀" },
+ ["ὶ"]={ "ι","̀" },
+ ["ὸ"]={ "ο","̀" },
+ ["ὺ"]={ "υ","̀" },
+ ["ὼ"]={ "ω","̀" },
+ ["ᾀ"]={ "ἀ","ͅ" },
+ ["ᾁ"]={ "ἁ","ͅ" },
+ ["ᾂ"]={ "ἂ","ͅ" },
+ ["ᾃ"]={ "ἃ","ͅ" },
+ ["ᾄ"]={ "ἄ","ͅ" },
+ ["ᾅ"]={ "ἅ","ͅ" },
+ ["ᾆ"]={ "ἆ","ͅ" },
+ ["ᾇ"]={ "ἇ","ͅ" },
+ ["ᾈ"]={ "Ἀ","ͅ" },
+ ["ᾉ"]={ "Ἁ","ͅ" },
+ ["ᾊ"]={ "Ἂ","ͅ" },
+ ["ᾋ"]={ "Ἃ","ͅ" },
+ ["ᾌ"]={ "Ἄ","ͅ" },
+ ["ᾍ"]={ "Ἅ","ͅ" },
+ ["ᾎ"]={ "Ἆ","ͅ" },
+ ["ᾏ"]={ "Ἇ","ͅ" },
+ ["ᾐ"]={ "ἠ","ͅ" },
+ ["ᾑ"]={ "ἡ","ͅ" },
+ ["ᾒ"]={ "ἢ","ͅ" },
+ ["ᾓ"]={ "ἣ","ͅ" },
+ ["ᾔ"]={ "ἤ","ͅ" },
+ ["ᾕ"]={ "ἥ","ͅ" },
+ ["ᾖ"]={ "ἦ","ͅ" },
+ ["ᾗ"]={ "ἧ","ͅ" },
+ ["ᾘ"]={ "Ἠ","ͅ" },
+ ["ᾙ"]={ "Ἡ","ͅ" },
+ ["ᾚ"]={ "Ἢ","ͅ" },
+ ["ᾛ"]={ "Ἣ","ͅ" },
+ ["ᾜ"]={ "Ἤ","ͅ" },
+ ["ᾝ"]={ "Ἥ","ͅ" },
+ ["ᾞ"]={ "Ἦ","ͅ" },
+ ["ᾟ"]={ "Ἧ","ͅ" },
+ ["ᾠ"]={ "ὠ","ͅ" },
+ ["ᾡ"]={ "ὡ","ͅ" },
+ ["ᾢ"]={ "ὢ","ͅ" },
+ ["ᾣ"]={ "ὣ","ͅ" },
+ ["ᾤ"]={ "ὤ","ͅ" },
+ ["ᾥ"]={ "ὥ","ͅ" },
+ ["ᾦ"]={ "ὦ","ͅ" },
+ ["ᾧ"]={ "ὧ","ͅ" },
+ ["ᾨ"]={ "Ὠ","ͅ" },
+ ["ᾩ"]={ "Ὡ","ͅ" },
+ ["ᾪ"]={ "Ὢ","ͅ" },
+ ["ᾫ"]={ "Ὣ","ͅ" },
+ ["ᾬ"]={ "Ὤ","ͅ" },
+ ["ᾭ"]={ "Ὥ","ͅ" },
+ ["ᾮ"]={ "Ὦ","ͅ" },
+ ["ᾯ"]={ "Ὧ","ͅ" },
+ ["ᾰ"]={ "α","̆" },
+ ["ᾱ"]={ "α","̄" },
+ ["ᾲ"]={ "ὰ","ͅ" },
+ ["ᾳ"]={ "α","ͅ" },
+ ["ᾴ"]={ "ά","ͅ" },
+ ["ᾶ"]={ "α","͂" },
+ ["ᾷ"]={ "ᾶ","ͅ" },
+ ["Ᾰ"]={ "Α","̆" },
+ ["Ᾱ"]={ "Α","̄" },
+ ["Ὰ"]={ "Α","̀" },
+ ["ᾼ"]={ "Α","ͅ" },
+ ["῁"]={ "¨","͂" },
+ ["ῂ"]={ "ὴ","ͅ" },
+ ["ῃ"]={ "η","ͅ" },
+ ["ῄ"]={ "ή","ͅ" },
+ ["ῆ"]={ "η","͂" },
+ ["ῇ"]={ "ῆ","ͅ" },
+ ["Ὲ"]={ "Ε","̀" },
+ ["Ὴ"]={ "Η","̀" },
+ ["ῌ"]={ "Η","ͅ" },
+ ["῍"]={ "᾿","̀" },
+ ["῎"]={ "᾿","́" },
+ ["῏"]={ "᾿","͂" },
+ ["ῐ"]={ "ι","̆" },
+ ["ῑ"]={ "ι","̄" },
+ ["ῒ"]={ "ϊ","̀" },
+ ["ῖ"]={ "ι","͂" },
+ ["ῗ"]={ "ϊ","͂" },
+ ["Ῐ"]={ "Ι","̆" },
+ ["Ῑ"]={ "Ι","̄" },
+ ["Ὶ"]={ "Ι","̀" },
+ ["῝"]={ "῾","̀" },
+ ["῞"]={ "῾","́" },
+ ["῟"]={ "῾","͂" },
+ ["ῠ"]={ "υ","̆" },
+ ["ῡ"]={ "υ","̄" },
+ ["ῢ"]={ "ϋ","̀" },
+ ["ῤ"]={ "ρ","̓" },
+ ["ῥ"]={ "ρ","̔" },
+ ["ῦ"]={ "υ","͂" },
+ ["ῧ"]={ "ϋ","͂" },
+ ["Ῠ"]={ "Υ","̆" },
+ ["Ῡ"]={ "Υ","̄" },
+ ["Ὺ"]={ "Υ","̀" },
+ ["Ῥ"]={ "Ρ","̔" },
+ ["῭"]={ "¨","̀" },
+ ["ῲ"]={ "ὼ","ͅ" },
+ ["ῳ"]={ "ω","ͅ" },
+ ["ῴ"]={ "ώ","ͅ" },
+ ["ῶ"]={ "ω","͂" },
+ ["ῷ"]={ "ῶ","ͅ" },
+ ["Ὸ"]={ "Ο","̀" },
+ ["Ὼ"]={ "Ω","̀" },
+ ["ῼ"]={ "Ω","ͅ" },
+ ["↚"]={ "←","̸" },
+ ["↛"]={ "→","̸" },
+ ["↮"]={ "↔","̸" },
+ ["⇍"]={ "⇐","̸" },
+ ["⇎"]={ "⇔","̸" },
+ ["⇏"]={ "⇒","̸" },
+ ["∄"]={ "∃","̸" },
+ ["∉"]={ "∈","̸" },
+ ["∌"]={ "∋","̸" },
+ ["∤"]={ "∣","̸" },
+ ["∦"]={ "∥","̸" },
+ ["≁"]={ "∼","̸" },
+ ["≄"]={ "≃","̸" },
+ ["≇"]={ "≅","̸" },
+ ["≉"]={ "≈","̸" },
+ ["≠"]={ "=","̸" },
+ ["≢"]={ "≡","̸" },
+ ["≭"]={ "≍","̸" },
+ ["≮"]={ "<","̸" },
+ ["≯"]={ ">","̸" },
+ ["≰"]={ "≤","̸" },
+ ["≱"]={ "≥","̸" },
+ ["≴"]={ "≲","̸" },
+ ["≵"]={ "≳","̸" },
+ ["≸"]={ "≶","̸" },
+ ["≹"]={ "≷","̸" },
+ ["⊀"]={ "≺","̸" },
+ ["⊁"]={ "≻","̸" },
+ ["⊄"]={ "⊂","̸" },
+ ["⊅"]={ "⊃","̸" },
+ ["⊈"]={ "⊆","̸" },
+ ["⊉"]={ "⊇","̸" },
+ ["⊬"]={ "⊢","̸" },
+ ["⊭"]={ "⊨","̸" },
+ ["⊮"]={ "⊩","̸" },
+ ["⊯"]={ "⊫","̸" },
+ ["⋠"]={ "≼","̸" },
+ ["⋡"]={ "≽","̸" },
+ ["⋢"]={ "⊑","̸" },
+ ["⋣"]={ "⊒","̸" },
+ ["⋪"]={ "⊲","̸" },
+ ["⋫"]={ "⊳","̸" },
+ ["⋬"]={ "⊴","̸" },
+ ["⋭"]={ "⊵","̸" },
+ ["⫝̸"]={ "⫝","̸" },
+ ["が"]={ "か","゙" },
+ ["ぎ"]={ "き","゙" },
+ ["ぐ"]={ "く","゙" },
+ ["げ"]={ "け","゙" },
+ ["ご"]={ "こ","゙" },
+ ["ざ"]={ "さ","゙" },
+ ["じ"]={ "し","゙" },
+ ["ず"]={ "す","゙" },
+ ["ぜ"]={ "せ","゙" },
+ ["ぞ"]={ "そ","゙" },
+ ["だ"]={ "た","゙" },
+ ["ぢ"]={ "ち","゙" },
+ ["づ"]={ "つ","゙" },
+ ["で"]={ "て","゙" },
+ ["ど"]={ "と","゙" },
+ ["ば"]={ "は","゙" },
+ ["ぱ"]={ "は","゚" },
+ ["び"]={ "ひ","゙" },
+ ["ぴ"]={ "ひ","゚" },
+ ["ぶ"]={ "ふ","゙" },
+ ["ぷ"]={ "ふ","゚" },
+ ["べ"]={ "へ","゙" },
+ ["ぺ"]={ "へ","゚" },
+ ["ぼ"]={ "ほ","゙" },
+ ["ぽ"]={ "ほ","゚" },
+ ["ゔ"]={ "う","゙" },
+ ["ゞ"]={ "ゝ","゙" },
+ ["ガ"]={ "カ","゙" },
+ ["ギ"]={ "キ","゙" },
+ ["グ"]={ "ク","゙" },
+ ["ゲ"]={ "ケ","゙" },
+ ["ゴ"]={ "コ","゙" },
+ ["ザ"]={ "サ","゙" },
+ ["ジ"]={ "シ","゙" },
+ ["ズ"]={ "ス","゙" },
+ ["ゼ"]={ "セ","゙" },
+ ["ゾ"]={ "ソ","゙" },
+ ["ダ"]={ "タ","゙" },
+ ["ヂ"]={ "チ","゙" },
+ ["ヅ"]={ "ツ","゙" },
+ ["デ"]={ "テ","゙" },
+ ["ド"]={ "ト","゙" },
+ ["バ"]={ "ハ","゙" },
+ ["パ"]={ "ハ","゚" },
+ ["ビ"]={ "ヒ","゙" },
+ ["ピ"]={ "ヒ","゚" },
+ ["ブ"]={ "フ","゙" },
+ ["プ"]={ "フ","゚" },
+ ["ベ"]={ "ヘ","゙" },
+ ["ペ"]={ "ヘ","゚" },
+ ["ボ"]={ "ホ","゙" },
+ ["ポ"]={ "ホ","゚" },
+ ["ヴ"]={ "ウ","゙" },
+ ["ヷ"]={ "ワ","゙" },
+ ["ヸ"]={ "ヰ","゙" },
+ ["ヹ"]={ "ヱ","゙" },
+ ["ヺ"]={ "ヲ","゙" },
+ ["ヾ"]={ "ヽ","゙" },
+ ["יִ"]={ "י","ִ" },
+ ["ײַ"]={ "ײ","ַ" },
+ ["שׁ"]={ "ש","ׁ" },
+ ["שׂ"]={ "ש","ׂ" },
+ ["שּׁ"]={ "שּ","ׁ" },
+ ["שּׂ"]={ "שּ","ׂ" },
+ ["אַ"]={ "א","ַ" },
+ ["אָ"]={ "א","ָ" },
+ ["אּ"]={ "א","ּ" },
+ ["בּ"]={ "ב","ּ" },
+ ["גּ"]={ "ג","ּ" },
+ ["דּ"]={ "ד","ּ" },
+ ["הּ"]={ "ה","ּ" },
+ ["וּ"]={ "ו","ּ" },
+ ["זּ"]={ "ז","ּ" },
+ ["טּ"]={ "ט","ּ" },
+ ["יּ"]={ "י","ּ" },
+ ["ךּ"]={ "ך","ּ" },
+ ["כּ"]={ "כ","ּ" },
+ ["לּ"]={ "ל","ּ" },
+ ["מּ"]={ "מ","ּ" },
+ ["נּ"]={ "נ","ּ" },
+ ["סּ"]={ "ס","ּ" },
+ ["ףּ"]={ "ף","ּ" },
+ ["פּ"]={ "פ","ּ" },
+ ["צּ"]={ "צ","ּ" },
+ ["קּ"]={ "ק","ּ" },
+ ["רּ"]={ "ר","ּ" },
+ ["שּ"]={ "ש","ּ" },
+ ["תּ"]={ "ת","ּ" },
+ ["וֹ"]={ "ו","ֹ" },
+ ["בֿ"]={ "ב","ֿ" },
+ ["כֿ"]={ "כ","ֿ" },
+ ["פֿ"]={ "פ","ֿ" },
+ ["𑂚"]={ "𑂙","𑂺" },
+ ["𑂜"]={ "𑂛","𑂺" },
+ ["𑂫"]={ "𑂥","𑂺" },
+ ["𑄮"]={ "𑄱","𑄧" },
+ ["𑄯"]={ "𑄲","𑄧" },
+ ["𑍋"]={ "𑍇","𑌾" },
+ ["𑍌"]={ "𑍇","𑍗" },
+ ["𑒻"]={ "𑒹","𑒺" },
+ ["𑒼"]={ "𑒹","𑒰" },
+ ["𑒾"]={ "𑒹","𑒽" },
+ ["𑖺"]={ "𑖸","𑖯" },
+ ["𑖻"]={ "𑖹","𑖯" },
+ ["𝅗𝅥"]={ "𝅗","𝅥" },
+ ["𝅘𝅥"]={ "𝅘","𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
+ ["𝆹𝅥"]={ "𝆹","𝅥" },
+ ["𝆺𝅥"]={ "𝆺","𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
+ },
+ },
+ },
+ ["name"]="collapse",
+ ["prepend"]=true,
+ ["type"]="ligature",
+}
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “fonts-ext”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-lig”] ---
-do --- [luaotfload, fontloader-2017-02-11.lua scope for “font-gbn” 850f31ba73ff8de96371d0aed2b2b4cb] ---
+do --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-gbn” 10ecdf01e7c926e5128ad8a9dff4d677] ---
-if not modules then modules={} end modules ['font-gbn']={
+if not modules then modules={} end modules ['luatex-fonts-gbn']={
version=1.001,
comment="companion to luatex-*.tex",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -21501,9 +29005,9 @@ if not modules then modules={} end modules ['font-gbn']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
+local next=next
local fonts=fonts
local nodes=nodes
local nuts=nodes.nuts
@@ -21523,14 +29027,13 @@ local getdisc=nuts.getdisc
local setchar=nuts.setchar
local setlink=nuts.setlink
local setprev=nuts.setprev
-local nodetail=nuts.tail
local n_ligaturing=node.ligaturing
local n_kerning=node.kerning
-local ligaturing=nuts.ligaturing
-local kerning=nuts.kerning
+local d_ligaturing=nuts.ligaturing
+local d_kerning=nuts.kerning
local basemodepass=true
-local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning=nil end
-local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning=nil end
+local function l_warning() logs.report("fonts","don't call 'node.ligaturing' directly") l_warning=nil end
+local function k_warning() logs.report("fonts","don't call 'node.kerning' directly") k_warning=nil end
function node.ligaturing(...)
if basemodepass and l_warning then
l_warning()
@@ -21543,20 +29046,32 @@ function node.kerning(...)
end
return n_kerning(...)
end
+function nuts.ligaturing(...)
+ if basemodepass and l_warning then
+ l_warning()
+ end
+ return d_ligaturing(...)
+end
+function nuts.kerning(...)
+ if basemodepass and k_warning then
+ k_warning()
+ end
+ return d_kerning(...)
+end
function nodes.handlers.setbasemodepass(v)
basemodepass=v
end
-function nodes.handlers.nodepass(head)
+local function nodepass(head,groupcode,size,packtype,direction)
local fontdata=fonts.hashes.identifiers
if fontdata then
- local nuthead=tonut(head)
local usedfonts={}
local basefonts={}
local prevfont=nil
local basefont=nil
local variants=nil
local redundant=nil
- for n in traverse_id(glyph_code,nuthead) do
+ local nofused=0
+ for n in traverse_id(glyph_code,head) do
local font=getfont(n)
if font~=prevfont then
if basefont then
@@ -21572,6 +29087,7 @@ function nodes.handlers.nodepass(head)
local processors=shared.processes
if processors and #processors>0 then
usedfonts[font]=processors
+ nofused=nofused+1
elseif basemodepass then
basefont={ n,nil }
basefonts[#basefonts+1]=basefont
@@ -21592,7 +29108,7 @@ function nodes.handlers.nodepass(head)
end
if variants then
local char=getchar(n)
- if char>=0xFE00 and (char<=0xFE0F or (char>=0xE0100 and char<=0xE01EF)) then
+ if (char>=0xFE00 and char<=0xFE0F) or (char>=0xE0100 and char<=0xE01EF) then
local hash=variants[char]
if hash then
local p=getprev(n)
@@ -21616,8 +29132,8 @@ function nodes.handlers.nodepass(head)
for i=1,#redundant do
local r=redundant[i]
local p,n=getboth(r)
- if r==nuthead then
- nuthead=n
+ if r==head then
+ head=n
setprev(n)
else
setlink(p,n)
@@ -21636,7 +29152,7 @@ function nodes.handlers.nodepass(head)
flush_node(r)
end
end
- for d in traverse_id(disc_code,nuthead) do
+ for d in traverse_id(disc_code,head) do
local _,_,r=getdisc(d)
if r then
for n in traverse_id(glyph_code,r) do
@@ -21652,6 +29168,7 @@ function nodes.handlers.nodepass(head)
local processors=shared.processes
if processors and #processors>0 then
usedfonts[font]=processors
+ nofused=nofused+1
end
end
end
@@ -21663,7 +29180,7 @@ function nodes.handlers.nodepass(head)
if next(usedfonts) then
for font,processors in next,usedfonts do
for i=1,#processors do
- head=processors[i](head,font,0) or head
+ head=processors[i](head,font,0,direction,nofused) or head
end
end
end
@@ -21673,54 +29190,77 @@ function nodes.handlers.nodepass(head)
local start=range[1]
local stop=range[2]
if start then
- local front=nuthead==start
- if not stop then
- stop=nodetail(start)
- end
+ local front=head==start
+ local prev,next
if stop then
- start,stop=ligaturing(start,stop)
- start,stop=kerning(start,stop)
- elseif start then
- start,stop=ligaturing(start,stop)
- start,stop=kerning(start,stop)
+ next=getnext(stop)
+ start,stop=d_ligaturing(start,stop)
+ start,stop=d_kerning(start,stop)
+ else
+ prev=getprev(start)
+ start=d_ligaturing(start)
+ start=d_kerning(start)
+ end
+ if prev then
+ setlink(prev,start)
end
- if front and nuthead~=start then
- head=tonode(start)
+ if next then
+ setlink(stop,next)
+ end
+ if front and head~=start then
+ head=start
end
end
end
end
- return head,true
- else
- return head,false
end
+ return head
end
-function nodes.handlers.basepass(head)
- if not basemodepass then
- head=n_ligaturing(head)
- head=n_kerning(head)
+local function basepass(head)
+ if basemodepass then
+ head=d_ligaturing(head)
+ head=d_kerning(head)
end
- return head,true
+ return head
end
-local nodepass=nodes.handlers.nodepass
-local basepass=nodes.handlers.basepass
+local protectpass=node.direct.protect_glyphs
local injectpass=nodes.injections.handler
-local protectpass=nodes.handlers.protectglyphs
-function nodes.simple_font_handler(head)
+function nodes.handlers.nodepass(head,...)
if head then
- head=nodepass(head)
+ return tonode(nodepass(tonut(head),...))
+ end
+end
+function nodes.handlers.basepass(head)
+ if head then
+ return tonode(basepass(tonut(head)))
+ end
+end
+function nodes.handlers.injectpass(head)
+ if head then
+ return tonode(injectpass(tonut(head)))
+ end
+end
+function nodes.handlers.protectpass(head)
+ if head then
+ protectpass(tonut(head))
+ return head
+ end
+end
+function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
+ if head then
+ head=tonut(head)
+ head=nodepass(head,groupcode,size,packtype,direction)
head=injectpass(head)
if not basemodepass then
head=basepass(head)
end
protectpass(head)
- return head,true
- else
- return head,false
+ head=tonode(head)
end
+ return head
end
-end --- [luaotfload, fontloader-2017-02-11.lua scope for “font-gbn”] ---
+end --- [luaotfload, fontloader-2018-09-24.lua scope for “fonts-gbn”] ---
--- vim:ft=lua:sw=2:ts=8:et:tw=79
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-gen.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-gen.lua
index 2be55cceabc..64f3be21832 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-gen.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-gen.lua
@@ -7,10 +7,18 @@ if not modules then modules = { } end modules ['luat-basics-gen'] = {
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
+-- We could load a few more of the general context libraries but it would
+-- not make plain / latex users more happy I guess. So, we stick to some
+-- placeholders.
+
+local match, gmatch, gsub, lower = string.match, string.gmatch, string.gsub, string.lower
+local formatters, split, format, dump = string.formatters, string.split, string.format, string.dump
+local loadfile, type = loadfile, type
+local setmetatable, getmetatable, collectgarbage = setmetatable, getmetatable, collectgarbage
+
local dummyfunction = function()
end
@@ -18,13 +26,22 @@ local dummyreporter = function(c)
return function(f,...)
local r = texio.reporter or texio.write_nl
if f then
- r(c .. " : " .. string.formatters(f,...))
+ r(c .. " : " .. (formatters or format)(f,...))
else
r("")
end
end
end
+local dummyreport = function(c,f,...)
+ local r = texio.reporter or texio.write_nl
+ if f then
+ r(c .. " : " .. (formatters or format)(f,...))
+ else
+ r("")
+ end
+end
+
statistics = {
register = dummyfunction,
starttiming = dummyfunction,
@@ -59,17 +76,18 @@ logs = {
new = dummyreporter,
reporter = dummyreporter,
messenger = dummyreporter,
- report = dummyfunction,
+ report = dummyreport,
}
callbacks = {
register = function(n,f)
return callback.register(n,f)
end,
-
}
-utilities = utilities or { } utilities.storage = {
+utilities = utilities or { }
+
+utilities.storage = utilities.storage or {
allocate = function(t)
return t or { }
end,
@@ -78,6 +96,28 @@ utilities = utilities or { } utilities.storage = {
end,
}
+utilities.parsers = utilities.parsers or {
+ -- these are less flexible than in context but ok
+ -- for generic purpose
+ settings_to_array = function(s)
+ return split(s,",")
+ end,
+ settings_to_hash = function(s)
+ local t = { }
+ for k, v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do
+ t[k] = v
+ end
+ return t
+ end,
+ settings_to_hash_colon_too = function(s)
+ local t = { }
+ for k, v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do
+ t[k] = v
+ end
+ return t
+ end,
+}
+
characters = characters or {
data = { }
}
@@ -98,17 +138,18 @@ local remapper = {
pfb = "type1 fonts", -- needed for vector loading
afm = "afm",
enc = "enc files",
+ lua = "tex",
}
function resolvers.findfile(name,fileformat)
- name = string.gsub(name,"\\","/")
+ name = gsub(name,"\\","/")
if not fileformat or fileformat == "" then
fileformat = file.suffix(name)
if fileformat == "" then
fileformat = "tex"
end
end
- fileformat = string.lower(fileformat)
+ fileformat = lower(fileformat)
fileformat = remapper[fileformat] or fileformat
local found = kpse.find_file(name,fileformat)
if not found or found == "" then
@@ -117,13 +158,6 @@ function resolvers.findfile(name,fileformat)
return found
end
--- function resolvers.findbinfile(name,fileformat)
--- if not fileformat or fileformat == "" then
--- fileformat = file.suffix(name)
--- end
--- return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
--- end
-
resolvers.findbinfile = resolvers.findfile
function resolvers.loadbinfile(filename,filetype)
@@ -191,14 +225,14 @@ do
cachepaths = "."
end
- cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":")
+ cachepaths = split(cachepaths,os.type == "windows" and ";" or ":")
for i=1,#cachepaths do
local cachepath = cachepaths[i]
if not lfs.isdir(cachepath) then
lfs.mkdirs(cachepath) -- needed for texlive and latex
if lfs.isdir(cachepath) then
- texio.write(string.format("(created cache path: %s)",cachepath))
+ logs.report("system","creating cache path '%s'",cachepath)
end
end
if file.is_writable(cachepath) then
@@ -217,16 +251,16 @@ do
end
if not writable then
- texio.write_nl("quiting: fix your writable cache path")
+ logs.report("system","no writeable cache path, quiting")
os.exit()
elseif #readables == 0 then
- texio.write_nl("quiting: fix your readable cache path")
+ logs.report("system","no readable cache path, quiting")
os.exit()
elseif #readables == 1 and readables[1] == writable then
- texio.write(string.format("(using cache: %s)",writable))
+ logs.report("system","using cache '%s'",writable)
else
- texio.write(string.format("(using write cache: %s)",writable))
- texio.write(string.format("(using read cache: %s)",table.concat(readables, " ")))
+ logs.report("system","using write cache '%s'",writable)
+ logs.report("system","using read cache '%s'",table.concat(readables," "))
end
end
@@ -258,75 +292,34 @@ function caches.is_writable(path,name)
return fullname and file.is_writable(fullname)
end
--- function caches.loaddata(paths,name)
--- for i=1,#paths do
--- local data = false
--- local luaname, lucname = makefullname(paths[i],name)
--- if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then
--- -- in case we used luatex and luajittex mixed ... lub or luc file
--- texio.write(string.format("(compiling luc: %s)",lucname))
--- data = loadfile(luaname)
--- if data then
--- data = data()
--- end
--- if data then
--- caches.compile(data,luaname,lucname)
--- return data
--- end
--- end
--- if lucname and lfs.isfile(lucname) then -- maybe also check for size
--- texio.write(string.format("(load luc: %s)",lucname))
--- data = loadfile(lucname)
--- if data then
--- data = data()
--- end
--- if data then
--- return data
--- else
--- texio.write(string.format("(loading failed: %s)",lucname))
--- end
--- end
--- if luaname and lfs.isfile(luaname) then
--- texio.write(string.format("(load lua: %s)",luaname))
--- data = loadfile(luaname)
--- if data then
--- data = data()
--- end
--- if data then
--- return data
--- end
--- end
--- end
--- end
-
function caches.loaddata(readables,name,writable)
for i=1,#readables do
local path = readables[i]
local loader = false
local luaname, lucname = makefullname(path,name)
if lfs.isfile(lucname) then
- texio.write(string.format("(load luc: %s)",lucname))
+ logs.report("system","loading luc file '%s'",lucname)
loader = loadfile(lucname)
end
if not loader and lfs.isfile(luaname) then
-- can be different paths when we read a file database from disk
local luacrap, lucname = makefullname(writable,name)
- texio.write(string.format("(compiling luc: %s)",lucname))
+ logs.report("system","compiling luc file '%s'",lucname)
if lfs.isfile(lucname) then
loader = loadfile(lucname)
end
caches.compile(data,luaname,lucname)
if lfs.isfile(lucname) then
- texio.write(string.format("(load luc: %s)",lucname))
+ logs.report("system","loading luc file '%s'",lucname)
loader = loadfile(lucname)
else
- texio.write(string.format("(loading failed: %s)",lucname))
+ logs.report("system","error in loading luc file '%s'",lucname)
end
if not loader then
- texio.write(string.format("(load lua: %s)",luaname))
+ logs.report("system","loading lua file '%s'",luaname)
loader = loadfile(luaname)
else
- texio.write(string.format("(loading failed: %s)",luaname))
+ logs.report("system","error in loading lua file '%s'",luaname)
end
end
if loader then
@@ -341,42 +334,19 @@ end
function caches.savedata(path,name,data)
local luaname, lucname = makefullname(path,name)
if luaname then
- texio.write(string.format("(save: %s)",luaname))
+ logs.report("system","saving lua file '%s'",luaname)
table.tofile(luaname,data,true)
if lucname and type(caches.compile) == "function" then
os.remove(lucname) -- better be safe
- texio.write(string.format("(save: %s)",lucname))
+ logs.report("system","saving luc file '%s'",lucname)
caches.compile(data,luaname,lucname)
end
end
end
--- According to KH os.execute is not permitted in plain/latex so there is
--- no reason to use the normal context way. So the method here is slightly
--- different from the one we have in context. We also use different suffixes
--- as we don't want any clashes (sharing cache files is not that handy as
--- context moves on faster.)
---
--- Beware: serialization might fail on large files (so maybe we should pcall
--- this) in which case one should limit the method to luac and enable support
--- for execution.
-
--- function caches.compile(data,luaname,lucname)
--- local d = io.loaddata(luaname)
--- if not d or d == "" then
--- d = table.serialize(data,true) -- slow
--- end
--- if d and d ~= "" then
--- local f = io.open(lucname,'w')
--- if f then
--- local s = loadstring(d)
--- if s then
--- f:write(string.dump(s,true))
--- end
--- f:close()
--- end
--- end
--- end
+-- The method here is slightly different from the one we have in context. We
+-- also use different suffixes as we don't want any clashes (sharing cache
+-- files is not that handy as context moves on faster.)
function caches.compile(data,luaname,lucname)
local d = io.loaddata(luaname)
@@ -388,23 +358,14 @@ function caches.compile(data,luaname,lucname)
if f then
local s = loadstring(d)
if s then
- f:write(string.dump(s,true))
+ f:write(dump(s,true))
end
f:close()
end
end
end
---
-
--- function table.setmetatableindex(t,f)
--- if type(t) ~= "table" then
--- f = f or t
--- t = { }
--- end
--- setmetatable(t,{ __index = f })
--- return t
--- end
+-- simplfied version:
function table.setmetatableindex(t,f)
if type(t) ~= "table" then
@@ -422,13 +383,23 @@ function table.setmetatableindex(t,f)
return t
end
+function table.makeweak(t)
+ local m = getmetatable(t)
+ if m then
+ m.__mode = "v"
+ else
+ setmetatable(t,{ __mode = "v" })
+ end
+ return t
+end
+
-- helper for plain:
arguments = { }
if arg then
for i=1,#arg do
- local k, v = string.match(arg[i],"^%-%-([^=]+)=?(.-)$")
+ local k, v = match(arg[i],"^%-%-([^=]+)=?(.-)$")
if k and v then
arguments[k] = v
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua
index 42a7a2e29eb..c3b467a11b3 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua
@@ -7,12 +7,12 @@ if not modules then modules = { } end modules ['luatex-fonts-nod'] = {
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
--- Don't depend on code here as it is only needed to complement the
--- font handler code.
+-- Don't depend on code here as it is only needed to complement the font handler
+-- code. I will move some to another namespace as I don't see other macro packages
+-- use the context logic. It's a subset anyway.
-- Attributes:
@@ -48,7 +48,6 @@ end
-- Nodes (a subset of context so that we don't get too much unused code):
nodes = { }
-nodes.pool = { }
nodes.handlers = { }
local nodecodes = { }
@@ -60,11 +59,11 @@ for k, v in next, node.types() do
nodecodes[k] = v
nodecodes[v] = k
end
-for i=0,#glyphcodes do
- glyphcodes[glyphcodes[i]] = i
+for k, v in next, glyphcodes do
+ glyphcodes[v] = k
end
-for i=0,#disccodes do
- disccodes[disccodes[i]] = i
+for k, v in next, glyphcodes do
+ disccodes[v] = k
end
nodes.nodecodes = nodecodes
@@ -73,11 +72,10 @@ nodes.disccodes = disccodes
local flush_node = node.flush_node
local remove_node = node.remove
-local new_node = node.new
local traverse_id = node.traverse_id
-nodes.handlers.protectglyphs = node.protect_glyphs
-nodes.handlers.unprotectglyphs = node.unprotect_glyphs
+nodes.handlers.protectglyphs = node.protect_glyphs -- beware: nodes!
+nodes.handlers.unprotectglyphs = node.unprotect_glyphs -- beware: nodes!
local math_code = nodecodes.math
local end_of_math = node.end_of_math
@@ -108,12 +106,6 @@ function nodes.delete(head,current)
return nodes.remove(head,current,true)
end
-function nodes.pool.kern(k)
- local n = new_node("kern",1)
- n.kern = k
- return n
-end
-
local getfield = node.getfield
local setfield = node.setfield
@@ -171,6 +163,8 @@ nodes.mlist_to_hlist = node.mlist_to_hlist
-- we can go nuts (e.g. experimental); this split permits us us keep code
-- used elsewhere stable but at the same time play around in context
+-- much of this will go away
+
local direct = node.direct
local nuts = { }
nodes.nuts = nuts
@@ -201,16 +195,40 @@ nuts.setattr = setfield
nuts.getfont = direct.getfont
nuts.setfont = direct.setfont
nuts.getsubtype = direct.getsubtype
-nuts.setsubtype = direct.setsubtype or function(n,s) setfield(n,"subtype",s) end
+nuts.setsubtype = direct.setsubtype
nuts.getchar = direct.getchar
nuts.setchar = direct.setchar
nuts.getdisc = direct.getdisc
nuts.setdisc = direct.setdisc
nuts.setlink = direct.setlink
+nuts.setsplit = direct.setsplit
nuts.getlist = direct.getlist
-nuts.setlist = direct.setlist or function(n,l) setfield(n,"list",l) end
-nuts.getleader = direct.getleader
-nuts.setleader = direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.setlist = direct.setlist
+
+nuts.getoffsets = direct.getoffsets or
+ function(n)
+ return getfield(n,"xoffset"), getfield(n,"yoffset")
+ end
+nuts.setoffsets = direct.setoffsets or
+ function(n,x,y)
+ if x then setfield(n,"xoffset",x) end
+ if y then setfield(n,"xoffset",y) end
+ end
+
+nuts.getleader = direct.getleader or function(n) return getfield(n,"leader") end
+nuts.setleader = direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.getcomponents = direct.getcomponents or function(n) return getfield(n,"components") end
+nuts.setcomponents = direct.setcomponents or function(n,c) setfield(n,"components",c) end
+nuts.getkern = direct.getkern or function(n) return getfield(n,"kern") end
+nuts.setkern = direct.setkern or function(n,k) setfield(n,"kern",k) end
+nuts.getdir = direct.getdir or function(n) return getfield(n,"dir") end
+nuts.setdir = direct.setdir or function(n,d) setfield(n,"dir",d) end
+nuts.getwidth = direct.getwidth or function(n) return getfield(n,"width") end
+nuts.setwidth = direct.setwidth or function(n,w) return setfield(n,"width",w) end
+nuts.getheight = direct.getheight or function(n) return getfield(n,"height") end
+nuts.setheight = direct.setheight or function(n,h) return setfield(n,"height",h) end
+nuts.getdepth = direct.getdepth or function(n) return getfield(n,"depth") end
+nuts.setdepth = direct.setdepth or function(n,d) return setfield(n,"depth",d) end
if not direct.is_glyph then
local getchar = direct.getchar
@@ -267,22 +285,14 @@ nuts.end_of_math = direct.end_of_math
nuts.traverse = direct.traverse
nuts.traverse_id = direct.traverse_id
nuts.traverse_char = direct.traverse_char
+nuts.traverse_glyph = direct.traverse_glyph
nuts.ligaturing = direct.ligaturing
nuts.kerning = direct.kerning
+nuts.new = direct.new
nuts.getprop = nuts.getattr
nuts.setprop = nuts.setattr
-local new_nut = direct.new
-nuts.new = new_nut
-nuts.pool = { }
-
-function nuts.pool.kern(k)
- local n = new_nut("kern",1)
- setfield(n,"kern",k)
- return n
-end
-
-- properties as used in the (new) injector:
local propertydata = direct.get_properties_table()
@@ -312,3 +322,182 @@ end
nodes.setprop = nodes.setproperty
nodes.getprop = nodes.getproperty
+
+-- a few helpers (we need to keep 'm in sync with context) .. some day components
+-- might go so here we isolate them
+
+local setprev = nuts.setprev
+local setnext = nuts.setnext
+local getnext = nuts.getnext
+local setlink = nuts.setlink
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local getcomponents = nuts.getcomponents
+local setcomponents = nuts.setcomponents
+
+local find_tail = nuts.tail
+local flush_list = nuts.flush_list
+local flush_node = nuts.flush_node
+local traverse_id = nuts.traverse_id
+local copy_node = nuts.copy_node
+
+local glyph_code = nodes.nodecodes.glyph
+
+function nuts.set_components(target,start,stop)
+ local head = getcomponents(target)
+ if head then
+ flush_list(head)
+ head = nil
+ end
+ if start then
+ setprev(start)
+ else
+ return nil
+ end
+ if stop then
+ setnext(stop)
+ end
+ local tail = nil
+ while start do
+ local c = getcomponents(start)
+ local n = getnext(start)
+ if c then
+ if head then
+ setlink(tail,c)
+ else
+ head = c
+ end
+ tail = find_tail(c)
+ setcomponents(start)
+ flush_node(start)
+ else
+ if head then
+ setlink(tail,start)
+ else
+ head = start
+ end
+ tail = start
+ end
+ start = n
+ end
+ setcomponents(target,head)
+ -- maybe also upgrade the subtype but we don't use it anyway
+ return head
+end
+
+nuts.get_components = nuts.getcomponents
+
+function nuts.take_components(target)
+ local c = getcomponents(target)
+ setcomponents(target)
+ -- maybe also upgrade the subtype but we don't use it anyway
+ return c
+end
+
+function nuts.count_components(n,marks)
+ local components = getcomponents(n)
+ if components then
+ if marks then
+ local i = 0
+ for g in traverse_id(glyph_code,components) do
+ if not marks[getchar(g)] then
+ i = i + 1
+ end
+ end
+ return i
+ else
+ return count(glyph_code,components)
+ end
+ else
+ return 0
+ end
+end
+
+function nuts.copy_no_components(g,copyinjection)
+ local components = getcomponents(g)
+ if components then
+ setcomponents(g)
+ local n = copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ setcomponents(g,components)
+ -- maybe also upgrade the subtype but we don't use it anyway
+ return n
+ else
+ local n = copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ return n
+ end
+end
+
+function nuts.copy_only_glyphs(current)
+ local head = nil
+ local previous = nil
+ for n in traverse_id(glyph_code,current) do
+ n = copy_node(n)
+ if head then
+ setlink(previous,n)
+ else
+ head = n
+ end
+ previous = n
+ end
+ return head
+end
+
+nuts.uses_font = direct.uses_font
+
+if not nuts.uses_font then
+ local getdisc = nuts.getdisc
+ local getfont = nuts.getfont
+ function nuts.uses_font(n,font)
+ local pre, post, replace = getdisc(n)
+ if pre then
+ -- traverse_char
+ for n in traverse_id(glyph_code,pre) do
+ if getfont(n) == font then
+ return true
+ end
+ end
+ end
+ if post then
+ for n in traverse_id(glyph_code,post) do
+ if getfont(n) == font then
+ return true
+ end
+ end
+ end
+ if replace then
+ for n in traverse_id(glyph_code,replace) do
+ if getfont(n) == font then
+ return true
+ end
+ end
+ end
+ return false
+ end
+end
+
+--
+do
+
+ -- another poor mans substitute ... i will move these to a more protected
+ -- namespace .. experimental hack
+
+ local dummy = tonut(node.new("glyph"))
+
+ nuts.traversers = {
+ glyph = nuts.traverse_id(nodecodes.glyph,dummy),
+ glue = nuts.traverse_id(nodecodes.glue,dummy),
+ disc = nuts.traverse_id(nodecodes.disc,dummy),
+ boundary = nuts.traverse_id(nodecodes.boundary,dummy),
+
+ char = nuts.traverse_char(dummy),
+
+ node = nuts.traverse(dummy),
+ }
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics.tex
deleted file mode 100644
index 1180c68e6c5..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics.tex
+++ /dev/null
@@ -1,93 +0,0 @@
-%D \module
-%D [ file=luatex-basics,
-%D version=2009.12.01,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Attribute Allocation,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D As soon as we feel the need this file will file will contain an extension
-%D to the standard plain register allocation. For the moment we stick to a
-%D rather dumb attribute allocator. We start at 256 because we don't want
-%D any interference with the attributes used in the font handler.
-
-\ifx\newattribute\undefined \else \endinput \fi
-
-\newcount \lastallocatedattribute \lastallocatedattribute=255
-
-\def\newattribute#1%
- {\global\advance\lastallocatedattribute 1
- \attributedef#1\lastallocatedattribute}
-
-% maybe we will have luatex-basics.lua some day for instance when more
-% (pdf) primitives have moved to macros)
-
-\directlua {
-
- gadgets = gadgets or { } % reserved namespace
-
- gadgets.functions = { }
- local registered = {}
-
- function gadgets.functions.reverve()
- local numb = newtoken.scan_int()
- local name = newtoken.scan_string()
- local okay = string.gsub(name,"[\string\\ ]","")
- registered[okay] = numb
- texio.write_nl("reserving lua function '"..okay.."' with number "..numb)
- end
-
- function gadgets.functions.register(name,f)
- local okay = string.gsub(name,"[\string\\ ]","")
- local numb = registered[okay]
- if numb then
- texio.write_nl("registering lua function '"..okay.."' with number "..numb)
- lua.get_functions_table()[numb] = f
- else
- texio.write_nl("lua function '"..okay.."' is not reserved")
- end
- end
-
-}
-
-\newcount\lastallocatedluafunction
-
-\def\newluafunction#1%
- {\ifdefined#1\else
- \global\advance\lastallocatedluafunction 1
- \global\chardef#1\lastallocatedluafunction
- \directlua{gadgets.functions.reserve()}#1{\detokenize{#1}}%
- \fi}
-
-% an example of usage (if we ever support it it will go to the plain gadgets module):
-%
-% \directlua {
-%
-% local cct = nil
-% local chr = nil
-%
-% gadgets.functions.register("UcharcatLuaOne",function()
-% chr = newtoken.scan_int()
-% cct = tex.getcatcode(chr)
-% tex.setcatcode(chr,newtoken.scan_int())
-% tex.sprint(unicode.utf8.char(chr))
-% end)
-%
-% gadgets.functions.register("UcharcatLuaTwo",function()
-% tex.setcatcode(chr,cct)
-% end)
-%
-% }
-%
-% \def\Ucharcat
-% {\expandafter\expandafter\expandafter\luafunction
-% \expandafter\expandafter\expandafter\UcharcatLuaTwo
-% \luafunction\UcharcatLuaOne}
-%
-% A:\the\catcode65:\Ucharcat 65 11:A:\the\catcode65\par
-% A:\the\catcode65:\Ucharcat 65 5:A:\the\catcode65\par
-% A:\the\catcode65:\Ucharcat 65 11:A:\the\catcode65\par
-
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-afk.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-afk.lua
index 8b65b063184..761016d3485 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-afk.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-afk.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['font-afk'] = {
version = 1.001,
- comment = "companion to font-afm.lua",
+ comment = "companion to font-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files",
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua
index 1c6bd56fd3d..87234dd460f 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua
@@ -13,32 +13,54 @@ if not modules then modules = { } end modules ['font-cff'] = {
-- This is a heavy one as it is a rather packed format. We don't need al the information
-- now but we might need it later (who know what magic we can do with metapost). So at
-- some point this might become a module. We just follow Adobe Technical Notes #5176 and
--- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX.
+-- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX but
+-- it's not the easiest source to read (and doesn't cover cff2).
-- For now we save the segments in a list of segments with the operator last in an entry
-- because that reflects the original. But it might make more sense to use a single array
-- per segment. For pdf a simple concat works ok, but for other purposes a operator first
-- flush is nicer.
+--
+-- In retrospect I could have looked into the backend code of LuaTeX but it never
+-- occurred to me that parsing charstrings was needed there (which has to to
+-- with merging subroutines and flattening, not so much with calculations.) On
+-- the other hand, we can now feed back cff2 stuff.
local next, type, tonumber = next, type, tonumber
-local byte = string.byte
+local byte, char, gmatch = string.byte, string.char, string.gmatch
local concat, remove = table.concat, table.remove
-local floor, abs, round, ceil = math.floor, math.abs, math.round, math.ceil
+local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max
local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct
local lpegmatch = lpeg.match
local formatters = string.formatters
+local bytetable = string.bytetable
local readers = fonts.handlers.otf.readers
local streamreader = readers.streamreader
-local readbytes = streamreader.readbytes
local readstring = streamreader.readstring
local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
-local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
+local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer
local setposition = streamreader.setposition
local getposition = streamreader.getposition
+local readbytetable = streamreader.readbytetable
+
+directives.register("fonts.streamreader",function()
+
+ streamreader = utilities.streams
+
+ readstring = streamreader.readstring
+ readbyte = streamreader.readcardinal1
+ readushort = streamreader.readcardinal2
+ readuint = streamreader.readcardinal3
+ readulong = streamreader.readcardinal4
+ setposition = streamreader.setposition
+ getposition = streamreader.getposition
+ readbytetable = streamreader.readbytetable
+
+end)
local setmetatableindex = table.setmetatableindex
@@ -50,6 +72,8 @@ local parsecharstring
local parsecharstrings
local resetcharstrings
local parseprivates
+local startparsing
+local stopparsing
local defaultstrings = { [0] = -- taken from ff
".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
@@ -130,13 +154,21 @@ local cffreaders = {
local function readheader(f)
local offset = getposition(f)
+ local major = readbyte(f)
local header = {
offset = offset,
- major = readbyte(f),
+ major = major,
minor = readbyte(f),
size = readbyte(f), -- headersize
- osize = readbyte(f), -- for offsets to start
}
+ if major == 1 then
+ header.dsize = readbyte(f) -- list of dict offsets
+ elseif major == 2 then
+ header.dsize = readushort(f) -- topdict size
+ else
+ -- I'm probably no longer around by then and we use AI's to
+ -- handle this kind of stuff, if we typeset documents at all.
+ end
setposition(f,offset+header.size)
return header
end
@@ -144,8 +176,8 @@ end
-- The indexes all look the same, so we share a loader. We could pass a handler
-- and run over the array but why bother, we only have a few uses.
-local function readlengths(f)
- local count = readushort(f)
+local function readlengths(f,longcount)
+ local count = longcount and readulong(f) or readushort(f)
if count == 0 then
return { }
end
@@ -159,7 +191,12 @@ local function readlengths(f)
local previous = read(f)
for i=1,count do
local offset = read(f)
- lengths[i] = offset - previous
+ local length = offset - previous
+ if length < 0 then
+ report("bad offset: %i",length)
+ length = 0
+ end
+ lengths[i] = length
previous = offset
end
return lengths
@@ -217,7 +254,8 @@ end
do
- -- We use a closure so that we don't need to pass too much around.
+ -- We use a closure so that we don't need to pass too much around. For cff2 we can
+ -- at some point use a simple version as there is less.
local stack = { }
local top = 0
@@ -271,7 +309,7 @@ do
result.encoding = stack[top]
top = 0
end
- + P("\17") / function()
+ + P("\17") / function() -- valid cff2
result.charstrings = stack[top]
top = 0
end
@@ -284,19 +322,32 @@ do
end
+ P("\19") / function()
result.subroutines = stack[top]
+ top = 0 -- new, forgotten ?
end
+ P("\20") / function()
result.defaultwidthx = stack[top]
+ top = 0 -- new, forgotten ?
end
+ P("\21") / function()
result.nominalwidthx = stack[top]
+ top = 0 -- new, forgotten ?
+ end
+ -- + P("\22") / function() -- reserved
+ -- end
+ -- + P("\23") / function() -- reserved
+ -- end
+ + P("\24") / function() -- new in cff2
+ result.vstore = stack[top]
+ top = 0
end
- -- + P("\22") / function() end -- reserved
- -- + P("\23") / function() end -- reserved
- -- + P("\24") / function() end -- reserved
- -- + P("\25") / function() end -- reserved
- -- + P("\26") / function() end -- reserved
- -- + P("\27") / function() end -- reserved
+ + P("\25") / function() -- new in cff2
+ result.maxstack = stack[top]
+ top = 0
+ end
+ -- + P("\26") / function() -- reserved
+ -- end
+ -- + P("\27") / function() -- reserved
+ -- end
local p_double = P("\12") * (
P("\00") / function()
@@ -327,7 +378,7 @@ do
result.charstringtype = stack[top]
top = 0
end
- + P("\07") / function()
+ + P("\07") / function() -- valid cff2
result.fontmatrix = { unpack(stack,1,6) }
top = 0
end
@@ -377,11 +428,11 @@ do
result.cid.uidbase = stack[top]
top = 0
end
- + P("\36") / function()
+ + P("\36") / function() -- valid cff2
result.cid.fdarray = stack[top]
top = 0
end
- + P("\37") / function()
+ + P("\37") / function() -- valid cff2
result.cid.fdselect = stack[top]
top = 0
end
@@ -502,12 +553,12 @@ do
+ p_unsupported
)^1
- parsedictionaries = function(data,dictionaries)
+ parsedictionaries = function(data,dictionaries,what)
stack = { }
strings = data.strings
for i=1,#dictionaries do
top = 0
- result = {
+ result = what == "cff" and {
monospaced = false,
italicangle = 0,
underlineposition = -100,
@@ -525,6 +576,13 @@ do
fonttype = 0,
count = 8720,
}
+ } or {
+ charstringtype = 2,
+ charset = 0,
+ vstore = 0,
+ cid = {
+ -- nothing yet
+ },
}
lpegmatch(p_dictionary,dictionaries[i])
dictionaries[i] = result
@@ -579,23 +637,32 @@ do
-- because there quite some variants are done in one helper with a lot of
-- testing for states.
- local x = 0
- local y = 0
- local width = false
- local r = 0
- local stems = 0
- local globalbias = 0
- local localbias = 0
- local globals = false
- local locals = false
- local depth = 1
- local xmin = 0
- local xmax = 0
- local ymin = 0
- local ymax = 0
- local checked = false
- local keepcurve = false
- local version = 2
+ local x = 0
+ local y = 0
+ local width = false
+ local r = 0
+ local stems = 0
+ local globalbias = 0
+ local localbias = 0
+ local nominalwidth = 0
+ local defaultwidth = 0
+ local charset = false
+ local globals = false
+ local locals = false
+ local depth = 1
+ local xmin = 0
+ local xmax = 0
+ local ymin = 0
+ local ymax = 0
+ local checked = false
+ local keepcurve = false
+ local version = 2
+ local regions = false
+ local nofregions = 0
+ local region = false
+ local factors = false
+ local axis = false
+ local vsindex = 0
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
@@ -611,16 +678,17 @@ do
-- All these indirect calls make this run slower but it's cleaner this way
-- and we cache the result. As we moved the boundingbox code inline we gain
- -- some back.
+ -- some back. I inlined some of then and a bit speed can be gained by more
+ -- inlining but not that much.
- local function moveto(x,y)
+ local function xymoveto()
if keepcurve then
r = r + 1
result[r] = { x, y, "m" }
end
if checked then
- if x < xmin then xmin = x elseif x > xmax then xmax = x end
- if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ if x > xmax then xmax = x elseif x < xmin then xmin = x end
+ if y > ymax then ymax = y elseif y < ymin then ymin = y end
else
xmin = x
ymin = y
@@ -630,14 +698,58 @@ do
end
end
- local function lineto(x,y)
+ local function xmoveto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "m" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif x > xmax then
+ xmax = x
+ elseif x < xmin then
+ xmin = x
+ end
+ end
+
+ local function ymoveto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "m" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif y > ymax then
+ ymax = y
+ elseif y < ymin then
+ ymin = y
+ end
+ end
+
+ local function moveto()
+ if trace_charstrings then
+ showstate("moveto")
+ end
+ top = 0 -- forgotten
+ xymoveto()
+ end
+
+ local function xylineto() -- we could inline, no blend
if keepcurve then
r = r + 1
result[r] = { x, y, "l" }
end
if checked then
- if x < xmin then xmin = x elseif x > xmax then xmax = x end
- if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ if x > xmax then xmax = x elseif x < xmin then xmin = x end
+ if y > ymax then ymax = y elseif y < ymin then ymin = y end
else
xmin = x
ymin = y
@@ -647,14 +759,53 @@ do
end
end
- local function curveto(x1,y1,x2,y2,x3,y3)
+ local function xlineto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "l" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif x > xmax then
+ xmax = x
+ elseif x < xmin then
+ xmin = x
+ end
+ end
+
+ local function ylineto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "l" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif y > ymax then
+ ymax = y
+ elseif y < ymin then
+ ymin = y
+ end
+ end
+
+ local function xycurveto(x1,y1,x2,y2,x3,y3) -- called local so no blend here
+ if trace_charstrings then
+ showstate("curveto")
+ end
if keepcurve then
r = r + 1
result[r] = { x1, y1, x2, y2, x3, y3, "c" }
end
if checked then
- if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
- if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end
+ if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end
else
xmin = x1
ymin = y1
@@ -662,22 +813,22 @@ do
ymax = y1
checked = true
end
- if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
- if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
- if x3 < xmin then xmin = x3 elseif x3 > xmax then xmax = x3 end
- if y3 < ymin then ymin = y3 elseif y3 > ymax then ymax = y3 end
+ if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end
+ if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end
+ if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end
+ if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end
end
local function rmoveto()
- if top > 2 then
- if not width then
+ if not width then
+ if top > 2 then
width = stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("rmoveto")
@@ -685,45 +836,45 @@ do
x = x + stack[top-1] -- dx1
y = y + stack[top] -- dy1
top = 0
- moveto(x,y)
+ xymoveto()
end
local function hmoveto()
- if top > 1 then
- if not width then
+ if not width then
+ if top > 1 then
width = stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("hmoveto")
end
x = x + stack[top] -- dx1
top = 0
- moveto(x,y)
+ xmoveto()
end
local function vmoveto()
- if top > 1 then
- if not width then
+ if not width then
+ if top > 1 then
width = stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("vmoveto")
end
y = y + stack[top] -- dy1
top = 0
- moveto(x,y)
+ ymoveto()
end
local function rlineto()
@@ -733,21 +884,7 @@ do
for i=1,top,2 do
x = x + stack[i] -- dxa
y = y + stack[i+1] -- dya
- lineto(x,y)
- end
- top = 0
- end
-
- local function xlineto(swap) -- x (y,x)+ | (x,y)+
- for i=1,top do
- if swap then
- x = x + stack[i]
- swap = false
- else
- y = y + stack[i]
- swap = true
- end
- lineto(x,y)
+ xylineto()
end
top = 0
end
@@ -756,14 +893,48 @@ do
if trace_charstrings then
showstate("hlineto")
end
- xlineto(true)
+ if top == 1 then
+ x = x + stack[1]
+ xlineto()
+ else
+ local swap = true
+ for i=1,top do
+ if swap then
+ x = x + stack[i]
+ xlineto()
+ swap = false
+ else
+ y = y + stack[i]
+ ylineto()
+ swap = true
+ end
+ end
+ end
+ top = 0
end
local function vlineto() -- y (x,y)+ | (y,x)+
if trace_charstrings then
showstate("vlineto")
end
- xlineto(false)
+ if top == 1 then
+ y = y + stack[1]
+ ylineto()
+ else
+ local swap = false
+ for i=1,top do
+ if swap then
+ x = x + stack[i]
+ xlineto()
+ swap = false
+ else
+ y = y + stack[i]
+ ylineto()
+ swap = true
+ end
+ end
+ end
+ top = 0
end
local function rrcurveto()
@@ -775,9 +946,9 @@ do
local ay = y + stack[i+1] -- dya
local bx = ax + stack[i+2] -- dxb
local by = ay + stack[i+3] -- dyb
- x = bx + stack[i+4] -- dxc
- y = by + stack[i+5] -- dyc
- curveto(ax,ay,bx,by,x,y)
+ x = bx + stack[i+4] -- dxc
+ y = by + stack[i+5] -- dyc
+ xycurveto(ax,ay,bx,by,x,y)
end
top = 0
end
@@ -788,17 +959,17 @@ do
end
local s = 1
if top % 2 ~= 0 then
- y = y + stack[1] -- dy1
+ y = y + stack[1] -- dy1
s = 2
end
for i=s,top,4 do
- local ax = x + stack[i] -- dxa
+ local ax = x + stack[i] -- dxa
local ay = y
local bx = ax + stack[i+1] -- dxb
local by = ay + stack[i+2] -- dyb
- x = bx + stack[i+3] -- dxc
+ x = bx + stack[i+3] -- dxc
y = by
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top = 0
end
@@ -810,28 +981,64 @@ do
local s = 1
local d = 0
if top % 2 ~= 0 then
- d = stack[1] -- dx1
+ d = stack[1] -- dx1
s = 2
end
for i=s,top,4 do
local ax = x + d
- local ay = y + stack[i] -- dya
+ local ay = y + stack[i] -- dya
local bx = ax + stack[i+1] -- dxb
local by = ay + stack[i+2] -- dyb
x = bx
- y = by + stack[i+3] -- dyc
- curveto(ax,ay,bx,by,x,y)
+ y = by + stack[i+3] -- dyc
+ xycurveto(ax,ay,bx,by,x,y)
d = 0
end
top = 0
end
+-- local function xxcurveto(swap)
+-- local last = top % 4 ~= 0 and stack[top]
+-- if last then
+-- top = top - 1
+-- end
+-- for i=1,top,4 do
+-- local ax, ay, bx, by
+-- if swap then
+-- ax = x + stack[i]
+-- ay = y
+-- bx = ax + stack[i+1]
+-- by = ay + stack[i+2]
+-- y = by + stack[i+3]
+-- if last and i+3 == top then
+-- x = bx + last
+-- else
+-- x = bx
+-- end
+-- swap = false
+-- else
+-- ax = x
+-- ay = y + stack[i]
+-- bx = ax + stack[i+1]
+-- by = ay + stack[i+2]
+-- x = bx + stack[i+3]
+-- if last and i+3 == top then
+-- y = by + last
+-- else
+-- y = by
+-- end
+-- swap = true
+-- end
+-- xycurveto(ax,ay,bx,by,x,y)
+-- end
+-- top = 0
+-- end
+
local function xxcurveto(swap)
local last = top % 4 ~= 0 and stack[top]
if last then
top = top - 1
end
- local sw = swap
for i=1,top,4 do
local ax, ay, bx, by
if swap then
@@ -859,11 +1066,12 @@ do
end
swap = true
end
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top = 0
end
+
local function hvcurveto()
if trace_charstrings then
showstate("hvcurveto")
@@ -889,11 +1097,11 @@ do
local by = ay + stack[i+3] -- dyb
x = bx + stack[i+4] -- dxc
y = by + stack[i+5] -- dyc
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
x = x + stack[top-1] -- dxc
y = y + stack[top] -- dyc
- lineto(x,y)
+ xylineto()
top = 0
end
@@ -905,7 +1113,7 @@ do
for i=1,top-6,2 do
x = x + stack[i]
y = y + stack[i+1]
- lineto(x,y)
+ xylineto()
end
end
local ax = x + stack[top-5]
@@ -914,7 +1122,7 @@ do
local by = ay + stack[top-2]
x = bx + stack[top-1]
y = by + stack[top]
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
top = 0
end
@@ -930,14 +1138,14 @@ do
local by = ay + stack[4] -- dy2
local cx = bx + stack[5] -- dx3
local cy = by + stack[6] -- dy3
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx = cx + stack[7] -- dx4
local dy = cy + stack[8] -- dy4
local ex = dx + stack[9] -- dx5
local ey = dy + stack[10] -- dy5
x = ex + stack[11] -- dx6
y = ey + stack[12] -- dy6
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -945,19 +1153,19 @@ do
if trace_charstrings then
showstate("hflex")
end
- local ax = x + stack[1] -- dx1
+ local ax = x + stack[1] -- dx1
local ay = y
local bx = ax + stack[2] -- dx2
local by = ay + stack[3] -- dy2
local cx = bx + stack[4] -- dx3
local cy = by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx = cx + stack[5] -- dx4
local dy = by
local ex = dx + stack[6] -- dx5
local ey = y
- x = ex + stack[7] -- dx6
- curveto(dx,dy,ex,ey,x,y)
+ x = ex + stack[7] -- dx6
+ xycurveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -971,13 +1179,13 @@ do
local by = ay + stack[4] -- dy2
local cx = bx + stack[5] -- dx3
local cy = by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx = cx + stack[6] -- dx4
local dy = by
local ex = dx + stack[7] -- dx5
local ey = dy + stack[8] -- dy5
- x = ex + stack[9] -- dx6
- curveto(dx,dy,ex,ey,x,y)
+ x = ex + stack[9] -- dx6
+ xycurveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -991,7 +1199,7 @@ do
local by = ay + stack[4] --dy2
local cx = bx + stack[5] --dx3
local cy = by + stack[6] --dy3
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx = cx + stack[7] --dx4
local dy = cy + stack[8] --dy4
local ex = dx + stack[9] --dx5
@@ -1001,7 +1209,7 @@ do
else
y = ey + stack[11]
end
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -1160,7 +1368,109 @@ do
top = 0
end
- -- so far for unsupported postscript
+ -- So far for unsupported postscript. Now some cff2 magic. As I still need
+ -- to wrap my head around the rather complex variable font specification
+ -- with regions and axis, the following approach kind of works but is more
+ -- some trial and error trick. It's still not clear how much of the complex
+ -- truetype description applies to cff.
+
+ local reginit = false
+
+ local function updateregions(n) -- n + 1
+ if regions then
+ local current = regions[n] or regions[1]
+ nofregions = #current
+ if axis and n ~= reginit then
+ factors = { }
+ for i=1,nofregions do
+ local region = current[i]
+ local s = 1
+ for j=1,#axis do
+ local f = axis[j]
+ local r = region[j]
+ local start = r.start
+ local peak = r.peak
+ local stop = r.stop
+ if start > peak or peak > stop then
+ -- * 1
+ elseif start < 0 and stop > 0 and peak ~= 0 then
+ -- * 1
+ elseif peak == 0 then
+ -- * 1
+ elseif f < start or f > stop then
+ -- * 0
+ s = 0
+ break
+ elseif f < peak then
+ s = s * (f - start) / (peak - start)
+ elseif f > peak then
+ s = s * (stop - f) / (stop - peak)
+ else
+ -- * 1
+ end
+ end
+ factors[i] = s
+ end
+ end
+ end
+ reginit = n
+ end
+
+ local function setvsindex()
+ local vsindex = stack[top]
+ if trace_charstrings then
+ showstate(formatters["vsindex %i"](vsindex))
+ end
+ updateregions(vsindex)
+ top = top - 1
+ end
+
+ local function blend()
+ local n = stack[top]
+ top = top - 1
+ if axis then
+ -- x (r1x,r2x,r3x)
+ -- (x,y) (r1x,r2x,r3x) (r1y,r2y,r3y)
+ if trace_charstrings then
+ local t = top - nofregions * n
+ local m = t - n
+ for i=1,n do
+ local k = m + i
+ local d = m + n + (i-1)*nofregions
+ local old = stack[k]
+ local new = old
+ for r=1,nofregions do
+ new = new + stack[d+r] * factors[r]
+ end
+ stack[k] = new
+ showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
+ end
+ top = t
+ elseif n == 1 then
+ top = top - nofregions
+ local v = stack[top]
+ for r=1,nofregions do
+ v = v + stack[top+r] * factors[r]
+ end
+ stack[top] = v
+ else
+ top = top - nofregions * n
+ local d = top
+ local k = top - n
+ for i=1,n do
+ k = k + 1
+ local v = stack[k]
+ for r=1,nofregions do
+ v = v + stack[d+r] * factors[r]
+ end
+ stack[k] = v
+ d = d + nofregions
+ end
+ end
+ else
+ -- error
+ end
+ end
-- Bah, we cannot use a fast lpeg because a hint has an unknown size and a
-- runtime capture cannot handle that well.
@@ -1181,8 +1491,8 @@ do
unsupported, -- 12 -- elsewhere
hsbw, -- 13 -- hsbw (type 1 cff)
unsupported, -- 14 -- endchar,
- unsupported, -- 15
- unsupported, -- 16
+ setvsindex, -- 15 -- cff2
+ blend, -- 16 -- cff2
unsupported, -- 17
getstem, -- 18 -- hstemhm
getmask, -- 19 -- hintmask
@@ -1218,9 +1528,95 @@ do
[037] = flex1,
}
- local p_bytes = Ct((P(1)/byte)^0)
+ local c_endchar = char(14)
+
+ local passon do
+
+ -- todo: round in blend
+ -- todo: delay this hash
+
+ local rshift = bit32.rshift
+ local band = bit32.band
+ local round = math.round
- local function call(scope,list,bias,process)
+ local encode = table.setmetatableindex(function(t,i)
+ for i=-2048,-1130 do
+ t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ for i=-1131,-108 do
+ local v = 0xFB00 - i - 108
+ t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=-107,107 do
+ t[i] = char(i + 139)
+ end
+ for i=108,1131 do
+ local v = 0xF700 + i - 108
+ t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=1132,2048 do
+ t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ return t[i]
+ end)
+
+ local function setvsindex()
+ local vsindex = stack[top]
+ updateregions(vsindex)
+ top = top - 1
+ end
+
+ local function blend()
+ local n = stack[top]
+ top = top - 1
+ if not axis then
+ -- fatal error
+ elseif n == 1 then
+ top = top - nofregions
+ local v = stack[top]
+ for r=1,nofregions do
+ v = v + stack[top+r] * factors[r]
+ end
+ stack[top] = round(v)
+ else
+ top = top - nofregions * n
+ local d = top
+ local k = top - n
+ for i=1,n do
+ k = k + 1
+ local v = stack[k]
+ for r=1,nofregions do
+ v = v + stack[d+r] * factors[r]
+ end
+ stack[k] = round(v)
+ d = d + nofregions
+ end
+ end
+ end
+
+ passon = function(operation)
+ if operation == 15 then
+ setvsindex()
+ elseif operation == 16 then
+ blend()
+ else
+ for i=1,top do
+ r = r + 1
+ result[r] = encode[stack[i]]
+ end
+ r = r + 1
+ result[r] = char(operation) -- maybe use a hash
+ top = 0
+ end
+ end
+
+ end
+
+ -- end of experiment
+
+ local process
+
+ local function call(scope,list,bias) -- ,process)
depth = depth + 1
if top == 0 then
showstate(formatters["unknown %s call"](scope))
@@ -1233,10 +1629,6 @@ do
end
local tab = list[index]
if tab then
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- list[index] = tab
- end
process(tab)
else
showstate(formatters["unknown %s call %i"](scope,index))
@@ -1246,54 +1638,63 @@ do
depth = depth - 1
end
- local function process(tab)
+ -- precompiling and reuse is much slower than redoing the calls
+
+ local justpass = false
+
+ process = function(tab)
local i = 1
local n = #tab
while i <= n do
local t = tab[i]
- if t >= 32 and t <= 246 then
- -- -107 .. +107
+ if t >= 32 then
top = top + 1
- stack[top] = t - 139
- i = i + 1
- elseif t >= 247 and t <= 250 then
- -- +108 .. +1131
- top = top + 1
- stack[top] = (t-247)*256 + tab[i+1] + 108
- i = i + 2
- elseif t >= 251 and t <= 254 then
- -- -1131 .. -108
- top = top + 1
- stack[top] = -(t-251)*256 - tab[i+1] - 108
- i = i + 2
+ if t <= 246 then
+ -- -107 .. +107
+ stack[top] = t - 139
+ i = i + 1
+ elseif t <= 250 then
+ -- +108 .. +1131
+ -- stack[top] = (t-247)*256 + tab[i+1] + 108
+ -- stack[top] = t*256 - 247*256 + tab[i+1] + 108
+ stack[top] = t*256 - 63124 + tab[i+1]
+ i = i + 2
+ elseif t <= 254 then
+ -- -1131 .. -108
+ -- stack[top] = -(t-251)*256 - tab[i+1] - 108
+ -- stack[top] = -t*256 + 251*256 - tab[i+1] - 108
+ stack[top] = -t*256 + 64148 - tab[i+1]
+ i = i + 2
+ else
+ local n = 0x100 * tab[i+1] + tab[i+2]
+ if n >= 0x8000 then
+ -- stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ stack[top] = n - 0x10000 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ else
+ stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ end
+ i = i + 5
+ end
elseif t == 28 then
-- -32768 .. +32767 : b1<<8 | b2
top = top + 1
local n = 0x100 * tab[i+1] + tab[i+2]
if n >= 0x8000 then
- stack[top] = n - 0xFFFF - 1
+ -- stack[top] = n - 0xFFFF - 1
+ stack[top] = n - 0x10000
else
stack[top] = n
end
i = i + 3
- elseif t == 255 then
- local n = 0x100 * tab[i+1] + tab[i+2]
- top = top + 1
- if n >= 0x8000 then
- stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
- else
- stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
- end
- i = i + 5
- elseif t == 11 then
+ elseif t == 11 then -- not in cff2
if trace_charstrings then
showstate("return")
end
return
elseif t == 10 then
- call("local",locals,localbias,process)
+ call("local",locals,localbias) -- ,process)
i = i + 1
- elseif t == 14 then -- endchar
+ elseif t == 14 then -- not in cff2
if width then
-- okay
elseif top > 0 then
@@ -1309,7 +1710,7 @@ do
end
return
elseif t == 29 then
- call("global",globals,globalbias,process)
+ call("global",globals,globalbias) -- ,process)
i = i + 1
elseif t == 12 then
i = i + 1
@@ -1324,20 +1725,25 @@ do
top = 0
end
i = i + 1
+ elseif justpass then
+ passon(t)
+ i = i + 1
else
local a = actions[t]
if a then
local s = a(t)
if s then
- i = i + s
+ i = i + s + 1
+ else
+ i = i + 1
end
else
if trace_charstrings then
showvalue("<action>",t)
end
top = 0
+ i = i + 1
end
- i = i + 1
end
end
end
@@ -1356,7 +1762,7 @@ do
-- if y < ymin then ymin = y end
-- if y > ymax then ymax = y end
-- -- we now have a reasonable start so we could
- -- -- simplyfy the next checks
+ -- -- simplify the next checks
-- for i=1,nofsegments do
-- local s = segments[i]
-- local x = s[1]
@@ -1393,150 +1799,63 @@ do
end
end
- parsecharstrings = function(data,glyphs,doshapes,tversion)
- -- for all charstrings
- local dictionary = data.dictionaries[1]
- local charstrings = dictionary.charstrings
- local charset = dictionary.charset
- local private = dictionary.private or { data = { } }
-
- keepcurve = doshapes
- version = tversion
- stack = { }
- glyphs = glyphs or { }
- strings = data.strings
- globals = data.routines or { }
- locals = dictionary.subroutines or { }
-
- globalbias, localbias = setbias(globals,locals)
+ local function processshape(tab,index)
- local nominalwidth = private.data.nominalwidthx or 0
- local defaultwidth = private.data.defaultwidthx or 0
-
- for i=1,#charstrings do
- local tab = charstrings[i]
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- end
- local index = i - 1
- x = 0
- y = 0
- width = false
- r = 0
- top = 0
- stems = 0
- result = { }
- --
- xmin = 0
- xmax = 0
- ymin = 0
- ymax = 0
- checked = false
- --
- if trace_charstrings then
- report("glyph: %i",index)
- report("data: % t",tab)
- end
- --
- process(tab)
- --
- local boundingbox = { round(xmin), round(ymin), round(xmax), round(ymax) }
- --
- if width == true or width == false then
- width = defaultwidth
- else
- width = nominalwidth + width
- end
- --
- -- trace_charstrings = index == 3078 -- todo: make tracker
- local glyph = glyphs[index] -- can be autodefined in otr
- if not glyph then
- glyphs[index] = {
- segments = doshapes ~= false and result or nil, -- optional
- boundingbox = boundingbox,
- width = width,
- name = charset[index],
- -- sidebearing = 0,
- }
- else
- glyph.segments = doshapes ~= false and result or nil
- glyph.boundingbox = boundingbox
- if not glyph.width then
- glyph.width = width
- end
- if charset and not glyph.name then
- glyph.name = charset[index]
- end
- -- glyph.sidebearing = 0 -- todo
- end
- if trace_charstrings then
- report("width: %s",tostring(width))
- report("boundingbox: % t",boundingbox)
- end
- charstrings[i] = nil -- free memory
- end
- return glyphs
- end
+ tab = bytetable(tab)
- parsecharstring = function(data,dictionary,tab,glyphs,index,doshapes,tversion)
- local private = dictionary.private
- keepcurve = doshapes
- version = tversion
- strings = data.strings -- or in dict?
- locals = dictionary.subroutines or { }
- globals = data.routines or { }
+ x = 0
+ y = 0
+ width = false
+ r = 0
+ top = 0
+ stems = 0
+ result = { } -- we could reuse it when only boundingbox calculations are needed
- globalbias, localbias = setbias(globals,locals)
+ xmin = 0
+ xmax = 0
+ ymin = 0
+ ymax = 0
+ checked = false
- local nominalwidth = private and private.data.nominalwidthx or 0
- local defaultwidth = private and private.data.defaultwidthx or 0
- --
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- end
- --
- x = 0
- y = 0
- width = false
- r = 0
- top = 0
- stems = 0
- result = { }
- --
- xmin = 0
- xmax = 0
- ymin = 0
- ymax = 0
- checked = false
- --
if trace_charstrings then
report("glyph: %i",index)
- report("data: % t",tab)
+ report("data : % t",tab)
end
- --
+
+ if regions then
+ updateregions(vsindex)
+ end
+
process(tab)
- --
- local boundingbox = { xmin, ymin, xmax, ymax }
- --
+
+ local boundingbox = {
+ round(xmin),
+ round(ymin),
+ round(xmax),
+ round(ymax),
+ }
+
if width == true or width == false then
width = defaultwidth
else
width = nominalwidth + width
end
- --
- index = index - 1
- --
+
local glyph = glyphs[index] -- can be autodefined in otr
- if not glyph then
- glyphs[index] = {
- segments = doshapes ~= false and result or nil, -- optional
- boundingbox = boundingbox,
- width = width,
- name = charset[index],
- -- sidebearing = 0,
- }
- else
- glyph.segments = doshapes ~= false and result or nil
+ if justpass then
+ r = r + 1
+ result[r] = c_endchar
+ local stream = concat(result)
+ -- if trace_charstrings then
+ -- report("vdata: %s",stream)
+ -- end
+ if glyph then
+ glyph.stream = stream
+ else
+ glyphs[index] = { stream = stream }
+ end
+ elseif glyph then
+ glyph.segments = keepcurve ~= false and result or nil
glyph.boundingbox = boundingbox
if not glyph.width then
glyph.width = width
@@ -1545,18 +1864,107 @@ do
glyph.name = charset[index]
end
-- glyph.sidebearing = 0 -- todo
+ elseif keepcurve then
+ glyphs[index] = {
+ segments = result,
+ boundingbox = boundingbox,
+ width = width,
+ name = charset and charset[index] or nil,
+ -- sidebearing = 0,
+ }
+ else
+ glyphs[index] = {
+ boundingbox = boundingbox,
+ width = width,
+ name = charset and charset[index] or nil,
+ }
end
- --
+
if trace_charstrings then
- report("width: %s",tostring(width))
+ report("width : %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
+
end
- resetcharstrings = function()
- result = { }
- top = 0
- stack = { }
+ startparsing = function(fontdata,data,streams)
+ reginit = false
+ axis = false
+ regions = data.regions
+ justpass = streams == true
+ if regions then
+ regions = { regions } -- needs checking
+ axis = data.factors or false
+ end
+ end
+
+ stopparsing = function(fontdata,data)
+ stack = { }
+ glyphs = false
+ result = { }
+ top = 0
+ locals = false
+ globals = false
+ strings = false
+ end
+
+ local function setwidths(private)
+ if not private then
+ return 0, 0
+ end
+ local privatedata = private.data
+ if not privatedata then
+ return 0, 0
+ end
+ return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0
+ end
+
+ parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams)
+
+ local dictionary = data.dictionaries[1]
+ local charstrings = dictionary.charstrings
+
+ keepcurve = doshapes
+ version = tversion
+ strings = data.strings
+ globals = data.routines or { }
+ locals = dictionary.subroutines or { }
+ charset = dictionary.charset
+ vsindex = dictionary.vsindex or 0
+ glyphs = glphs or { }
+
+ globalbias, localbias = setbias(globals,locals)
+ nominalwidth, defaultwidth = setwidths(dictionary.private)
+
+ startparsing(fontdata,data,streams)
+
+ for index=1,#charstrings do
+ processshape(charstrings[index],index-1)
+ charstrings[index] = nil -- free memory (what if used more often?)
+ end
+
+ stopparsing(fontdata,data)
+
+ return glyphs
+ end
+
+ parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion)
+
+ keepcurve = doshapes
+ version = tversion
+ strings = data.strings
+ globals = data.routines or { }
+ locals = dictionary.subroutines or { }
+ charset = false
+ vsindex = dictionary.vsindex or 0
+ glyphs = glphs or { }
+
+ globalbias, localbias = setbias(globals,locals)
+ nominalwidth, defaultwidth = setwidths(dictionary.private)
+
+ processshape(tab,index-1)
+
+ -- return glyphs[index]
end
end
@@ -1564,7 +1972,7 @@ end
local function readglobals(f,data)
local routines = readlengths(f)
for i=1,#routines do
- routines[i] = readstring(f,routines[i])
+ routines[i] = readbytetable(f,routines[i])
end
data.routines = routines
end
@@ -1578,8 +1986,7 @@ local function readcharsets(f,data,dictionary)
local strings = data.strings
local nofglyphs = data.nofglyphs
local charsetoffset = dictionary.charset
-
- if charsetoffset ~= 0 then
+ if charsetoffset and charsetoffset ~= 0 then
setposition(f,header.offset+charsetoffset)
local format = readbyte(f)
local charset = { [0] = ".notdef" }
@@ -1605,6 +2012,9 @@ local function readcharsets(f,data,dictionary)
else
report("cff parser: unsupported charset format %a",format)
end
+ else
+ dictionary.nocharset = true
+ dictionary.charset = nil
end
end
@@ -1627,7 +2037,7 @@ local function readlocals(f,data,dictionary)
setposition(f,header.offset+private.offset+subroutineoffset)
local subroutines = readlengths(f)
for i=1,#subroutines do
- subroutines[i] = readstring(f,subroutines[i])
+ subroutines[i] = readbytetable(f,subroutines[i])
end
dictionary.subroutines = subroutines
private.data.subroutines = nil
@@ -1642,16 +2052,18 @@ end
-- These charstrings are little programs and described in: Technical Note #5177. A truetype
-- font has only one dictionary.
-local function readcharstrings(f,data)
+local function readcharstrings(f,data,what)
local header = data.header
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
- local type = dictionary.charstringtype
+ local stringtype = dictionary.charstringtype
local offset = dictionary.charstrings
- if type == 2 then
+ if type(offset) ~= "number" then
+ -- weird
+ elseif stringtype == 2 then
setposition(f,header.offset+offset)
-- could be a metatable .. delayed loading
- local charstrings = readlengths(f)
+ local charstrings = readlengths(f,what=="cff2")
local nofglyphs = #charstrings
for i=1,nofglyphs do
charstrings[i] = readstring(f,charstrings[i])
@@ -1659,7 +2071,7 @@ local function readcharstrings(f,data)
data.nofglyphs = nofglyphs
dictionary.charstrings = charstrings
else
- report("unsupported charstr type %i",type)
+ report("unsupported charstr type %i",stringtype)
data.nofglyphs = 0
dictionary.charstrings = { }
end
@@ -1681,31 +2093,38 @@ local function readcidprivates(f,data)
parseprivates(data,dictionaries)
end
-local function readnoselect(f,data,glyphs,doshapes,version)
+readers.parsecharstrings = parsecharstrings -- used in font-onr.lua (type 1)
+
+local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
- readcharsets(f,data,dictionary)
+ readcharstrings(f,data,version)
+ if version == "cff2" then
+ dictionary.charset = nil
+ else
+ readencodings(f,data)
+ readcharsets(f,data,dictionary)
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
readlocals(f,data,dictionary)
- parsecharstrings(data,glyphs,doshapes,version)
- resetcharstrings()
+ startparsing(fontdata,data,streams)
+ parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
+ stopparsing(fontdata,data)
end
-readers.parsecharstrings = parsecharstrings
-
-local function readfdselect(f,data,glyphs,doshapes,version)
+local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local header = data.header
local dictionaries = data.dictionaries
local dictionary = dictionaries[1]
local cid = dictionary.cid
local cidselect = cid and cid.fdselect
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
+ readcharstrings(f,data,version)
+ if version ~= "cff2" then
+ readencodings(f,data)
+ end
local charstrings = dictionary.charstrings
local fdindex = { }
local nofglyphs = data.nofglyphs
@@ -1742,6 +2161,7 @@ local function readfdselect(f,data,glyphs,doshapes,version)
else
-- unsupported format
end
+ -- hm, always
if maxindex >= 0 then
local cidarray = cid.fdarray
setposition(f,header.offset+cidarray)
@@ -1755,85 +2175,157 @@ local function readfdselect(f,data,glyphs,doshapes,version)
for i=1,#dictionaries do
readlocals(f,data,dictionaries[i])
end
+ startparsing(fontdata,data,streams)
for i=1,#charstrings do
- parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ charstrings[i] = nil
end
- resetcharstrings()
+ stopparsing(fontdata,data)
end
end
+local gotodatatable = readers.helpers.gotodatatable
+
+local function cleanup(data,dictionaries)
+ -- for i=1,#dictionaries do
+ -- local d = dictionaries[i]
+ -- d.subroutines = nil
+ -- end
+ -- data.strings = nil
+ -- if data then
+ -- data.charstrings = nil
+ -- data.routines = nil
+ -- end
+end
+
function readers.cff(f,fontdata,specification)
--- if specification.glyphs then
- if specification.details then
- local datatable = fontdata.tables.cff
- if datatable then
- local offset = datatable.offset
- local glyphs = fontdata.glyphs
- if not f then
- report("invalid filehandle")
- return
- end
- if offset then
- setposition(f,offset)
- end
- local header = readheader(f)
- if header.major > 1 then
- report("version mismatch")
- return
- end
- local names = readfontnames(f)
- local dictionaries = readtopdictionaries(f)
- local strings = readstrings(f)
- local data = {
- header = header,
- names = names,
- dictionaries = dictionaries,
- strings = strings,
- nofglyphs = fontdata.nofglyphs,
- }
- --
- parsedictionaries(data,data.dictionaries)
- --
- local d = dictionaries[1]
- local c = d.cid
- fontdata.cffinfo = {
- familynamename = d.familyname,
- fullname = d.fullname,
- boundingbox = d.boundingbox,
- weight = d.weight,
- italicangle = d.italicangle,
- underlineposition = d.underlineposition,
- underlinethickness = d.underlinethickness,
- monospaced = d.monospaced,
- }
- fontdata.cidinfo = c and {
- registry = c.registry,
- ordering = c.ordering,
- supplement = c.supplement,
- }
- --
- if not specification.glyphs then
- -- we only want some metadata
+ local tableoffset = gotodatatable(f,fontdata,"cff",specification.details)
+ if tableoffset then
+ local header = readheader(f)
+ if header.major ~= 1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local glyphs = fontdata.glyphs
+ local names = readfontnames(f)
+ local dictionaries = readtopdictionaries(f)
+ local strings = readstrings(f)
+ local data = {
+ header = header,
+ names = names,
+ dictionaries = dictionaries,
+ strings = strings,
+ nofglyphs = fontdata.nofglyphs,
+ }
+ --
+ parsedictionaries(data,dictionaries,"cff")
+ --
+ local dic = dictionaries[1]
+ local cid = dic.cid
+ fontdata.cffinfo = {
+ familynamename = dic.familyname,
+ fullname = dic.fullname,
+ boundingbox = dic.boundingbox,
+ weight = dic.weight,
+ italicangle = dic.italicangle,
+ underlineposition = dic.underlineposition,
+ underlinethickness = dic.underlinethickness,
+ monospaced = dic.monospaced,
+ }
+ fontdata.cidinfo = cid and {
+ registry = cid.registry,
+ ordering = cid.ordering,
+ supplement = cid.supplement,
+ }
+ --
+ if specification.glyphs then
+ local all = specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff")
else
- local cid = d.cid
- if cid and cid.fdselect then
- readfdselect(f,data,glyphs,specification.shapes or false)
- else
- readnoselect(f,data,glyphs,specification.shapes or false)
- end
+ readnoselect(f,fontdata,data,glyphs,all,"cff")
end
+ end
+ cleanup(data,dictionaries)
+ end
+end
+
+function readers.cff2(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs)
+ if tableoffset then
+ local header = readheader(f)
+ if header.major ~= 2 then
+ report("only version %s is supported for table %a",2,"cff2")
+ return
+ end
+ local glyphs = fontdata.glyphs
+ local dictionaries = { readstring(f,header.dsize) }
+ local data = {
+ header = header,
+ dictionaries = dictionaries,
+ nofglyphs = fontdata.nofglyphs,
+ }
+ --
+ parsedictionaries(data,dictionaries,"cff2")
+ --
+ local offset = dictionaries[1].vstore
+ if offset > 0 then
+ local storeoffset = dictionaries[1].vstore + data.header.offset + 2 -- cff has a preceding size field
+ local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors)
--
- -- cleanup (probably more can go)
- --
- -- for i=1,#dictionaries do
- -- local d = dictionaries[i]
- -- d.subroutines = nil
- -- end
- -- data.strings = nil
- -- if data then
- -- data.charstrings = nil
- -- data.routines = nil
- -- end
+ data.regions = regions
+ data.deltas = deltas
+ else
+ data.regions = { }
+ data.deltas = { }
+ end
+ data.factors = specification.factors
+ --
+ local cid = data.dictionaries[1].cid
+ local all = specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ else
+ readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ end
+ cleanup(data,dictionaries)
+ end
+end
+
+-- temporary helper needed for checking backend patches
+
+function readers.cffcheck(filename)
+ local f = io.open(filename,"rb")
+ if f then
+ local fontdata = {
+ glyphs = { },
+ }
+ local header = readheader(f)
+ if header.major ~= 1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local names = readfontnames(f)
+ local dictionaries = readtopdictionaries(f)
+ local strings = readstrings(f)
+ local glyphs = { }
+ local data = {
+ header = header,
+ names = names,
+ dictionaries = dictionaries,
+ strings = strings,
+ glyphs = glyphs,
+ nofglyphs = 4,
+ }
+ --
+ parsedictionaries(data,dictionaries,"cff")
+ --
+ local cid = data.dictionaries[1].cid
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,false)
+ else
+ readnoselect(f,fontdata,data,glyphs,false)
end
+ return data
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cid.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cid.lua
index 0eaacdfbd54..781bc9fec97 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cid.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cid.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['font-cid'] = {
version = 1.001,
- comment = "companion to font-otf.lua (cidmaps)",
+ comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua
index 18f2217108a..e8bcd56a263 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua
@@ -8,11 +8,14 @@ if not modules then modules = { } end modules ['font-con'] = {
-- some names of table entries will be changed (no _)
-local next, tostring, rawget = next, tostring, rawget
+local next, tostring, tonumber, rawget = next, tostring, tonumber, rawget
local format, match, lower, gsub, find = string.format, string.match, string.lower, string.gsub, string.find
-local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
+local sort, insert, concat = table.sort, table.insert, table.concat
+local sortedkeys, sortedhash, serialize, fastcopy = table.sortedkeys, table.sortedhash, table.serialize, table.fastcopy
local derivetable = table.derive
local ioflush = io.flush
+local round = math.round
+local setmetatable, getmetatable, rawget, rawset = setmetatable, getmetatable, rawget, rawset
local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
local trace_scaling = false trackers.register("fonts.scaling", function(v) trace_scaling = v end)
@@ -43,7 +46,7 @@ constructors.namemode = "fullpath" -- will be a function
constructors.version = 1.01
constructors.cache = containers.define("fonts", "constructors", constructors.version, false)
-constructors.privateoffset = 0xF0000 -- 0x10FFFF
+constructors.privateoffset = 0xF0000 -- 0x10FFFF | context also uses privates: 0xE000-0xEFFF
constructors.cacheintex = true -- so we see the original table in fonts.font
@@ -88,6 +91,31 @@ function constructors.scaled(scaledpoints, designsize) -- handles designsize in
end
end
+function constructors.getprivate(tfmdata)
+ local properties = tfmdata.properties
+ local private = properties.private
+ properties.private = private + 1
+ return private
+end
+
+function constructors.setmathparameter(tfmdata,name,value)
+ local m = tfmdata.mathparameters
+ local c = tfmdata.MathConstants
+ if m then
+ m[name] = value
+ end
+ if c and c ~= m then
+ c[name] = value
+ end
+end
+
+function constructors.getmathparameter(tfmdata,name)
+ local p = tfmdata.mathparameters or tfmdata.MathConstants
+ if p then
+ return p[name]
+ end
+end
+
--[[ldx--
<p>Beware, the boundingbox is passed as reference so we may not overwrite it
in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
@@ -221,27 +249,87 @@ function constructors.trytosharefont(target,tfmdata)
end
end
+-- function constructors.enhanceparameters(parameters)
+-- local xheight = parameters.x_height
+-- local quad = parameters.quad
+-- local space = parameters.space
+-- local stretch = parameters.space_stretch
+-- local shrink = parameters.space_shrink
+-- local extra = parameters.extra_space
+-- local slant = parameters.slant
+-- -- synonyms
+-- parameters.xheight = xheight
+-- parameters.spacestretch = stretch
+-- parameters.spaceshrink = shrink
+-- parameters.extraspace = extra
+-- parameters.em = quad
+-- parameters.ex = xheight
+-- parameters.slantperpoint = slant
+-- parameters.spacing = {
+-- width = space,
+-- stretch = stretch,
+-- shrink = shrink,
+-- extra = extra,
+-- }
+-- end
+
+local synonyms = {
+ exheight = "x_height",
+ xheight = "x_height",
+ ex = "x_height",
+ emwidth = "quad",
+ em = "quad",
+ spacestretch = "space_stretch",
+ stretch = "space_stretch",
+ spaceshrink = "space_shrink",
+ shrink = "space_shrink",
+ extraspace = "extra_space",
+ xspace = "extra_space",
+ slantperpoint = "slant",
+}
+
function constructors.enhanceparameters(parameters)
- local xheight = parameters.x_height
- local quad = parameters.quad
- local space = parameters.space
- local stretch = parameters.space_stretch
- local shrink = parameters.space_shrink
- local extra = parameters.extra_space
- local slant = parameters.slant
- parameters.xheight = xheight
- parameters.spacestretch = stretch
- parameters.spaceshrink = shrink
- parameters.extraspace = extra
- parameters.em = quad
- parameters.ex = xheight
- parameters.slantperpoint = slant
- parameters.spacing = {
- width = space,
- stretch = stretch,
- shrink = shrink,
- extra = extra,
- }
+ local mt = getmetatable(parameters)
+ local getter = function(t,k)
+ if not k then
+ return nil
+ end
+ local s = synonyms[k]
+ if s then
+ return rawget(t,s) or (mt and mt[s]) or nil
+ end
+ if k == "spacing" then
+ return {
+ width = t.space,
+ stretch = t.space_stretch,
+ shrink = t.space_shrink,
+ extra = t.extra_space,
+ }
+ end
+ return mt and mt[k] or nil
+ end
+ local setter = function(t,k,v)
+ if not k then
+ return 0
+ end
+ local s = synonyms[k]
+ if s then
+ rawset(t,s,v)
+ elseif k == "spacing" then
+ if type(v) == "table" then
+ rawset(t,"space",v.width or 0)
+ rawset(t,"space_stretch",v.stretch or 0)
+ rawset(t,"space_shrink",v.shrink or 0)
+ rawset(t,"extra_space",v.extra or 0)
+ end
+ else
+ rawset(t,k,v)
+ end
+ end
+ setmetatable(parameters, {
+ __index = getter,
+ __newindex = setter,
+ })
end
local function mathkerns(v,vdelta)
@@ -263,7 +351,7 @@ local psfake = 0
local function fixedpsname(psname,fallback)
local usedname = psname
if psname and psname ~= "" then
- if find(psname," ") then
+ if find(psname," ",1,true) then
usedname = gsub(psname,"[%s]+","-")
else
-- we assume that the name is sane enough (we might sanitize completely some day)
@@ -321,7 +409,7 @@ function constructors.scale(tfmdata,specification)
--
local mathsize = tonumber(specification.mathsize) or 0
local textsize = tonumber(specification.textsize) or scaledpoints
- local forcedsize = tonumber(parameters.mathsize ) or 0
+ local forcedsize = tonumber(parameters.mathsize ) or 0 -- can be set by the feature "mathsize"
local extrafactor = tonumber(specification.factor ) or 1
if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then
scaledpoints = parameters.scriptpercentage * textsize / 100
@@ -329,6 +417,8 @@ function constructors.scale(tfmdata,specification)
scaledpoints = parameters.scriptscriptpercentage * textsize / 100
elseif forcedsize > 1000 then -- safeguard
scaledpoints = forcedsize
+ else
+ -- in context x and xx also use mathsize
end
targetparameters.mathsize = mathsize -- context specific
targetparameters.textsize = textsize -- context specific
@@ -342,10 +432,6 @@ function constructors.scale(tfmdata,specification)
local defaultdepth = resources.defaultdepth or 0
local units = parameters.units or 1000
--
- if target.fonts then
- target.fonts = fastcopy(target.fonts) -- maybe we virtualize more afterwards
- end
- --
-- boundary keys are no longer needed as we now have a string 'right_boundary'
-- that can be used in relevant tables (kerns and ligatures) ... not that I ever
-- used them
@@ -387,7 +473,8 @@ function constructors.scale(tfmdata,specification)
local psname = properties.psname or tfmdata.psname
local name = properties.name or tfmdata.name
--
- -- the psname used in pdf file as well as for selecting subfont in ttc
+ -- The psname used in pdf file as well as for selecting subfont in ttc although
+ -- we don't need that subfont look up here (mapfile stuff).
--
local psname, psfixed = fixedpsname(psname,fontname or fullname or file.nameonly(filename))
--
@@ -405,30 +492,41 @@ function constructors.scale(tfmdata,specification)
-- expansion (hz)
local expansion = parameters.expansion
if expansion then
- target.stretch = expansion.stretch
- target.shrink = expansion.shrink
- target.step = expansion.step
- target.auto_expand = expansion.auto
+ target.stretch = expansion.stretch
+ target.shrink = expansion.shrink
+ target.step = expansion.step
end
- -- protrusion
- local protrusion = parameters.protrusion
- if protrusion then
- target.auto_protrude = protrusion.auto
+ -- slanting
+ local slantfactor = parameters.slantfactor or 0
+ if slantfactor ~= 0 then
+ target.slant = slantfactor * 1000
+ else
+ target.slant = 0
end
-- widening
local extendfactor = parameters.extendfactor or 0
if extendfactor ~= 0 and extendfactor ~= 1 then
hdelta = hdelta * extendfactor
- target.extend = extendfactor * 1000 -- extent ?
+ target.extend = extendfactor * 1000
else
target.extend = 1000 -- extent ?
end
- -- slanting
- local slantfactor = parameters.slantfactor or 0
- if slantfactor ~= 0 then
- target.slant = slantfactor * 1000
+ -- squeezing
+ local squeezefactor = parameters.squeezefactor or 0
+ if squeezefactor ~= 0 and squeezefactor ~= 1 then
+ vdelta = vdelta * squeezefactor
+ target.squeeze = squeezefactor * 1000
else
- target.slant = 0
+ target.squeeze = 1000 -- extent ?
+ end
+ -- effects
+ local mode = parameters.mode or 0
+ if mode ~= 0 then
+ target.mode = mode
+ end
+ local width = parameters.width or 0
+ if width ~= 0 then
+ target.width = width * delta * 1000 / 655360
end
--
targetparameters.factor = delta
@@ -437,9 +535,11 @@ function constructors.scale(tfmdata,specification)
targetparameters.size = scaledpoints
targetparameters.units = units
targetparameters.scaledpoints = askedscaledpoints
+ targetparameters.mode = mode
+ targetparameters.width = width
--
local isvirtual = properties.virtualized or tfmdata.type == "virtual"
- local hasquality = target.auto_expand or target.auto_protrude
+ local hasquality = parameters.expansion or parameters.protrusion
local hasitalics = properties.hasitalics
local autoitalicamount = properties.autoitalicamount
local stackmath = not properties.nostackmath
@@ -450,6 +550,13 @@ function constructors.scale(tfmdata,specification)
local writingmode = properties.writingmode or "horizontal"
local identity = properties.identity or "horizontal"
--
+ local vfonts = target.fonts
+ if vfonts and #vfonts > 0 then
+ target.fonts = fastcopy(vfonts) -- maybe we virtualize more afterwards
+ elseif isvirtual then
+ target.fonts = { { id = 0 } } -- catch error
+ end
+ --
if changed and not next(changed) then
changed = false
end
@@ -485,7 +592,7 @@ function constructors.scale(tfmdata,specification)
targetparameters.descender = delta * descender
end
--
- constructors.enhanceparameters(targetparameters) -- official copies for us
+ constructors.enhanceparameters(targetparameters) -- official copies for us, now virtual
--
local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0
local scaledwidth = defaultwidth * hdelta
@@ -548,10 +655,15 @@ function constructors.scale(tfmdata,specification)
local chr, description, index
if changed then
local c = changed[unicode]
- if c then
- description = descriptions[c] or descriptions[unicode] or character
- character = characters[c] or character
- index = description.index or c
+ if c and c ~= unicode then
+ if c then
+ description = descriptions[c] or descriptions[unicode] or character
+ character = characters[c] or character
+ index = description.index or c
+ else
+ description = descriptions[unicode] or character
+ index = description.index or unicode
+ end
else
description = descriptions[unicode] or character
index = description.index or unicode
@@ -657,12 +769,15 @@ function constructors.scale(tfmdata,specification)
local t = { }
for i=1,#vv do
local vvi = vv[i]
- t[i] = {
- ["start"] = (vvi["start"] or 0)*vdelta,
- ["end"] = (vvi["end"] or 0)*vdelta,
- ["advance"] = (vvi["advance"] or 0)*vdelta,
- ["extender"] = vvi["extender"],
- ["glyph"] = vvi["glyph"],
+ local s = vvi["start"] or 0
+ local e = vvi["end"] or 0
+ local a = vvi["advance"] or 0
+ t[i] = { -- zero check nicer for 5.3
+ ["start"] = s == 0 and 0 or s * vdelta,
+ ["end"] = e == 0 and 0 or e * vdelta,
+ ["advance"] = a == 0 and 0 or a * vdelta,
+ ["extender"] = vvi["extender"],
+ ["glyph"] = vvi["glyph"],
}
end
chr.vert_variants = t
@@ -672,12 +787,15 @@ function constructors.scale(tfmdata,specification)
local t = { }
for i=1,#hv do
local hvi = hv[i]
- t[i] = {
- ["start"] = (hvi["start"] or 0)*hdelta,
- ["end"] = (hvi["end"] or 0)*hdelta,
- ["advance"] = (hvi["advance"] or 0)*hdelta,
- ["extender"] = hvi["extender"],
- ["glyph"] = hvi["glyph"],
+ local s = hvi["start"] or 0
+ local e = hvi["end"] or 0
+ local a = hvi["advance"] or 0
+ t[i] = { -- zero check nicer for 5.3
+ ["start"] = s == 0 and 0 or s * hdelta,
+ ["end"] = e == 0 and 0 or e * hdelta,
+ ["advance"] = a == 0 and 0 or a * hdelta,
+ ["extender"] = hvi["extender"],
+ ["glyph"] = hvi["glyph"],
}
end
chr.horiz_variants = t
@@ -767,7 +885,7 @@ function constructors.scale(tfmdata,specification)
local ok = false
for i=1,#vc do
local key = vc[i][1]
- if key == "right" or key == "down" then
+ if key == "right" or key == "down" or key == "rule" then
ok = true
break
end
@@ -791,7 +909,7 @@ function constructors.scale(tfmdata,specification)
else
chr.commands = vc
end
- chr.index = nil
+ -- chr.index = nil
end
end
targetcharacters[unicode] = chr
@@ -803,6 +921,24 @@ function constructors.scale(tfmdata,specification)
--
constructors.trytosharefont(target,tfmdata)
--
+ -- catch inconsistencies
+ --
+ local vfonts = target.fonts
+-- if isvirtual then
+if isvirtual or target.type == "virtual" or properties.virtualized then
+ properties.virtualized = true
+target.type = "virtual"
+ if not vfonts or #vfonts == 0 then
+ target.fonts = { { id = 0 } }
+ end
+ elseif vfonts then
+ properties.virtualized = true
+ target.type = "virtual"
+ if #vfonts == 0 then
+ target.fonts = { { id = 0 } }
+ end
+ end
+ --
return target
end
@@ -826,16 +962,9 @@ function constructors.finalize(tfmdata)
--
if not parameters.expansion then
parameters.expansion = {
- stretch = tfmdata.stretch or 0,
- shrink = tfmdata.shrink or 0,
- step = tfmdata.step or 0,
- auto = tfmdata.auto_expand or false,
- }
- end
- --
- if not parameters.protrusion then
- parameters.protrusion = {
- auto = auto_protrude
+ stretch = tfmdata.stretch or 0,
+ shrink = tfmdata.shrink or 0,
+ step = tfmdata.step or 0,
}
end
--
@@ -843,14 +972,26 @@ function constructors.finalize(tfmdata)
parameters.size = tfmdata.size
end
--
- if not parameters.extendfactor then
- parameters.extendfactor = tfmdata.extend or 0
+ if not parameters.mode then
+ parameters.mode = 0
+ end
+ --
+ if not parameters.width then
+ parameters.width = 0
end
--
if not parameters.slantfactor then
parameters.slantfactor = tfmdata.slant or 0
end
--
+ if not parameters.extendfactor then
+ parameters.extendfactor = tfmdata.extend or 0
+ end
+ --
+ if not parameters.squeezefactor then
+ parameters.squeezefactor = tfmdata.squeeze or 0
+ end
+ --
local designsize = parameters.designsize
if designsize then
parameters.minsize = tfmdata.minsize or designsize
@@ -939,10 +1080,11 @@ function constructors.finalize(tfmdata)
tfmdata.stretch = nil
tfmdata.shrink = nil
tfmdata.step = nil
- tfmdata.auto_expand = nil
- tfmdata.auto_protrude = nil
- tfmdata.extend = nil
tfmdata.slant = nil
+ tfmdata.extend = nil
+ tfmdata.squeeze = nil
+ tfmdata.mode = nil
+ tfmdata.width = nil
tfmdata.units = nil
tfmdata.units_per_em = nil
--
@@ -963,49 +1105,26 @@ constructors.hashmethods = hashmethods
function constructors.hashfeatures(specification) -- will be overloaded
local features = specification.features
if features then
- local t, tn = { }, 0
- for category, list in next, features do
+ local t, n = { }, 0
+ for category, list in sortedhash(features) do
if next(list) then
local hasher = hashmethods[category]
if hasher then
local hash = hasher(list)
if hash then
- tn = tn + 1
- t[tn] = category .. ":" .. hash
+ n = n + 1
+ t[n] = category .. ":" .. hash
end
end
end
end
- if tn > 0 then
+ if n > 0 then
return concat(t," & ")
end
end
return "unknown"
end
--- hashmethods.normal = function(list)
--- local s = { }
--- local n = 0
--- for k, v in next, list do
--- if not k then
--- -- no need to add to hash
--- elseif k == "number" or k == "features" then
--- -- no need to add to hash (maybe we need a skip list)
--- else
--- n = n + 1
--- s[n] = k
--- end
--- end
--- if n > 0 then
--- sort(s)
--- for i=1,n do
--- local k = s[i]
--- s[i] = k .. '=' .. tostring(list[k])
--- end
--- return concat(s,"+")
--- end
--- end
-
hashmethods.normal = function(list)
local s = { }
local n = 0
@@ -1016,7 +1135,18 @@ hashmethods.normal = function(list)
-- no need to add to hash (maybe we need a skip list)
else
n = n + 1
- s[n] = k .. '=' .. tostring(v)
+ if type(v) == "table" then
+ -- table.sequenced
+ local t = { }
+ local m = 0
+ for k, v in next, v do
+ m = m + 1
+ t[m] = k .. '=' .. tostring(v)
+ end
+ s[n] = k .. '={' .. concat(t,",") .. "}"
+ else
+ s[n] = k .. '=' .. tostring(v)
+ end
end
end
if n > 0 then
@@ -1026,7 +1156,7 @@ hashmethods.normal = function(list)
end
--[[ldx--
-<p>In principle we can share tfm tables when we are in node for a font, but then
+<p>In principle we can share tfm tables when we are in need for a font, but then
we need to define a font switch as an id/attr switch which is no fun, so in that
case users can best use dynamic features ... so, we will not use that speedup. Okay,
when we get rid of base mode we can optimize even further by sharing, but then we
@@ -1040,13 +1170,15 @@ function constructors.hashinstance(specification,force)
specification.hash = hash
end
if size < 1000 and designsizes[hash] then
- size = math.round(constructors.scaled(size,designsizes[hash]))
- specification.size = size
+ size = round(constructors.scaled(size,designsizes[hash]))
+ else
+ size = round(size)
end
+ specification.size = size
if fallbacks then
- return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ return hash .. ' @ ' .. size .. ' @ ' .. fallbacks
else
- return hash .. ' @ ' .. tostring(size)
+ return hash .. ' @ ' .. size
end
end
@@ -1255,11 +1387,13 @@ do
if not enhancers then
- local actions = allocate()
- local before = allocate()
- local after = allocate()
- local order = allocate()
- local patches = { before = before, after = after }
+ local actions = allocate() -- no need to allocate thee
+ local before = allocate()
+ local after = allocate()
+ local order = allocate()
+ local known = { }
+ local nofsteps = 0
+ local patches = { before = before, after = after }
local trace = false
local report = logs.reporter("fonts",format .. " enhancing")
@@ -1285,7 +1419,7 @@ do
report("%s enhancing file %a","start",filename)
end
ioflush() -- we want instant messages
- for e=1,#order do
+ for e=1,nofsteps do
local enhancer = order[e]
local b = before[enhancer]
if b then
@@ -1295,7 +1429,7 @@ do
end
end
end
- enhance(enhancer,data,filename,raw)
+ enhance(enhancer,data,filename,raw) -- we have one installed: check extra features
local a = after[enhancer]
if a then
for pattern, action in next, a do
@@ -1317,7 +1451,9 @@ do
if actions[what] then
-- overloading, e.g."check extra features"
else
- order[#order+1] = what
+ nofsteps = nofsteps + 1
+ order[nofsteps] = what
+ known[what] = nofsteps
end
actions[what] = action
else
@@ -1325,7 +1461,19 @@ do
end
end
- -- fonts.constructors.otf.enhancers.patch("before","migrate metadata","cambria",function() end)
+ -- We used to have a lot of enhancers but no longer with the new font loader. The order of enhancers
+ -- is the order of definition. The before/after patches are there for old times sake and happen
+ -- before or after a (named) enhancer. An example of a set enhancer is "check extra features" so one
+ -- one set patches before or after that is applied. Unknown enhancers are auto-registered. It's a bit
+ -- messy but we keep it for compatibility reasons.
+ --
+ -- fonts.handlers.otf.enhancers.patches.register("before","some patches","somefont",function(data,filename)
+ -- print("!!!!!!!") -- before | after
+ -- end)
+ --
+ -- fonts.handlers.otf.enhancers.register("more patches",function(data,filename)
+ -- print("???????") -- enhance
+ -- end)
local function patch(what,where,pattern,action)
local pw = patches[what]
@@ -1334,7 +1482,12 @@ do
if ww then
ww[pattern] = action
else
- pw[where] = { [pattern] = action}
+ pw[where] = { [pattern] = action }
+ if not known[where] then
+ nofsteps = nofsteps + 1
+ order[nofsteps] = where
+ known[where] = nofsteps
+ end
end
end
end
@@ -1343,7 +1496,11 @@ do
register = register,
apply = apply,
patch = patch,
- patches = { register = patch }, -- for old times sake
+ report = report,
+ patches = {
+ register = patch,
+ report = report,
+ }, -- for old times sake
}
handler.enhancers = enhancers
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-def.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-def.lua
index 88d6145665b..e5101e7f656 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-def.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-def.lua
@@ -11,8 +11,9 @@ if not modules then modules = { } end modules ['font-def'] = {
local lower, gsub = string.lower, string.gsub
local tostring, next = tostring, next
local lpegmatch = lpeg.match
-local suffixonly, removesuffix = file.suffix, file.removesuffix
+local suffixonly, removesuffix, basename = file.suffix, file.removesuffix, file.basename
local formatters = string.formatters
+local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys
local allocate = utilities.storage.allocate
@@ -20,7 +21,6 @@ local trace_defining = false trackers .register("fonts.defining", function
local directive_embedall = false directives.register("fonts.embedall", function(v) directive_embedall = v end)
trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading")
-trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*")
local report_defining = logs.reporter("fonts","defining")
@@ -80,53 +80,6 @@ and prepares a table that will move along as we proceed.</p>
-- name name(sub) name(sub)*spec name*spec
-- name@spec*oeps
-local splitter, splitspecifiers = nil, "" -- not so nice
-
-local P, C, S, Cc = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc
-
-local left = P("(")
-local right = P(")")
-local colon = P(":")
-local space = P(" ")
-
-definers.defaultlookup = "file"
-
-local prefixpattern = P(false)
-
-local function addspecifier(symbol)
- splitspecifiers = splitspecifiers .. symbol
- local method = S(splitspecifiers)
- local lookup = C(prefixpattern) * colon
- local sub = left * C(P(1-left-right-method)^1) * right
- local specification = C(method) * C(P(1)^1)
- local name = C((1-sub-specification)^1)
- splitter = P((lookup + Cc("")) * name * (sub + Cc("")) * (specification + Cc("")))
-end
-
-local function addlookup(str,default)
- prefixpattern = prefixpattern + P(str)
-end
-
-definers.addlookup = addlookup
-
-addlookup("file")
-addlookup("name")
-addlookup("spec")
-
-local function getspecification(str)
- return lpegmatch(splitter,str or "") -- weird catch
-end
-
-definers.getspecification = getspecification
-
-function definers.registersplit(symbol,action,verbosename)
- addspecifier(symbol)
- variants[symbol] = action
- if verbosename then
- variants[verbosename] = action
- end
-end
-
local function makespecification(specification,lookup,name,sub,method,detail,size)
size = size or 655360
if not lookup or lookup == "" then
@@ -151,13 +104,65 @@ local function makespecification(specification,lookup,name,sub,method,detail,siz
return t
end
-
definers.makespecification = makespecification
-function definers.analyze(specification, size)
- -- can be optimized with locals
- local lookup, name, sub, method, detail = getspecification(specification or "")
- return makespecification(specification, lookup, name, sub, method, detail, size)
+if context then
+
+ local splitter, splitspecifiers = nil, "" -- not so nice
+
+ local P, C, S, Cc, Cs = lpeg.P, lpeg.C, lpeg.S, lpeg.Cc, lpeg.Cs
+
+ local left = P("(")
+ local right = P(")")
+ local colon = P(":")
+ local space = P(" ")
+ local lbrace = P("{")
+ local rbrace = P("}")
+
+ definers.defaultlookup = "file"
+
+ local prefixpattern = P(false)
+
+ local function addspecifier(symbol)
+ splitspecifiers = splitspecifiers .. symbol
+ local method = S(splitspecifiers)
+ local lookup = C(prefixpattern) * colon
+ local sub = left * C(P(1-left-right-method)^1) * right
+ local specification = C(method) * C(P(1)^1)
+ local name = Cs((lbrace/"") * (1-rbrace)^1 * (rbrace/"") + (1-sub-specification)^1)
+ splitter = P((lookup + Cc("")) * name * (sub + Cc("")) * (specification + Cc("")))
+ end
+
+ local function addlookup(str)
+ prefixpattern = prefixpattern + P(str)
+ end
+
+ definers.addlookup = addlookup
+
+ addlookup("file")
+ addlookup("name")
+ addlookup("spec")
+
+ local function getspecification(str)
+ return lpegmatch(splitter,str or "") -- weird catch
+ end
+
+ definers.getspecification = getspecification
+
+ function definers.registersplit(symbol,action,verbosename)
+ addspecifier(symbol)
+ variants[symbol] = action
+ if verbosename then
+ variants[verbosename] = action
+ end
+ end
+
+ function definers.analyze(specification, size)
+ -- can be optimized with locals
+ local lookup, name, sub, method, detail = getspecification(specification or "")
+ return makespecification(specification, lookup, name, sub, method, detail, size)
+ end
+
end
--[[ldx--
@@ -184,11 +189,30 @@ end
function resolvers.name(specification)
local resolve = fonts.names.resolve
if resolve then
- local resolved, sub, subindex = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions
+ local resolved, sub, subindex, instance = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions
if resolved then
specification.resolved = resolved
specification.sub = sub
specification.subindex = subindex
+ -- new, needed for experiments
+ if instance then
+ specification.instance = instance
+ local features = specification.features
+ if not features then
+ features = { }
+ specification.features = features
+ end
+ local normal = features.normal
+ if not normal then
+ normal = { }
+ features.normal = normal
+ end
+ normal.instance = instance
+ if not callbacks.supported.glyph_stream_provider then
+ normal.variableshapes = true -- for the moment
+ end
+ end
+ --
local suffix = lower(suffixonly(resolved))
if fonts.formats[suffix] then
specification.forced = suffix
@@ -294,10 +318,71 @@ local function checkembedding(tfmdata)
tfmdata.embedding = embedding
end
+local function checkfeatures(tfmdata)
+ local resources = tfmdata.resources
+ local shared = tfmdata.shared
+ if resources and shared then
+ local features = resources.features
+ local usedfeatures = shared.features
+ if features and usedfeatures then
+ local usedlanguage = usedfeatures.language or "dflt"
+ local usedscript = usedfeatures.script or "dflt"
+ local function check(what)
+ if what then
+ local foundlanguages = { }
+ for feature, scripts in next, what do
+ if usedscript == "auto" or scripts["*"] then
+ -- ok
+ elseif not scripts[usedscript] then
+ -- report_defining("font %!font:name!, feature %a, no script %a",
+ -- tfmdata,feature,usedscript)
+ else
+ for script, languages in next, scripts do
+ if languages["*"] then
+ -- ok
+ elseif not languages[usedlanguage] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,usedlanguage)
+ end
+ end
+ end
+ for script, languages in next, scripts do
+ for language in next, languages do
+ foundlanguages[language] = true
+ end
+ end
+ end
+ if false then
+ foundlanguages["*"] = nil
+ foundlanguages = sortedkeys(foundlanguages)
+ for feature, scripts in sortedhash(what) do
+ for script, languages in next, scripts do
+ if not languages["*"] then
+ for i=1,#foundlanguages do
+ local language = foundlanguages[i]
+ if not languages[language] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,language)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ check(features.gsub)
+ check(features.gpos)
+ end
+ end
+end
+
function definers.loadfont(specification)
local hash = constructors.hashinstance(specification)
+ -- todo: also hash by instance / factors
local tfmdata = loadedfonts[hash] -- hashes by size !
if not tfmdata then
+ -- normally context will not end up here often (if so there is an issue somewhere)
local forced = specification.forced or ""
if forced ~= "" then
local reader = readers[lower(forced)] -- normally forced is already lowered
@@ -327,6 +412,7 @@ function definers.loadfont(specification)
checkembedding(tfmdata) -- todo: general postprocessor
loadedfonts[hash] = tfmdata
designsizes[specification.hash] = tfmdata.parameters.designsize
+ checkfeatures(tfmdata)
end
end
if not tfmdata then
@@ -335,10 +421,6 @@ function definers.loadfont(specification)
return tfmdata
end
-function constructors.checkvirtualids()
- -- dummy in plain version
-end
-
function constructors.readanddefine(name,size) -- no id -- maybe a dummy first
local specification = definers.analyze(name,size)
local method = specification.method
@@ -352,7 +434,6 @@ function constructors.readanddefine(name,size) -- no id -- maybe a dummy first
local tfmdata = definers.loadfont(specification)
if tfmdata then
tfmdata.properties.hash = hash
- constructors.checkvirtualids(tfmdata) -- experiment, will become obsolete when slots can selfreference
id = font.define(tfmdata)
definers.register(tfmdata,id)
else
@@ -437,8 +518,8 @@ function definers.read(specification,size,id) -- id can be optional, name can al
local properties = tfmdata.properties or { }
local parameters = tfmdata.parameters or { }
report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
- properties.format or "unknown", id, properties.name, parameters.size, properties.encodingbytes,
- properties.encodingname, properties.fullname, file.basename(properties.filename))
+ properties.format or "unknown", id or "-", properties.name, parameters.size, properties.encodingbytes,
+ properties.encodingname, properties.fullname, basename(properties.filename))
end
statistics.stoptiming(fonts)
return tfmdata
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua
index 13095f7e699..1fe4289b2f7 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua
@@ -48,21 +48,36 @@ if not modules then modules = { } end modules ['font-dsp'] = {
-- of node lists is not noticeable faster for latin texts, but for arabic we gain some 10%
-- (and could probably gain a bit more).
+-- All this packing in the otf format is somewhat obsessive as nowadays 4K resolution
+-- multi-gig videos pass through our networks and storage and memory is abundant.
+
+-- Although we use a few table readers there i sno real gain in there (apart from having
+-- less code. After all there are often not that many demanding features.
+
local next, type = next, type
-local bittest = bit32.btest
+local band = bit32.band
+local extract = bit32.extract
+local bor = bit32.bor
+local lshift = bit32.lshift
local rshift = bit32.rshift
-local concat = table.concat
+local gsub = string.gsub
local lower = string.lower
-local copy = table.copy
local sub = string.sub
local strip = string.strip
local tohash = table.tohash
+local concat = table.concat
+local copy = table.copy
local reversed = table.reversed
+local sort = table.sort
+local insert = table.insert
+local round = math.round
+local settings_to_hash = utilities.parsers.settings_to_hash_colon_too
local setmetatableindex = table.setmetatableindex
local formatters = string.formatters
local sortedkeys = table.sortedkeys
local sortedhash = table.sortedhash
+local sequenced = table.sequenced
local report = logs.reporter("otf reader")
@@ -71,18 +86,62 @@ local streamreader = readers.streamreader
local setposition = streamreader.setposition
local getposition = streamreader.getposition
-local skipshort = streamreader.skipshort
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
+local readinteger = streamreader.readinteger1
local readshort = streamreader.readinteger2 -- 16-bit signed integer
-local readfword = readshort
local readstring = streamreader.readstring
local readtag = streamreader.readtag
local readbytes = streamreader.readbytes
+local readfixed = streamreader.readfixed4
+local read2dot14 = streamreader.read2dot14
+local skipshort = streamreader.skipshort
+local skipbytes = streamreader.skip
+local readbytetable = streamreader.readbytetable
+local readbyte = streamreader.readbyte
+local readcardinaltable = streamreader.readcardinaltable
+local readintegertable = streamreader.readintegertable
+local readfword = readshort
+
+local short = 2
+local ushort = 2
+local ulong = 4
+
+directives.register("fonts.streamreader",function()
+
+ streamreader = utilities.streams
+
+ setposition = streamreader.setposition
+ getposition = streamreader.getposition
+ readushort = streamreader.readcardinal2
+ readulong = streamreader.readcardinal4
+ readinteger = streamreader.readinteger1
+ readshort = streamreader.readinteger2
+ readstring = streamreader.readstring
+ readtag = streamreader.readtag
+ readbytes = streamreader.readbytes
+ readfixed = streamreader.readfixed4
+ read2dot14 = streamreader.read2dot14
+ skipshort = streamreader.skipshort
+ skipbytes = streamreader.skip
+ readbytetable = streamreader.readbytetable
+ readbyte = streamreader.readbyte
+ readcardinaltable = streamreader.readcardinaltable
+ readintegertable = streamreader.readintegertable
+ readfword = readshort
+
+end)
local gsubhandlers = { }
local gposhandlers = { }
+readers.gsubhandlers = gsubhandlers
+readers.gposhandlers = gposhandlers
+
+local helpers = readers.helpers
+local gotodatatable = helpers.gotodatatable
+local setvariabledata = helpers.setvariabledata
+
local lookupidoffset = -1 -- will become 1 when we migrate (only -1 for comparign with old)
local classes = {
@@ -121,6 +180,57 @@ local chaindirections = {
reversechainedcontextsingle = -1,
}
+local function setmetrics(data,where,tag,d)
+ local w = data[where]
+ if w then
+ local v = w[tag]
+ if v then
+ -- it looks like some fonts set the value and not the delta
+ -- report("adding %s to %s.%s value %s",d,where,tag,v)
+ w[tag] = v + d
+ end
+ end
+end
+
+local variabletags = {
+ hasc = function(data,d) setmetrics(data,"windowsmetrics","typoascender",d) end,
+ hdsc = function(data,d) setmetrics(data,"windowsmetrics","typodescender",d) end,
+ hlgp = function(data,d) setmetrics(data,"windowsmetrics","typolinegap",d) end,
+ hcla = function(data,d) setmetrics(data,"windowsmetrics","winascent",d) end,
+ hcld = function(data,d) setmetrics(data,"windowsmetrics","windescent",d) end,
+ vasc = function(data,d) setmetrics(data,"vhea not done","ascent",d) end,
+ vdsc = function(data,d) setmetrics(data,"vhea not done","descent",d) end,
+ vlgp = function(data,d) setmetrics(data,"vhea not done","linegap",d) end,
+ xhgt = function(data,d) setmetrics(data,"windowsmetrics","xheight",d) end,
+ cpht = function(data,d) setmetrics(data,"windowsmetrics","capheight",d) end,
+ sbxs = function(data,d) setmetrics(data,"windowsmetrics","subscriptxsize",d) end,
+ sbys = function(data,d) setmetrics(data,"windowsmetrics","subscriptysize",d) end,
+ sbxo = function(data,d) setmetrics(data,"windowsmetrics","subscriptxoffset",d) end,
+ sbyo = function(data,d) setmetrics(data,"windowsmetrics","subscriptyoffset",d) end,
+ spxs = function(data,d) setmetrics(data,"windowsmetrics","superscriptxsize",d) end,
+ spys = function(data,d) setmetrics(data,"windowsmetrics","superscriptysize",d) end,
+ spxo = function(data,d) setmetrics(data,"windowsmetrics","superscriptxoffset",d) end,
+ spyo = function(data,d) setmetrics(data,"windowsmetrics","superscriptyoffset",d) end,
+ strs = function(data,d) setmetrics(data,"windowsmetrics","strikeoutsize",d) end,
+ stro = function(data,d) setmetrics(data,"windowsmetrics","strikeoutpos",d) end,
+ unds = function(data,d) setmetrics(data,"postscript","underlineposition",d) end,
+ undo = function(data,d) setmetrics(data,"postscript","underlinethickness",d) end,
+}
+
+local read_cardinal = {
+ streamreader.readcardinal1,
+ streamreader.readcardinal2,
+ streamreader.readcardinal3,
+ streamreader.readcardinal4,
+}
+
+local read_integer = {
+ streamreader.readinteger1,
+ streamreader.readinteger2,
+ streamreader.readinteger3,
+ streamreader.readinteger4,
+}
+
-- Traditionally we use these unique names (so that we can flatten the lookup list
-- (we create subsets runtime) but I will adapt the old code to newer names.
@@ -164,7 +274,7 @@ local lookupnames = {
-- local lookupstate = setmetatableindex(function(t,k)
-- local v = { }
-- for kk, vv in next, lookupbits do
--- if bittest(k,kk) then
+-- if band(k,kk) ~= 0 then
-- v[vv] = true
-- end
-- end
@@ -174,36 +284,286 @@ local lookupnames = {
local lookupflags = setmetatableindex(function(t,k)
local v = {
- bittest(k,0x0008) and true or false, -- ignoremarks
- bittest(k,0x0004) and true or false, -- ignoreligatures
- bittest(k,0x0002) and true or false, -- ignorebaseglyphs
- bittest(k,0x0001) and true or false, -- r2l
+ band(k,0x0008) ~= 0 and true or false, -- ignoremarks
+ band(k,0x0004) ~= 0 and true or false, -- ignoreligatures
+ band(k,0x0002) ~= 0 and true or false, -- ignorebaseglyphs
+ band(k,0x0001) ~= 0 and true or false, -- r2l
}
t[k] = v
return v
end)
+-- Variation stores: it's not entirely clear if the regions are a shared
+-- resource (it looks like they are). Anyway, we play safe and use a
+-- share.
+
+-- values can be anything the min/max permits so we can either think of
+-- real values of a fraction along the axis (probably easier)
+
+-- wght:400,wdth:100,ital:1
+
+local function axistofactors(str)
+ local t = settings_to_hash(str)
+ for k, v in next, t do
+ t[k] = tonumber(v) or v -- this also normalizes numbers itself
+ end
+ return t
+end
+
+local hash = table.setmetatableindex(function(t,k)
+ local v = sequenced(axistofactors(k),",")
+ t[k] = v
+ return v
+end)
+
+helpers.normalizedaxishash = hash
+
+local cleanname = fonts.names and fonts.names.cleanname or function(name)
+ return name and (gsub(lower(name),"[^%a%d]","")) or nil
+end
+
+helpers.cleanname = cleanname
+
+function helpers.normalizedaxis(str)
+ return hash[str] or str
+end
+
+-- contradicting spec ... (signs) so i'll check it and fix it once we have
+-- proper fonts
+
+local function getaxisscale(segments,minimum,default,maximum,user)
+ --
+ -- returns the right values cf example in standard
+ --
+ if not minimum or not default or not maximum then
+ return false
+ end
+ if user < minimum then
+ user = minimum
+ elseif user > maximum then
+ user = maximum
+ end
+ if user < default then
+ default = - (default - user) / (default - minimum)
+ elseif user > default then
+ default = (user - default) / (maximum - default)
+ else
+ default = 0
+ end
+ if not segments then
+ return default
+ end
+ local e
+ for i=1,#segments do
+ local s = segments[i]
+ if type(s) ~= "number" then
+ report("using default axis scale")
+ return default
+ elseif s[1] >= default then
+ if s[2] == default then
+ return default
+ else
+ e = i
+ break
+ end
+ end
+ end
+ if e then
+ local b = segments[e-1]
+ local e = segments[e]
+ return b[2] + (e[2] - b[2]) * (default - b[1]) / (e[1] - b[1])
+ else
+ return false
+ end
+end
+
+local function getfactors(data,instancespec)
+ if instancespec == true then
+ -- take default
+ elseif type(instancespec) ~= "string" or instancespec == "" then
+ return
+ end
+ local variabledata = data.variabledata
+ if not variabledata then
+ return
+ end
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ local segments = variabledata.segments
+ if instances and axis then
+ local values
+ if instancespec == true then
+ -- first instance:
+ -- values = instances[1].values
+ -- axis defaults:
+ values = { }
+ for i=1,#axis do
+ values[i] = {
+ -- axis = axis[i].tag,
+ value = axis[i].default,
+ }
+ end
+
+ else
+ for i=1,#instances do
+ local instance = instances[i]
+ if cleanname(instance.subfamily) == instancespec then
+ values = instance.values
+ break
+ end
+ end
+ end
+ if values then
+ local factors = { }
+ for i=1,#axis do
+ local a = axis[i]
+ factors[i] = getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
+ end
+ return factors
+ end
+ local values = axistofactors(hash[instancespec] or instancespec)
+ if values then
+ local factors = { }
+ for i=1,#axis do
+ local a = axis[i]
+ local d = a.default
+ factors[i] = getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
+ end
+ return factors
+ end
+ end
+end
+
+local function getscales(regions,factors)
+ local scales = { }
+ for i=1,#regions do
+ local region = regions[i]
+ local s = 1
+ for j=1,#region do
+ local axis = region[j]
+ local f = factors[j]
+ local start = axis.start
+ local peak = axis.peak
+ local stop = axis.stop
+ -- get rid of these tests, false flag
+ if start > peak or peak > stop then
+ -- * 1
+ elseif start < 0 and stop > 0 and peak ~= 0 then
+ -- * 1
+ elseif peak == 0 then
+ -- * 1
+ elseif f < start or f > stop then
+ -- * 0
+ s = 0
+ break
+ elseif f < peak then
+ -- s = - s * (f - start) / (peak - start)
+ s = s * (f - start) / (peak - start)
+ elseif f > peak then
+ s = s * (stop - f) / (stop - peak)
+ else
+ -- * 1
+ end
+ end
+ scales[i] = s
+ end
+ return scales
+end
+
+helpers.getaxisscale = getaxisscale
+helpers.getfactors = getfactors
+helpers.getscales = getscales
+helpers.axistofactors = axistofactors
+
+local function readvariationdata(f,storeoffset,factors) -- store
+ local position = getposition(f)
+ setposition(f,storeoffset)
+ -- header
+ local format = readushort(f)
+ local regionoffset = storeoffset + readulong(f)
+ local nofdeltadata = readushort(f)
+ local deltadata = readcardinaltable(f,nofdeltadata,ulong)
+ -- regions
+ setposition(f,regionoffset)
+ local nofaxis = readushort(f)
+ local nofregions = readushort(f)
+ local regions = { }
+ for i=1,nofregions do -- 0
+ local t = { }
+ for i=1,nofaxis do
+ t[i] = { -- maybe no keys, just 1..3
+ start = read2dot14(f),
+ peak = read2dot14(f),
+ stop = read2dot14(f),
+ }
+ end
+ regions[i] = t
+ end
+ -- deltas
+ if factors then
+ for i=1,nofdeltadata do
+ setposition(f,storeoffset+deltadata[i])
+ local nofdeltasets = readushort(f)
+ local nofshorts = readushort(f)
+ local nofregions = readushort(f)
+ local usedregions = { }
+ local deltas = { }
+ for i=1,nofregions do
+ usedregions[i] = regions[readushort(f)+1]
+ end
+ -- we could test before and save a for
+ for i=1,nofdeltasets do
+ local t = readintegertable(f,nofshorts,short)
+ for i=nofshorts+1,nofregions do
+ t[i] = readinteger(f)
+ end
+ deltas[i] = t
+ end
+ deltadata[i] = {
+ regions = usedregions,
+ deltas = deltas,
+ scales = factors and getscales(usedregions,factors) or nil,
+ }
+ end
+ end
+ setposition(f,position)
+ return regions, deltadata
+end
+
+helpers.readvariationdata = readvariationdata
+
-- Beware: only use the simple variant if we don't set keys/values (otherwise too many entries). We
-- could also have a variant that applies a function but there is no real benefit in this.
local function readcoverage(f,offset,simple)
setposition(f,offset)
local coverageformat = readushort(f)
- local coverage = { }
if coverageformat == 1 then
local nofcoverage = readushort(f)
if simple then
- for i=1,nofcoverage do
- coverage[i] = readushort(f)
+ -- often 1 or 2
+ if nofcoverage == 1 then
+ return { readushort(f) }
+ elseif nofcoverage == 2 then
+ return { readushort(f), readushort(f) }
+ else
+ return readcardinaltable(f,nofcoverage,ushort)
end
+ elseif nofcoverage == 1 then
+ return { [readushort(f)] = 0 }
+ elseif nofcoverage == 2 then
+ return { [readushort(f)] = 0, [readushort(f)] = 1 }
else
+ local coverage = { }
for i=0,nofcoverage-1 do
coverage[readushort(f)] = i -- index in record
end
+ return coverage
end
elseif coverageformat == 2 then
local nofranges = readushort(f)
- local n = simple and 1 or 0 -- needs checking
+ local coverage = { }
+ local n = simple and 1 or 0 -- needs checking
for i=1,nofranges do
local firstindex = readushort(f)
local lastindex = readushort(f)
@@ -220,10 +580,11 @@ local function readcoverage(f,offset,simple)
end
end
end
+ return coverage
else
report("unknown coverage format %a ",coverageformat)
+ return { }
end
- return coverage
end
local function readclassdef(f,offset,preset)
@@ -283,36 +644,168 @@ end
-- extra readers
-local function readposition(f,format)
+local skips = { [0] =
+ 0, -- ----
+ 1, -- ---x
+ 1, -- --y-
+ 2, -- --yx
+ 1, -- -h--
+ 2, -- -h-x
+ 2, -- -hy-
+ 3, -- -hyx
+ 2, -- v--x
+ 2, -- v-y-
+ 3, -- v-yx
+ 2, -- vh--
+ 3, -- vh-x
+ 3, -- vhy-
+ 4, -- vhyx
+}
+
+-- We can assume that 0 is nothing and in fact we can start at 1 as
+-- usual in Lua to make sure of that.
+
+local function readvariation(f,offset)
+ local p = getposition(f)
+ setposition(f,offset)
+ local outer = readushort(f)
+ local inner = readushort(f)
+ local format = readushort(f)
+ setposition(f,p)
+ if format == 0x8000 then
+ return outer, inner
+ end
+end
+
+local function readposition(f,format,mainoffset,getdelta)
if format == 0 then
- return nil
+ return false
end
- -- maybe fast test on 0x0001 + 0x0002 + 0x0004 + 0x0008 (profile first)
- local x = bittest(format,0x0001) and readshort(f) or 0 -- placement
- local y = bittest(format,0x0002) and readshort(f) or 0 -- placement
- local h = bittest(format,0x0004) and readshort(f) or 0 -- advance
- local v = bittest(format,0x0008) and readshort(f) or 0 -- advance
- if x == 0 and y == 0 and h == 0 and v == 0 then
- return nil
+ -- a few happen often
+ if format == 0x04 then
+ local h = readshort(f)
+ if h == 0 then
+ return true -- all zero
+ else
+ return { 0, 0, h, 0 }
+ end
+ end
+ if format == 0x05 then
+ local x = readshort(f)
+ local h = readshort(f)
+ if x == 0 and h == 0 then
+ return true -- all zero
+ else
+ return { x, 0, h, 0 }
+ end
+ end
+ if format == 0x44 then
+ local h = readshort(f)
+ if getdelta then
+ local d = readshort(f) -- short or ushort
+ if d > 0 then
+ local outer, inner = readvariation(f,mainoffset+d)
+ if outer then
+ h = h + getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,1)
+ end
+ if h == 0 then
+ return true -- all zero
+ else
+ return { 0, 0, h, 0 }
+ end
+ end
+ --
+ -- todo:
+ --
+ -- if format == 0x55 then
+ -- local x = readshort(f)
+ -- local h = readshort(f)
+ -- ....
+ -- end
+ --
+ local x = band(format,0x1) ~= 0 and readshort(f) or 0 -- x placement
+ local y = band(format,0x2) ~= 0 and readshort(f) or 0 -- y placement
+ local h = band(format,0x4) ~= 0 and readshort(f) or 0 -- h advance
+ local v = band(format,0x8) ~= 0 and readshort(f) or 0 -- v advance
+ if format >= 0x10 then
+ local X = band(format,0x10) ~= 0 and skipshort(f) or 0
+ local Y = band(format,0x20) ~= 0 and skipshort(f) or 0
+ local H = band(format,0x40) ~= 0 and skipshort(f) or 0
+ local V = band(format,0x80) ~= 0 and skipshort(f) or 0
+ local s = skips[extract(format,4,4)]
+ if s > 0 then
+ skipshort(f,s)
+ end
+ if getdelta then
+ if X > 0 then
+ local outer, inner = readvariation(f,mainoffset+X)
+ if outer then
+ x = x + getdelta(outer,inner)
+ end
+ end
+ if Y > 0 then
+ local outer, inner = readvariation(f,mainoffset+Y)
+ if outer then
+ y = y + getdelta(outer,inner)
+ end
+ end
+ if H > 0 then
+ local outer, inner = readvariation(f,mainoffset+H)
+ if outer then
+ h = h + getdelta(outer,inner)
+ end
+ end
+ if V > 0 then
+ local outer, inner = readvariation(f,mainoffset+V)
+ if outer then
+ v = v + getdelta(outer,inner)
+ end
+ end
+ end
+ return { x, y, h, v }
+ elseif x == 0 and y == 0 and h == 0 and v == 0 then
+ return true -- all zero
else
return { x, y, h, v }
end
end
-local function readanchor(f,offset)
+local function readanchor(f,offset,getdelta) -- maybe also ignore 0's as in pos
if not offset or offset == 0 then
return nil -- false
end
setposition(f,offset)
- local format = readshort(f)
- if format == 0 then
- report("invalid anchor format %i @ position %i",format,offset)
- return false
- elseif format > 3 then
- report("unsupported anchor format %i @ position %i",format,offset)
- return false
+ -- no need to skip as we position each
+ local format = readshort(f) -- 1: x y 2: x y index 3 x y X Y
+ local x = readshort(f)
+ local y = readshort(f)
+ if format == 3 then
+ if getdelta then
+ local X = readshort(f)
+ local Y = readshort(f)
+ if X > 0 then
+ local outer, inner = readvariation(f,offset+X)
+ if outer then
+ x = x + getdelta(outer,inner)
+ end
+ end
+ if Y > 0 then
+ local outer, inner = readvariation(f,offset+Y)
+ if outer then
+ y = y + getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ return { x, y } -- , { xindex, yindex }
+ else
+ return { x, y }
end
- return { readshort(f), readshort(f) }
end
-- common handlers: inlining can be faster but we cache anyway
@@ -325,23 +818,17 @@ local function readfirst(f,offset)
return { readushort(f) }
end
-local function readarray(f,offset,first)
+-- quite often 0, 1, 2
+
+function readarray(f,offset)
if offset then
setposition(f,offset)
end
local n = readushort(f)
- if first then
- local t = { first }
- for i=2,n do
- t[i] = readushort(f)
- end
- return t, n
+ if n == 1 then
+ return { readushort(f) }, 1
elseif n > 0 then
- local t = { }
- for i=1,n do
- t[i] = readushort(f)
- end
- return t, n
+ return readcardinaltable(f,n,ushort), n
end
end
@@ -390,7 +877,13 @@ local function readlookuparray(f,noflookups,nofcurrent)
if index > length then
length = index
end
- lookups[index] = readushort(f) + 1
+ local lookup = readushort(f) + 1
+ local list = lookups[index]
+ if list then
+ list[#list+1] = lookup
+ else
+ lookups[index] = { lookup }
+ end
end
for index=1,length do
if not lookups[index] then
@@ -736,10 +1229,7 @@ function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
elseif subtype == 2 then -- in streamreader a seek and fetch is faster than a temp table
local coverage = readushort(f)
local nofreplacements = readushort(f)
- local replacements = { }
- for i=1,nofreplacements do
- replacements[i] = readushort(f)
- end
+ local replacements = readcardinaltable(f,nofreplacements,ushort)
local coverage = readcoverage(f,tableoffset + coverage) -- not simple as we need to set key/value anyway
for index, newindex in next, coverage do
newindex = newindex + 1
@@ -767,18 +1257,10 @@ local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
if subtype == 1 then
local coverage = readushort(f)
local nofsequence = readushort(f)
- local sequences = { }
- for i=1,nofsequence do
- sequences[i] = readushort(f)
- end
+ local sequences = readcardinaltable(f,nofsequence,ushort)
for i=1,nofsequence do
setposition(f,tableoffset + sequences[i])
- local n = readushort(f)
- local s = { }
- for i=1,n do
- s[i] = readushort(f)
- end
- sequences[i] = s
+ sequences[i] = readcardinaltable(f,readushort(f),ushort)
end
local coverage = readcoverage(f,tableoffset + coverage)
for index, newindex in next, coverage do
@@ -813,19 +1295,20 @@ function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,no
if subtype == 1 then
local coverage = readushort(f)
local nofsets = readushort(f)
- local ligatures = { }
- for i=1,nofsets do
- ligatures[i] = readushort(f)
- end
+ local ligatures = readcardinaltable(f,nofsets,ushort)
for i=1,nofsets do
local offset = lookupoffset + offset + ligatures[i]
setposition(f,offset)
local n = readushort(f)
- local l = { }
- for i=1,n do
- l[i] = offset + readushort(f)
+ if n == 1 then
+ ligatures[i] = { offset + readushort(f) }
+ else
+ local l = { }
+ for i=1,n do
+ l[i] = offset + readushort(f)
+ end
+ ligatures[i] = l
end
- ligatures[i] = l
end
local coverage = readcoverage(f,tableoffset + coverage)
for index, newindex in next, coverage do
@@ -883,12 +1366,14 @@ function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffs
before = readcoveragearray(f,tableoffset,before,true)
after = readcoveragearray(f,tableoffset,after,true)
return {
- coverage = {
- format = "reversecoverage", -- reversesub
- before = before,
- current = current,
- after = after,
- replacements = replacements,
+ format = "reversecoverage", -- reversesub
+ rules = {
+ {
+ before = before,
+ current = current,
+ after = after,
+ replacements = replacements,
+ }
}
}, "reversechainedcontextsingle"
else
@@ -898,20 +1383,21 @@ end
-- gpos handlers
-local function readpairsets(f,tableoffset,sets,format1,format2)
+local function readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
local done = { }
for i=1,#sets do
local offset = sets[i]
local reused = done[offset]
if not reused then
- setposition(f,tableoffset + offset)
+ offset = tableoffset + offset
+ setposition(f,offset)
local n = readushort(f)
reused = { }
for i=1,n do
reused[i] = {
readushort(f), -- second glyph id
- readposition(f,format1),
- readposition(f,format2)
+ readposition(f,format1,offset,getdelta),
+ readposition(f,format2,offset,getdelta),
}
end
done[offset] = reused
@@ -921,14 +1407,14 @@ local function readpairsets(f,tableoffset,sets,format1,format2)
return sets
end
-local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,mainoffset,getdelta)
local classlist1 = { }
for i=1,nofclasses1 do
local classlist2 = { }
classlist1[i] = classlist2
for j=1,nofclasses2 do
- local one = readposition(f,format1)
- local two = readposition(f,format2)
+ local one = readposition(f,format1,mainoffset,getdelta)
+ local two = readposition(f,format2,mainoffset,getdelta)
if one or two then
classlist2[j] = { one, two }
else
@@ -944,34 +1430,35 @@ end
function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
- local subtype = readushort(f)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
if subtype == 1 then
local coverage = readushort(f)
local format = readushort(f)
- local value = readposition(f,format)
+ local value = readposition(f,format,tableoffset,getdelta)
local coverage = readcoverage(f,tableoffset+coverage)
for index, newindex in next, coverage do
- coverage[index] = value
+ coverage[index] = value -- will be packed and shared anyway
end
return {
- format = "pair",
- coverage = coverage
+ format = "single",
+ coverage = coverage,
}
elseif subtype == 2 then
local coverage = readushort(f)
local format = readushort(f)
- local values = { }
local nofvalues = readushort(f)
+ local values = { }
for i=1,nofvalues do
- values[i] = readposition(f,format)
+ values[i] = readposition(f,format,tableoffset,getdelta)
end
local coverage = readcoverage(f,tableoffset+coverage)
for index, newindex in next, coverage do
coverage[index] = values[newindex+1]
end
return {
- format = "pair",
- coverage = coverage
+ format = "single",
+ coverage = coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"single")
@@ -983,18 +1470,17 @@ end
-- ValueFormat1 applies to the ValueRecord of the first glyph in each pair. ValueRecords for all first glyphs must use ValueFormat1. If ValueFormat1 is set to zero (0), the corresponding glyph has no ValueRecord and, therefore, should not be repositioned.
-- ValueFormat2 applies to the ValueRecord of the second glyph in each pair. ValueRecords for all second glyphs must use ValueFormat2. If ValueFormat2 is set to null, then the second glyph of the pair is the “next” glyph for which a lookup should be performed.
--- !!!!! this needs checking: when both false, we have no hit so then we might need to fall through
-
function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
- local subtype = readushort(f)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
if subtype == 1 then
local coverage = readushort(f)
local format1 = readushort(f)
local format2 = readushort(f)
local sets = readarray(f)
- sets = readpairsets(f,tableoffset,sets,format1,format2)
+ sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
coverage = readcoverage(f,tableoffset + coverage)
for index, newindex in next, coverage do
local set = sets[newindex+1]
@@ -1006,9 +1492,9 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first = value[2]
local second = value[3]
if first or second then
- hash[other] = { first, second } -- needs checking
+ hash[other] = { first, second or nil } -- needs checking
else
- hash[other] = nil
+ hash[other] = nil -- what if set, maybe warning
end
end
end
@@ -1016,7 +1502,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format = "pair",
- coverage = coverage
+ coverage = coverage,
}
elseif subtype == 2 then
local coverage = readushort(f)
@@ -1026,7 +1512,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local classdef2 = readushort(f)
local nofclasses1 = readushort(f) -- incl class 0
local nofclasses2 = readushort(f) -- incl class 0
- local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+ local classlist = readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
coverage = readcoverage(f,tableoffset+coverage)
classdef1 = readclassdef(f,tableoffset+classdef1,coverage)
classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs)
@@ -1042,7 +1528,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first = offsets[1]
local second = offsets[2]
if first or second then
- hash[paired] = { first, second }
+ hash[paired] = { first, second or nil }
else
-- upto the next lookup for this combination
end
@@ -1054,7 +1540,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format = "pair",
- coverage = usedcoverage
+ coverage = usedcoverage,
}
elseif subtype == 3 then
report("yet unsupported subtype %a in %a positioning",subtype,"pair")
@@ -1066,7 +1552,8 @@ end
function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
- local subtype = readushort(f)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
if subtype == 1 then
local coverage = tableoffset + readushort(f)
local nofrecords = readushort(f)
@@ -1075,24 +1562,34 @@ function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local entry = readushort(f)
local exit = readushort(f)
records[i] = {
- entry = entry ~= 0 and (tableoffset + entry) or false,
- exit = exit ~= 0 and (tableoffset + exit ) or false,
+ -- entry = entry ~= 0 and (tableoffset + entry) or false,
+ -- exit = exit ~= 0 and (tableoffset + exit ) or nil,
+ entry ~= 0 and (tableoffset + entry) or false,
+ exit ~= 0 and (tableoffset + exit ) or nil,
}
end
+ -- slot 1 will become hash after loading and it must be unique because we
+ -- pack the tables (packed we turn the cc-* into a zero)
+ local cc = (fontdata.temporary.cursivecount or 0) + 1
+ fontdata.temporary.cursivecount = cc
+ cc = "cc-" .. cc
coverage = readcoverage(f,coverage)
for i=1,nofrecords do
local r = records[i]
records[i] = {
- 1, -- will become hash after loading (must be unique per lookup when packed)
- readanchor(f,r.entry) or nil,
- readanchor(f,r.exit ) or nil,
+ -- 1,
+ cc,
+ -- readanchor(f,r.entry,getdelta) or false,
+ -- readanchor(f,r.exit, getdelta) or nil,
+ readanchor(f,r[1],getdelta) or false,
+ readanchor(f,r[2],getdelta) or nil,
}
end
for index, newindex in next, coverage do
coverage[index] = records[newindex+1]
end
return {
- coverage = coverage
+ coverage = coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"cursive")
@@ -1102,7 +1599,8 @@ end
local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature)
local tableoffset = lookupoffset + offset
setposition(f,tableoffset)
- local subtype = readushort(f)
+ local subtype = readushort(f)
+ local getdelta = fontdata.temporary.getdelta
if subtype == 1 then
-- we are one based, not zero
local markcoverage = tableoffset + readushort(f)
@@ -1121,17 +1619,12 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local lastanchor = fontdata.lastanchor or 0
local usedanchors = { }
--
--- local placeholder = (fontdata.markcount or 0) + 1
--- fontdata.markcount = placeholder
--- placeholder = "m" .. placeholder
- --
for i=1,nofmarkclasses do
local class = readushort(f) + 1
local offset = readushort(f)
if offset == 0 then
markclasses[i] = false
else
--- markclasses[i] = { placeholder, class, markoffset + offset }
markclasses[i] = { class, markoffset + offset }
end
usedanchors[class] = true
@@ -1139,8 +1632,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
for i=1,nofmarkclasses do
local mc = markclasses[i]
if mc then
--- mc[3] = readanchor(f,mc[3])
- mc[2] = readanchor(f,mc[2])
+ mc[2] = readanchor(f,mc[2],getdelta)
end
end
--
@@ -1194,7 +1686,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local classes = components[c]
if classes then
for i=1,nofclasses do
- local anchor = readanchor(f,classes[i])
+ local anchor = readanchor(f,classes[i],getdelta)
local bclass = baseclasses[i]
local bentry = bclass[b]
if bentry then
@@ -1204,7 +1696,6 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
end
end
end
--- components[i] = classes
end
end
end
@@ -1237,7 +1728,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local r = baserecords[i]
local b = basecoverage[i]
for j=1,nofclasses do
- baseclasses[j][b] = readanchor(f,r[j])
+ baseclasses[j][b] = readanchor(f,r[j],getdelta)
end
end
for index, newindex in next, markcoverage do
@@ -1295,10 +1786,10 @@ do
setposition(f,offset)
local designsize = readushort(f)
if designsize > 0 then -- we could also have a threshold
- local fontstyle = readushort(f)
- local guimenuid = readushort(f)
- local minsize = readushort(f)
- local maxsize = readushort(f)
+ local fontstyleid = readushort(f)
+ local guimenuid = readushort(f)
+ local minsize = readushort(f)
+ local maxsize = readushort(f)
if minsize == 0 and maxsize == 0 and fontstyleid == 0 and guimenuid == 0 then
minsize = designsize
maxsize = designsize
@@ -1328,6 +1819,10 @@ do
end
end
+ -- function plugins.rvrn(f,fontdata,tableoffset,feature)
+ -- -- todo, at least a message
+ -- end
+
-- feature order needs checking ... as we loop over a hash ... however, in the file
-- they are sorted so order is not that relevant
@@ -1461,10 +1956,15 @@ do
local parameters = readushort(f) -- feature.parameters
local noflookups = readushort(f)
if noflookups > 0 then
- local lookups = { }
+-- local lookups = { }
+-- feature.lookups = lookups
+-- for j=1,noflookups do
+-- lookups[j] = readushort(f) + 1
+-- end
+ local lookups = readcardinaltable(f,noflookups,ushort)
feature.lookups = lookups
for j=1,noflookups do
- lookups[j] = readushort(f) + 1
+ lookups[j] = lookups[j] + 1
end
end
if parameters > 0 then
@@ -1480,14 +1980,11 @@ do
local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
setposition(f,lookupoffset)
- local lookups = { }
local noflookups = readushort(f)
- for i=1,noflookups do
- lookups[i] = readushort(f)
- end
+ local lookups = readcardinaltable(f,noflookups,ushort)
for lookupid=1,noflookups do
- local index = lookups[lookupid]
- setposition(f,lookupoffset+index)
+ local offset = lookups[lookupid]
+ setposition(f,lookupoffset+offset)
local subtables = { }
local typebits = readushort(f)
local flagbits = readushort(f)
@@ -1495,11 +1992,10 @@ do
local lookupflags = lookupflags[flagbits]
local nofsubtables = readushort(f)
for j=1,nofsubtables do
- local offset = readushort(f)
- subtables[j] = offset + index -- we can probably put lookupoffset here
+ subtables[j] = offset + readushort(f) -- we can probably put lookupoffset here
end
-- which one wins?
- local markclass = bittest(flagbits,0x0010) -- usemarkfilteringset
+ local markclass = band(flagbits,0x0010) ~= 0 -- usemarkfilteringset
if markclass then
markclass = readushort(f) -- + 1
end
@@ -1521,26 +2017,12 @@ do
return lookups
end
- local function readscriptoffsets(f,fontdata,tableoffset)
- if not tableoffset then
- return
- end
- setposition(f,tableoffset)
- local version = readulong(f)
- if version ~= 0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,what,fontdata.filename)
- return
- end
- --
- return tableoffset + readushort(f), tableoffset + readushort(f), tableoffset + readushort(f)
- end
-
local f_lookupname = formatters["%s_%s_%s"]
- local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
+ local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
- local sequences = fontdata.sequences or { }
- local sublookuplist = fontdata.sublookups or { }
+ local sequences = fontdata.sequences or { }
+ local sublookuplist = fontdata.sublookups or { }
fontdata.sequences = sequences
fontdata.sublookups = sublookuplist
local nofsublookups = #sublookuplist
@@ -1555,6 +2037,8 @@ do
local noflookups = #lookups
local lookupprefix = sub(what,2,2) -- g[s|p][ub|os]
--
+ local usedlookups = false -- setmetatableindex("number")
+ --
for lookupid=1,noflookups do
local lookup = lookups[lookupid]
local lookuptype = lookup.type
@@ -1565,7 +2049,7 @@ do
local nofsubtables = #subtables
local order = lookup.order
local flags = lookup.flags
- -- this is expected in th efont handler (faster checking)
+ -- this is expected in the font handler (faster checking)
if flags[1] then flags[1] = "mark" end
if flags[2] then flags[2] = "ligature" end
if flags[3] then flags[3] = "base" end
@@ -1593,10 +2077,11 @@ do
local rules = step.rules
if rules then
for i=1,#rules do
- local rule = rules[i]
- local before = rule.before
- local current = rule.current
- local after = rule.after
+ local rule = rules[i]
+ local before = rule.before
+ local current = rule.current
+ local after = rule.after
+ local replacements = rule.replacements
if before then
for i=1,#before do
before[i] = tohash(before[i])
@@ -1605,15 +2090,44 @@ do
rule.before = reversed(before)
end
if current then
- for i=1,#current do
- current[i] = tohash(current[i])
+ if replacements then
+ -- We have a reverse lookup and therefore only one current entry. We might need
+ -- to reverse the order in the before and after lists so that needs checking.
+ local first = current[1]
+ local hash = { }
+ local repl = { }
+ for i=1,#first do
+ local c = first[i]
+ hash[c] = true
+ repl[c] = replacements[i]
+ end
+ rule.current = { hash }
+ rule.replacements = repl
+ else
+ for i=1,#current do
+ current[i] = tohash(current[i])
+ end
end
+ else
+ -- weird lookup
end
if after then
for i=1,#after do
after[i] = tohash(after[i])
end
end
+ if usedlookups then
+ local lookups = rule.lookups
+ if lookups then
+ for k, v in next, lookups do
+ if v then
+ for k, v in next, v do
+ usedlookups[v] = usedlookups[v] + 1
+ end
+ end
+ end
+ end
+ end
end
end
end
@@ -1665,6 +2179,10 @@ do
end
end
+ if usedlookups then
+ report("used %s lookups: % t",what,sortedkeys(usedlookups))
+ end
+
-- When we have a context, we have sublookups that resolve into lookups for which we need to
-- know the type. We split the main lookuptable in two parts: sequences (the main lookups)
-- and subtable lookups (simple specs with no features). We could keep them merged and might do
@@ -1698,56 +2216,63 @@ do
report_issue(i,what,sequence,"empty")
rule.lookups = nil
else
- -- we can have holes in rlookups
- -- for index, lookupid in sortedhash(rlookups) do
+ -- we can have holes in rlookups flagged false and we can have multiple lookups
+ -- applied (first time seen in seguemj)
local length = #rlookups
--- for index in next, rlookups do
--- if index > length then
--- length = index
--- end
--- end
for index=1,length do
- local lookupid = rlookups[index]
- if lookupid then
- local h = sublookuphash[lookupid]
- if not h then
- -- here we have a lookup that is used independent as well
- -- as in another one
- local lookup = lookups[lookupid]
- if lookup then
- local d = lookup.done
- if d then
- nofsublookups = nofsublookups + 1
- -- report("registering %i as sublookup %i",lookupid,nofsublookups)
- h = {
- index = nofsublookups, -- handy for tracing
- name = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
- derived = true, -- handy for tracing
- steps = d.steps,
- nofsteps = d.nofsteps,
- type = d.lookuptype,
- markclass = d.markclass or nil,
- flags = d.flags,
- -- chain = d.chain,
- }
- sublookuplist[nofsublookups] = copy(h) -- we repack later
- sublookuphash[lookupid] = nofsublookups
- sublookupcheck[lookupid] = 1
- h = nofsublookups --- patch by Hans
+ local lookuplist = rlookups[index]
+ if lookuplist then
+ local length = #lookuplist
+ local found = { }
+ local noffound = 0
+ for index=1,length do
+ local lookupid = lookuplist[index]
+ if lookupid then
+ local h = sublookuphash[lookupid]
+ if not h then
+ -- here we have a lookup that is used independent as well
+ -- as in another one
+ local lookup = lookups[lookupid]
+ if lookup then
+ local d = lookup.done
+ if d then
+ nofsublookups = nofsublookups + 1
+ -- report("registering %i as sublookup %i",lookupid,nofsublookups)
+ local l = {
+ index = nofsublookups, -- handy for tracing
+ name = f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
+ derived = true, -- handy for tracing
+ steps = d.steps,
+ nofsteps = d.nofsteps,
+ type = d.lookuptype or "gsub_single", -- todo: check type
+ markclass = d.markclass or nil,
+ flags = d.flags,
+ -- chain = d.chain,
+ }
+ sublookuplist[nofsublookups] = copy(l) -- we repack later
+ sublookuphash[lookupid] = nofsublookups
+ sublookupcheck[lookupid] = 1
+ h = nofsublookups
+ else
+ report_issue(i,what,sequence,"missing")
+ rule.lookups = nil
+ break
+ end
+ else
+ report_issue(i,what,sequence,"bad")
+ rule.lookups = nil
+ break
+ end
else
- report_issue(i,what,sequence,"missing")
- rule.lookups = nil
- break
+ sublookupcheck[lookupid] = sublookupcheck[lookupid] + 1
+ end
+ if h then
+ noffound = noffound + 1
+ found[noffound] = h
end
- else
- report_issue(i,what,sequence,"bad")
- rule.lookups = nil
- break
end
- else
- sublookupcheck[lookupid] = sublookupcheck[lookupid] + 1
end
- rlookups[index] = h or false
+ rlookups[index] = noffound > 0 and found or false
else
rlookups[index] = false
end
@@ -1764,45 +2289,122 @@ do
if n == 0 and t ~= "extension" then
local d = l.done
report("%s lookup %s of type %a is not used",what,d and d.name or l.name,t)
- -- inspect(l)
end
end
end
- local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
- local datatable = fontdata.tables[what]
- if not datatable then
- return
- end
- local tableoffset = datatable.offset
- if not tableoffset then
- return
+ local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ setposition(f,variationsoffset)
+ local version = readulong(f)
+ local nofrecords = readulong(f)
+ local records = { }
+ for i=1,nofrecords do
+ records[i] = {
+ conditions = readulong(f),
+ substitutions = readulong(f),
+ }
end
- local scriptoffset, featureoffset, lookupoffset = readscriptoffsets(f,fontdata,tableoffset)
- if not scriptoffset then
- return
+ for i=1,nofrecords do
+ local record = records[i]
+ local offset = record.conditions
+ if offset == 0 then
+ record.condition = nil
+ record.matchtype = "always"
+ else
+ local offset = variationsoffset+offset
+ setposition(f,offset)
+ local nofconditions = readushort(f)
+ local conditions = { }
+ for i=1,nofconditions do
+ conditions[i] = offset + readulong(f)
+ end
+ record.conditions = conditions
+ record.matchtype = "condition"
+ end
end
- --
- local scripts = readscriplan(f,fontdata,scriptoffset)
- local features = readfeatures(f,fontdata,featureoffset)
- --
- local scriptlangs, featurehash, featureorder = reorderfeatures(fontdata,scripts,features)
- --
- if fontdata.features then
- fontdata.features[what] = scriptlangs
- else
- fontdata.features = { [what] = scriptlangs }
+ for i=1,nofrecords do
+ local record = records[i]
+ if record.matchtype == "condition" then
+ local conditions = record.conditions
+ for i=1,#conditions do
+ setposition(f,conditions[i])
+ conditions[i] = {
+ format = readushort(f),
+ axis = readushort(f),
+ minvalue = read2dot14(f),
+ maxvalue = read2dot14(f),
+ }
+ end
+ end
end
- --
- if not lookupstoo then
- return
+
+ for i=1,nofrecords do
+ local record = records[i]
+ local offset = record.substitutions
+ if offset == 0 then
+ record.substitutions = { }
+ else
+ setposition(f,variationsoffset + offset)
+ local version = readulong(f)
+ local nofsubstitutions = readushort(f)
+ local substitutions = { }
+ for i=1,nofsubstitutions do
+ substitutions[readushort(f)] = readulong(f)
+ end
+ for index, alternates in sortedhash(substitutions) do
+ if index == 0 then
+ record.substitutions = false
+ else
+ local tableoffset = variationsoffset + offset + alternates
+ setposition(f,tableoffset)
+ local parameters = readulong(f) -- feature parameters
+ local noflookups = readushort(f)
+ local lookups = readcardinaltable(f,noflookups,ushort) -- not sure what to do with these
+ -- todo : resolve to proper lookups
+ record.substitutions = lookups
+ end
+ end
+ end
end
- --
- local lookups = readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
- --
- if lookups then
- resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
+ setvariabledata(fontdata,"features",records)
+ end
+
+ local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
+ local tableoffset = gotodatatable(f,fontdata,what,true)
+ if tableoffset then
+ local version = readulong(f)
+ local scriptoffset = tableoffset + readushort(f)
+ local featureoffset = tableoffset + readushort(f)
+ local lookupoffset = tableoffset + readushort(f)
+ local variationsoffset = version > 0x00010000 and (tableoffset + readulong(f)) or 0
+ if not scriptoffset then
+ return
+ end
+ local scripts = readscriplan(f,fontdata,scriptoffset)
+ local features = readfeatures(f,fontdata,featureoffset)
+ --
+ local scriptlangs, featurehash, featureorder = reorderfeatures(fontdata,scripts,features)
+ --
+ if fontdata.features then
+ fontdata.features[what] = scriptlangs
+ else
+ fontdata.features = { [what] = scriptlangs }
+ end
+ --
+ if not lookupstoo then
+ return
+ end
+ --
+ local lookups = readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
+ --
+ if lookups then
+ resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ end
+ --
+ if variationsoffset > 0 then
+ loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ end
end
end
@@ -1822,61 +2424,64 @@ do
report("ignoring global kern table using gpos kern feature")
return
end
- report("adding global kern table as gpos feature %a",name)
setposition(f,datatable.offset)
local version = readushort(f)
local noftables = readushort(f)
- local kerns = setmetatableindex("table")
- for i=1,noftables do
- local version = readushort(f)
- local length = readushort(f)
- local coverage = readushort(f)
- -- bit 8-15 of coverage: format 0 or 2
- local format = bit32.rshift(coverage,8) -- is this ok?
- if format == 0 then
- local nofpairs = readushort(f)
- local searchrange = readushort(f)
- local entryselector = readushort(f)
- local rangeshift = readushort(f)
- for i=1,nofpairs do
- kerns[readushort(f)][readushort(f)] = readfword(f)
+ if noftables > 1 then
+ report("adding global kern table as gpos feature %a",name)
+ local kerns = setmetatableindex("table")
+ for i=1,noftables do
+ local version = readushort(f)
+ local length = readushort(f)
+ local coverage = readushort(f)
+ -- bit 8-15 of coverage: format 0 or 2
+ local format = rshift(coverage,8) -- is this ok
+ if format == 0 then
+ local nofpairs = readushort(f)
+ local searchrange = readushort(f)
+ local entryselector = readushort(f)
+ local rangeshift = readushort(f)
+ for i=1,nofpairs do
+ kerns[readushort(f)][readushort(f)] = readfword(f)
+ end
+ elseif format == 2 then
+ -- apple specific so let's ignore it
+ else
+ -- not supported by ms
end
- elseif format == 2 then
- -- apple specific so let's ignore it
- else
- -- not supported by ms
end
- end
- local feature = { dflt = { dflt = true } }
- if not features then
- fontdata.features = { gpos = { [name] = feature } }
- elseif not gposfeatures then
- fontdata.features.gpos = { [name] = feature }
- else
- gposfeatures[name] = feature
- end
- local sequences = fontdata.sequences
- if not sequences then
- sequences = { }
- fontdata.sequences = sequences
- end
- local nofsequences = #sequences + 1
- sequences[nofsequences] = {
- index = nofsequences,
- name = name,
- steps = {
- {
- coverage = kerns,
- format = "kern",
+ local feature = { dflt = { dflt = true } }
+ if not features then
+ fontdata.features = { gpos = { [name] = feature } }
+ elseif not gposfeatures then
+ fontdata.features.gpos = { [name] = feature }
+ else
+ gposfeatures[name] = feature
+ end
+ local sequences = fontdata.sequences
+ if not sequences then
+ sequences = { }
+ fontdata.sequences = sequences
+ end
+ local nofsequences = #sequences + 1
+ sequences[nofsequences] = {
+ index = nofsequences,
+ name = name,
+ steps = {
+ {
+ coverage = kerns,
+ format = "kern",
+ },
},
- },
- nofsteps = 1,
- type = "gpos_pair",
- -- type = "gpos_single", -- maybe better
- flags = { false, false, false, false },
- order = { name },
- features = { [name] = feature },
- }
+ nofsteps = 1,
+ type = "gpos_pair",
+ flags = { false, false, false, false },
+ order = { name },
+ features = { [name] = feature },
+ }
+ else
+ report("ignoring empty kern table of feature %a",name)
+ end
end
function readers.gsub(f,fontdata,specification)
@@ -1897,26 +2502,30 @@ do
end
function readers.gdef(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.gdef
- if datatable then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readulong(f)
- local classoffset = tableoffset + readushort(f)
- local attachmentoffset = tableoffset + readushort(f) -- used for bitmaps
- local ligaturecarets = tableoffset + readushort(f) -- used in editors (maybe nice for tracing)
- local markclassoffset = tableoffset + readushort(f)
- local marksetsoffset = version == 0x00010002 and (tableoffset + readushort(f))
- local glyphs = fontdata.glyphs
- local marks = { }
- local markclasses = setmetatableindex("table")
- local marksets = setmetatableindex("table")
- fontdata.marks = marks
- fontdata.markclasses = markclasses
- fontdata.marksets = marksets
- -- class definitions
- setposition(f,classoffset)
+ if not specification.glyphs then
+ return
+ end
+ local datatable = fontdata.tables.gdef
+ if datatable then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ local version = readulong(f)
+ local classoffset = readushort(f)
+ local attachmentoffset = readushort(f) -- used for bitmaps
+ local ligaturecarets = readushort(f) -- used in editors (maybe nice for tracing)
+ local markclassoffset = readushort(f)
+ local marksetsoffset = version >= 0x00010002 and readushort(f) or 0
+ local varsetsoffset = version >= 0x00010003 and readulong(f) or 0
+ local glyphs = fontdata.glyphs
+ local marks = { }
+ local markclasses = setmetatableindex("table")
+ local marksets = setmetatableindex("table")
+ fontdata.marks = marks
+ fontdata.markclasses = markclasses
+ fontdata.marksets = marksets
+ -- class definitions
+ if classoffset ~= 0 then
+ setposition(f,tableoffset + classoffset)
local classformat = readushort(f)
if classformat == 1 then
local firstindex = readushort(f)
@@ -1944,8 +2553,10 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- -- mark classes
- setposition(f,markclassoffset)
+ end
+ -- mark classes
+ if markclassoffset ~= 0 then
+ setposition(f,tableoffset + markclassoffset)
local classformat = readushort(f)
if classformat == 1 then
local firstindex = readushort(f)
@@ -1964,24 +2575,55 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- -- mark sets : todo: just make the same as class sets above
- if marksetsoffset and marksetsoffset > tableoffset then -- zero offset means no table
- setposition(f,marksetsoffset)
- local format = readushort(f)
- if format == 1 then
- local nofsets = readushort(f)
- local sets = { }
- for i=1,nofsets do
- sets[i] = readulong(f)
+ end
+ -- mark sets : todo: just make the same as class sets above
+ if marksetsoffset ~= 0 then
+ marksetsoffset = tableoffset + marksetsoffset
+ setposition(f,marksetsoffset)
+ local format = readushort(f)
+ if format == 1 then
+ local nofsets = readushort(f)
+ local sets = readcardinaltable(f,nofsets,ulong)
+ for i=1,nofsets do
+ local offset = sets[i]
+ if offset ~= 0 then
+ marksets[i] = readcoverage(f,marksetsoffset+offset)
end
- for i=1,nofsets do
- local offset = sets[i]
- if offset ~= 0 then
- marksets[i] = readcoverage(f,marksetsoffset+offset)
+ end
+ end
+ end
+
+ local factors = specification.factors
+
+ if (specification.variable or factors) and varsetsoffset ~= 0 then
+
+ local regions, deltas = readvariationdata(f,tableoffset+varsetsoffset,factors)
+
+ -- setvariabledata(fontdata,"gregions",regions)
+
+ if factors then
+ fontdata.temporary.getdelta = function(outer,inner)
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local dd = 0
+ for i=1,#scales do
+ local di = d[i]
+ if di then
+ dd = dd + scales[i] * di
+ else
+ break
+ end
+ end
+ return round(dd)
end
end
+ return 0
end
end
+
end
end
end
@@ -2178,14 +2820,8 @@ local function readmathvariants(f,fontdata,offset)
local hcoverage = readushort(f)
local vnofglyphs = readushort(f)
local hnofglyphs = readushort(f)
- local vconstruction = { }
- local hconstruction = { }
- for i=1,vnofglyphs do
- vconstruction[i] = readushort(f)
- end
- for i=1,hnofglyphs do
- hconstruction[i] = readushort(f)
- end
+ local vconstruction = readcardinaltable(f,vnofglyphs,ushort)
+ local hconstruction = readcardinaltable(f,hnofglyphs,ushort)
fontdata.mathconstants.MinConnectorOverlap = minoverlap
@@ -2243,7 +2879,7 @@ local function readmathvariants(f,fontdata,offset)
advance = readushort(f),
}
local flags = readushort(f)
- if bittest(flags,0x0001) then
+ if band(flags,0x0001) ~= 0 then
p.extender = 1 -- true
end
parts[i] = p
@@ -2270,173 +2906,719 @@ local function readmathvariants(f,fontdata,offset)
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.math
- if datatable then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readulong(f)
- if version ~= 0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
- return
- end
- local constants = readushort(f)
- local glyphinfo = readushort(f)
- local variants = readushort(f)
- if constants == 0 then
- report("the math table of %a has no constants",fontdata.filename)
- else
- readmathconstants(f,fontdata,tableoffset+constants)
+ local tableoffset = gotodatatable(f,fontdata,"math",specification.glyphs)
+ if tableoffset then
+ local version = readulong(f)
+ -- if version ~= 0x00010000 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
+ -- return
+ -- end
+ local constants = readushort(f)
+ local glyphinfo = readushort(f)
+ local variants = readushort(f)
+ if constants == 0 then
+ report("the math table of %a has no constants",fontdata.filename)
+ else
+ readmathconstants(f,fontdata,tableoffset+constants)
+ end
+ if glyphinfo ~= 0 then
+ readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
+ end
+ if variants ~= 0 then
+ readmathvariants(f,fontdata,tableoffset+variants)
+ end
+ end
+end
+
+function readers.colr(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"colr",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ if version ~= 0 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
+ return
+ end
+ if not fontdata.tables.cpal then
+ report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
+ fontdata.colorpalettes = { }
+ end
+ local glyphs = fontdata.glyphs
+ local nofglyphs = readushort(f)
+ local baseoffset = readulong(f)
+ local layeroffset = readulong(f)
+ local noflayers = readushort(f)
+ local layerrecords = { }
+ local maxclass = 0
+ -- The special value 0xFFFF is foreground (but we index from 1). It
+ -- more looks like indices into a palette so 'class' is a better name
+ -- than 'palette'.
+ setposition(f,tableoffset + layeroffset)
+ for i=1,noflayers do
+ local slot = readushort(f)
+ local class = readushort(f)
+ if class < 0xFFFF then
+ class = class + 1
+ if class > maxclass then
+ maxclass = class
+ end
end
- if glyphinfo ~= 0 then
- readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
+ layerrecords[i] = {
+ slot = slot,
+ class = class,
+ }
+ end
+ fontdata.maxcolorclass = maxclass
+ setposition(f,tableoffset + baseoffset)
+ for i=0,nofglyphs-1 do
+ local glyphindex = readushort(f)
+ local firstlayer = readushort(f)
+ local noflayers = readushort(f)
+ local t = { }
+ for i=1,noflayers do
+ t[i] = layerrecords[firstlayer+i]
end
- if variants ~= 0 then
- readmathvariants(f,fontdata,tableoffset+variants)
+ glyphs[glyphindex].colors = t
+ end
+ end
+ fontdata.hascolor = true
+end
+
+function readers.cpal(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"cpal",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ -- if version > 1 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
+ -- return
+ -- end
+ local nofpaletteentries = readushort(f)
+ local nofpalettes = readushort(f)
+ local nofcolorrecords = readushort(f)
+ local firstcoloroffset = readulong(f)
+ local colorrecords = { }
+ local palettes = readcardinaltable(f,nofpalettes,ushort)
+ if version == 1 then
+ -- used for guis
+ local palettettypesoffset = readulong(f)
+ local palettelabelsoffset = readulong(f)
+ local paletteentryoffset = readulong(f)
+ end
+ setposition(f,tableoffset+firstcoloroffset)
+ for i=1,nofcolorrecords do
+ local b, g, r, a = readbytes(f,4)
+ colorrecords[i] = {
+ r, g, b, a ~= 255 and a or nil,
+ }
+ end
+ for i=1,nofpalettes do
+ local p = { }
+ local o = palettes[i]
+ for j=1,nofpaletteentries do
+ p[j] = colorrecords[o+j]
end
+ palettes[i] = p
end
+ fontdata.colorpalettes = palettes
end
end
-function readers.colr(f,fontdata,specification)
- local datatable = fontdata.tables.colr
- if datatable then
- if specification.glyphs then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readushort(f)
- if version ~= 0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
- return
+function readers.svg(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"svg",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ -- if version ~= 0 then
+ -- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
+ -- return
+ -- end
+ local glyphs = fontdata.glyphs
+ local indexoffset = tableoffset + readulong(f)
+ local reserved = readulong(f)
+ setposition(f,indexoffset)
+ local nofentries = readushort(f)
+ local entries = { }
+ for i=1,nofentries do
+ entries[i] = {
+ first = readushort(f),
+ last = readushort(f),
+ offset = indexoffset + readulong(f),
+ length = readulong(f),
+ }
+ end
+ for i=1,nofentries do
+ local entry = entries[i]
+ setposition(f,entry.offset)
+ entries[i] = {
+ first = entry.first,
+ last = entry.last,
+ data = readstring(f,entry.length)
+ }
+ end
+ fontdata.svgshapes = entries
+ end
+ fontdata.hascolor = true
+end
+
+function readers.sbix(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"sbix",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ local flags = readushort(f)
+ local nofstrikes = readulong(f)
+ local strikes = { }
+ local nofglyphs = fontdata.nofglyphs
+ for i=1,nofstrikes do
+ strikes[i] = readulong(f)
+ end
+ -- if true then
+ local shapes = { }
+ local done = 0
+ for i=1,nofstrikes do
+ local strikeoffset = strikes[i] + tableoffset
+ setposition(f,strikeoffset)
+ strikes[i] = {
+ ppem = readushort(f),
+ ppi = readushort(f),
+ offset = strikeoffset
+ }
end
- if not fontdata.tables.cpal then
- report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
- fontdata.colorpalettes = { }
- end
- local glyphs = fontdata.glyphs
- local nofglyphs = readushort(f)
- local baseoffset = readulong(f)
- local layeroffset = readulong(f)
- local noflayers = readushort(f)
- local layerrecords = { }
- local maxclass = 0
- -- The special value 0xFFFF is foreground (but we index from 1). It
- -- more looks like indices into a palette so 'class' is a better name
- -- than 'palette'.
- setposition(f,tableoffset + layeroffset)
- for i=1,noflayers do
- local slot = readushort(f)
- local class = readushort(f)
- if class < 0xFFFF then
- class = class + 1
- if class > maxclass then
- maxclass = class
+ -- highest first
+ sort(strikes,function(a,b)
+ if b.ppem == a.ppem then
+ return b.ppi < a.ppi
+ else
+ return b.ppem < a.ppem
+ end
+ end)
+ local glyphs = { }
+ for i=1,nofstrikes do
+ local strike = strikes[i]
+ local strikeppem = strike.ppem
+ local strikeppi = strike.ppi
+ local strikeoffset = strike.offset
+ setposition(f,strikeoffset)
+ for i=0,nofglyphs do
+ glyphs[i] = readulong(f)
+ end
+ local glyphoffset = glyphs[0]
+ for i=0,nofglyphs-1 do
+ local nextoffset = glyphs[i+1]
+ if not shapes[i] then
+ local datasize = nextoffset - glyphoffset
+ if datasize > 0 then
+ setposition(f,strikeoffset + glyphoffset)
+ shapes[i] = {
+ x = readshort(f),
+ y = readshort(f),
+ tag = readtag(f), -- maybe for tracing
+ data = readstring(f,datasize-8),
+ ppem = strikeppem, -- not used, for tracing
+ ppi = strikeppi, -- not used, for tracing
+ }
+ done = done + 1
+ if done == nofglyphs then
+ break
+ end
+ end
end
+ glyphoffset = nextoffset
end
- layerrecords[i] = {
- slot = slot,
- class = class,
+ end
+ fontdata.sbixshapes = shapes
+ -- else
+ -- for i=1,nofstrikes do
+ -- local strikeoffset = strikes[i] + tableoffset
+ -- setposition(f,strikeoffset)
+ -- local glyphs = { }
+ -- strikes[i] = {
+ -- ppem = readushort(f),
+ -- ppi = readushort(f),
+ -- glyphs = glyphs,
+ -- }
+ -- for i=0,nofglyphs do
+ -- glyphs[i] = readulong(f)
+ -- end
+ -- local glyphoffset = glyphs[0]
+ -- for i=0,nofglyphs-1 do
+ -- local nextoffset = glyphs[i+1]
+ -- local datasize = nextoffset - glyphoffset
+ -- if datasize > 0 then
+ -- setposition(f,strikeoffset + glyphoffset)
+ -- glyphs[i] = {
+ -- x = readshort(f),
+ -- y = readshort(f),
+ -- tag = readtag(f),
+ -- data = readstring(f,datasize-8)
+ -- }
+ -- glyphoffset = nextoffset
+ -- end
+ -- end
+ -- end
+ -- fontdata.sbixshapes = strikes
+ -- end
+ end
+end
+
+-- function readers.cblc(f,fontdata,specification)
+-- local tableoffset = gotodatatable(f,fontdata,"cblc",specification.glyphs)
+-- if tableoffset then
+-- end
+-- end
+--
+-- function readers.cbdt(f,fontdata,specification)
+-- local tableoffset = gotodatatable(f,fontdata,"ctdt",specification.glyphs)
+-- if tableoffset then
+--
+-- local function getmetrics(f)
+-- return {
+-- ascender = readinteger(f),
+-- descender = readinteger(f),
+-- widthmax = readcardinal(f),
+-- caretslopedumerator = readinteger(f),
+-- caretslopedenominator = readinteger(f),
+-- caretoffset = readinteger(f),
+-- minorigin = readinteger(f),
+-- minadvance = readinteger(f),
+-- maxbefore = readinteger(f),
+-- minafter = readinteger(f),
+-- pad1 = readinteger(f),
+-- pad2 = readinteger(f),
+-- }
+-- end
+--
+-- local majorversion = readushort(f)
+-- local minorversion = readushort(f)
+-- local nofsizetables = readulong(f)
+-- local sizetable = { }
+-- for i=1,nofsizetables do
+-- sizetable[i] = {
+-- subtables = readulong(f),
+-- indexsize = readulong(f),
+-- nofsubtables = readulong(f),
+-- colorref = readulong(f),
+-- hormetrics = getmetrics(f),
+-- vermetrics = getmetrics(f),
+-- firstindex = readushort(f),
+-- lastindex = readushort(f),
+-- ppemx = readbyte(f),
+-- ppemy = readbyte(f),
+-- bitdepth = readbyte(f),
+-- flags = readbyte(f),
+-- }
+-- end
+--
+-- sort(sizetable,function(a,b)
+-- if b.ppemx == a.ppemx then
+-- return b.bitdepth < a.bitdepth
+-- else
+-- return b.ppemx < a.ppemx
+-- end
+-- end)
+--
+-- local shapes = { }
+--
+-- for i=1,nofsizetables do
+-- local s = sizetables[i]
+-- for j=firstindex,lastindex do
+-- if not shapes[j] then
+-- shapes[j] = {
+-- i
+-- }
+-- end
+-- end
+-- end
+--
+-- inspect(shapes)
+--
+-- end
+-- end
+
+-- function readers.ebdt(f,fontdata,specification)
+-- if specification.glyphs then
+-- end
+-- end
+
+-- function readers.ebsc(f,fontdata,specification)
+-- if specification.glyphs then
+-- end
+-- end
+
+-- function readers.eblc(f,fontdata,specification)
+-- if specification.glyphs then
+-- end
+-- end
+
+-- + AVAR : optional
+-- + CFF2 : otf outlines
+-- - CVAR : ttf hinting, not needed
+-- + FVAR : the variations
+-- + GVAR : ttf outline changes
+-- + HVAR : horizontal changes
+-- + MVAR : metric changes
+-- + STAT : relations within fonts
+-- * VVAR : vertical changes
+--
+-- * BASE : extra baseline adjustments
+-- - GASP : not needed
+-- + GDEF : not needed (carets)
+-- + GPOS : adapted device tables (needed?)
+-- + GSUB : new table
+-- + NAME : 25 added
+
+function readers.stat(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"stat",true) -- specification.variable
+ if tableoffset then
+ local extras = fontdata.extras
+ local version = readulong(f) -- 0x00010000
+ local axissize = readushort(f)
+ local nofaxis = readushort(f)
+ local axisoffset = readulong(f)
+ local nofvalues = readushort(f)
+ local valuesoffset = readulong(f)
+ local fallbackname = extras[readushort(f)] -- beta fonts mess up
+ local axis = { }
+ local values = { }
+ setposition(f,tableoffset+axisoffset)
+ for i=1,nofaxis do
+ local tag = readtag(f)
+ axis[i] = {
+ tag = tag,
+ name = lower(extras[readushort(f)] or tag),
+ ordering = readushort(f), -- maybe gaps
+ variants = { }
+ }
+ end
+ -- flags:
+ --
+ -- 0x0001 : OlderSiblingFontAttribute
+ -- 0x0002 : ElidableAxisValueName
+ -- 0xFFFC : reservedFlags
+ --
+ setposition(f,tableoffset+valuesoffset)
+ for i=1,nofvalues do
+ values[i] = readushort(f)
+ end
+ for i=1,nofvalues do
+ setposition(f,tableoffset + valuesoffset + values[i])
+ local format = readushort(f)
+ local index = readushort(f) + 1
+ local flags = readushort(f)
+ local name = lower(extras[readushort(f)] or "no name")
+ local value = readfixed(f)
+ local variant
+ if format == 1 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ }
+ elseif format == 2 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ minimum = readfixed(f),
+ maximum = readfixed(f),
+ }
+ elseif format == 3 then
+ variant = {
+ flags = flags,
+ name = name,
+ value = value,
+ link = readfixed(f),
}
end
- fontdata.maxcolorclass = maxclass
- setposition(f,tableoffset + baseoffset)
- for i=0,nofglyphs-1 do
- local glyphindex = readushort(f)
- local firstlayer = readushort(f)
- local noflayers = readushort(f)
- local t = { }
- for i=1,noflayers do
- t[i] = layerrecords[firstlayer+i]
+ insert(axis[index].variants,variant)
+ end
+ sort(axis,function(a,b)
+ return a.ordering < b.ordering
+ end)
+ for i=1,#axis do
+ local a = axis[i]
+ sort(a.variants,function(a,b)
+ return a.name < b.name
+ end)
+ a.ordering = nil
+ end
+ setvariabledata(fontdata,"designaxis",axis)
+ setvariabledata(fontdata,"fallbackname",fallbackname)
+ end
+end
+
+-- The avar table is optional and used in combination with fvar. Given the
+-- detailed explanation about bad values we expect the worst and do some
+-- checking.
+
+function readers.avar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"avar",true) -- specification.variable
+ if tableoffset then
+
+ local function collect()
+ local nofvalues = readushort(f)
+ local values = { }
+ local lastfrom = false
+ local lastto = false
+ for i=1,nofvalues do
+ local f, t = read2dot14(f), read2dot14(f)
+ if lastfrom and f <= lastfrom then
+ -- ignore
+ elseif lastto and t >= lastto then
+ -- ignore
+ else
+ values[#values+1] = { f, t }
+ lastfrom, lastto = f, t
+ end
+ end
+ nofvalues = #values
+ if nofvalues > 2 then
+ local some = values[1]
+ if some[1] == -1 and some[2] == -1 then
+ some = values[nofvalues]
+ if some[1] == 1 and some[2] == 1 then
+ for i=2,nofvalues-1 do
+ some = values[i]
+ if some[1] == 0 and some[2] == 0 then
+ return values
+ end
+ end
+ end
end
- glyphs[glyphindex].colors = t
end
+ return false
end
- fontdata.hascolor = true
+
+ local majorversion = readushort(f) -- 1
+ local minorversion = readushort(f) -- 0
+ local reserved = readushort(f)
+ local nofaxis = readushort(f)
+ local segments = { }
+ for i=1,nofaxis do
+ segments[i] = collect()
+ end
+ setvariabledata(fontdata,"segments",segments)
end
end
-function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.cpal
- if datatable then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readushort(f)
- if version > 1 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
- return
+function readers.fvar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"fvar",true) -- specification.variable or specification.instancenames
+ if tableoffset then
+ local version = readulong(f) -- 1.0
+ local offsettoaxis = tableoffset + readushort(f)
+ local reserved = skipshort(f)
+ -- pair 1
+ local nofaxis = readushort(f)
+ local sizeofaxis = readushort(f)
+ -- pair 2
+ local nofinstances = readushort(f)
+ local sizeofinstances = readushort(f)
+ --
+ local extras = fontdata.extras
+ local axis = { }
+ local instances = { }
+ --
+ setposition(f,offsettoaxis)
+ --
+ for i=1,nofaxis do
+ axis[i] = {
+ tag = readtag(f), -- ital opsz slnt wdth wght
+ minimum = readfixed(f),
+ default = readfixed(f),
+ maximum = readfixed(f),
+ flags = readushort(f),
+ name = lower(extras[readushort(f)] or "bad name"),
+ }
+ local n = sizeofaxis - 20
+ if n > 0 then
+ skipbytes(f,n)
+ elseif n < 0 then
+ -- error
end
- local nofpaletteentries = readushort(f)
- local nofpalettes = readushort(f)
- local nofcolorrecords = readushort(f)
- local firstcoloroffset = readulong(f)
- local colorrecords = { }
- local palettes = { }
- for i=1,nofpalettes do
- palettes[i] = readushort(f)
- end
- if version == 1 then
- -- used for guis
- local palettettypesoffset = readulong(f)
- local palettelabelsoffset = readulong(f)
- local paletteentryoffset = readulong(f)
- end
- setposition(f,tableoffset+firstcoloroffset)
- for i=1,nofcolorrecords do
- local b, g, r, a = readbytes(f,4)
- colorrecords[i] = {
- r, g, b, a ~= 255 and a or nil,
+ end
+ --
+ local nofbytes = 2 + 2 + 2 + nofaxis * 4
+ local readpsname = nofbytes <= sizeofinstances
+ local skippable = sizeofinstances - nofbytes
+ for i=1,nofinstances do
+ local subfamid = readushort(f)
+ local flags = readushort(f) -- 0, not used yet
+ local values = { }
+ for i=1,nofaxis do
+ values[i] = {
+ axis = axis[i].tag,
+ value = readfixed(f),
}
end
- for i=1,nofpalettes do
- local p = { }
- local o = palettes[i]
- for j=1,nofpaletteentries do
- p[j] = colorrecords[o+j]
- end
- palettes[i] = p
+ local psnameid = readpsname and readushort(f) or 0xFFFF
+ if subfamid == 2 or subfamid == 17 then
+ -- okay
+ elseif subfamid == 0xFFFF then
+ subfamid = nil
+ elseif subfamid <= 256 or subfamid >= 32768 then
+ subfamid = nil -- actually an error
+ end
+ if psnameid == 6 then
+ -- okay
+ elseif psnameid == 0xFFFF then
+ psnameid = nil
+ elseif psnameid <= 256 or psnameid >= 32768 then
+ psnameid = nil -- actually an error
+ end
+ instances[i] = {
+ -- flags = flags,
+ subfamily = extras[subfamid],
+ psname = psnameid and extras[psnameid] or nil,
+ values = values,
+ }
+ if skippable > 0 then
+ skipbytes(f,skippable)
end
- fontdata.colorpalettes = palettes
end
+ setvariabledata(fontdata,"axis",axis)
+ setvariabledata(fontdata,"instances",instances)
end
end
-function readers.svg(f,fontdata,specification)
- local datatable = fontdata.tables.svg
- if datatable then
- if specification.glyphs then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readushort(f)
- if version ~= 0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
- return
- end
- local glyphs = fontdata.glyphs
- local indexoffset = tableoffset + readulong(f)
- local reserved = readulong(f)
- setposition(f,indexoffset)
- local nofentries = readushort(f)
- local entries = { }
- for i=1,nofentries do
- entries[i] = {
- first = readushort(f),
- last = readushort(f),
- offset = indexoffset + readulong(f),
- length = readulong(f),
- }
+function readers.hvar(f,fontdata,specification)
+ local factors = specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset = gotodatatable(f,fontdata,"hvar",specification.variable)
+ if not tableoffset then
+ return
+ end
+
+ local version = readulong(f) -- 1.0
+ local variationoffset = tableoffset + readulong(f) -- the store
+ local advanceoffset = tableoffset + readulong(f)
+ local lsboffset = tableoffset + readulong(f)
+ local rsboffset = tableoffset + readulong(f)
+
+ local regions = { }
+ local variations = { }
+ local innerindex = { } -- size is mapcount
+ local outerindex = { } -- size is mapcount
+
+ if variationoffset > 0 then
+ regions, deltas = readvariationdata(f,variationoffset,factors)
+ end
+
+ if not regions then
+ -- for now .. what to do ?
+ return
+ end
+
+ if advanceoffset > 0 then
+ --
+ -- innerIndexBitCountMask = 0x000F
+ -- mapEntrySizeMask = 0x0030
+ -- reservedFlags = 0xFFC0
+ --
+ -- outerIndex = entry >> ((entryFormat & innerIndexBitCountMask) + 1)
+ -- innerIndex = entry & ((1 << ((entryFormat & innerIndexBitCountMask) + 1)) - 1)
+ --
+ setposition(f,advanceoffset)
+ local format = readushort(f) -- todo: check
+ local mapcount = readushort(f)
+ local entrysize = rshift(band(format,0x0030),4) + 1
+ local nofinnerbits = band(format,0x000F) + 1 -- n of inner bits
+ local innermask = lshift(1,nofinnerbits) - 1
+ local readcardinal = read_cardinal[entrysize] -- 1 upto 4 bytes
+ for i=0,mapcount-1 do
+ local mapdata = readcardinal(f)
+ outerindex[i] = rshift(mapdata,nofinnerbits)
+ innerindex[i] = band(mapdata,innermask)
+ end
+ -- use last entry when no match i
+ setvariabledata(fontdata,"hvarwidths",true)
+ local glyphs = fontdata.glyphs
+ for i=0,fontdata.nofglyphs-1 do
+ local glyph = glyphs[i]
+ local width = glyph.width
+ if width then
+ local outer = outerindex[i] or 0
+ local inner = innerindex[i] or i
+ if outer and inner then -- not needed
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local deltaw = 0
+ for i=1,#scales do
+ local di = d[i]
+ if di then
+ deltaw = deltaw + scales[i] * di
+ else
+ break -- can't happen
+ end
+ end
+-- report("index: %i, outer: %i, inner: %i, deltas: %|t, scales: %|t, width: %i, delta %i",
+-- i,outer,inner,d,scales,width,round(deltaw))
+ glyph.width = width + round(deltaw)
+ end
+ end
+ end
end
- for i=1,nofentries do
- local entry = entries[i]
- setposition(f,entry.offset)
- entries[i] = {
- first = entry.first,
- last = entry.last,
- data = readstring(f,entry.length)
- }
+ end
+
+ end
+
+ -- if lsboffset > 0 then
+ -- -- we don't use left side bearings
+ -- end
+
+ -- if rsboffset > 0 then
+ -- -- we don't use right side bearings
+ -- end
+
+ -- setvariabledata(fontdata,"hregions",regions)
+
+end
+
+function readers.vvar(f,fontdata,specification)
+ if not specification.variable then
+ return
+ end
+end
+
+function readers.mvar(f,fontdata,specification)
+ local tableoffset = gotodatatable(f,fontdata,"mvar",specification.variable)
+ if tableoffset then
+ local version = readulong(f) -- 1.0
+ local reserved = skipshort(f,1)
+ local recordsize = readushort(f)
+ local nofrecords = readushort(f)
+ local offsettostore = tableoffset + readushort(f)
+ local dimensions = { }
+ local factors = specification.factors
+ if factors then
+ local regions, deltas = readvariationdata(f,offsettostore,factors)
+ for i=1,nofrecords do
+ local tag = readtag(f)
+ local var = variabletags[tag]
+ if var then
+ local outer = readushort(f)
+ local inner = readushort(f)
+ local delta = deltas[outer+1]
+ if delta then
+ local d = delta.deltas[inner+1]
+ if d then
+ local scales = delta.scales
+ local dd = 0
+ for i=1,#scales do
+ dd = dd + scales[i] * d[i]
+ end
+ var(fontdata,round(dd))
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ if recordsize > 8 then -- 4 + 2 + 2
+ skipbytes(recordsize-8)
+ end
end
- fontdata.svgshapes = entries
end
- fontdata.hascolor = true
+ -- setvariabledata(fontdata,"mregions",regions)
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-effects.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-effects.lua
new file mode 100644
index 00000000000..578c8bc1027
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-effects.lua
@@ -0,0 +1,414 @@
+if not modules then modules = { } end modules ['font-imp-effects'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv and hand-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: pickup from goodies: if type(effect) then ...
+
+local next, type, tonumber = next, type, tonumber
+local is_boolean = string.is_boolean
+
+local fonts = fonts
+
+local handlers = fonts.handlers
+local registerotffeature = handlers.otf.features.register
+local registerafmfeature = handlers.afm.features.register
+
+local settings_to_hash = utilities.parsers.settings_to_hash_colon_too
+
+local helpers = fonts.helpers
+local prependcommands = helpers.prependcommands
+local charcommand = helpers.commands.char
+local leftcommand = helpers.commands.left
+local rightcommand = helpers.commands.right
+local upcommand = helpers.commands.up
+local downcommand = helpers.commands.down
+local dummycommand = helpers.commands.dummy
+
+----- constructors = fonts.constructors
+----- getmathparameter = constructors.getmathparameter
+----- setmathparameter = constructors.setmathparameter
+
+local report_effect = logs.reporter("fonts","effect")
+local report_slant = logs.reporter("fonts","slant")
+local report_extend = logs.reporter("fonts","extend")
+local report_squeeze = logs.reporter("fonts","squeeze")
+
+local trace = false
+
+trackers.register("fonts.effect", function(v) trace = v end)
+trackers.register("fonts.slant", function(v) trace = v end)
+trackers.register("fonts.extend", function(v) trace = v end)
+trackers.register("fonts.squeeze",function(v) trace = v end)
+
+local function initializeslant(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 1 then
+ value = 1
+ elseif value < -1 then
+ value = -1
+ end
+ if trace then
+ report_slant("applying %0.3f",value)
+ end
+ tfmdata.parameters.slantfactor = value
+end
+
+local specification = {
+ name = "slant",
+ description = "slant glyphs",
+ initializers = {
+ base = initializeslant,
+ node = initializeslant,
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+local function initializeextend(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 10 then
+ value = 10
+ elseif value < -10 then
+ value = -10
+ end
+ if trace then
+ report_extend("applying %0.3f",value)
+ end
+ tfmdata.parameters.extendfactor = value
+end
+
+local specification = {
+ name = "extend",
+ description = "scale glyphs horizontally",
+ initializers = {
+ base = initializeextend,
+ node = initializeextend,
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+local function initializesqueeze(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ elseif value > 10 then
+ value = 10
+ elseif value < -10 then
+ value = -10
+ end
+ if trace then
+ report_squeeze("applying %0.3f",value)
+ end
+ tfmdata.parameters.squeezefactor = value
+end
+
+local specification = {
+ name = "squeeze",
+ description = "scale glyphs vertically",
+ initializers = {
+ base = initializesqueeze,
+ node = initializesqueeze,
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+local effects = {
+ inner = 0,
+ normal = 0,
+ outer = 1,
+ outline = 1,
+ both = 2,
+ hidden = 3,
+}
+
+local function initializeeffect(tfmdata,value)
+ local spec
+ if type(value) == "number" then
+ spec = { width = value }
+ else
+ spec = settings_to_hash(value)
+ end
+ local effect = spec.effect or "both"
+ local width = tonumber(spec.width) or 0
+ local mode = effects[effect]
+ if not mode then
+ report_effect("invalid effect %a",effect)
+ elseif width == 0 and mode == 0 then
+ report_effect("invalid width %a for effect %a",width,effect)
+ else
+ local parameters = tfmdata.parameters
+ local properties = tfmdata.properties
+ parameters.mode = mode
+ parameters.width = width * 1000
+ if is_boolean(spec.auto) == true then
+ local squeeze = 1 - width/20
+ local average = (1 - squeeze) * width * 100
+ spec.squeeze = squeeze
+ spec.extend = 1 + width/2
+ spec.wdelta = average
+ spec.hdelta = average/2
+ spec.ddelta = average/2
+ spec.vshift = average/2
+ end
+ local factor = tonumber(spec.factor) or 0
+ local hfactor = tonumber(spec.hfactor) or factor
+ local vfactor = tonumber(spec.vfactor) or factor
+ local delta = tonumber(spec.delta) or 1
+ local wdelta = tonumber(spec.wdelta) or delta
+ local hdelta = tonumber(spec.hdelta) or delta
+ local ddelta = tonumber(spec.ddelta) or hdelta
+ local vshift = tonumber(spec.vshift) or 0
+ local slant = spec.slant
+ local extend = spec.extend
+ local squeeze = spec.squeeze
+ if slant then
+ initializeslant(tfmdata,slant)
+ end
+ if extend then
+ initializeextend(tfmdata,extend)
+ end
+ if squeeze then
+ initializesqueeze(tfmdata,squeeze)
+ end
+ properties.effect = {
+ effect = effect,
+ width = width,
+ factor = factor,
+ hfactor = hfactor,
+ vfactor = vfactor,
+ wdelta = wdelta,
+ hdelta = hdelta,
+ ddelta = ddelta,
+ vshift = vshift,
+ slant = tfmdata.parameters.slantfactor,
+ extend = tfmdata.parameters.extendfactor,
+ squeeze = tfmdata.parameters.squeezefactor,
+ }
+ end
+end
+
+local rules = {
+ "RadicalRuleThickness",
+ "OverbarRuleThickness",
+ "FractionRuleThickness",
+ "UnderbarRuleThickness",
+}
+
+-- local commands = char.commands
+-- if commands then
+-- local command = commands[1]
+-- if command and command[1] == "right" then
+-- commands[1] = rightcommand[command[2]-snap]
+-- end
+-- end
+
+local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ if delta ~= 0 then
+ for i=1,#rules do
+ local name = rules[i]
+ local value = mathparameters[name]
+ if value then
+ mathparameters[name] = (squeeze or 1) * (value + dx)
+ end
+ end
+ end
+end
+
+local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+
+ local function wdpatch(char)
+ if wsnap ~= 0 then
+ char.width = char.width + wdelta/2
+ end
+ end
+
+ local function htpatch(char)
+ if hsnap ~= 0 then
+ local height = char.height
+ if height then
+ char.height = char.height + 2 * dy
+ end
+ end
+ end
+
+ local character = characters[0x221A]
+
+ if character and character.next then
+-- print("base char",0x221A,table.sequenced(character))
+ local char = character
+ local next = character.next
+ wdpatch(char)
+ htpatch(char)
+ while next do
+ char = characters[next]
+ wdpatch(char)
+ htpatch(char)
+-- print("next char",next,table.sequenced(char))
+ next = char.next
+ end
+ if char then
+ local v = char.vert_variants
+ if v then
+ local top = v[#v]
+ if top then
+ local char = characters[top.glyph]
+-- print("top char",top.glyph,table.sequenced(char))
+ htpatch(char)
+ end
+ end
+ end
+ end
+end
+
+-- local show_effect = { "lua", function(f,c)
+-- report_effect("font id %i, char %C",f,c)
+-- inspect(fonts.hashes.characters[f][c])
+-- end }
+
+-- local show_effect = { "lua", "print('!')" }
+
+local function manipulateeffect(tfmdata)
+ local effect = tfmdata.properties.effect
+ if effect then
+ local characters = tfmdata.characters
+ local parameters = tfmdata.parameters
+ local mathparameters = tfmdata.mathparameters
+ local multiplier = effect.width * 100
+ local factor = parameters.factor
+ local hfactor = parameters.hfactor
+ local vfactor = parameters.vfactor
+ local wdelta = effect.wdelta * hfactor * multiplier
+ local hdelta = effect.hdelta * vfactor * multiplier
+ local ddelta = effect.ddelta * vfactor * multiplier
+ local vshift = effect.vshift * vfactor * multiplier
+ local squeeze = effect.squeeze
+ local hshift = wdelta / 2
+ local dx = multiplier * vfactor
+ local dy = vshift
+ local factor = (1 + effect.factor) * factor
+ local hfactor = (1 + effect.hfactor) * hfactor
+ local vfactor = (1 + effect.vfactor) * vfactor
+ local vshift = vshift ~= 0 and upcommand[vshift] or false
+ for unicode, character in next, characters do
+ local oldwidth = character.width
+ local oldheight = character.height
+ local olddepth = character.depth
+ if oldwidth and oldwidth > 0 then
+ character.width = oldwidth + wdelta
+ local commands = character.commands
+ local hshift = rightcommand[hshift]
+ if vshift then
+ if commands then
+ prependcommands ( commands,
+-- show_effect,
+ hshift,
+ vshift
+ )
+ else
+ character.commands = {
+-- show_effect,
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
+ else
+ if commands then
+ prependcommands ( commands,
+-- show_effect,
+ hshift
+ )
+ else
+ character.commands = {
+-- show_effect,
+ hshift,
+ charcommand[unicode]
+ }
+ end
+ end
+ end
+ if oldheight and oldheight > 0 then
+ character.height = oldheight + hdelta
+ end
+ if olddepth and olddepth > 0 then
+ character.depth = olddepth + ddelta
+ end
+ end
+ if mathparameters then
+ setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+ end
+ parameters.factor = factor
+ parameters.hfactor = hfactor
+ parameters.vfactor = vfactor
+ if trace then
+ report_effect("applying")
+ report_effect(" effect : %s", effect.effect)
+ report_effect(" width : %s => %s", effect.width, multiplier)
+ report_effect(" factor : %s => %s", effect.factor, factor )
+ report_effect(" hfactor : %s => %s", effect.hfactor,hfactor)
+ report_effect(" vfactor : %s => %s", effect.vfactor,vfactor)
+ report_effect(" wdelta : %s => %s", effect.wdelta, wdelta)
+ report_effect(" hdelta : %s => %s", effect.hdelta, hdelta)
+ report_effect(" ddelta : %s => %s", effect.ddelta, ddelta)
+ end
+ end
+end
+
+local specification = {
+ name = "effect",
+ description = "apply effects to glyphs",
+ initializers = {
+ base = initializeeffect,
+ node = initializeeffect,
+ },
+ manipulators = {
+ base = manipulateeffect,
+ node = manipulateeffect,
+ },
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+local function initializeoutline(tfmdata,value)
+ value = tonumber(value)
+ if not value then
+ value = 0
+ else
+ value = tonumber(value) or 0
+ end
+ local parameters = tfmdata.parameters
+ local properties = tfmdata.properties
+ parameters.mode = effects.outline
+ parameters.width = value * 1000
+ properties.effect = {
+ effect = effect,
+ width = width,
+ }
+end
+
+local specification = {
+ name = "outline",
+ description = "outline glyphs",
+ initializers = {
+ base = initializeoutline,
+ node = initializeoutline,
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-italics.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-italics.lua
new file mode 100644
index 00000000000..83c785d3876
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-italics.lua
@@ -0,0 +1,147 @@
+if not modules then modules = { } end modules ['font-imp-italics'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv and hand-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next = next
+
+local fonts = fonts
+local handlers = fonts.handlers
+local registerotffeature = handlers.otf.features.register
+local registerafmfeature = handlers.afm.features.register
+
+local function initialize(tfmdata,key,value)
+ for unicode, character in next, tfmdata.characters do
+ local olditalic = character.italic
+ if olditalic and olditalic ~= 0 then
+ character.width = character.width + olditalic
+ character.italic = 0
+ end
+ end
+end
+
+local specification = {
+ name = "italicwidths",
+ description = "add italic to width",
+ manipulators = {
+ base = initialize,
+ node = initialize, -- only makes sense for math
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+local function initialize(tfmdata,value) -- hm, always value
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim but we might need another guess
+ local parameters = tfmdata.parameters
+ local italicangle = parameters.italicangle
+ if italicangle and italicangle ~= 0 then
+ local properties = tfmdata.properties
+ local factor = tonumber(value) or 1
+ properties.hasitalics = true
+ properties.autoitalicamount = factor * (parameters.uwidth or 40)/2
+ end
+ end
+end
+
+local specification = {
+ name = "itlc",
+ description = "italic correction",
+ initializers = {
+ base = initialize,
+ node = initialize,
+ }
+}
+
+registerotffeature(specification)
+registerafmfeature(specification)
+
+if context then
+
+ local function initialize(tfmdata,value) -- yes no delay
+ tfmdata.properties.textitalics = toboolean(value)
+ end
+
+ local specification = {
+ name = "textitalics",
+ description = "use alternative text italic correction",
+ initializers = {
+ base = initialize,
+ node = initialize,
+ }
+ }
+
+ registerotffeature(specification)
+ registerafmfeature(specification)
+
+end
+
+-- no longer used
+
+-- if context then
+--
+-- -- local function initializemathitalics(tfmdata,value) -- yes no delay
+-- -- tfmdata.properties.mathitalics = toboolean(value)
+-- -- end
+-- --
+-- -- local specification = {
+-- -- name = "mathitalics",
+-- -- description = "use alternative math italic correction",
+-- -- initializers = {
+-- -- base = initializemathitalics,
+-- -- node = initializemathitalics,
+-- -- }
+-- -- }
+-- --
+-- -- registerotffeature(specification)
+-- -- registerafmfeature(specification)
+--
+-- end
+
+-- -- also not used, only when testing
+
+if context then
+
+ local letter = characters.is_letter
+ local always = true
+
+ local function collapseitalics(tfmdata,key,value)
+ local threshold = value == true and 100 or tonumber(value)
+ if threshold and threshold > 0 then
+ if threshold > 100 then
+ threshold = 100
+ end
+ for unicode, data in next, tfmdata.characters do
+ if always or letter[unicode] or letter[data.unicode] then
+ local italic = data.italic
+ if italic and italic ~= 0 then
+ local width = data.width
+ if width and width ~= 0 then
+ local delta = threshold * italic / 100
+ data.width = width + delta
+ data.italic = italic - delta
+ end
+ end
+ end
+ end
+ end
+ end
+
+ local dimensions_specification = {
+ name = "collapseitalics",
+ description = "collapse italics",
+ manipulators = {
+ base = collapseitalics,
+ node = collapseitalics,
+ }
+ }
+
+ registerotffeature(dimensions_specification)
+ registerafmfeature(dimensions_specification)
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-ligatures.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-ligatures.lua
new file mode 100644
index 00000000000..091eb5d4b45
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-ligatures.lua
@@ -0,0 +1,136 @@
+if not modules then modules = { } end modules ['font-imp-ligatures'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local lpegmatch = lpeg.match
+local utfsplit = utf.split
+local settings_to_array = utilities.parsers.settings_to_array
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+local registerotffeature = otf.features.register
+local addotffeature = otf.addfeature
+
+-- This is a quick and dirty hack.
+
+local lookups = { }
+local protect = { }
+local revert = { }
+local zwjchar = 0x200C
+local zwj = { zwjchar }
+
+addotffeature {
+ name = "blockligatures",
+ type = "chainsubstitution",
+ nocheck = true, -- because there is no 0x200C in the font
+ prepend = true, -- make sure we do it early
+ future = true, -- avoid nilling due to no steps yet
+ lookups = {
+ {
+ type = "multiple",
+ data = lookups,
+ },
+ },
+ data = {
+ rules = protect,
+ }
+}
+
+addotffeature {
+ name = "blockligatures",
+ type = "chainsubstitution",
+ nocheck = true, -- because there is no 0x200C in the font
+ append = true, -- this is done late
+ overload = false, -- we don't want to overload the previous definition
+ lookups = {
+ {
+ type = "ligature",
+ data = lookups,
+ },
+ },
+ data = {
+ rules = revert,
+ }
+}
+
+registerotffeature {
+ name = 'blockligatures',
+ description = 'block certain ligatures',
+}
+
+local splitter = lpeg.splitat(":")
+
+local function blockligatures(str)
+
+ local t = settings_to_array(str)
+
+ for i=1,#t do
+ local ti = t[i]
+ local before, current, after = lpegmatch(splitter,ti)
+ if current and after then -- before is returned when no match
+ -- experimental joke
+ if before then
+ before = utfsplit(before)
+ for i=1,#before do
+ before[i] = { before[i] }
+ end
+ end
+ if current then
+ current = utfsplit(current)
+ end
+ if after then
+ after = utfsplit(after)
+ for i=1,#after do
+ after[i] = { after[i] }
+ end
+ end
+ else
+ before = nil
+ current = utfsplit(ti)
+ after = nil
+ end
+ if #current > 1 then
+ local one = current[1]
+ local two = current[2]
+ lookups[one] = { one, zwjchar }
+ local one = { one }
+ local two = { two }
+ local new = #protect + 1
+ protect[new] = {
+ before = before,
+ current = { one, two },
+ after = after,
+ lookups = { 1 }, -- not shared !
+ }
+ revert[new] = {
+ -- before = before,
+ current = { one, zwj },
+ -- after = { two, unpack(after) },
+ after = { two },
+ lookups = { 1 }, -- not shared !
+ }
+ end
+ end
+end
+
+-- blockligatures("\0\0")
+
+otf.helpers.blockligatures = blockligatures
+
+-- blockligatures("fi,ff")
+-- blockligatures("fl")
+-- blockligatures("u:fl:age")
+
+if context then
+
+ interfaces.implement {
+ name = "blockligatures",
+ arguments = "string",
+ actions = blockligatures,
+ }
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-tex.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-tex.lua
new file mode 100644
index 00000000000..b4b9a7b6943
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-imp-tex.lua
@@ -0,0 +1,144 @@
+if not modules then modules = { } end modules ['font-imp-tex'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next = next
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+local registerotffeature = otf.features.register
+local addotffeature = otf.addfeature
+
+-- tlig (we need numbers for some fonts so ...)
+
+local specification = {
+ type = "ligature",
+ order = { "tlig" },
+ prepend = true,
+ data = {
+ -- endash = "hyphen hyphen",
+ -- emdash = "hyphen hyphen hyphen",
+ [0x2013] = { 0x002D, 0x002D },
+ [0x2014] = { 0x002D, 0x002D, 0x002D },
+ -- quotedblleft = "quoteleft quoteleft",
+ -- quotedblright = "quoteright quoteright",
+ -- quotedblleft = "grave grave",
+ -- quotedblright = "quotesingle quotesingle",
+ -- quotedblbase = "comma comma",
+ },
+}
+
+addotffeature("tlig",specification)
+
+registerotffeature {
+ -- this makes it a known feature (in tables)
+ name = "tlig",
+ description = "tex ligatures",
+}
+
+-- trep
+
+local specification = {
+ type = "substitution",
+ order = { "trep" },
+ prepend = true,
+ data = {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+ },
+}
+
+addotffeature("trep",specification)
+
+registerotffeature {
+ -- this makes it a known feature (in tables)
+ name = "trep",
+ description = "tex replacements",
+}
+
+-- some day this will be moved to font-imp-scripts.lua
+
+-- anum
+
+local anum_arabic = {
+ [0x0030] = 0x0660,
+ [0x0031] = 0x0661,
+ [0x0032] = 0x0662,
+ [0x0033] = 0x0663,
+ [0x0034] = 0x0664,
+ [0x0035] = 0x0665,
+ [0x0036] = 0x0666,
+ [0x0037] = 0x0667,
+ [0x0038] = 0x0668,
+ [0x0039] = 0x0669,
+}
+
+local anum_persian = {
+ [0x0030] = 0x06F0,
+ [0x0031] = 0x06F1,
+ [0x0032] = 0x06F2,
+ [0x0033] = 0x06F3,
+ [0x0034] = 0x06F4,
+ [0x0035] = 0x06F5,
+ [0x0036] = 0x06F6,
+ [0x0037] = 0x06F7,
+ [0x0038] = 0x06F8,
+ [0x0039] = 0x06F9,
+}
+
+local function valid(data)
+ local features = data.resources.features
+ if features then
+ for k, v in next, features do
+ for k, v in next, v do
+ if v.arab then
+ return true
+ end
+ end
+ end
+ end
+end
+
+local specification = {
+ {
+ type = "substitution",
+ features = { arab = { urd = true, dflt = true } },
+ order = { "anum" },
+ data = anum_arabic,
+ valid = valid,
+ },
+ {
+ type = "substitution",
+ features = { arab = { urd = true } },
+ order = { "anum" },
+ data = anum_persian,
+ valid = valid,
+ },
+}
+
+addotffeature("anum",specification)
+
+registerotffeature {
+ -- this makes it a known feature (in tables)
+ name = "anum",
+ description = "arabic digits",
+}
+
+-- -- example:
+--
+-- fonts.handlers.otf.addfeature {
+-- name = "hangulfix",
+-- type = "substitution",
+-- features = { ["hang"] = { ["*"] = true } },
+-- data = {
+-- [0x1160] = 0x119E,
+-- },
+-- order = { "hangulfix" },
+-- flags = { },
+-- prepend = true,
+-- })
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ini.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ini.lua
index abc319484d2..3d5dd27a2d5 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ini.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ini.lua
@@ -10,21 +10,22 @@ if not modules then modules = { } end modules ['font-ini'] = {
<p>Not much is happening here.</p>
--ldx]]--
-local allocate = utilities.storage.allocate
+local allocate = utilities.storage.allocate
-fonts = fonts or { }
-local fonts = fonts
+fonts = fonts or { }
+local fonts = fonts
-fonts.hashes = { identifiers = allocate() }
+fonts.hashes = fonts.hashes or { identifiers = allocate() }
+fonts.tables = fonts.tables or { }
+fonts.helpers = fonts.helpers or { }
+fonts.tracers = fonts.tracers or { } -- for the moment till we have move to moduledata
+fonts.specifiers = fonts.specifiers or { } -- in format !
-fonts.tables = fonts.tables or { }
-fonts.helpers = fonts.helpers or { }
-fonts.tracers = fonts.tracers or { } -- for the moment till we have move to moduledata
-fonts.specifiers = fonts.specifiers or { } -- in format !
+fonts.analyzers = { } -- not needed here
+fonts.readers = { }
+fonts.definers = { methods = { } }
+fonts.loggers = { register = function() end }
-fonts.analyzers = { } -- not needed here
-fonts.readers = { }
-fonts.definers = { methods = { } }
-fonts.loggers = { register = function() end }
-
-fontloader.totable = fontloader.to_table -- not used
+if context then
+ fontloader = nil
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua
index e2254f8ca0e..a7fbfe49e89 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua
@@ -10,15 +10,17 @@ local tonumber, next, type = tonumber, next, type
local match, format, find, concat, gsub, lower = string.match, string.format, string.find, table.concat, string.gsub, string.lower
local P, R, S, C, Ct, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.match
-local floor = math.floor
local formatters = string.formatters
local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys
+local rshift = bit32.rshift
local trace_loading = false trackers.register("fonts.loading", function(v) trace_loading = v end)
local trace_mapping = false trackers.register("fonts.mapping", function(v) trace_mapping = v end)
local report_fonts = logs.reporter("fonts","loading") -- not otf only
+-- force_ligatures was true for a while so that these emoji's with bad names work too
+
local force_ligatures = false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures = v end)
local fonts = fonts or { }
@@ -76,6 +78,9 @@ end
local f_single = formatters["%04X"]
local f_double = formatters["%04X%04X"]
+-- floor(x/256) => rshift(x, 8)
+-- floor(x/1024) => rshift(x,10)
+
-- 0.684 0.661 0,672 0.650 : cache at lua end (more mem)
-- 0.682 0,672 0.698 0.657 : no cache (moderate mem i.e. lua strings)
-- 0.644 0.647 0.655 0.645 : convert in c (less mem in theory)
@@ -86,7 +91,7 @@ local f_double = formatters["%04X%04X"]
-- s = f_single(unicode)
-- else
-- unicode = unicode - 0x10000
--- s = f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
+-- s = f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
-- end
-- t[unicode] = s
-- return s
@@ -145,7 +150,7 @@ local function tounicode16(unicode)
return f_single(unicode)
else
unicode = unicode - 0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
+ return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
end
end
@@ -157,33 +162,122 @@ local function tounicode16sequence(unicodes)
t[l] = f_single(u)
else
u = u - 0x10000
- t[l] = f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
+ t[l] = f_double(rshift(u,10)+0xD800,u%1024+0xDC00)
end
end
return concat(t)
end
-local function tounicode(unicode,name)
- if type(unicode) == "table" then
- local t = { }
- for l=1,#unicode do
- local u = unicode[l]
- if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then
- t[l] = f_single(u)
- else
- u = u - 0x10000
- t[l] = f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
- end
+-- local function tounicode(unicode)
+-- if type(unicode) == "table" then
+-- local t = { }
+-- for l=1,#unicode do
+-- local u = unicode[l]
+-- if u < 0xD7FF or (u > 0xDFFF and u <= 0xFFFF) then
+-- t[l] = f_single(u)
+-- else
+-- u = u - 0x10000
+-- t[l] = f_double(rshift(u,10)+0xD800,u%1024+0xDC00)
+-- end
+-- end
+-- return concat(t)
+-- else
+-- if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then
+-- return f_single(unicode)
+-- else
+-- unicode = unicode - 0x10000
+-- return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
+-- end
+-- end
+-- end
+
+local unknown = f_single(0xFFFD)
+
+-- local function tounicode(unicode)
+-- if type(unicode) == "table" then
+-- local t = { }
+-- for l=1,#unicode do
+-- t[l] = tounicode(unicode[l])
+-- end
+-- return concat(t)
+-- elseif unicode >= 0x00E000 and unicode <= 0x00F8FF then
+-- return unknown
+-- elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFF then
+-- return unknown
+-- elseif unicode >= 0x100000 and unicode <= 0x10FFFF then
+-- return unknown
+-- elseif unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then
+-- return f_single(unicode)
+-- else
+-- unicode = unicode - 0x10000
+-- return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
+-- end
+-- end
+
+-- local hash = table.setmetatableindex(function(t,k)
+-- local v
+-- if k >= 0x00E000 and k <= 0x00F8FF then
+-- v = unknown
+-- elseif k >= 0x0F0000 and k <= 0x0FFFFF then
+-- v = unknown
+-- elseif k >= 0x100000 and k <= 0x10FFFF then
+-- v = unknown
+-- elseif k < 0xD7FF or (k > 0xDFFF and k <= 0xFFFF) then
+-- v = f_single(k)
+-- else
+-- k = k - 0x10000
+-- v = f_double(rshift(k,10)+0xD800,k%1024+0xDC00)
+-- end
+-- t[k] = v
+-- return v
+-- end)
+--
+-- table.makeweak(hash)
+--
+-- local function tounicode(unicode)
+-- if type(unicode) == "table" then
+-- local t = { }
+-- for l=1,#unicode do
+-- t[l] = hash[unicode[l]]
+-- end
+-- return concat(t)
+-- else
+-- return hash[unicode]
+-- end
+-- end
+
+local hash = { }
+local conc = { }
+
+-- table.makeweak(hash)
+
+table.setmetatableindex(hash,function(t,k)
+ if type(k) == "table" then
+ local n = #k
+ for l=1,n do
+ conc[l] = hash[k[l]]
end
- return concat(t)
+ return concat(conc,"",1,n)
+ end
+ local v
+ if k >= 0x00E000 and k <= 0x00F8FF then
+ v = unknown
+ elseif k >= 0x0F0000 and k <= 0x0FFFFF then
+ v = unknown
+ elseif k >= 0x100000 and k <= 0x10FFFF then
+ v = unknown
+ elseif k < 0xD7FF or (k > 0xDFFF and k <= 0xFFFF) then
+ v = f_single(k)
else
- if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then
- return f_single(unicode)
- else
- unicode = unicode - 0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
- end
+ k = k - 0x10000
+ v = f_double(rshift(k,10)+0xD800,k%1024+0xDC00)
end
+ t[k] = v
+ return v
+end)
+
+local function tounicode(unicode)
+ return hash[unicode]
end
local function fromunicode16(str)
@@ -216,6 +310,8 @@ mappings.tounicode16 = tounicode16
mappings.tounicode16sequence = tounicode16sequence
mappings.fromunicode16 = fromunicode16
+-- mozilla emoji has bad lig names: name = gsub(name,"(u[a-f0-9_]+)%-([a-f0-9_]+)","%1_%2")
+
local ligseparator = P("_")
local varseparator = P(".")
local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * C((1 - ligseparator - varseparator)^1))^0)
@@ -239,7 +335,7 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator *
do
- local overloads = allocate {
+ local overloads = {
IJ = { name = "I_J", unicode = { 0x49, 0x4A }, mess = 0x0132 },
ij = { name = "i_j", unicode = { 0x69, 0x6A }, mess = 0x0133 },
ff = { name = "f_f", unicode = { 0x66, 0x66 }, mess = 0xFB00 },
@@ -249,9 +345,12 @@ do
ffl = { name = "f_f_l", unicode = { 0x66, 0x66, 0x6C }, mess = 0xFB04 },
fj = { name = "f_j", unicode = { 0x66, 0x6A } },
fk = { name = "f_k", unicode = { 0x66, 0x6B } },
+
+ -- endash = { name = "endash", unicode = 0x2013, mess = 0x2013 },
+ -- emdash = { name = "emdash", unicode = 0x2014, mess = 0x2014 },
}
- local o = { }
+ local o = allocate { }
for k, v in next, overloads do
local name = v.name
@@ -269,7 +368,7 @@ do
end
-function mappings.addtounicode(data,filename,checklookups)
+function mappings.addtounicode(data,filename,checklookups,forceligatures)
local resources = data.resources
local unicodes = resources.unicodes
if not unicodes then
@@ -464,41 +563,54 @@ function mappings.addtounicode(data,filename,checklookups)
checklookups(data,missing,nofmissing)
end
- -- todo: go lowercase
-
- local collected = false
local unicoded = 0
- -- for du, glyph in next, descriptions do
- for i=1,#dlist do
- local du = dlist[i]
- local glyph = descriptions[du]
- if glyph.class == "ligature" and (force_ligatures or not glyph.unicode) then
- if not collected then
- collected = fonts.handlers.otf.readers.getcomponents(data)
- if not collected then
- break
- end
+ local collected = fonts.handlers.otf.readers.getcomponents(data) -- neglectable overhead
+
+ local function resolve(glyph,u)
+ local n = #u
+ for i=1,n do
+ if u[i] > private then
+ n = 0
+ break
end
- local u = collected[du] -- always tables
- if u then
- local n = #u
- for i=1,n do
- if u[i] > private then
- n = 0
- break
- end
+ end
+ if n > 0 then
+ if n > 1 then
+ glyph.unicode = u
+ else
+ glyph.unicode = u[1]
+ end
+ unicoded = unicoded + 1
+ end
+ end
+
+ if not collected then
+ -- move on
+ elseif forceligatures or force_ligatures then
+ for i=1,#dlist do
+ local du = dlist[i]
+ if du >= private or (du >= 0xE000 and du <= 0xF8FF) then
+ local u = collected[du] -- always tables
+ if u then
+ resolve(descriptions[du],u)
end
- if n > 0 then
- if n > 1 then
- glyph.unicode = u
- else
- glyph.unicode = u[1]
+ end
+ end
+ else
+ for i=1,#dlist do
+ local du = dlist[i]
+ if du >= private or (du >= 0xE000 and du <= 0xF8FF) then
+ local glyph = descriptions[du]
+ if glyph.class == "ligature" and not glyph.unicode then
+ local u = collected[du] -- always tables
+ if u then
+ resolve(glyph,u)
end
- unicoded = unicoded + 1
end
end
end
end
+
if trace_mapping and unicoded > 0 then
report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded)
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ocl.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ocl.lua
index 65a1c63427c..f97487ecd42 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ocl.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ocl.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['font-ocl'] = {
version = 1.001,
- comment = "companion to font-otf.lua (context)",
+ comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
@@ -8,17 +8,25 @@ if not modules then modules = { } end modules ['font-ocl'] = {
-- todo : user list of colors
-local tostring, next, format = tostring, next, string.format
+local tostring, tonumber, next = tostring, tonumber, next
local round, max = math.round, math.round
+local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash
+local setmetatableindex = table.setmetatableindex
-local formatters = string.formatters
-local tounicode = fonts.mappings.tounicode
+local formatters = string.formatters
+local tounicode = fonts.mappings.tounicode
-local otf = fonts.handlers.otf
+local helpers = fonts.helpers
-local f_color = formatters["pdf:direct:%f %f %f rg"]
-local f_gray = formatters["pdf:direct:%f g"]
-local s_black = "pdf:direct:0 g"
+local charcommand = helpers.commands.char
+local rightcommand = helpers.commands.right
+local leftcommand = helpers.commands.left
+local downcommand = helpers.commands.down
+
+local otf = fonts.handlers.otf
+
+local f_color = formatters["%.3f %.3f %.3f rg"]
+local f_gray = formatters["%.3f g"]
if context then
@@ -39,7 +47,7 @@ else
function otf.getactualtext(s)
return
- "/Span << /ActualText <feff" .. n .. "> >> BDC",
+ "/Span << /ActualText <feff" .. s .. "> >> BDC",
"EMC"
end
@@ -47,32 +55,40 @@ end
local sharedpalettes = { }
+local hash = setmetatableindex(function(t,k)
+ local v = { "pdf", "direct", k }
+ t[k] = v
+ return v
+end)
+
if context then
- local graytorgb = attributes.colors.graytorgb
- local cmyktorgb = attributes.colors.cmyktorgb
+ local colors = attributes.list[attributes.private('color')] or { }
+ local transparencies = attributes.list[attributes.private('transparency')] or { }
function otf.registerpalette(name,values)
sharedpalettes[name] = values
for i=1,#values do
local v = values[i]
- local r, g, b
- local s = v.s
- if s then
- r, g, b = graytorgb(s)
+ local c = nil
+ local t = nil
+ if type(v) == "table" then
+ c = colors.register(name,"rgb",
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )
else
- local c, m, y, k = v.c, v.m, v.y, v.k
- if c or m or y or k then
- r, g, b = cmyktorgb(c or 0,m or 0,y or 0,k or 0)
- else
- r, g, b = v.r, v.g, v.b
- end
+ c = colors[v]
+ t = transparencies[v]
+ end
+ if c and t then
+ values[i] = hash[lpdf.color(1,c) .. " " .. lpdf.transparency(t)]
+ elseif c then
+ values[i] = hash[lpdf.color(1,c)]
+ elseif t then
+ values[i] = hash[lpdf.color(1,t)]
end
- values[i] = {
- max(r and round(r*255) or 0,255),
- max(g and round(g*255) or 0,255),
- max(b and round(b*255) or 0,255)
- }
end
end
@@ -82,23 +98,138 @@ else -- for generic
sharedpalettes[name] = values
for i=1,#values do
local v = values[i]
- values[i] = {
- max(round((v.r or 0)*255),255),
- max(round((v.g or 0)*255),255),
- max(round((v.b or 0)*255),255)
- }
+ values[i] = hash[f_color(
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )]
end
end
end
-local function initializecolr(tfmdata,kind,value) -- hm, always value
+-- We need to force page first because otherwise the q's get outside the font switch and
+-- as a consequence the next character has no font set (well, it has: the preceding one). As
+-- a consequence these fonts are somewhat inefficient as each glyph gets the font set. It's
+-- a side effect of the fact that a font is handled when a character gets flushed. Okay, from
+-- now on we can use text as literal mode.
+
+local function convert(t,k)
+ local v = { }
+ for i=1,#k do
+ local p = k[i]
+ local r, g, b = p[1], p[2], p[3]
+ if r == g and g == b then
+ v[i] = hash[f_gray(r/255)]
+ else
+ v[i] = hash[f_color(r/255,g/255,b/255)]
+ end
+ end
+ t[k] = v
+ return v
+end
+
+local start = { "pdf", "mode", "font" } -- force text mode (so get q Q right)
+----- stop = { "pdf", "mode", "page" } -- force page mode (else overlap)
+local push = { "pdf", "page", "q" }
+local pop = { "pdf", "page", "Q" }
+
+if not LUATEXFUNCTIONALITY or LUATEXFUNCTIONALITY < 6472 then -- for outside context (till tl 2019)
+ start = { "nop" }
+ ----- = stop
+end
+
+-- -- This one results in color directives inside BT ET but has less q Q pairs. It
+-- -- only shows the first glyph in acrobat and nothing more. No problem with other
+-- -- renderers.
+--
+-- local function initialize(tfmdata,kind,value) -- hm, always value
+-- if value then
+-- local resources = tfmdata.resources
+-- local palettes = resources.colorpalettes
+-- if palettes then
+-- --
+-- local converted = resources.converted
+-- if not converted then
+-- converted = setmetatableindex(convert)
+-- resources.converted = converted
+-- end
+-- local colorvalues = sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
+-- local classes = #colorvalues
+-- if classes == 0 then
+-- return
+-- end
+-- --
+-- local characters = tfmdata.characters
+-- local descriptions = tfmdata.descriptions
+-- local properties = tfmdata.properties
+-- --
+-- properties.virtualized = true
+-- tfmdata.fonts = {
+-- { id = 0 }
+-- }
+-- --
+-- local getactualtext = otf.getactualtext
+-- local default = colorvalues[#colorvalues]
+-- local b, e = getactualtext(tounicode(0xFFFD))
+-- local actualb = { "pdf", "page", b } -- saves tables
+-- local actuale = { "pdf", "page", e } -- saves tables
+-- --
+-- for unicode, character in next, characters do
+-- local description = descriptions[unicode]
+-- if description then
+-- local colorlist = description.colors
+-- if colorlist then
+-- local u = description.unicode or characters[unicode].unicode
+-- local w = character.width or 0
+-- local s = #colorlist
+-- local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
+-- local t = {
+-- start,
+-- not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }
+-- }
+-- local n = 2
+-- local l = nil
+-- n = n + 1 t[n] = push
+-- for i=1,s do
+-- local entry = colorlist[i]
+-- local v = colorvalues[entry.class] or default
+-- if v and l ~= v then
+-- n = n + 1 t[n] = v
+-- l = v
+-- end
+-- n = n + 1 t[n] = charcommand[entry.slot]
+-- if s > 1 and i < s and goback then
+-- n = n + 1 t[n] = goback
+-- end
+-- end
+-- n = n + 1 t[n] = pop
+-- n = n + 1 t[n] = actuale
+-- n = n + 1 t[n] = stop
+-- character.commands = t
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+--
+-- -- Here we have no color change in BT .. ET and more q Q pairs but even then acrobat
+-- -- fails displaying the overlays correctly. Other renderers do it right.
+
+local function initialize(tfmdata,kind,value) -- hm, always value
if value then
- local palettes = tfmdata.resources.colorpalettes
+ local resources = tfmdata.resources
+ local palettes = resources.colorpalettes
if palettes then
--
- local palette = sharedpalettes[value] or palettes[tonumber(value) or 1] or palettes[1] or { }
- local classes = #palette
+ local converted = resources.converted
+ if not converted then
+ converted = setmetatableindex(convert)
+ resources.converted = converted
+ end
+ local colorvalues = sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or { }
+ local classes = #colorvalues
if classes == 0 then
return
end
@@ -106,54 +237,56 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value
local characters = tfmdata.characters
local descriptions = tfmdata.descriptions
local properties = tfmdata.properties
- local colorvalues = { }
--
properties.virtualized = true
tfmdata.fonts = {
{ id = 0 }
}
--
- for i=1,classes do
- local p = palette[i]
- local r, g, b = p[1], p[2], p[3]
- if r == g and g == b then
- colorvalues[i] = { "special", f_gray(r/255) }
- else
- colorvalues[i] = { "special", f_color(r/255,g/255,b/255) }
- end
- end
- --
local getactualtext = otf.getactualtext
+ local default = colorvalues[#colorvalues]
+ local b, e = getactualtext(tounicode(0xFFFD))
+ local actualb = { "pdf", "page", b } -- saves tables
+ local actuale = { "pdf", "page", e } -- saves tables
--
for unicode, character in next, characters do
local description = descriptions[unicode]
if description then
local colorlist = description.colors
if colorlist then
- local b, e = getactualtext(tounicode(characters[unicode].unicode or 0xFFFD))
+ local u = description.unicode or characters[unicode].unicode
local w = character.width or 0
local s = #colorlist
+ local goback = w ~= 0 and leftcommand[w] or nil -- needs checking: are widths the same
local t = {
- -- We need to force page first because otherwise the q's get outside
- -- the font switch and as a consequence the next character has no font
- -- set (well, it has: the preceding one). As a consequence these fonts
- -- are somewhat inefficient as each glyph gets the font set. It's a
- -- side effect of the fact that a font is handled when a character gets
- -- flushed.
- { "special", "pdf:page:q" },
- { "special", "pdf:raw:" .. b }
+ start, -- really needed
+ not u and actualb or { "pdf", "page", (getactualtext(tounicode(u))) }
}
- local n = #t
+ local n = 2
+ local l = nil
+ local f = false
for i=1,s do
local entry = colorlist[i]
- n = n + 1 t[n] = colorvalues[entry.class] or s_black
- n = n + 1 t[n] = { "char", entry.slot }
- if s > 1 and i < s and w ~= 0 then
- n = n + 1 t[n] = { "right", -w }
+ local v = colorvalues[entry.class] or default
+ if v and l ~= v then
+ if f then
+ n = n + 1 t[n] = pop
+ end
+ n = n + 1 t[n] = push
+ f = true
+ n = n + 1 t[n] = v
+ l = v
+ end
+ n = n + 1 t[n] = charcommand[entry.slot]
+ if s > 1 and i < s and goback then
+ n = n + 1 t[n] = goback
end
end
- n = n + 1 t[n] = { "special", "pdf:page:" .. e }
- n = n + 1 t[n] = { "special", "pdf:raw:Q" }
+ if f then
+ n = n + 1 t[n] = pop
+ end
+ n = n + 1 t[n] = actuale
+ -- n = n + 1 t[n] = stop -- not needed
character.commands = t
end
end
@@ -166,19 +299,13 @@ fonts.handlers.otf.features.register {
name = "colr",
description = "color glyphs",
manipulators = {
- base = initializecolr,
- node = initializecolr,
+ base = initialize,
+ node = initialize,
}
}
-local otfsvg = otf.svg or { }
-otf.svg = otfsvg
-otf.svgenabled = true
-
do
- local nofstreams = 0
-
-- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ]
-- local f_getstream = formatters[ [[svg-glyph-%05i]] ]
@@ -190,47 +317,152 @@ do
-- end
-- end
- local f_name = formatters[ [[svg-glyph-%05i]] ]
- local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local nofstreams = 0
+ local f_name = formatters[ [[pdf-glyph-%05i]] ]
+ local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local hashed = { }
+ local cache = { }
+
+ if epdf then
+
+ local openpdf = epdf.openMemStream
+
+ function otf.storepdfdata(pdf)
+ local done = hashed[pdf]
+ if not done then
+ nofstreams = nofstreams + 1
+ local o, n = openpdf(pdf,#pdf,f_name(nofstreams))
+ cache[n] = o -- we need to keep in mem
+ done = f_used(n)
+ hashed[pdf] = done
+ end
+ return nil, done, nil
+ end
+
+ else
- local cache = { }
+ local openpdf = pdfe.new
+ ----- prefix = "data:application/pdf,"
+
+ function otf.storepdfdata(pdf)
+ local done = hashed[pdf]
+ if not done then
+ nofstreams = nofstreams + 1
+ local f = f_name(nofstreams)
+ local n = openpdf(pdf,#pdf,f)
+ done = f_used(n)
+ hashed[pdf] = done
+ end
+ return nil, done, nil
+ end
- function otfsvg.storepdfdata(pdf)
- nofstreams = nofstreams + 1
- local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
- cache[n] = o -- we need to keep in mem
- return nil, f_used(n), nil
end
- if context then
-
- local storepdfdata = otfsvg.storepdfdata
- local initialized = false
-
- function otfsvg.storepdfdata(pdf)
- if not initialized then
- if resolvers.setmemstream then
- local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
- local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ]
- local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
- storepdfdata = function(pdf)
- nofstreams = nofstreams + 1
- return
- f_setstream(nofstreams,pdf),
- f_getstream(nofstreams),
- f_nilstream(nofstreams)
- end
- otfsvg.storepdfdata = storepdfdata
+ -- maybe more efficient but much slower (and we hash already)
+ --
+ -- if context then
+ --
+ -- local storepdfdata = otf.storepdfdata
+ -- local initialized = false
+ --
+ -- function otf.storepdfdata(pdf)
+ -- if not initialized then
+ -- if resolvers.setmemstream then
+ -- local f_setstream = formatters[ [[resolvers.setmemstream("pdf-glyph-%05i",%q,true)]] ]
+ -- local f_getstream = formatters[ [[memstream:///pdf-glyph-%05i]] ]
+ -- local f_nilstream = formatters[ [[resolvers.resetmemstream("pdf-glyph-%05i",true)]] ]
+ -- storepdfdata = function(pdf)
+ -- local done = hashed[pdf]
+ -- local set = nil
+ -- local reset = nil
+ -- if not done then
+ -- nofstreams = nofstreams + 1
+ -- set = f_setstream(nofstreams,pdf)
+ -- done = f_getstream(nofstreams)
+ -- reset = f_nilstream(nofstreams)
+ -- hashed[pdf] = done
+ -- end
+ -- return set, done, reset
+ -- end
+ -- otf.storepdfdata = storepdfdata
+ -- end
+ -- initialized = true
+ -- end
+ -- return storepdfdata(pdf)
+ -- end
+ --
+ -- end
+
+end
+
+local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg
+ if not tfmdata or not pdfshapes or not kind then
+ return
+ end
+ --
+ local characters = tfmdata.characters
+ local properties = tfmdata.properties
+ local parameters = tfmdata.parameters
+ local hfactor = parameters.hfactor
+ --
+ properties.virtualized = true
+ --
+ tfmdata.fonts = {
+ { id = 0 } -- not really needed
+ }
+ --
+ local getactualtext = otf.getactualtext
+ local storepdfdata = otf.storepdfdata
+ --
+ local b, e = getactualtext(tounicode(0xFFFD))
+ local actualb = { "pdf", "page", b } -- saves tables
+ local actuale = { "pdf", "page", e } -- saves tables
+ --
+ for unicode, character in sortedhash(characters) do -- sort is nicer for svg
+ local index = character.index
+ if index then
+ local pdf = pdfshapes[index]
+ local typ = type(pdf)
+ local data = nil
+ local dx = nil
+ local dy = nil
+ if typ == "table" then
+ data = pdf.data
+ dx = pdf.dx or 0
+ dy = pdf.dy or 0
+ elseif typ == "string" then
+ data = pdf
+ dx = 0
+ dy = 0
+ end
+ if data then
+ -- We can delay storage by a lua function in commands: but then we need to
+ -- be able to provide our own mem stream name (so that we can reserve it).
+ local setcode, name, nilcode = storepdfdata(data)
+ if name then
+ local bt = unicode and getactualtext(unicode)
+ local wd = character.width or 0
+ local ht = character.height or 0
+ local dp = character.depth or 0
+ character.commands = {
+ not unicode and actualb or { "pdf", "page", (getactualtext(unicode)) },
+ downcommand[dp + dy * hfactor],
+ rightcommand[dx * hfactor],
+ -- setcode and { "lua", setcode } or nop,
+ { "image", { filename = name, width = wd, height = ht, depth = dp } },
+ -- nilcode and { "lua", nilcode } or nop,
+ actuale,
+ }
+ character[kind] = true
end
- initialized = true
end
- return storepdfdata(pdf)
end
-
end
-
end
+local otfsvg = otf.svg or { }
+otf.svg = otfsvg
+otf.svgenabled = true
do
@@ -261,77 +493,66 @@ do
end
- -- function otfsvg.topdf(svgshapes)
- -- local svgfile = "temp-otf-svg-shape.svg"
- -- local pdffile = "temp-otf-svg-shape.pdf"
- -- local command = "inkscape " .. svgfile .. " --export-pdf=" .. pdffile
- -- local testrun = false
- -- local pdfshapes = { }
- -- local nofshapes = #svgshapes
- -- local filterglyph = otfsvg.filterglyph
- -- report_svg("processing %i svg containers",nofshapes)
- -- statistics.starttiming()
- -- for i=1,nofshapes do
- -- local entry = svgshapes[i]
- -- for index=entry.first,entry.last do
- -- local data = filterglyph(entry,index)
- -- savedata(svgfile,tostring(data))
- -- if data and data ~= "" then
- -- report_svg("processing svg shape of glyph %i in container %i",index,i)
- -- os.execute(command)
- -- pdfshapes[index] = loaddata(pdffile)
- -- end
- -- end
- -- if testrun and i > testrun then
- -- report_svg("quiting test run")
- -- break
- -- end
- -- end
- -- remove(svgfile)
- -- statistics.stoptiming()
- -- report_svg("conversion time: %0.3f",statistics.elapsedtime())
- -- return pdfshapes
- -- end
+ local runner = sandbox and sandbox.registerrunner {
+ name = "otfsvg",
+ program = "inkscape",
+ method = "pipeto",
+ template = "--shell > temp-otf-svg-shape.log",
+ reporter = report_svg,
+ }
+
+ if not runner then
+ --
+ -- poor mans variant for generic:
+ --
+ runner = function()
+ return io.open("inkscape --shell > temp-otf-svg-shape.log","w")
+ end
+ end
function otfsvg.topdf(svgshapes)
- local inkscape = io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
- local pdfshapes = { }
- local nofshapes = #svgshapes
- local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
- local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert = formatters["%s --export-pdf=%s\n"]
- local filterglyph = otfsvg.filterglyph
- report_svg("processing %i svg containers",nofshapes)
- statistics.starttiming()
- for i=1,nofshapes do
- local entry = svgshapes[i]
- for index=entry.first,entry.last do
- local data = filterglyph(entry,index)
- if data and data ~= "" then
- local svgfile = f_svgfile(index)
- local pdffile = f_pdffile(index)
- savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[index] = true
+ local pdfshapes = { }
+ local inkscape = runner()
+ if inkscape then
+ local nofshapes = #svgshapes
+ local f_svgfile = formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile = formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert = formatters["%s --export-pdf=%s\n"]
+ local filterglyph = otfsvg.filterglyph
+ local nofdone = 0
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming()
+ for i=1,nofshapes do
+ local entry = svgshapes[i]
+ for index=entry.first,entry.last do
+ local data = filterglyph(entry,index)
+ if data and data ~= "" then
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
+ savedata(svgfile,data)
+ inkscape:write(f_convert(svgfile,pdffile))
+ pdfshapes[index] = true
+ nofdone = nofdone + 1
+ if nofdone % 100 == 0 then
+ report_svg("%i shapes processed",nofdone)
+ end
+ end
end
end
- end
- inkscape:write("quit\n")
- -- while inkscape:read("*a") do
- -- os.sleep(0.1)
- -- end
- inkscape:close()
- report_svg("processing %i pdf results",nofshapes)
- for index in next, pdfshapes do
- local svgfile = f_svgfile(index)
- local pdffile = f_pdffile(index)
- pdfshapes[index] = loaddata(pdffile)
- remove(svgfile)
- remove(pdffile)
- end
- statistics.stoptiming()
- if statistics.elapsedseconds then
- report_svg("svg conversion time %s",statistics.elapsedseconds())
+ inkscape:write("quit\n")
+ inkscape:close()
+ report_svg("processing %i pdf results",nofshapes)
+ for index in next, pdfshapes do
+ local svgfile = f_svgfile(index)
+ local pdffile = f_pdffile(index)
+ pdfshapes[index] = loaddata(pdffile)
+ remove(svgfile)
+ remove(pdffile)
+ end
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
+ end
end
return pdfshapes
end
@@ -340,17 +561,12 @@ end
local function initializesvg(tfmdata,kind,value) -- hm, always value
if value and otf.svgenabled then
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local properties = tfmdata.properties
- --
- local svg = properties.svg
+ local svg = tfmdata.properties.svg
local hash = svg and svg.hash
local timestamp = svg and svg.timestamp
if not hash then
return
end
- --
local pdffile = containers.read(otf.pdfcache,hash)
local pdfshapes = pdffile and pdffile.pdfshapes
if not pdfshapes or pdffile.timestamp ~= timestamp then
@@ -362,44 +578,7 @@ local function initializesvg(tfmdata,kind,value) -- hm, always value
timestamp = timestamp,
})
end
- if not pdfshapes or not next(pdfshapes) then
- return
- end
- --
- properties.virtualized = true
- tfmdata.fonts = {
- { id = 0 }
- }
- --
- local getactualtext = otf.getactualtext
- local storepdfdata = otfsvg.storepdfdata
- --
- local nop = { "nop" }
- --
- for unicode, character in next, characters do
- local index = character.index
- if index then
- local pdf = pdfshapes[index]
- if pdf then
- local setcode, name, nilcode = storepdfdata(pdf)
- if name then
- local bt, et = getactualtext(unicode)
- local wd = character.width or 0
- local ht = character.height or 0
- local dp = character.depth or 0
- character.commands = {
- { "special", "pdf:direct:" .. bt },
- { "down", dp },
- setcode and { "lua", setcode } or nop,
- { "image", { filename = name, width = wd, height = ht, depth = dp } },
- nilcode and { "lua", nilcode } or nop,
- { "special", "pdf:direct:" .. et },
- }
- character.svg = true
- end
- end
- end
- end
+ pdftovirtual(tfmdata,pdfshapes,"svg")
end
end
@@ -411,3 +590,114 @@ fonts.handlers.otf.features.register {
node = initializesvg,
}
}
+
+-- This can be done differently e.g. with ffi and gm and we can share code anway. Using
+-- batchmode in gm is not faster and as it accumulates we would need to flush all
+-- individual shapes.
+
+local otfsbix = otf.sbix or { }
+otf.sbix = otfsbix
+otf.sbixenabled = true
+
+do
+
+ -- for now png but also other bitmap formats
+
+ local report_sbix = logs.reporter("fonts","sbix conversion")
+
+ local loaddata = io.loaddata
+ local savedata = io.savedata
+ local remove = os.remove
+
+ local runner = sandbox and sandbox.registerrunner {
+ name = "otfsbix",
+ program = "gm",
+ template = "convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log",
+ -- reporter = report_sbix,
+ }
+
+ if not runner then
+ --
+ -- poor mans variant for generic:
+ --
+ runner = function()
+ return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log")
+ end
+ end
+
+ -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from
+ -- that file but creating thousands of small files is no fun either.
+
+ function otfsbix.topdf(sbixshapes)
+ local pdfshapes = { }
+ local sbixfile = "temp-otf-sbix-shape.sbix"
+ local pdffile = "temp-otf-sbix-shape.pdf"
+ local nofdone = 0
+ local indices = sortedkeys(sbixshapes) -- can be sparse
+ local nofindices = #indices
+ report_sbix("processing %i sbix containers",nofindices)
+ statistics.starttiming()
+ for i=1,nofindices do
+ local index = indices[i]
+ local entry = sbixshapes[index]
+ local data = entry.data
+ local x = entry.x
+ local y = entry.y
+ savedata(sbixfile,data)
+ runner()
+ pdfshapes[index] = {
+ x = x ~= 0 and x or nil,
+ y = y ~= 0 and y or nil,
+ data = loaddata(pdffile),
+ }
+ nofdone = nofdone + 1
+ if nofdone % 100 == 0 then
+ report_sbix("%i shapes processed",nofdone)
+ end
+ end
+ report_sbix("processing %i pdf results",nofindices)
+ remove(sbixfile)
+ remove(pdffile)
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ return pdfshapes
+ -- end
+ end
+
+end
+
+local function initializesbix(tfmdata,kind,value) -- hm, always value
+ if value and otf.sbixenabled then
+ local sbix = tfmdata.properties.sbix
+ local hash = sbix and sbix.hash
+ local timestamp = sbix and sbix.timestamp
+ if not hash then
+ return
+ end
+ local pdffile = containers.read(otf.pdfcache,hash)
+ local pdfshapes = pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp ~= timestamp then
+ local sbixfile = containers.read(otf.sbixcache,hash)
+ local sbixshapes = sbixfile and sbixfile.sbixshapes
+ pdfshapes = sbixshapes and otfsbix.topdf(sbixshapes) or { }
+ containers.write(otf.pdfcache, hash, {
+ pdfshapes = pdfshapes,
+ timestamp = timestamp,
+ })
+ end
+ --
+ pdftovirtual(tfmdata,pdfshapes,"sbix")
+ end
+end
+
+fonts.handlers.otf.features.register {
+ name = "sbix",
+ description = "sbix glyphs",
+ manipulators = {
+ base = initializesbix,
+ node = initializesbix,
+ }
+}
+
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua
index d9b9c65dff4..85b9d406e18 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua
@@ -22,12 +22,11 @@ add features.</p>
local fonts, logs, trackers, containers, resolvers = fonts, logs, trackers, containers, resolvers
local next, type, tonumber, rawget = next, type, tonumber, rawget
-local match, gmatch, lower, gsub, strip, find = string.match, string.gmatch, string.lower, string.gsub, string.strip, string.find
-local char, byte, sub = string.char, string.byte, string.sub
+local match, gsub = string.match, string.gsub
local abs = math.abs
-local bxor, rshift = bit32.bxor, bit32.rshift
local P, S, R, Cmt, C, Ct, Cs, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg
local lpegmatch, patterns = lpeg.match, lpeg.patterns
+local sortedhash = table.sortedhash
local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
@@ -41,6 +40,8 @@ local derivetable = table.derive
local findbinfile = resolvers.findbinfile
+local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF
+
local definers = fonts.definers
local readers = fonts.readers
local constructors = fonts.constructors
@@ -58,7 +59,7 @@ local registerafmfeature = afmfeatures.register
local afmenhancers = constructors.enhancers.afm
local registerafmenhancer = afmenhancers.register
-afm.version = 1.512 -- incrementing this number one up will force a re-cache
+afm.version = 1.513 -- incrementing this number one up will force a re-cache
afm.cache = containers.define("fonts", "one", afm.version, true)
afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*)
@@ -85,7 +86,7 @@ function afm.load(filename)
local name = file.removesuffix(file.basename(filename))
local data = containers.read(afm.cache,name)
local attr = lfs.attributes(filename)
- local size, time = attr.size or 0, attr.modification or 0
+ local size, time = attr and attr.size or 0, attr and attr.modification or 0
--
local pfbfile = file.replacesuffix(name,"pfb")
local pfbname = resolvers.findfile(pfbfile,"pfb") or ""
@@ -139,9 +140,9 @@ local function enhance_unify_names(data, filename)
local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
local unicodes = { }
local names = { }
- local private = constructors.privateoffset
+ local private = data.private or privateoffset
local descriptions = data.descriptions
- for name, blob in next, data.characters do
+ for name, blob in sortedhash(data.characters) do -- sorting is nicer for privates
local code = unicodevector[name] -- or characters.name_to_unicode[name]
if not code then
code = lpegmatch(uparser,name)
@@ -179,13 +180,13 @@ local function enhance_unify_names(data, filename)
end
end
data.characters = nil
+ data.private = private
local resources = data.resources
- local filename = resources.filename or file.removesuffix(file.basename(filename))
+ local filename = resources.filename or file.removesuffix(file.basename(filename))
resources.filename = resolvers.unresolve(filename) -- no shortcut
resources.unicodes = unicodes -- name to unicode
- resources.marks = { } -- todo
- -- resources.names = names -- name to index
- resources.private = private
+ resources.marks = { } -- todo
+ -- resources.names = names -- name to index
end
local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
@@ -587,6 +588,7 @@ local function copytotfm(data)
properties.fullname = fullname
properties.psname = fullname
properties.name = filename or fullname or fontname
+ properties.private = properties.private or data.private or privateoffset
--
if next(characters) then
return {
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-onr.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-onr.lua
index 6c33b24c644..7c806c69206 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-onr.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-onr.lua
@@ -41,7 +41,7 @@ handlers.afm = afm
local readers = afm.readers or { }
afm.readers = readers
-afm.version = 1.512 -- incrementing this number one up will force a re-cache
+afm.version = 1.513 -- incrementing this number one up will force a re-cache
--[[ldx--
<p>We start with the basic reader which we give a name similar to the built in <l n='tfm'/>
@@ -89,7 +89,7 @@ do
local dup = P("dup")
local put = P("put")
local array = P("array")
- local name = P("/") * C((R("az")+R("AZ")+R("09")+S("-_."))^1)
+ local name = P("/") * C((R("az","AZ","09")+S("-_."))^1)
local digits = R("09")^1
local cardinal = digits / tonumber
local spaces = P(" ")^1
@@ -103,32 +103,40 @@ do
return position + 1
end
- local setroutine = function(str,position,index,size)
+ local setroutine = function(str,position,index,size,filename)
local forward = position + tonumber(size)
- local stream = sub(str,position+1,forward)
- routines[index] = decrypt(stream,4330,4)
+ local stream = decrypt(sub(str,position+1,forward),4330,4)
+ routines[index] = { byte(stream,1,#stream) }
return forward
end
- local setvector = function(str,position,name,size)
+ local setvector = function(str,position,name,size,filename)
local forward = position + tonumber(size)
if n >= m then
return #str
elseif forward < #str then
+ if n == 0 and name ~= ".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename) -- luatex needs that
+ n = n + 1
+ end
vector[n] = name
- n = n + 1 -- we compensate for notdef at the cff loader end
+ n = n + 1
return forward
else
return #str
end
end
- local setshapes = function(str,position,name,size)
+ local setshapes = function(str,position,name,size,filename)
local forward = position + tonumber(size)
local stream = sub(str,position+1,forward)
if n > m then
return #str
elseif forward < #str then
+ if n == 0 and name ~= ".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename) -- luatex needs that
+ n = n + 1
+ end
vector[n] = name
n = n + 1
chars [n] = decrypt(stream,4330,4)
@@ -144,15 +152,15 @@ do
local p_filterroutines = -- dup <i> <n> RD or -| <n encrypted bytes> NP or |
(1-subroutines)^0 * subroutines * spaces * Cmt(cardinal,initialize)
- * (Cmt(cardinal * spaces * cardinal * p_rd, setroutine) * p_np + P(1))^1
+ * (Cmt(cardinal * spaces * cardinal * p_rd * Carg(1), setroutine) * p_np + P(1))^1
local p_filtershapes = -- /foo <n> RD <n encrypted bytes> ND
(1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize)
- * (Cmt(name * spaces * cardinal * p_rd, setshapes) * p_nd + P(1))^1
+ * (Cmt(name * spaces * cardinal * p_rd * Carg(1) , setshapes) * p_nd + P(1))^1
local p_filternames = Ct (
(1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize)
- * (Cmt(name * spaces * cardinal, setvector) + P(1))^1
+ * (Cmt(name * spaces * cardinal * Carg(1), setvector) + P(1))^1
)
-- /Encoding 256 array
@@ -177,7 +185,7 @@ do
return
end
- if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then
+ if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then
report_pfb("no font in %a",filename)
return
end
@@ -192,14 +200,14 @@ do
binary = decrypt(binary,55665,4)
local names = { }
+
local encoding = lpegmatch(p_filterencoding,ascii)
local glyphs = { }
routines, vector, chars = { }, { }, { }
-
if shapestoo then
- lpegmatch(p_filterroutines,binary)
- lpegmatch(p_filtershapes,binary)
+ lpegmatch(p_filterroutines,binary,1,filename)
+ lpegmatch(p_filtershapes,binary,1,filename)
local data = {
dictionaries = {
{
@@ -209,9 +217,9 @@ do
}
},
}
- fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
+ fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,true)
else
- lpegmatch(p_filternames,binary)
+ lpegmatch(p_filternames,binary,1,filename)
end
names = vector
@@ -233,7 +241,7 @@ do
if trace_loading then
report_afm("getting index data from %a",pfbname)
end
- for index=1,#vector do
+ for index=0,#vector do -- hm, zero, often space or notdef
local name = vector[index]
local char = characters[name]
if char then
@@ -241,6 +249,10 @@ do
report_afm("glyph %a has index %a",name,index)
end
char.index = index
+ else
+ if trace_indexing then
+ report_afm("glyph %a has index %a but no data",name,index)
+ end
end
end
end
@@ -410,10 +422,6 @@ local fullparser = ( P("StartFontMetrics") * fontdata * name / start )
* ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0
* ( P("EndFontMetrics") / stop )
-local fullparser = ( P("StartFontMetrics") * fontdata * name / start )
- * ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0
- * ( P("EndFontMetrics") / stop )
-
local infoparser = ( P("StartFontMetrics") * fontdata * name / start )
* ( p_parameters + (1-P("EndFontMetrics")) )^0
* ( P("EndFontMetrics") / stop )
@@ -463,17 +471,17 @@ function readers.loadfont(afmname,pfbname)
local data = read(resolvers.findfile(afmname),fullparser)
if data then
if not pfbname or pfbname == "" then
- pfbname = file.replacesuffix(file.nameonly(afmname),"pfb")
- pfbname = resolvers.findfile(pfbname)
+ pfbname = resolvers.findfile(file.replacesuffix(file.nameonly(afmname),"pfb"))
end
if pfbname and pfbname ~= "" then
data.resources.filename = resolvers.unresolve(pfbname)
get_indexes(data,pfbname)
- elseif trace_loading then
+ return data
+ else -- if trace_loading then
report_afm("no pfb file for %a",afmname)
- -- data.resources.filename = "unset" -- better than loading the afm file
+ -- better than loading the afm file: data.resources.filename = rawname
+ -- but that will still crash the backend so we just return nothing now
end
- return data
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua
index b67cc924113..32d791b48e9 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua
@@ -6,72 +6,85 @@ if not modules then modules = { } end modules ['font-osd'] = { -- script devanag
license = "see context related readme files"
}
--- I'll optimize this one with ischar (much faster) when I see a reason (read: I need a
--- proper test case first).
--- This is a version of font-odv.lua adapted to the new font loader and more
--- direct hashing. The initialization code has been adapted (more efficient). One day
--- I'll speed this up ... char swapping and properties.
+-- we need to check nbsphash (context only)
-- A few remarks:
--
--- This code is a partial rewrite of the code that deals with devanagari. The data and logic
--- is by Kai Eigner and based based on Microsoft's OpenType specifications for specific
--- scripts, but with a few improvements. More information can be found at:
+-- This code is a partial rewrite of the code that deals with devanagari. The data
+-- and logic is by Kai Eigner and based based on Microsoft's OpenType specifications
+-- for specific scripts, but with a few improvements. More information can be found
+-- at:
--
-- deva: http://www.microsoft.com/typography/OpenType%20Dev/devanagari/introO.mspx
-- dev2: http://www.microsoft.com/typography/OpenType%20Dev/devanagari/intro.mspx
--
--- Rajeesh Nambiar provided patches for the malayalam variant. Thanks to feedback from
--- the mailing list some aspects could be improved.
+-- Rajeesh Nambiar provided patches for the malayalam variant. Thanks to feedback
+-- from the mailing list some aspects could be improved.
--
--- As I touched nearly all code, reshuffled it, optimized a lot, etc. etc. (imagine how
--- much can get messed up in over a week work) it could be that I introduced bugs. There
--- is more to gain (esp in the functions applied to a range) but I'll do that when
--- everything works as expected. Kai's original code is kept in font-odk.lua as a reference
--- so blame me (HH) for bugs.
+-- As I touched nearly all code, reshuffled it, optimized a lot, etc. etc. (imagine
+-- how much can get messed up in over a week work) it could be that I introduced
+-- bugs. There is more to gain (esp in the functions applied to a range) but I'll do
+-- that when everything works as expected. Kai's original code is kept in
+-- font-odk.lua as a reference so blame me (HH) for bugs. (We no longer ship that
+-- file as the code below has diverted too much and in the meantime has more than
+-- doubled in size.)
--
--- Interesting is that Kai managed to write this on top of the existing otf handler. Only a
--- few extensions were needed, like a few more analyzing states and dealing with changed
--- head nodes in the core scanner as that only happens here. There's a lot going on here
--- and it's only because I touched nearly all code that I got a bit of a picture of what
--- happens. For in-depth knowledge one needs to consult Kai.
+-- Interesting is that Kai managed to write this on top of the existing otf handler.
+-- Only a few extensions were needed, like a few more analyzing states and dealing
+-- with changed head nodes in the core scanner as that only happens here. There's a
+-- lot going on here and it's only because I touched nearly all code that I got a
+-- bit of a picture of what happens. For in-depth knowledge one needs to consult
+-- Kai.
--
--- The rewrite mostly deals with efficiency, both in terms of speed and code. We also made
--- sure that it suits generic use as well as use in ConTeXt. I removed some buglets but can
--- as well have messed up the logic by doing this. For this we keep the original around
--- as that serves as reference. Due to the lots of reshuffling glyphs quite some leaks
--- occur(red) but once I'm satisfied with the rewrite I'll weed them. I also integrated
--- initialization etc into the regular mechanisms.
+-- The rewrite mostly deals with efficiency, both in terms of speed and code. We
+-- also made sure that it suits generic use as well as use in ConTeXt. I removed
+-- some buglets but can as well have messed up the logic by doing this. For this we
+-- keep the original around as that serves as reference. Due to the lots of
+-- reshuffling glyphs quite some leaks occur(red) but once I'm satisfied with the
+-- rewrite I'll weed them. I also integrated initialization etc into the regular
+-- mechanisms.
--
--- In the meantime, we're down from 25.5-3.5=22 seconds to 17.7-3.5=14.2 seconds for a 100
--- page sample (mid 2012) with both variants so it's worth the effort. Some more speedup is
--- to be expected. Due to the method chosen it will never be real fast. If I ever become a
--- power user I'll have a go at some further speed up. I will rename some functions (and
--- features) once we don't need to check the original code. We now use a special subset
--- sequence for use inside the analyzer (after all we could can store this in the dataset
--- and save redundant analysis).
+-- In the meantime, we're down from 25.5-3.5=22 seconds to 17.7-3.5=14.2 seconds for
+-- a 100 page sample (mid 2012) with both variants so it's worth the effort. Some
+-- more speedup is to be expected. Due to the method chosen it will never be real
+-- fast. If I ever become a power user I'll have a go at some further speed up. I
+-- will rename some functions (and features) once we don't need to check the
+-- original code. We now use a special subset sequence for use inside the analyzer
+-- (after all we could can store this in the dataset and save redundant analysis).
--
--- I might go for an array approach with respect to attributes (and reshuffling). Easier.
+-- By now we have yet another incremental improved version. In the end I might
+-- rewrite the code.
--
--- Some data will move to char-def.lua (some day).
---
--- By now we have yet another incremental improved version. In the end I might rewrite the
--- code.
-
-- Hans Hagen, PRAGMA-ADE, Hasselt NL
---
--- We could have c_nukta, c_halant, c_ra is we know that they are never used mixed within
--- one script .. yes or no?
+
+-- Todo:
--
-- Matras: according to Microsoft typography specifications "up to one of each type:
-- pre-, above-, below- or post- base", but that does not seem to be right. It could
-- become an option.
+--
+-- Resources:
+--
+-- The tables that we had here are now generated from char-def.lua or in the case of
+-- generic usage loaded from luatex-basics-chr.lua. Still a couple of entries need
+-- to be added to char-def.lua but finally I moved the indic specific tables there.
+-- For generic usage one can create the relevant resources by running:
+--
+-- context luatex-basics-prepare.tex
+--
+-- and an overview with:
+--
+-- context --global s-fonts-basics.mkiv
+--
+-- For now we have defined: bengali, devanagari, gujarati, gurmukhi, kannada,
+-- malayalam, oriya, tamil and tolugu but not all are checked. Also, some of the
+-- code below might need to be adapted to the extra scripts.
local insert, imerge, copy = table.insert, table.imerge, table.copy
local next, type = next, type
-local report_devanagari = logs.reporter("otf","devanagari")
+local report = logs.reporter("otf","devanagari")
fonts = fonts or { }
fonts.analyzers = fonts.analyzers or { }
@@ -86,8 +99,6 @@ local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
local nuts = nodes.nuts
-local tonode = nuts.tonode
-local tonut = nuts.tonut
local getnext = nuts.getnext
local getprev = nuts.getprev
@@ -121,6 +132,9 @@ local a_state = attributes.private('state')
local a_syllabe = attributes.private('syllabe')
local dotted_circle = 0x25CC
+local c_nbsp = 0x00A0
+local c_zwnj = 0x200C
+local c_zwj = 0x200D
local states = fonts.analyzers.states -- not features
@@ -139,327 +153,193 @@ replace_all_nbsp = function(head) -- delayed definition
return replace_all_nbsp(head)
end
-local xprocesscharacters = nil
+local processcharacters = nil
if context then
- xprocesscharacters = function(head,font)
- xprocesscharacters = nodes.handlers.characters
- return xprocesscharacters(head,font)
+ local fontprocesses = fonts.hashes.processes
+ function processcharacters(head,font)
+ local processors = fontprocesses[font]
+ for i=1,#processors do
+ head = processors[i](head,font,0)
+ end
+ return head
end
else
- xprocesscharacters = function(head,font)
- xprocesscharacters = nodes.handlers.nodepass -- generic
- return xprocesscharacters(head,font)
+ function processcharacters(head,font)
+ local processors = fontdata[font].shared.processes
+ for i=1,#processors do
+ head = processors[i](head,font,0)
+ end
+ return head
end
end
-local function processcharacters(head,font)
- return tonut(xprocesscharacters(tonode(head))) -- can be more efficient in context, just direct call
-end
-
--- local fontprocesses = fonts.hashes.processes
---
--- function processcharacters(head,font)
--- local processors = fontprocesses[font]
--- for i=1,#processors do
--- head = processors[i](head,font,0)
--- end
--- return head, true
--- end
-
--- In due time there will be entries here for scripts like Bengali, Gujarati,
--- Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu. Feel free to provide the
--- code points.
-
-- We can assume that script are not mixed in the source but if that is the case
-- we might need to have consonants etc per script and initialize a local table
--- pointing to the right one.
-
--- new, to be checked:
---
--- U+00978 : DEVANAGARI LETTER MARWARI DDA
--- U+00980 : BENGALI ANJI
--- U+00C00 : TELUGU SIGN COMBINING CANDRABINDU ABOVE
--- U+00C34 : TELUGU LETTER LLLA
--- U+00C81 : KANNADA SIGN CANDRABINDU
--- U+00D01 : MALAYALAM SIGN CANDRABINDU
--- U+00DE6 : SINHALA LITH DIGIT ZERO
--- U+00DE7 : SINHALA LITH DIGIT ONE
--- U+00DE8 : SINHALA LITH DIGIT TWO
--- U+00DE9 : SINHALA LITH DIGIT THREE
--- U+00DEA : SINHALA LITH DIGIT FOUR
--- U+00DEB : SINHALA LITH DIGIT FIVE
--- U+00DEC : SINHALA LITH DIGIT SIX
--- U+00DED : SINHALA LITH DIGIT SEVEN
--- U+00DEE : SINHALA LITH DIGIT EIGHT
--- U+00DEF : SINHALA LITH DIGIT NINE
-
-local consonant = {
- -- devanagari
- [0x0915] = true, [0x0916] = true, [0x0917] = true, [0x0918] = true,
- [0x0919] = true, [0x091A] = true, [0x091B] = true, [0x091C] = true,
- [0x091D] = true, [0x091E] = true, [0x091F] = true, [0x0920] = true,
- [0x0921] = true, [0x0922] = true, [0x0923] = true, [0x0924] = true,
- [0x0925] = true, [0x0926] = true, [0x0927] = true, [0x0928] = true,
- [0x0929] = true, [0x092A] = true, [0x092B] = true, [0x092C] = true,
- [0x092D] = true, [0x092E] = true, [0x092F] = true, [0x0930] = true,
- [0x0931] = true, [0x0932] = true, [0x0933] = true, [0x0934] = true,
- [0x0935] = true, [0x0936] = true, [0x0937] = true, [0x0938] = true,
- [0x0939] = true, [0x0958] = true, [0x0959] = true, [0x095A] = true,
- [0x095B] = true, [0x095C] = true, [0x095D] = true, [0x095E] = true,
- [0x095F] = true, [0x0979] = true, [0x097A] = true,
- -- kannada
- [0x0C95] = true, [0x0C96] = true, [0x0C97] = true, [0x0C98] = true,
- [0x0C99] = true, [0x0C9A] = true, [0x0C9B] = true, [0x0C9C] = true,
- [0x0C9D] = true, [0x0C9E] = true, [0x0C9F] = true, [0x0CA0] = true,
- [0x0CA1] = true, [0x0CA2] = true, [0x0CA3] = true, [0x0CA4] = true,
- [0x0CA5] = true, [0x0CA6] = true, [0x0CA7] = true, [0x0CA8] = true,
- [0x0CA9] = true, [0x0CAA] = true, [0x0CAB] = true, [0x0CAC] = true,
- [0x0CAD] = true, [0x0CAE] = true, [0x0CAF] = true, [0x0CB0] = true,
- [0x0CB1] = true, [0x0CB2] = true, [0x0CB3] = true, [0x0CB4] = true,
- [0x0CB5] = true, [0x0CB6] = true, [0x0CB7] = true, [0x0CB8] = true,
- [0x0CB9] = true,
- [0x0CDE] = true, -- obsolete
- -- malayalam
- [0x0D15] = true, [0x0D16] = true, [0x0D17] = true, [0x0D18] = true,
- [0x0D19] = true, [0x0D1A] = true, [0x0D1B] = true, [0x0D1C] = true,
- [0x0D1D] = true, [0x0D1E] = true, [0x0D1F] = true, [0x0D20] = true,
- [0x0D21] = true, [0x0D22] = true, [0x0D23] = true, [0x0D24] = true,
- [0x0D25] = true, [0x0D26] = true, [0x0D27] = true, [0x0D28] = true,
- [0x0D29] = true, [0x0D2A] = true, [0x0D2B] = true, [0x0D2C] = true,
- [0x0D2D] = true, [0x0D2E] = true, [0x0D2F] = true, [0x0D30] = true,
- [0x0D31] = true, [0x0D32] = true, [0x0D33] = true, [0x0D34] = true,
- [0x0D35] = true, [0x0D36] = true, [0x0D37] = true, [0x0D38] = true,
- [0x0D39] = true, [0x0D3A] = true,
-}
+-- pointing to the right one. But not now.
-local independent_vowel = {
- -- devanagari
- [0x0904] = true, [0x0905] = true, [0x0906] = true, [0x0907] = true,
- [0x0908] = true, [0x0909] = true, [0x090A] = true, [0x090B] = true,
- [0x090C] = true, [0x090D] = true, [0x090E] = true, [0x090F] = true,
- [0x0910] = true, [0x0911] = true, [0x0912] = true, [0x0913] = true,
- [0x0914] = true, [0x0960] = true, [0x0961] = true, [0x0972] = true,
- [0x0973] = true, [0x0974] = true, [0x0975] = true, [0x0976] = true,
- [0x0977] = true,
- -- kannada
- [0x0C85] = true, [0x0C86] = true, [0x0C87] = true, [0x0C88] = true,
- [0x0C89] = true, [0x0C8A] = true, [0x0C8B] = true, [0x0C8C] = true,
- [0x0C8D] = true, [0x0C8E] = true, [0x0C8F] = true, [0x0C90] = true,
- [0x0C91] = true, [0x0C92] = true, [0x0C93] = true, [0x0C94] = true,
- -- malayalam
- [0x0D05] = true, [0x0D06] = true, [0x0D07] = true, [0x0D08] = true,
- [0x0D09] = true, [0x0D0A] = true, [0x0D0B] = true, [0x0D0C] = true,
- [0x0D0E] = true, [0x0D0F] = true, [0x0D10] = true, [0x0D12] = true,
- [0x0D13] = true, [0x0D14] = true,
-}
-
-local dependent_vowel = { -- matra
- -- devanagari
- [0x093A] = true, [0x093B] = true, [0x093E] = true, [0x093F] = true,
- [0x0940] = true, [0x0941] = true, [0x0942] = true, [0x0943] = true,
- [0x0944] = true, [0x0945] = true, [0x0946] = true, [0x0947] = true,
- [0x0948] = true, [0x0949] = true, [0x094A] = true, [0x094B] = true,
- [0x094C] = true, [0x094E] = true, [0x094F] = true, [0x0955] = true,
- [0x0956] = true, [0x0957] = true, [0x0962] = true, [0x0963] = true,
- -- kannada
- [0x0CBE] = true, [0x0CBF] = true, [0x0CC0] = true, [0x0CC1] = true,
- [0x0CC2] = true, [0x0CC3] = true, [0x0CC4] = true, [0x0CC5] = true,
- [0x0CC6] = true, [0x0CC7] = true, [0x0CC8] = true, [0x0CC9] = true,
- [0x0CCA] = true, [0x0CCB] = true, [0x0CCC] = true,
- -- malayalam
- [0x0D3E] = true, [0x0D3F] = true, [0x0D40] = true, [0x0D41] = true,
- [0x0D42] = true, [0x0D43] = true, [0x0D44] = true, [0x0D46] = true,
- [0x0D47] = true, [0x0D48] = true, [0x0D4A] = true, [0x0D4B] = true,
- [0x0D4C] = true, [0x0D57] = true,
-}
+local indicgroups = characters and characters.indicgroups
-local vowel_modifier = {
- -- devanagari
- [0x0900] = true, [0x0901] = true, [0x0902] = true, [0x0903] = true,
- -- A8E0 - A8F1 are cantillation marks for the Samaveda and may not belong here.
- [0xA8E0] = true, [0xA8E1] = true, [0xA8E2] = true, [0xA8E3] = true,
- [0xA8E4] = true, [0xA8E5] = true, [0xA8E6] = true, [0xA8E7] = true,
- [0xA8E8] = true, [0xA8E9] = true, [0xA8EA] = true, [0xA8EB] = true,
- [0xA8EC] = true, [0xA8ED] = true, [0xA8EE] = true, [0xA8EF] = true,
- [0xA8F0] = true, [0xA8F1] = true,
- -- malayalam
- [0x0D02] = true, [0x0D03] = true,
-}
+if not indicgroups and characters then
-local stress_tone_mark = {
- [0x0951] = true, [0x0952] = true, [0x0953] = true, [0x0954] = true,
- -- kannada
- [0x0CCD] = true,
- -- malayalam
- [0x0D4D] = true,
-}
+ local indic = {
+ c = { }, -- consonant
+ i = { }, -- independent vowel
+ d = { }, -- dependent vowel
+ m = { }, -- vowel modifier
+ s = { }, -- stress tone mark
+ o = { }, -- other
+ }
-local nukta = {
- -- devanagari
- [0x093C] = true,
- -- kannada:
- [0x0CBC] = true,
-}
+ local indicmarks = {
+ l = { }, -- left | pre_mark
+ t = { }, -- top | above_mark
+ b = { }, -- bottom | below_mark
+ r = { }, -- right | post_mark
+ s = { }, -- split | twopart_mark
+ }
-local halant = {
- -- devanagari
- [0x094D] = true,
- -- kannada
- [0x0CCD] = true,
- -- malayalam
- [0x0D4D] = true,
-}
+ local indicclasses = {
+ nukta = { },
+ halant = { },
+ ra = { },
+ anudatta = { },
+ }
-local ra = {
- -- devanagari
- [0x0930] = true,
- -- kannada
- [0x0CB0] = true,
- -- malayalam
- [0x0D30] = true,
-}
+ local indicorders = {
+ bp = { }, -- before_postscript
+ ap = { }, -- after_postscript
+ bs = { }, -- before_half
+ as = { }, -- after_half
+ bh = { }, -- before_subscript
+ ah = { }, -- after_subscript
+ bm = { }, -- before_main
+ am = { }, -- after_main
+ }
-local c_anudatta = 0x0952 -- used to be tables
-local c_nbsp = 0x00A0 -- used to be tables
-local c_zwnj = 0x200C -- used to be tables
-local c_zwj = 0x200D -- used to be tables
+ for k, v in next, characters.data do
+ local i = v.indic
+ if i then
+ indic[i][k] = true
+ i = v.indicmark
+ if i then
+ if i == "s" then
+ local s = v.specials
+ indicmarks[i][k] = { s[2], s[3] }
+ else
+ indicmarks[i][k] = true
+ end
+ end
+ i = v.indicclass
+ if i then
+ indicclasses[i][k] = true
+ end
+ i = v.indicorder
+ if i then
+ indicorders[i][k] = true
+ end
+ end
+ end
-local zw_char = { -- could also be inlined
- [0x200C] = true,
- [0x200D] = true,
-}
+ indicgroups = {
+ consonant = indic.c,
+ independent_vowel = indic.i,
+ dependent_vowel = indic.d,
+ vowel_modifier = indic.m,
+ stress_tone_mark = indic.s,
+ -- other = indic.o,
+ pre_mark = indicmarks.l,
+ above_mark = indicmarks.t,
+ below_mark = indicmarks.b,
+ post_mark = indicmarks.r,
+ twopart_mark = indicmarks.s,
+ nukta = indicclasses.nukta,
+ halant = indicclasses.halant,
+ ra = indicclasses.ra,
+ anudatta = indicclasses.anudatta,
+ before_postscript = indicorders.bp,
+ after_postscript = indicorders.ap,
+ before_half = indicorders.bh,
+ after_half = indicorders.ah,
+ before_subscript = indicorders.bs,
+ after_subscript = indicorders.as,
+ before_main = indicorders.bm,
+ after_main = indicorders.am,
+ }
--- 0C82 anusvara
--- 0C83 visarga
--- 0CBD avagraha
--- 0CD5 length mark
--- 0CD6 ai length mark
--- 0CE0 letter ll
--- 0CE1 letter rr
--- 0CE2 vowel sign l
--- 0CE2 vowel sign ll
--- 0CF1 sign
--- 0CF2 sign
--- OCE6 - OCEF digits
-
-local pre_mark = {
- [0x093F] = true, [0x094E] = true,
- -- malayalam
- [0x0D46] = true, [0x0D47] = true, [0x0D48] = true,
-}
+ indic = nil
+ indicmarks = nil
+ indicclasses = nil
+ indicorders = nil
-local above_mark = {
- [0x0900] = true, [0x0901] = true, [0x0902] = true, [0x093A] = true,
- [0x0945] = true, [0x0946] = true, [0x0947] = true, [0x0948] = true,
- [0x0951] = true, [0x0953] = true, [0x0954] = true, [0x0955] = true,
- [0xA8E0] = true, [0xA8E1] = true, [0xA8E2] = true, [0xA8E3] = true,
- [0xA8E4] = true, [0xA8E5] = true, [0xA8E6] = true, [0xA8E7] = true,
- [0xA8E8] = true, [0xA8E9] = true, [0xA8EA] = true, [0xA8EB] = true,
- [0xA8EC] = true, [0xA8ED] = true, [0xA8EE] = true, [0xA8EF] = true,
- [0xA8F0] = true, [0xA8F1] = true,
- -- malayalam
- [0x0D4E] = true,
-}
+ characters.indicgroups = indicgroups
-local below_mark = {
- [0x093C] = true, [0x0941] = true, [0x0942] = true, [0x0943] = true,
- [0x0944] = true, [0x094D] = true, [0x0952] = true, [0x0956] = true,
- [0x0957] = true, [0x0962] = true, [0x0963] = true,
-}
+end
-local post_mark = {
- [0x0903] = true, [0x093B] = true, [0x093E] = true, [0x0940] = true,
- [0x0949] = true, [0x094A] = true, [0x094B] = true, [0x094C] = true,
- [0x094F] = true,
-}
+local consonant = indicgroups.consonant
+local independent_vowel = indicgroups.independent_vowel
+local dependent_vowel = indicgroups.dependent_vowel
+local vowel_modifier = indicgroups.vowel_modifier
+local stress_tone_mark = indicgroups.stress_tone_mark
+local pre_mark = indicgroups.pre_mark
+local above_mark = indicgroups.above_mark
+local below_mark = indicgroups.below_mark
+local post_mark = indicgroups.post_mark
+local twopart_mark = indicgroups.twopart_mark
+local nukta = indicgroups.nukta
+local halant = indicgroups.halant
+local ra = indicgroups.ra
+local anudatta = indicgroups.anudatta
+
+local before_postscript = indicgroups.before_postscript
+local after_postscript = indicgroups.after_postscript
+local before_half = indicgroups.before_half
+local after_half = indicgroups.after_half
+local before_subscript = indicgroups.before_subscript
+local after_subscript = indicgroups.after_subscript
+local before_main = indicgroups.before_main
+local after_main = indicgroups.after_main
+
+local mark_four = table.merged (
+ pre_mark,
+ above_mark,
+ below_mark,
+ post_mark
+)
+
+local mark_above_below_post = table.merged (
+ above_mark,
+ below_mark,
+ post_mark
+)
-local twopart_mark = {
- -- malayalam
- [0x0D4A] = { 0x0D46, 0x0D3E, }, -- ൊ
- [0x0D4B] = { 0x0D47, 0x0D3E, }, -- ോ
- [0x0D4C] = { 0x0D46, 0x0D57, }, -- ൌ
-}
+-- We use some pseudo features as we need to manipulate the nodelist based
+-- on information in the font as well as already applied features. We can
+-- probably replace some of the code below by injecting 'real' features
+-- using the extension mechanism.
-local mark_four = { } -- As we access these frequently an extra hash is used.
-
-for k, v in next, pre_mark do mark_four[k] = pre_mark end
-for k, v in next, above_mark do mark_four[k] = above_mark end
-for k, v in next, below_mark do mark_four[k] = below_mark end
-for k, v in next, post_mark do mark_four[k] = post_mark end
-
-local mark_above_below_post = { }
-
-for k, v in next, above_mark do mark_above_below_post[k] = above_mark end
-for k, v in next, below_mark do mark_above_below_post[k] = below_mark end
-for k, v in next, post_mark do mark_above_below_post[k] = post_mark end
-
--- Again, this table can be extended for other scripts than devanagari. Actually,
--- for ConTeXt this kind of data is kept elsewhere so eventually we might move
--- tables to someplace else.
-
-local reorder_class = {
- -- devanagari
- [0x0930] = "before postscript",
- [0x093F] = "before half",
- [0x0940] = "after subscript",
- [0x0941] = "after subscript",
- [0x0942] = "after subscript",
- [0x0943] = "after subscript",
- [0x0944] = "after subscript",
- [0x0945] = "after subscript",
- [0x0946] = "after subscript",
- [0x0947] = "after subscript",
- [0x0948] = "after subscript",
- [0x0949] = "after subscript",
- [0x094A] = "after subscript",
- [0x094B] = "after subscript",
- [0x094C] = "after subscript",
- [0x0962] = "after subscript",
- [0x0963] = "after subscript",
- [0x093E] = "after subscript",
- -- kannada:
- [0x0CB0] = "after postscript", -- todo in code below
- [0x0CBF] = "before subscript", -- todo in code below
- [0x0CC6] = "before subscript", -- todo in code below
- [0x0CCC] = "before subscript", -- todo in code below
- [0x0CBE] = "before subscript", -- todo in code below
- [0x0CE2] = "before subscript", -- todo in code below
- [0x0CE3] = "before subscript", -- todo in code below
- [0x0CC1] = "before subscript", -- todo in code below
- [0x0CC2] = "before subscript", -- todo in code below
- [0x0CC3] = "after subscript",
- [0x0CC4] = "after subscript",
- [0x0CD5] = "after subscript",
- [0x0CD6] = "after subscript",
- -- malayalam
+local zw_char = { -- both_joiners_true
+ [c_zwnj] = true,
+ [c_zwj ] = true,
}
--- We use some pseudo features as we need to manipulate the nodelist based
--- on information in the font as well as already applied features.
-
local dflt_true = {
dflt = true
}
-local dev2_defaults = {
+local two_defaults = {
dev2 = dflt_true,
}
-local deva_defaults = {
+local one_defaults = {
dev2 = dflt_true,
deva = dflt_true,
}
local false_flags = { false, false, false, false }
-local both_joiners_true = {
- [0x200C] = true,
- [0x200D] = true,
-}
-
local sequence_reorder_matras = {
- features = { dv01 = dev2_defaults },
+ features = { dv01 = two_defaults },
flags = false_flags,
name = "dv01_reorder_matras",
order = { "dv01" },
@@ -467,14 +347,13 @@ local sequence_reorder_matras = {
nofsteps = 1,
steps = {
{
- osdstep = true,
coverage = pre_mark,
}
}
}
local sequence_reorder_reph = {
- features = { dv02 = dev2_defaults },
+ features = { dv02 = two_defaults },
flags = false_flags,
name = "dv02_reorder_reph",
order = { "dv02" },
@@ -482,14 +361,13 @@ local sequence_reorder_reph = {
nofsteps = 1,
steps = {
{
- osdstep = true,
coverage = { },
}
}
}
local sequence_reorder_pre_base_reordering_consonants = {
- features = { dv03 = dev2_defaults },
+ features = { dv03 = two_defaults },
flags = false_flags,
name = "dv03_reorder_pre_base_reordering_consonants",
order = { "dv03" },
@@ -497,22 +375,21 @@ local sequence_reorder_pre_base_reordering_consonants = {
nofsteps = 1,
steps = {
{
- osdstep = true,
coverage = { },
}
}
}
local sequence_remove_joiners = {
- features = { dv04 = deva_defaults },
+ features = { dv04 = one_defaults },
flags = false_flags,
name = "dv04_remove_joiners",
order = { "dv04" },
type = "devanagari_remove_joiners",
nofsteps = 1,
steps = {
- { osdstep = true,
- coverage = both_joiners_true,
+ {
+ coverage = zw_char, -- both_joiners_true
},
}
}
@@ -522,38 +399,85 @@ local sequence_remove_joiners = {
-- as it might depends on the font. Not that it's a bottleneck.
local basic_shaping_forms = {
- nukt = true,
+ -- init = true, -- new
+ -- abvs = true, -- new
akhn = true,
- rphf = true,
- pref = true,
- rkrf = true,
blwf = true,
+ -- calt = true, -- new
+ cjct = true,
half = true,
+ -- haln = true, -- new
+ nukt = true,
+ pref = true,
+ -- pres = true, -- new
pstf = true,
+ -- psts = true, -- new
+ rkrf = true,
+ rphf = true,
vatu = true,
- cjct = true,
}
local valid = {
- akhn = true, -- malayalam
- rphf = true,
- pref = true,
- half = true,
+ -- akhn = true, -- malayalam
+ -- rphf = true,
+ -- pref = true,
+ -- half = true,
+ -- blwf = true,
+ -- pstf = true,
+ -- pres = true, -- malayalam
+ -- blws = true, -- malayalam
+ -- psts = true, -- malayalam
+ abvs = true,
+ akhn = true,
blwf = true,
+ calt = true,
+ cjct = true,
+ half = true,
+ haln = true,
+ nukt = true,
+ pref = true,
+ pres = true,
pstf = true,
- pres = true, -- malayalam
- blws = true, -- malayalam
- psts = true, -- malayalam
+ psts = true,
+ rkrf = true,
+ rphf = true,
+ vatu = true,
+ pres = true,
+ abvs = true,
+ blws = true,
+ psts = true,
+ haln = true,
+ calt = true,
}
+local scripts = { }
+
+local scripts_one = { "deva", "mlym", "beng", "gujr", "guru", "knda", "orya", "taml", "telu" }
+local scripts_two = { "dev2", "mlm2", "bng2", "gjr2", "gur2", "knd2", "ory2", "tml2", "tel2" }
+
+local nofscripts = #scripts_one
+
+for i=1,nofscripts do
+ local one = scripts_one[i]
+ local two = scripts_two[i]
+ scripts[one] = true
+ scripts[two] = true
+ two_defaults[one] = dflt_true
+ one_defaults[one] = dflt_true
+ one_defaults[two] = dflt_true
+end
+
+local function valid_one(s) for i=1,nofscripts do if s[scripts_one[i]] then return true end end end
+local function valid_two(s) for i=1,nofscripts do if s[scripts_two[i]] then return true end end end
+
local function initializedevanagi(tfmdata)
local script, language = otf.scriptandlanguage(tfmdata,attr) -- todo: take fast variant
- if script == "deva" or script == "dev2" or script =="mlym" or script == "mlm2" then
+ if scripts[script] then
local resources = tfmdata.resources
local devanagari = resources.devanagari
if not devanagari then
--
- report_devanagari("adding devanagari features to font")
+ report("adding devanagari features to font")
--
local gsubfeatures = resources.features.gsub
local sequences = resources.sequences
@@ -572,10 +496,10 @@ local function initializedevanagi(tfmdata)
end
local insertindex = lastmatch + 1
--
- gsubfeatures["dv01"] = dev2_defaults -- reorder matras
- gsubfeatures["dv02"] = dev2_defaults -- reorder reph
- gsubfeatures["dv03"] = dev2_defaults -- reorder pre base reordering consonants
- gsubfeatures["dv04"] = deva_defaults -- remove joiners
+ gsubfeatures["dv01"] = two_defaults -- reorder matras
+ gsubfeatures["dv02"] = two_defaults -- reorder reph
+ gsubfeatures["dv03"] = two_defaults -- reorder pre base reordering consonants
+ gsubfeatures["dv04"] = one_defaults -- remove joiners
--
local reorder_pre_base_reordering_consonants = copy(sequence_reorder_pre_base_reordering_consonants)
local reorder_reph = copy(sequence_reorder_reph)
@@ -631,43 +555,31 @@ local function initializedevanagi(tfmdata)
end
end
end
- for kind, spec in next, features do -- beware, this is
- if spec.dev2 and valid[kind] then
+ for kind, spec in next, features do
+ -- if spec.dev2 and valid[kind] then
+ if valid[kind] and valid_two(spec)then
for i=1,nofsteps do
local step = steps[i]
local coverage = step.coverage
if coverage then
local reph = false
if kind == "rphf" then
- --
- -- KE: I don't understand the rationale behind osdstep. The original if
- -- statement checked whether coverage is contextual chaining.
- --
- -- HH: The osdstep signals that we deal with our own feature here, not
- -- one in the font itself so it was just a safeguard against us overloading
- -- something driven by the font.
- --
- -- if step.osdstep then -- selective
- if true then -- always
- -- rphf acts on consonant + halant
- for k, v in next, ra do
- local r = coverage[k]
- if r then
- local h = false
- for k, v in next, halant do
- local h = r[k]
- if h then
- reph = h.ligature or false
- break
- end
- end
- if reph then
+ -- rphf acts on consonant + halant
+ for k, v in next, ra do
+ local r = coverage[k]
+ if r then
+ local h = false
+ for k, v in next, halant do
+ local h = r[k]
+ if h then
+ reph = h.ligature or false
break
end
end
+ if reph then
+ break
+ end
end
- else
- -- rphf might be result of other handler/chainproc
end
end
seqsubset[#seqsubset+1] = { kind, coverage, reph }
@@ -716,8 +628,30 @@ local function initializedevanagi(tfmdata)
sharedfeatures["pstf"] = true
sharedfeatures["pref"] = true
sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
- gsubfeatures ["dv03"] = dev2_defaults -- reorder pre base reordering consonants
+ gsubfeatures ["dv03"] = two_defaults -- reorder pre base reordering consonants
insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants)
+ -- elseif script == "beng" then
+ -- elseif script == "bng2" then
+ -- elseif script == "gujr" then
+ -- elseif script == "gjr2" then
+ -- elseif script == "guru" then
+ -- elseif script == "gur2" then
+ -- elseif script == "knda" then
+ -- elseif script == "knd2" then
+ elseif script == "taml" then
+ sharedfeatures["dv04"] = true -- dv04_remove_joiners
+sharedfeatures["pstf"] = true
+ elseif script == "tml2" then
+-- sharedfeatures["pstf"] = true
+-- sharedfeatures["pref"] = true
+-- sharedfeatures["dv01"] = true -- dv01_reorder_matras
+-- sharedfeatures["dv02"] = true -- dv02_reorder_reph
+-- sharedfeatures["dv03"] = true -- dv03_reorder_pre_base_reordering_consonants
+-- sharedfeatures["dv04"] = true -- dv04_remove_joiners
+ -- elseif script == "telu" then
+ -- elseif script == "tel2" then
+ else
+ report("todo: enable the right features for script %a",script)
end
end
end
@@ -732,9 +666,22 @@ registerotffeature {
},
}
+local show_syntax_errors = false
+
+local function inject_syntax_error(head,current,char)
+ local signal = copy_node(current)
+ copyinjection(signal,current)
+ if pre_mark[char] then
+ setchar(signal,dotted_circle)
+ else
+ setchar(current,dotted_circle)
+ end
+ return insert_node_after(head,current,signal)
+end
+
-- hm, this is applied to one character:
-local function deva_initialize(font,attr) -- we need a proper hook into the dataset initializer
+local function initialize_one(font,attr) -- we need a proper hook into the dataset initializer
local tfmdata = fontdata[font]
local datasets = otf.dataset(tfmdata,font,attr) -- don't we know this one?
@@ -773,9 +720,9 @@ local function deva_initialize(font,attr) -- we need a proper hook into the data
end
-local function deva_reorder(head,start,stop,font,attr,nbspaces)
+local function reorder_one(head,start,stop,font,attr,nbspaces)
- local reph, vattu, blwfcache = deva_initialize(font,attr) -- todo: a hash[font]
+ local reph, vattu, blwfcache = initialize_one(font,attr) -- todo: a hash[font]
local current = start
local n = getnext(start)
@@ -812,40 +759,39 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
lastcons = current
current = getnext(current)
if current ~= stop then
- if nukta[getchar(current)] then
+ local char = getchar(current)
+ if nukta[char] then
current = getnext(current)
+ char = getchar(current)
end
- if getchar(current) == c_zwj then
- if current ~= stop then
- local next = getnext(current)
- if next ~= stop and halant[getchar(next)] then
- current = next
- next = getnext(current)
- local tmp = next and getnext(next) or nil -- needs checking
- local changestop = next == stop
- local tempcurrent = copy_node(next)
- copyinjection(tempcurrent,next)
- local nextcurrent = copy_node(current)
- copyinjection(nextcurrent,current) -- KE: necessary? HH: probably not as positioning comes later and we rawget/set
- setlink(tempcurrent,nextcurrent)
- setprop(tempcurrent,a_state,s_blwf)
- tempcurrent = processcharacters(tempcurrent,font)
- setprop(tempcurrent,a_state,unsetvalue)
- if getchar(next) == getchar(tempcurrent) then
- flush_list(tempcurrent)
- local n = copy_node(current)
- copyinjection(n,current) -- KE: necessary? HH: probably not as positioning comes later and we rawget/set
- setchar(current,dotted_circle)
- head = insert_node_after(head, current, n)
- else
- setchar(current,getchar(tempcurrent)) -- we assumes that the result of blwf consists of one node
- local freenode = getnext(current)
- setlink(current,tmp)
- flush_node(freenode)
- flush_list(tempcurrent)
- if changestop then
- stop = current
- end
+ if char == c_zwj and current ~= stop then
+ local next = getnext(current)
+ if next ~= stop and halant[getchar(next)] then
+ current = next
+ next = getnext(current)
+ local tmp = next and getnext(next) or nil -- needs checking
+ local changestop = next == stop
+ local tempcurrent = copy_node(next)
+ copyinjection(tempcurrent,next)
+ local nextcurrent = copy_node(current)
+ copyinjection(nextcurrent,current) -- KE: necessary? HH: probably not as positioning comes later and we rawget/set
+ setlink(tempcurrent,nextcurrent)
+ setprop(tempcurrent,a_state,s_blwf)
+ tempcurrent = processcharacters(tempcurrent,font)
+ setprop(tempcurrent,a_state,unsetvalue)
+ if getchar(next) == getchar(tempcurrent) then
+ flush_list(tempcurrent)
+ if show_syntax_errors then
+ head, current = inject_syntax_error(head,current,char)
+ end
+ else
+ setchar(current,getchar(tempcurrent)) -- we assumes that the result of blwf consists of one node
+ local freenode = getnext(current)
+ setlink(current,tmp)
+ flush_node(freenode)
+ flush_list(tempcurrent)
+ if changestop then
+ stop = current
end
end
end
@@ -1140,6 +1086,7 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
head = remove_node(head,start)
setlink(start,next)
setlink(current,start)
+ -- setlink(current,start,next) -- maybe
start = startnext
break
end
@@ -1151,41 +1098,39 @@ function handlers.devanagari_reorder_matras(head,start) -- no leak
return head, start, true
end
--- todo: way more caching of attributes and font
-
--- Reph’s original position is always at the beginning of the syllable, (i.e. it is not reordered at the character reordering stage).
--- However, it will be reordered according to the basic-forms shaping results.
--- Possible positions for reph, depending on the script, are; after main, before post-base consonant forms,
--- and after post-base consonant forms.
-
--- 1 If reph should be positioned after post-base consonant forms, proceed to step 5.
--- 2 If the reph repositioning class is not after post-base: target position is after the first explicit halant glyph between
--- the first post-reph consonant and last main consonant. If ZWJ or ZWNJ are following this halant, position is moved after it.
--- If such position is found, this is the target position. Otherwise, proceed to the next step.
--- Note: in old-implementation fonts, where classifications were fixed in shaping engine,
--- there was no case where reph position will be found on this step.
--- 3 If reph should be repositioned after the main consonant: from the first consonant not ligated with main,
--- or find the first consonant that is not a potential pre-base reordering Ra.
--- 4 If reph should be positioned before post-base consonant, find first post-base classified consonant not ligated with main.
--- If no consonant is found, the target position should be before the first matra, syllable modifier sign or vedic sign.
--- 5 If no consonant is found in steps 3 or 4, move reph to a position immediately before the first post-base matra,
--- syllable modifier sign or vedic sign that has a reordering class after the intended reph position.
--- For example, if the reordering position for reph is post-main, it will skip above-base matras that also have a post-main position.
--- 6 Otherwise, reorder reph to the end of the syllable.
-
--- hm, this only looks at the start of a nodelist ... is this supposed to be line based?
+-- Reph’s original position is always at the beginning of the syllable, (i.e. it is
+-- not reordered at the character reordering stage). However, it will be reordered
+-- according to the basic-forms shaping results. Possible positions for reph,
+-- depending on the script, are; after main, before post-base consonant forms, and
+-- after post-base consonant forms.
+
+-- In Devanagari reph has reordering position 'before postscript' and dev2 only
+-- follows step 2, 4, and 6.
function handlers.devanagari_reorder_reph(head,start)
- -- since in Devanagari reph has reordering position 'before postscript' dev2 only follows step 2, 4, and 6,
- -- the other steps are still ToDo (required for scripts other than dev2)
local current = getnext(start)
local startnext = nil
local startprev = nil
local startfont = getfont(start)
local startattr = getprop(start,a_syllabe)
+ --
+ ::step_1::
+ --
+ -- If reph should be positioned after post-base consonant forms, proceed to step 5.
+ --
+ ::step_2::
+ --
+ -- If the reph repositioning class is not after post-base: target position is after
+ -- the first explicit halant glyph between the first post-reph consonant and last
+ -- main consonant. If ZWJ or ZWNJ are following this halant, position is moved after
+ -- it. If such position is found, this is the target position. Otherwise, proceed to
+ -- the next step. Note: in old-implementation fonts, where classifications were
+ -- fixed in shaping engine, there was no case where reph position will be found on
+ -- this step.
+ --
while current do
local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then -- step 2
+ if char and getprop(current,a_syllabe) == startattr then
if halant[char] and not getprop(current,a_state) then
local next = getnext(current)
if next then
@@ -1199,6 +1144,7 @@ function handlers.devanagari_reorder_reph(head,start)
head = remove_node(head,start)
setlink(start,next)
setlink(current,start)
+ -- setlink(current,start,next) -- maybe
start = startnext
startattr = getprop(start,a_syllabe)
break
@@ -1208,17 +1154,31 @@ function handlers.devanagari_reorder_reph(head,start)
break
end
end
+ ::step_3::
+ --
+ -- If reph should be repositioned after the main consonant: from the first consonant
+ -- not ligated with main, or find the first consonant that is not a potential
+ -- pre-base reordering Ra.
+ --
+ -- Kai: todo
+ --
+ ::step_4::
+ --
+ -- If reph should be positioned before post-base consonant, find first post-base
+ -- classified consonant not ligated with main. If no consonant is found, the target
+ -- position should be before the first matra, syllable modifier sign or vedic sign.
+ --
if not startnext then
current = getnext(start)
while current do
local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then -- step 4
+ if char and getprop(current,a_syllabe) == startattr then
if getprop(current,a_state) == s_pstf then -- post-base
startnext = getnext(start)
head = remove_node(head,start)
- local prev = getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
+ -- setlink(getprev(current),start,current) -- maybe
start = startnext
startattr = getprop(start,a_syllabe)
break
@@ -1229,16 +1189,22 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
end
- -- todo: determine position for reph with reordering position other than 'before postscript'
- -- (required for scripts other than dev2)
- -- leaks
+ --
+ ::step_5::
+ --
+ -- If no consonant is found in steps 3 or 4, move reph to a position immediately
+ -- before the first post-base matra, syllable modifier sign or vedic sign that has a
+ -- reordering class after the intended reph position. For example, if the reordering
+ -- position for reph is post-main, it will skip above-base matras that also have a
+ -- post-main position.
+ --
if not startnext then
current = getnext(start)
local c = nil
while current do
local char = ischar(current,startfont)
- if char and getprop(current,a_syllabe) == startattr then -- step 5
- if not c and mark_above_below_post[char] and reorder_class[char] ~= "after subscript" then
+ if char and getprop(current,a_syllabe) == startattr then
+ if not c and mark_above_below_post[char] and not after_subscript[char] then
c = current
end
current = getnext(current)
@@ -1250,21 +1216,25 @@ function handlers.devanagari_reorder_reph(head,start)
if c then
startnext = getnext(start)
head = remove_node(head,start)
- local prev = getprev(c)
- setlink(prev,start)
+ setlink(getprev(c),start)
setlink(start,c)
+ -- setlink(getprev(c),start,c) -- maybe
-- end
start = startnext
startattr = getprop(start,a_syllabe)
end
end
- -- leaks
+ --
+ ::step_6::
+ --
+ -- Otherwise, reorder reph to the end of the syllable.
+ --
if not startnext then
current = start
local next = getnext(current)
while next do
local nextchar = ischar(next,startfont)
- if nextchar and getprop(next,a_syllabe) == startattr then --step 6
+ if nextchar and getprop(next,a_syllabe) == startattr then
current = next
next = getnext(current)
else
@@ -1274,9 +1244,9 @@ function handlers.devanagari_reorder_reph(head,start)
if start ~= current then
startnext = getnext(start)
head = remove_node(head,start)
- local next = getnext(current)
- setlink(start,next)
+ setlink(start,getnext(current))
setlink(current,start)
+ -- setlink(current,start,getnext(current)) -- maybe
start = startnext
end
end
@@ -1284,16 +1254,20 @@ function handlers.devanagari_reorder_reph(head,start)
return head, start, true
end
--- we can cache some checking (v)
-
-- If a pre-base reordering consonant is found, reorder it according to the following rules:
--
--- 1 Only reorder a glyph produced by substitution during application of the feature.
--- (Note that a font may shape a Ra consonant with the feature generally but block it in certain contexts.)
--- 2 Try to find a target position the same way as for pre-base matra. If it is found, reorder pre-base consonant glyph.
+-- 1 Only reorder a glyph produced by substitution during application of the feature. (Note
+-- that a font may shape a Ra consonant with the feature generally but block it in certain
+-- contexts.)
+-- 2 Try to find a target position the same way as for pre-base matra. If it is found, reorder
+-- pre-base consonant glyph.
-- 3 If position is not found, reorder immediately before main consonant.
--- UNTESTED: NOT CALLED IN EXAMPLE
+-- Here we implement a few handlers:
+--
+-- function(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+-- return head, start, done
+-- end
function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
local current = start
@@ -1320,6 +1294,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
removenode(start,start)
setlink(start,next)
setlink(current,start)
+ -- setlink(current,start,next) -- maybe
start = startnext
break
end
@@ -1337,9 +1312,9 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
if not consonant[char] and getprop(current,a_state) then -- main
startnext = getnext(start)
removenode(start,start)
- local prev = getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
+ -- setlink(getprev(current),start,current) -- maybe
start = startnext
break
end
@@ -1352,32 +1327,6 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
return head, start, true
end
--- function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
--- local stop = getnext(start)
--- local font = getfont(start)
--- while stop do
--- local char = ischar(stop)
--- if char and (char == c_zwnj or char == c_zwj) then
--- stop = getnext(stop)
--- else
--- break
--- end
--- end
--- if stop then
--- setnext(getprev(stop))
--- setprev(stop,getprev(start))
--- end
--- local prev = getprev(start)
--- if prev then
--- setnext(prev,stop)
--- end
--- if head == start then
--- head = stop
--- end
--- flush_list(start)
--- return head, stop, true
--- end
-
function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement)
local stop = getnext(start)
local font = getfont(start)
@@ -1399,13 +1348,13 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
setnext(prev)
end
if head == start then
- head = stop
+ head = stop
end
flush_list(start)
return head, stop, true
end
-local function dev2_initialize(font,attr)
+local function initialize_two(font,attr)
local devanagari = fontdata[font].resources.devanagari
@@ -1420,9 +1369,9 @@ end
-- this one will be merged into the caller: it saves a call, but we will then make function
-- of the actions
-local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pass over (determine stop in sweep)
+local function reorder_two(head,start,stop,font,attr,nbspaces) -- maybe do a pass over (determine stop in sweep)
- local seqsubset, reorderreph = dev2_initialize(font,attr)
+ local seqsubset, reorderreph = initialize_two(font,attr)
local reph = false -- was nil ... probably went unnoticed because never assigned
local halfpos = nil
@@ -1433,7 +1382,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
for i=1,#seqsubset do
- -- maybe quit if start == stop
+ -- this can be done more efficient, the last test and less getnext
local subset = seqsubset[i]
local kind = subset[1]
@@ -1452,8 +1401,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
if found[n] then --above-base: rphf Consonant + Halant
local afternext = next ~= stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then -- ZWJ and ZWNJ prevent creation of reph
- current = next
- current = getnext(current)
+ current = afternext -- getnext(next)
elseif current == start then
setprop(current,a_state,s_rphf)
current = next
@@ -1589,7 +1537,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
next = getnext(current)
local tmp = getnext(next)
local changestop = next == stop
- setnext(next,nil)
+ setnext(next)
setprop(current,a_state,s_pref)
current = processcharacters(current,font)
setprop(current,a_state,s_blwf)
@@ -1599,10 +1547,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
setprop(current,a_state,unsetvalue)
if halant[getchar(current)] then
setnext(getnext(current),tmp)
- local nc = copy_node(current)
- copyinjection(nc,current)
- setchar(current,dotted_circle)
- head = insert_node_after(head,current,nc)
+ if show_syntax_errors then
+ head, current = inject_syntax_error(head,current,char)
+ end
else
setnext(current,tmp) -- assumes that result of pref, blwf, or pstf consists of one node
if changestop then
@@ -1690,9 +1637,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
end
start = current
end
- local prev = getprev(halfpos)
- setlink(prev,current)
+ setlink(getprev(halfpos),current)
setlink(current,halfpos)
+ -- setlink(getprev(halfpos),current,halfpos) -- maybe
halfpos = current
elseif above_mark[char] then -- After main consonant
target = basepos
@@ -1721,9 +1668,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
if current == stop then
stop = prev
end
- local next = getnext(target)
- setlink(current,next)
+ setlink(current,getnext(target))
setlink(target,current)
+ -- setlink(target,current,getnext(target)) -- maybe
end
end
end
@@ -1750,8 +1697,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces) -- maybe do a pa
if stop == next then
stop = current
end
- local prev = getprev(c)
- setlink(prev,next)
+ setlink(getprev(c),next)
local nextnext = getnext(next)
setnext(current,nextnext)
local nextnextnext = getnext(nextnext)
@@ -1999,7 +1945,7 @@ local function analyze_next_chars_two(c,font)
if not v then
return c
end
- if v == c_anudatta then
+ if anudatta[v] then
c = n
n = getnext(c)
if not n then
@@ -2098,35 +2044,23 @@ local function analyze_next_chars_two(c,font)
end
end
-local function inject_syntax_error(head,current,mark)
- local signal = copy_node(current)
- copyinjection(signal,current)
- if mark == pre_mark then -- THIS IS WRONG: pre_mark is a table
- setchar(signal,dotted_circle)
- else
- setchar(current,dotted_circle)
- end
- return insert_node_after(head,current,signal)
-end
-
-- It looks like these two analyzers were written independently but they share
-- a lot. Common code has been synced.
-function methods.deva(head,font,attr)
- head = tonut(head)
+local function method_one(head,font,attr)
local current = head
local start = true
local done = false
local nbspaces = 0
while current do
- local char = ischar(current,font)
+ local char = ischar(current,font)
if char then
done = true
local syllablestart = current
local syllableend = nil
local c = current
local n = getnext(c)
- local first = char
+ local first = char
if n and ra[first] then
local second = ischar(n,font)
if second and halant[second] then
@@ -2158,10 +2092,10 @@ function methods.deva(head,font,attr)
end
if standalone then
-- stand alone cluster (at the start of the word only): #[Ra+H]+NBSP+[N]+[<[<ZWJ|ZWNJ>]+H+C>]+[{M}+[N]+[H]]+[SM]+[(VD)]
- local syllableend = analyze_next_chars_one(c,font,2)
- current = getnext(syllableend)
+ local syllableend = analyze_next_chars_one(c,font,2)
+ current = getnext(syllableend)
if syllablestart ~= syllableend then
- head, current, nbspaces = deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head, current, nbspaces = reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current = getnext(current)
end
else
@@ -2267,7 +2201,7 @@ function methods.deva(head,font,attr)
end
end
if syllablestart ~= syllableend then
- head, current, nbspaces = deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head, current, nbspaces = reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current = getnext(current)
end
elseif independent_vowel[char] then
@@ -2289,9 +2223,11 @@ function methods.deva(head,font,attr)
end
end
else
- local mark = mark_four[char]
- if mark then
- head, current = inject_syntax_error(head,current,mark)
+ if show_syntax_errors then
+ local mark = mark_four[char]
+ if mark then
+ head, current = inject_syntax_error(head,current,char)
+ end
end
current = getnext(current)
end
@@ -2306,16 +2242,13 @@ function methods.deva(head,font,attr)
head = replace_all_nbsp(head)
end
- head = tonode(head)
-
return head, done
end
-- there is a good change that when we run into one with subtype < 256 that the rest is also done
-- so maybe we can omit this check (it's pretty hard to get glyphs in the stream out of the blue)
-function methods.dev2(head,font,attr)
- head = tonut(head)
+local function method_two(head,font,attr)
local current = head
local start = true
local done = false
@@ -2338,7 +2271,7 @@ function methods.dev2(head,font,attr)
local nextnextchar = ischar(n,font)
if nextnextchar then
c = n
- char = nextnextchar
+ char = nextnextchar
end
end
end
@@ -2385,14 +2318,14 @@ function methods.dev2(head,font,attr)
end
end
if syllableend and syllablestart ~= syllableend then
- head, current, nbspaces = dev2_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head, current, nbspaces = reorder_two(head,syllablestart,syllableend,font,attr,nbspaces)
end
- if not syllableend then
+ if not syllableend and show_syntax_errors then
local char = ischar(current,font)
if char and not getprop(current,a_state) then
local mark = mark_four[char]
if mark then
- head, current = inject_syntax_error(head,current,mark)
+ head, current = inject_syntax_error(head,current,char)
end
end
end
@@ -2404,10 +2337,10 @@ function methods.dev2(head,font,attr)
head = replace_all_nbsp(head)
end
- head = tonode(head)
-
return head, done
end
-methods.mlym = methods.deva
-methods.mlm2 = methods.dev2
+for i=1,nofscripts do
+ methods[scripts_one[i]] = method_one
+ methods[scripts_two[i]] = method_two
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua
index b8944e0c0c9..48ec6b976de 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['font-ota'] = {
version = 1.001,
- comment = "companion to font-otf.lua (analysing)",
+ comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
@@ -32,7 +32,6 @@ local a_state = attributes.private('state')
local nuts = nodes.nuts
local tonut = nuts.tonut
-local getfield = nuts.getfield
local getnext = nuts.getnext
local getprev = nuts.getprev
local getprev = nuts.getprev
@@ -43,7 +42,6 @@ local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
local ischar = nuts.is_char
-local traverse_id = nuts.traverse_id
local end_of_math = nuts.end_of_math
local nodecodes = nodes.nodecodes
@@ -72,7 +70,7 @@ local s_isol = 4 local s_blwf = 10
local s_mark = 5 local s_pstf = 11
local s_rest = 6
-local states = {
+local states = allocate {
init = s_init,
medi = s_medi,
med2 = s_medi,
@@ -89,7 +87,7 @@ local states = {
pstf = s_pstf,
}
-local features = {
+local features = allocate {
init = s_init,
medi = s_medi,
med2 = s_medi,
@@ -113,6 +111,8 @@ analyzers.useunicodemarks = false
-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace
+-- done can go away as can tonut
+
function analyzers.setstate(head,font)
local useunicodemarks = analyzers.useunicodemarks
local tfmdata = fontdata[font]
@@ -248,12 +248,12 @@ local function warning(current,what)
end
end
-local mappers = {
- l = s_init, -- left
- d = s_medi, -- double
- c = s_medi, -- joiner
- r = s_fina, -- right
- u = s_isol, -- nonjoiner
+local mappers = allocate {
+ l = s_init, -- left
+ d = s_medi, -- double
+ c = s_medi, -- joiner
+ r = s_fina, -- right
+ u = s_isol, -- nonjoiner
}
-- we can also use this trick for devanagari
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua
index a55320903fb..c2e89599a92 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua
@@ -1,15 +1,16 @@
if not modules then modules = { } end modules ['font-otc'] = {
version = 1.001,
- comment = "companion to font-otf.lua (context)",
+ comment = "companion to font-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-local format, insert, sortedkeys, tohash = string.format, table.insert, table.sortedkeys, table.tohash
+local insert, sortedkeys, sortedhash, tohash = table.insert, table.sortedkeys, table.sortedhash, table.tohash
local type, next = type, next
local lpegmatch = lpeg.match
local utfbyte, utflen = utf.byte, utf.len
+local sortedhash = table.sortedhash
-- we assume that the other otf stuff is loaded already
@@ -21,6 +22,10 @@ local otf = fonts.handlers.otf
local registerotffeature = otf.features.register
local setmetatableindex = table.setmetatableindex
+local checkmerge = fonts.helpers.checkmerge
+local checkflags = fonts.helpers.checkflags
+local checksteps = fonts.helpers.checksteps
+
local normalized = {
substitution = "substitution",
single = "substitution",
@@ -29,6 +34,7 @@ local normalized = {
multiple = "multiple",
kern = "kern",
pair = "pair",
+ single = "single",
chainsubstitution = "chainsubstitution",
chainposition = "chainposition",
}
@@ -40,6 +46,7 @@ local types = {
multiple = "gsub_multiple",
kern = "gpos_pair",
pair = "gpos_pair",
+ single = "gpos_single",
chainsubstitution = "gsub_contextchain",
chainposition = "gpos_contextchain",
}
@@ -195,13 +202,15 @@ local function addfeature(data,feature,specifications)
local stepkey = coverup.stepkey
local register = coverup.register
- local function prepare_substitution(list,featuretype)
+ local function prepare_substitution(list,featuretype,nocheck)
local coverage = { }
local cover = coveractions[featuretype]
for code, replacement in next, list do
local unicode = tounicode(code)
local description = descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip = skip + 1
+ else
if type(replacement) == "table" then
replacement = replacement[1]
end
@@ -212,26 +221,24 @@ local function addfeature(data,feature,specifications)
else
skip = skip + 1
end
- else
- skip = skip + 1
end
end
return coverage
end
- local function prepare_alternate(list,featuretype)
+ local function prepare_alternate(list,featuretype,nocheck)
local coverage = { }
local cover = coveractions[featuretype]
for code, replacement in next, list do
local unicode = tounicode(code)
local description = descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip = skip + 1
elseif type(replacement) == "table" then
local r = { }
for i=1,#replacement do
local u = tounicode(replacement[i])
- r[i] = descriptions[u] and u or unicode
+ r[i] = (nocheck or descriptions[u]) and u or unicode
end
cover(coverage,unicode,r)
done = done + 1
@@ -248,19 +255,19 @@ local function addfeature(data,feature,specifications)
return coverage
end
- local function prepare_multiple(list,featuretype)
+ local function prepare_multiple(list,featuretype,nocheck)
local coverage = { }
local cover = coveractions[featuretype]
for code, replacement in next, list do
local unicode = tounicode(code)
local description = descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip = skip + 1
elseif type(replacement) == "table" then
local r, n = { }, 0
for i=1,#replacement do
local u = tounicode(replacement[i])
- if descriptions[u] then
+ if nocheck or descriptions[u] then
n = n + 1
r[n] = u
end
@@ -284,13 +291,15 @@ local function addfeature(data,feature,specifications)
return coverage
end
- local function prepare_ligature(list,featuretype)
+ local function prepare_ligature(list,featuretype,nocheck)
local coverage = { }
local cover = coveractions[featuretype]
for code, ligature in next, list do
local unicode = tounicode(code)
local description = descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip = skip + 1
+ else
if type(ligature) == "string" then
ligature = { lpegmatch(splitter,ligature) }
end
@@ -298,7 +307,7 @@ local function addfeature(data,feature,specifications)
for i=1,#ligature do
local l = ligature[i]
local u = tounicode(l)
- if descriptions[u] then
+ if nocheck or descriptions[u] then
ligature[i] = u
else
present = false
@@ -311,16 +320,23 @@ local function addfeature(data,feature,specifications)
else
skip = skip + 1
end
- else
- skip = skip + 1
end
end
return coverage
end
+ local function resetspacekerns()
+ -- a bit of a hack, this nil setting but it forces a
+ -- rehash of the resources needed .. the feature itself
+ -- should be a kern (at least for now)
+ data.properties.hasspacekerns = true
+ data.resources .spacekerns = nil
+ end
+
local function prepare_kern(list,featuretype)
local coverage = { }
local cover = coveractions[featuretype]
+ local isspace = false
for code, replacement in next, list do
local unicode = tounicode(code)
local description = descriptions[unicode]
@@ -330,11 +346,17 @@ local function addfeature(data,feature,specifications)
local u = tounicode(k)
if u then
r[u] = v
+ if u == 32 then
+ isspace = true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done = done + 1
+ if unicode == 32 then
+ isspace = true
+ end
else
skip = skip + 1
end
@@ -342,6 +364,9 @@ local function addfeature(data,feature,specifications)
skip = skip + 1
end
end
+ if isspace then
+ resetspacekerns()
+ end
return coverage
end
@@ -358,11 +383,17 @@ local function addfeature(data,feature,specifications)
local u = tounicode(k)
if u then
r[u] = v
+ if u == 32 then
+ isspace = true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done = done + 1
+ if unicode == 32 then
+ isspace = true
+ end
else
skip = skip + 1
end
@@ -370,22 +401,25 @@ local function addfeature(data,feature,specifications)
skip = skip + 1
end
end
+ if isspace then
+ resetspacekerns()
+ end
else
report_otf("unknown cover type %a",featuretype)
end
return coverage
end
+ local prepare_single = prepare_pair -- we could have a better test on the spec
+
local function prepare_chain(list,featuretype,sublookups)
-- todo: coveractions
local rules = list.rules
local coverage = { }
if rules then
- local rulehash = { }
- local rulesize = 0
- local sequence = { }
- local nofsequences = 0
- local lookuptype = types[featuretype]
+ local rulehash = { }
+ local rulesize = 0
+ local lookuptype = types[featuretype]
for nofrules=1,#rules do
local rule = rules[nofrules]
local current = rule.current
@@ -415,15 +449,30 @@ local function addfeature(data,feature,specifications)
local lookups = rule.lookups or false
local subtype = nil
if lookups and sublookups then
- for k, v in next, lookups do
- local lookup = sublookups[v]
- if lookup then
- lookups[k] = lookup
- if not subtype then
- subtype = lookup.type
+ for k, v in sortedhash(lookups) do
+ local t = type(v)
+ if t == "table" then
+ -- already ok
+ for i=1,#v do
+ local vi = v[i]
+ if type(vi) ~= "table" then
+ v[i] = { vi }
+ end
+ end
+ elseif t == "number" then
+ local lookup = sublookups[v]
+ if lookup then
+ lookups[k] = { lookup }
+ if not subtype then
+ subtype = lookup.type
+ end
+ elseif v == 0 then
+ lookups[k] = { { type = "gsub_remove" } }
+ else
+ lookups[k] = false -- { false } -- new
end
else
- -- already expanded
+ lookups[k] = false -- { false } -- new
end
end
end
@@ -454,14 +503,17 @@ local function addfeature(data,feature,specifications)
replacements, -- 7
subtype, -- 8
}
- for unic in next, sequence[start] do
+-- for unic in next, sequence[start] do
+ for unic in sortedhash(sequence[start]) do
local cu = coverage[unic]
if not cu then
coverage[unic] = rulehash -- can now be done cleaner i think
end
end
+ sequence.n = nofsequences
end
end
+ rulehash.n = rulesize
end
return coverage
end
@@ -502,7 +554,7 @@ local function addfeature(data,feature,specifications)
local s = sequences[i]
local f = s.features
if f then
- for k in next, f do
+ for k in sortedhash(f) do -- next, f do
if k == position then
index = i
break
@@ -552,12 +604,17 @@ local function addfeature(data,feature,specifications)
local askedsteps = specification.steps or specification.subtables or { specification.data } or { }
local featuretype = normalized[specification.type or "substitution"] or "substitution"
local featureflags = specification.flags or noflags
+ local nocheck = specification.nocheck
+ local futuresteps = specification.futuresteps
local featureorder = specification.order or { feature }
local featurechain = (featuretype == "chainsubstitution" or featuretype == "chainposition") and 1 or 0
local nofsteps = 0
local steps = { }
local sublookups = specification.lookups
local category = nil
+ --
+ checkflags(specification,resources)
+ --
if sublookups then
local s = { }
for i=1,#sublookups do
@@ -572,28 +629,36 @@ local function addfeature(data,feature,specifications)
local coverage = nil
local format = nil
if featuretype == "substitution" then
- coverage = prepare_substitution(list,featuretype)
+ coverage = prepare_substitution(list,featuretype,nocheck)
elseif featuretype == "ligature" then
- coverage = prepare_ligature(list,featuretype)
+ coverage = prepare_ligature(list,featuretype,nocheck)
elseif featuretype == "alternate" then
- coverage = prepare_alternate(list,featuretype)
+ coverage = prepare_alternate(list,featuretype,nocheck)
elseif featuretype == "multiple" then
- coverage = prepare_multiple(list,featuretype)
- elseif featuretype == "kern" then
- format = "kern"
+ coverage = prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype == "kern" or featuretype == "move" then
+ format = featuretype
coverage = prepare_kern(list,featuretype)
elseif featuretype == "pair" then
format = "pair"
coverage = prepare_pair(list,featuretype)
+ elseif featuretype == "single" then
+ format = "single"
+ coverage = prepare_single(list,featuretype)
end
if coverage and next(coverage) then
nofsteps = nofsteps + 1
steps[nofsteps] = register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
end
end
+ --
+ checkmerge(specification)
+ checksteps(specification)
+ --
s[i] = {
[stepkey] = steps,
nofsteps = nofsteps,
+ flags = featureflags,
type = types[featuretype],
}
end
@@ -605,24 +670,28 @@ local function addfeature(data,feature,specifications)
local format = nil
if featuretype == "substitution" then
category = "gsub"
- coverage = prepare_substitution(list,featuretype)
+ coverage = prepare_substitution(list,featuretype,nocheck)
elseif featuretype == "ligature" then
category = "gsub"
- coverage = prepare_ligature(list,featuretype)
+ coverage = prepare_ligature(list,featuretype,nocheck)
elseif featuretype == "alternate" then
category = "gsub"
- coverage = prepare_alternate(list,featuretype)
+ coverage = prepare_alternate(list,featuretype,nocheck)
elseif featuretype == "multiple" then
category = "gsub"
- coverage = prepare_multiple(list,featuretype)
- elseif featuretype == "kern" then
+ coverage = prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype == "kern" or featuretype == "move" then
category = "gpos"
- format = "kern"
+ format = featuretype
coverage = prepare_kern(list,featuretype)
elseif featuretype == "pair" then
category = "gpos"
format = "pair"
coverage = prepare_pair(list,featuretype)
+ elseif featuretype == "single" then
+ category = "gpos"
+ format = "single"
+ coverage = prepare_single(list,featuretype)
elseif featuretype == "chainsubstitution" then
category = "gsub"
coverage = prepare_chain(list,featuretype,sublookups)
@@ -645,6 +714,7 @@ local function addfeature(data,feature,specifications)
askedfeatures[k] = tohash(v)
end
end
+ --
if featureflags[1] then featureflags[1] = "mark" end
if featureflags[2] then featureflags[2] = "ligature" end
if featureflags[3] then featureflags[3] = "base" end
@@ -659,6 +729,10 @@ local function addfeature(data,feature,specifications)
nofsteps = nofsteps,
type = steptype,
}
+ --
+ checkflags(sequence,resources)
+ checkmerge(sequence)
+ checksteps(sequence)
-- position | prepend | append
local first, last = getrange(sequences,category)
inject(specification,sequences,sequence,first,last,category,feature)
@@ -708,11 +782,16 @@ function otf.addfeature(name,specification)
specification, name = validspecification(specification,name)
if name and specification then
local slot = knownfeatures[name]
- if slot then
- -- we overload one .. should be option
- else
+ if not slot then
+ -- we have a new one
slot = #extrafeatures + 1
knownfeatures[name] = slot
+ elseif specification.overload == false then
+ -- we add an extre one
+ slot = #extrafeatures + 1
+ knownfeatures[name] = slot
+ else
+ -- we overload a previous one
end
specification.name = name -- to be sure
extrafeatures[slot] = specification
@@ -735,177 +814,6 @@ otf.enhancers.enhance = enhance
otf.enhancers.register("check extra features",enhance)
--- tlig --
-
-local tlig = { -- we need numbers for some fonts so ...
- -- endash = "hyphen hyphen",
- -- emdash = "hyphen hyphen hyphen",
- [0x2013] = { 0x002D, 0x002D },
- [0x2014] = { 0x002D, 0x002D, 0x002D },
- -- quotedblleft = "quoteleft quoteleft",
- -- quotedblright = "quoteright quoteright",
- -- quotedblleft = "grave grave",
- -- quotedblright = "quotesingle quotesingle",
- -- quotedblbase = "comma comma",
-}
-
-local tlig_specification = {
- type = "ligature",
- features = everywhere,
- data = tlig,
- order = { "tlig" },
- flags = noflags,
- prepend = true,
-}
-
-otf.addfeature("tlig",tlig_specification)
-
-registerotffeature {
- -- this makes it a known feature (in tables)
- name = 'tlig',
- description = 'tex ligatures',
-}
-
--- trep
-
-local trep = {
- -- [0x0022] = 0x201D,
- [0x0027] = 0x2019,
- -- [0x0060] = 0x2018,
-}
-
-local trep_specification = {
- type = "substitution",
- features = everywhere,
- data = trep,
- order = { "trep" },
- flags = noflags,
- prepend = true,
-}
-
-otf.addfeature("trep",trep_specification)
-
-registerotffeature {
- -- this makes it a known feature (in tables)
- name = 'trep',
- description = 'tex replacements',
-}
-
--- -- tcom (obsolete, was already not set for a while)
-
--- if characters.combined then
---
--- local tcom = { }
---
--- local function initialize()
--- characters.initialize()
--- for first, seconds in next, characters.combined do
--- for second, combination in next, seconds do
--- tcom[combination] = { first, second }
--- end
--- end
--- -- return false
--- end
---
--- local tcom_specification = {
--- type = "ligature",
--- features = everywhere,
--- data = tcom,
--- order = { "tcom" },
--- flags = noflags,
--- initialize = initialize,
--- }
---
--- otf.addfeature("tcom",tcom_specification)
---
--- registerotffeature {
--- name = 'tcom',
--- description = 'tex combinations',
--- }
---
--- end
-
--- anum
-
-local anum_arabic = {
- [0x0030] = 0x0660,
- [0x0031] = 0x0661,
- [0x0032] = 0x0662,
- [0x0033] = 0x0663,
- [0x0034] = 0x0664,
- [0x0035] = 0x0665,
- [0x0036] = 0x0666,
- [0x0037] = 0x0667,
- [0x0038] = 0x0668,
- [0x0039] = 0x0669,
-}
-
-local anum_persian = {
- [0x0030] = 0x06F0,
- [0x0031] = 0x06F1,
- [0x0032] = 0x06F2,
- [0x0033] = 0x06F3,
- [0x0034] = 0x06F4,
- [0x0035] = 0x06F5,
- [0x0036] = 0x06F6,
- [0x0037] = 0x06F7,
- [0x0038] = 0x06F8,
- [0x0039] = 0x06F9,
-}
-
-local function valid(data)
- local features = data.resources.features
- if features then
- for k, v in next, features do
- for k, v in next, v do
- if v.arab then
- return true
- end
- end
- end
- end
-end
-
-local anum_specification = {
- {
- type = "substitution",
- features = { arab = { urd = true, dflt = true } },
- order = { "anum" },
- data = anum_arabic,
- flags = noflags, -- { },
- valid = valid,
- },
- {
- type = "substitution",
- features = { arab = { urd = true } },
- order = { "anum" },
- data = anum_persian,
- flags = noflags, -- { },
- valid = valid,
- },
-}
-
-otf.addfeature("anum",anum_specification) -- todo: only when there is already an arab script feature
-
-registerotffeature {
- -- this makes it a known feature (in tables)
- name = 'anum',
- description = 'arabic digits',
-}
-
--- maybe:
-
--- fonts.handlers.otf.addfeature("hangulfix",{
--- type = "substitution",
--- features = { ["hang"] = { ["*"] = true } },
--- data = {
--- [0x1160] = 0x119E,
--- },
--- order = { "hangulfix" },
--- flags = { },
--- prepend = true,
--- })
-
-- fonts.handlers.otf.features.register {
-- name = 'hangulfix',
-- description = 'fixes for hangul',
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oti.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oti.lua
index e10a261cd2b..4c6053be073 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oti.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oti.lua
@@ -160,3 +160,103 @@ function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
end
end
end
+
+-- the following might become available generic in due time but for now
+-- this is some context playground (development code)
+
+-- if not context then
+-- return
+-- end
+
+-- local helpers = otf.readers.helpers
+-- local axistofactors = helpers.axistofactors
+-- local normalizedaxis = helpers.normalizedaxis
+-- local getaxisscale = helpers.getaxisscale
+-- local cleanname = containers.cleanname
+
+-- local function validvariable(tfmdata)
+-- if tfmdata.properties.factors then
+-- return
+-- end
+-- local resources = tfmdata.resources
+-- local variabledata = resources and resources.variabledata
+-- if not variabledata then
+-- return
+-- end
+-- local instances = variabledata.instances
+-- local axis = variabledata.axis
+-- local segments = variabledata.segments
+-- if instances and axis then
+-- return instances, axis, segments
+-- end
+-- end
+
+-- local function initializeinstance(tfmdata,value)
+-- if type(value) == "string" then
+-- local instances, axis, segments = validvariable(tfmdata)
+-- if instances then
+-- local values
+-- for i=1,#instances do
+-- local instance = instances[i]
+-- if cleanname(instance.subfamily) == value then
+-- values = instance.values
+-- break
+-- end
+-- end
+-- if values then
+-- local factors = { }
+-- for i=1,#axis do
+-- local a = axis[i]
+-- factors[i] = getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
+-- end
+-- tfmdata.properties.instance = {
+-- hash = instance,
+-- factors = factors,
+-- }
+-- end
+-- else
+-- report("incomplete variable data")
+-- end
+-- end
+-- end
+
+-- local function initializeaxis(tfmdata,value)
+-- if type(value) == "string" then
+-- local instances, axis, segments = validvariable(tfmdata)
+-- if instances then
+-- local values = axistofactors(value)
+-- if values then
+-- local factors = { }
+-- for i=1,#axis do
+-- local a = axis[i]
+-- local d = a.default
+-- factors[i] = getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
+-- end
+-- tfmdata.properties.instance = {
+-- hash = cleanname(value),
+-- factors = factors,
+-- }
+-- end
+-- else
+-- report("incomplete variable data")
+-- end
+-- end
+-- end
+
+-- registerotffeature {
+-- name = "instance",
+-- description = "variation instance",
+-- initializers = {
+-- node = initializeinstance,
+-- base = initializeinstance,
+-- }
+-- }
+
+-- registerotffeature {
+-- name = "axis",
+-- description = "variation axis",
+-- initializers = {
+-- node = initializeaxis,
+-- base = initializeaxis,
+-- }
+-- }
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua
index 68cf608ec94..8d1b540be0f 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua
@@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['font-otj'] = {
}
-- This property based variant is not faster but looks nicer than the attribute one. We
--- need to use rawget (which is apbout 4 times slower than a direct access but we cannot
+-- need to use rawget (which is about 4 times slower than a direct access but we cannot
-- get/set that one for our purpose! This version does a bit more with discretionaries
-- (and Kai has tested it with his collection of weird fonts.)
@@ -16,31 +16,37 @@ if not modules then modules = { } end modules ['font-otj'] = {
-- cleaner to have an identification pass here. Also, I need to keep tracing in mind so
-- being too clever here is dangerous.
--- The subtype test is not needed as there will be no (new) properties set, given that we
--- reset the properties.
-
-- As we have a rawget on properties we don't need one on injections.
--- The use_advance code is just a test and is meant for testing and manuals. There is no
+-- The use_advance code was just a test and is meant for testing and manuals. There is no
-- performance (or whatever) gain and using kerns is somewhat cleaner (at least for now).
--- Maybe: subtype fontkern when pure kerns.
+-- An alternative is to have a list per base of all marks and then do a run over the node
+-- list that resolves the accumulated l/r/x/y and then do an inject pass.
+
+-- if needed we can flag a kern node as immutable
+
+-- The thing with these positioning options is that it is not clear what Uniscribe does with
+-- the 2rl flag and we keep oscillating a between experiments.
if not nodes.properties then return end
-local next, rawget = next, rawget
+local next, rawget, tonumber = next, rawget, tonumber
local fastcopy = table.fastcopy
-local registertracker = trackers.register
+local registertracker = trackers.register
+local registerdirective = directives.register
local trace_injections = false registertracker("fonts.injections", function(v) trace_injections = v end)
local trace_marks = false registertracker("fonts.injections.marks", function(v) trace_marks = v end)
local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end)
local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end)
--- use_advance is just an experiment: it makes copying glyphs (instead of new_glyph) dangerous
-
-local use_advance = false directives.register("fonts.injections.advance", function(v) use_advance = v end)
+-- local fix_cursive_marks = false
+--
+-- registerdirective("fonts.injections.fixcursivemarks", function(v)
+-- fix_cursive_marks = v
+-- end)
local report_injections = logs.reporter("fonts","injections")
local report_spaces = logs.reporter("fonts","spaces")
@@ -50,6 +56,7 @@ local attributes, nodes, node = attributes, nodes, node
fonts = fonts
local hashes = fonts.hashes
local fontdata = hashes.identifiers
+local fontmarks = hashes.marks
----- parameters = fonts.hashes.parameters -- not in generic
----- resources = fonts.hashes.resources -- not in generic
@@ -69,92 +76,105 @@ local glue_code = nodecodes.glue
local nuts = nodes.nuts
local nodepool = nuts.pool
-local newkern = nodepool.kern
-
local tonode = nuts.tonode
local tonut = nuts.tonut
-local getfield = nuts.getfield
local setfield = nuts.setfield
local getnext = nuts.getnext
local getprev = nuts.getprev
local getid = nuts.getid
local getfont = nuts.getfont
-local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
+local getoffsets = nuts.getoffsets
local getboth = nuts.getboth
-
-local ischar = nuts.is_char
-
local getdisc = nuts.getdisc
local setdisc = nuts.setdisc
+local setoffsets = nuts.setoffsets
+local ischar = nuts.is_char
+local getkern = nuts.getkern
+local setkern = nuts.setkern
+local setlink = nuts.setlink
+local setwidth = nuts.setwidth
+local getwidth = nuts.getwidth
+
+----- traverse_id = nuts.traverse_id
+----- traverse_char = nuts.traverse_char
+local nextchar = nuts.traversers.char
+local nextglue = nuts.traversers.glue
-local traverse_id = nuts.traverse_id
-local traverse_char = nuts.traverse_char
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local properties = nodes.properties.data
-function injections.installnewkern(nk)
- newkern = nk or newkern
-end
+local fontkern = nuts.pool and nuts.pool.fontkern -- context
+local italickern = nuts.pool and nuts.pool.italickern -- context
-local nofregisteredkerns = 0
-local nofregisteredpairs = 0
-local nofregisteredmarks = 0
-local nofregisteredcursives = 0
-local keepregisteredcounts = false
+local useitalickerns = false
+
+directives.register("fonts.injections.useitalics", function(v)
+ if v then
+ report_injections("using italics for space kerns (tracing only)")
+ end
+ useitalickerns = v
+end)
+
+do if not fontkern then -- generic
+
+ local thekern = nuts.new("kern",0) -- fontkern
+ local setkern = nuts.setkern
+ local copy_node = nuts.copy_node
+
+ fontkern = function(k)
+ local n = copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+
+end end
+
+do if not italickern then -- generic
+
+ local thekern = nuts.new("kern",3) -- italiccorrection
+ local setkern = nuts.setkern
+ local copy_node = nuts.copy_node
+
+ italickern = function(k)
+ local n = copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+
+end end
+
+function injections.installnewkern() end -- obsolete
+
+local nofregisteredkerns = 0
+local nofregisteredpositions = 0
+local nofregisteredmarks = 0
+local nofregisteredcursives = 0
+local keepregisteredcounts = false
function injections.keepcounts()
keepregisteredcounts = true
end
function injections.resetcounts()
- nofregisteredkerns = 0
- nofregisteredpairs = 0
- nofregisteredmarks = 0
- nofregisteredcursives = 0
- keepregisteredcounts = false
+ nofregisteredkerns = 0
+ nofregisteredpositions = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ keepregisteredcounts = false
end
-- We need to make sure that a possible metatable will not kick in unexpectedly.
--- function injections.reset(n)
--- local p = rawget(properties,n)
--- if p and rawget(p,"injections") then
--- p.injections = nil
--- end
--- end
-
--- function injections.copy(target,source)
--- local sp = rawget(properties,source)
--- if sp then
--- local tp = rawget(properties,target)
--- local si = rawget(sp,"injections")
--- if si then
--- si = fastcopy(si)
--- if tp then
--- tp.injections = si
--- else
--- propertydata[target] = {
--- injections = si,
--- }
--- end
--- else
--- if tp then
--- tp.injections = nil
--- end
--- end
--- end
--- end
-
function injections.reset(n)
local p = rawget(properties,n)
if p then
- p.injections = false -- { }
+ p.injections = false -- { } -- nil should work too as we use rawget
else
- properties[n] = false -- { injections = { } }
+ properties[n] = false -- { injections = { } } -- nil should work too as we use rawget
end
end
@@ -162,14 +182,13 @@ function injections.copy(target,source)
local sp = rawget(properties,source)
if sp then
local tp = rawget(properties,target)
- -- local si = rawget(sp,"injections")
local si = sp.injections
if si then
si = fastcopy(si)
if tp then
tp.injections = si
else
- propertydata[target] = {
+ properties[target] = {
injections = si,
}
end
@@ -188,10 +207,9 @@ function injections.copy(target,source)
end
end
-function injections.setligaindex(n,index)
+function injections.setligaindex(n,index) -- todo: don't set when 0
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections")
local i = p.injections
if i then
i.ligaindex = index
@@ -212,7 +230,6 @@ end
function injections.getligaindex(n,default)
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections")
local i = p.injections
if i then
return i.ligaindex or default
@@ -221,7 +238,15 @@ function injections.getligaindex(n,default)
return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
+
+ -- The standard says something about the r2lflag related to the first in a series:
+ --
+ -- When this bit is set, the last glyph in a given sequence to which the cursive
+ -- attachment lookup is applied, will be positioned on the baseline.
+ --
+ -- But it looks like we don't need to consider it.
+
local dx = factor*(exit[1]-entry[1])
local dy = -factor*(exit[2]-entry[2])
local ws = tfmstart.width
@@ -239,7 +264,6 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
--
local p = rawget(properties,start)
if p then
- -- local i = rawget(p,"injections")
local i = p.injections
if i then
i.cursiveanchor = true
@@ -257,7 +281,6 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
end
local p = rawget(properties,nxt)
if p then
- -- local i = rawget(p,"injections")
local i = p.injections
if i then
i.cursivex = dx
@@ -279,17 +302,19 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
return dx, dy, nofregisteredcursives
end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used
- local x = factor*spec[1]
- local y = factor*spec[2]
- local w = factor*spec[3]
- local h = factor*spec[4]
+-- kind: 0=single 1=first of pair, 2=second of pair
+
+function injections.setposition(kind,current,factor,rlmode,spec,injection)
+ local x = factor * (spec[1] or 0)
+ local y = factor * (spec[2] or 0)
+ local w = factor * (spec[3] or 0)
+ local h = factor * (spec[4] or 0)
if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay?
local yoffset = y - h
local leftkern = x -- both kerns are set in a pair kern compared
local rightkern = w - x -- to normal kerns where we set only leftkern
if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
- nofregisteredpairs = nofregisteredpairs + 1
+ nofregisteredpositions = nofregisteredpositions + 1
if rlmode and rlmode < 0 then
leftkern, rightkern = rightkern, leftkern
end
@@ -298,8 +323,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
end
local p = rawget(properties,current)
if p then
- -- local i = p[injection]
- local i = rawget(p,injection)
+ local i = p[injection]
if i then
if leftkern ~= 0 then
i.leftkern = (i.leftkern or 0) + leftkern
@@ -336,15 +360,15 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
},
}
end
- return x, y, w, h, nofregisteredpairs
+ return x, y, w, h, nofregisteredpositions
end
end
return x, y, w, h -- no bound
end
--- This needs checking for rl < 0 but it is unlikely that a r2l script uses kernclasses between
--- glyphs so we're probably safe (KE has a problematic font where marks interfere with rl < 0 in
--- the previous case)
+-- The next one is used for simple kerns coming from a truetype kern table. The r2l
+-- variant variant needs checking but it is unlikely that a r2l script uses thsi
+-- feature.
function injections.setkern(current,factor,rlmode,x,injection)
local dx = factor * x
@@ -355,8 +379,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
injection = "injections"
end
if p then
- -- local i = rawget(p,injection)
- local i = rawget(p,injection)
+ local i = p[injection]
if i then
i.leftkern = dx + (i.leftkern or 0)
else
@@ -377,8 +400,62 @@ function injections.setkern(current,factor,rlmode,x,injection)
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) -- ba=baseanchor, ma=markanchor
+-- This one is an optimization of pairs where we have only a "w" entry. This one is
+-- potentially different from the previous one wrt r2l. It needs checking. The
+-- optimization relates to smaller tma files.
+
+function injections.setmove(current,factor,rlmode,x,injection)
+ local dx = factor * x
+ if dx ~= 0 then
+ nofregisteredkerns = nofregisteredkerns + 1
+ local p = rawget(properties,current)
+ if not injection then
+ injection = "injections"
+ end
+ if rlmode and rlmode < 0 then
+ -- we need to swap with a single so then we also need to to it here
+ -- as move is just a simple single
+ if p then
+ local i = p[injection]
+ if i then
+ i.rightkern = dx + (i.rightkern or 0)
+ else
+ p[injection] = {
+ rightkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ rightkern = dx,
+ },
+ }
+ end
+ else
+ if p then
+ local i = p[injection]
+ if i then
+ i.leftkern = dx + (i.leftkern or 0)
+ else
+ p[injection] = {
+ leftkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ leftkern = dx,
+ },
+ }
+ end
+ end
+ return dx, nofregisteredkerns
+ else
+ return 0, 0
+ end
+end
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) -- ba=baseanchor, ma=markanchor
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
nofregisteredmarks = nofregisteredmarks + 1
if rlmode >= 0 then
@@ -387,15 +464,20 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmar
local p = rawget(properties,start)
-- hm, dejavu serif does a sloppy mark2mark before mark2base
if p then
- -- local i = rawget(p,"injections")
local i = p.injections
if i then
if i.markmark then
-- out of order mkmk: yes or no or option
else
- i.markx = dx
- i.marky = dy
- i.markdir = rlmode or 0
+ if dx ~= 0 then
+ i.markx = dx
+ end
+ if y ~= 0 then
+ i.marky = dy
+ end
+ if rlmode then
+ i.markdir = rlmode
+ end
i.markbase = nofregisteredmarks
i.markbasenode = base
i.markmark = mkmk
@@ -441,7 +523,7 @@ local function show(n,what,nested,symbol)
if n then
local p = rawget(properties,n)
if p then
- local i = rawget(p,what)
+ local i = p[what]
if i then
local leftkern = i.leftkern or 0
local rightkern = i.rightkern or 0
@@ -483,7 +565,7 @@ end
local function showsub(n,what,where)
report_injections("begin subrun: %s",where)
- for n in traverse_id(glyph_code,n) do
+ for n in nextchar, n do
showchar(n,where)
show(n,what,where," ")
end
@@ -491,8 +573,9 @@ local function showsub(n,what,where)
end
local function trace(head,where)
- report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered",
- where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
+ report_injections()
+ report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
+ where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
local n = head
while n do
local id = getid(n)
@@ -527,11 +610,12 @@ local function show_result(head)
while current do
local id = getid(current)
if id == glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",
- getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+ local w = getwidth(current)
+ local x, y = getoffsets(current)
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
skipping = false
elseif id == kern_code then
- report_injections("kern: %p",getfield(current,"kern"))
+ report_injections("kern: %p",getkern(current))
skipping = false
elseif not skipping then
report_injections()
@@ -539,6 +623,7 @@ local function show_result(head)
end
current = getnext(current)
end
+ report_injections()
end
-- G +D-pre G
@@ -550,7 +635,6 @@ end
-- +D-replace +D-replace
local function inject_kerns_only(head,where)
- head = tonut(head)
if trace_injections then
trace(head,"kerns")
end
@@ -558,7 +642,7 @@ local function inject_kerns_only(head,where)
local prev = nil
local next = nil
local prevdisc = nil
- local prevglyph = nil
+ -- local prevglyph = nil
local pre = nil -- saves a lookup
local post = nil -- saves a lookup
local replace = nil -- saves a lookup
@@ -566,96 +650,75 @@ local function inject_kerns_only(head,where)
local posttail = nil -- saves a lookup
local replacetail = nil -- saves a lookup
while current do
- local id = getid(current)
local next = getnext(current)
- if id == glyph_code then
- if getsubtype(current) < 256 then
- local p = rawget(properties,current)
- if p then
- -- local i = rawget(p,"injections")
- local i = p.injections
- if i then
- -- left|glyph|right
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(current,"xoffset",leftkern)
- setfield(current,"xadvance",leftkern)
- else
- insert_node_before(head,current,newkern(leftkern))
+ local char, id = ischar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ -- left|glyph|right
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ head = insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ if prevdisc then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(leftkern))
+ done = true
end
end
end
- if prevdisc then
- local done = false
- if post then
- -- local i = rawget(p,"postinjections")
- local i = p.postinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(post,"xadvance",leftkern)
- else
- insert_node_after(post,posttail,newkern(leftkern))
- done = true
- end
- end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(leftkern))
+ done = true
end
end
- if replace then
- -- local i = rawget(p,"replaceinjections")
- local i = p.replaceinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(replace,"xadvance",leftkern)
- else
- insert_node_after(replace,replacetail,newkern(leftkern))
- done = true
- end
- end
- end
- else
- -- local i = rawget(p,"emptyinjections")
- local i = p.emptyinjections
- if i then
- -- glyph|disc|glyph (special case)
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern
- end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setfield(prev,"replace",fontkern(leftkern)) -- maybe also leftkern
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
- end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
end
end
prevdisc = nil
- prevglyph = current
+ -- prevglyph = current
+ elseif char == false then
+ -- other font
+ prevdisc = nil
+ -- prevglyph = current
elseif id == disc_code then
pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
local done = false
if pre then
-- left|pre glyphs|right
- for n in traverse_char(pre) do
+ for n in nextchar, pre do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"preinjections")
local i = p.injections or p.preinjections
if i then
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(pre,"xoffset",leftkern)
- setfield(pre,"xadvance",leftkern)
- else
- pre = insert_node_before(pre,n,newkern(leftkern))
- done = true
- end
+ pre = insert_node_before(pre,n,fontkern(leftkern))
+ done = true
end
end
end
@@ -663,21 +726,15 @@ local function inject_kerns_only(head,where)
end
if post then
-- left|post glyphs|right
- for n in traverse_char(post) do
+ for n in nextchar, post do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"postinjections")
local i = p.injections or p.postinjections
if i then
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(post,"xoffset",leftkern)
- setfield(post,"xadvance",leftkern)
- else
- post = insert_node_before(post,n,newkern(leftkern))
- done = true
- end
+ post = insert_node_before(post,n,fontkern(leftkern))
+ done = true
end
end
end
@@ -685,21 +742,15 @@ local function inject_kerns_only(head,where)
end
if replace then
-- left|replace glyphs|right
- for n in traverse_char(replace) do
+ for n in nextchar, replace do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"replaceinjections")
local i = p.injections or p.replaceinjections
if i then
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- if use_advance then
- setfield(replace,"xoffset",leftkern)
- setfield(replace,"xadvance",leftkern)
- else
- replace = insert_node_before(replace,n,newkern(leftkern))
- done = true
- end
+ replace = insert_node_before(replace,n,fontkern(leftkern))
+ done = true
end
end
end
@@ -708,10 +759,10 @@ local function inject_kerns_only(head,where)
if done then
setdisc(current,pre,post,replace)
end
- prevglyph = nil
+ -- prevglyph = nil
prevdisc = current
else
- prevglyph = nil
+ -- prevglyph = nil
prevdisc = nil
end
prev = current
@@ -723,13 +774,15 @@ local function inject_kerns_only(head,where)
else
nofregisteredkerns = 0
end
- return tonode(head), true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
-local function inject_pairs_only(head,where)
- head = tonut(head)
+local function inject_positions_only(head,where)
if trace_injections then
- trace(head,"pairs")
+ trace(head,"positions")
end
local current = head
local prev = nil
@@ -743,110 +796,110 @@ local function inject_pairs_only(head,where)
local posttail = nil -- saves a lookup
local replacetail = nil -- saves a lookup
while current do
- local id = getid(current)
local next = getnext(current)
- if id == glyph_code then
- if getsubtype(current) < 256 then
- local p = rawget(properties,current)
- if p then
- -- local i = rawget(p,"injections")
- local i = p.injections
- if i then
- -- left|glyph|right
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(current,"yoffset",yoffset)
- end
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- head = insert_node_before(head,current,newkern(leftkern))
+ local char, id = ischar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ -- left|glyph|right
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setoffsets(current,false,yoffset)
+ end
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if leftkern and leftkern ~= 0 then
+ if rightkern and leftkern == -rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern = 0
+ else
+ head = insert_node_before(head,current,fontkern(leftkern))
end
+ end
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(head,current,newkern(rightkern))
- end
- else
- -- local i = rawget(p,"emptyinjections")
- local i = p.emptyinjections
- if i then
- -- glyph|disc|glyph (special case)
--- is this okay?
- local rightkern = i.rightkern
- if rightkern and rightkern ~= 0 then
- if next and getid(next) == disc_code then
- if replace then
- -- error, we expect an empty one
- else
- setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern
- end
+ if next and getid(next) == disc_code then
+ if replace then
+ -- error, we expect an empty one
+ else
+ setfield(next,"replace",fontkern(rightkern)) -- maybe also leftkern
end
end
end
end
- if prevdisc then
- local done = false
- if post then
- -- local i = rawget(p,"postinjections")
- local i = p.postinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done = true
- end
+ end
+ if prevdisc then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(leftkern))
+ done = true
end
end
- if replace then
- -- local i = rawget(p,"replaceinjections")
- local i = p.replaceinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done = true
- end
- end
- else
- local i = p.emptyinjections
- if i then
--- new .. okay?
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern
- end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(leftkern))
+ done = true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i = p.emptyinjections
+ if i then
+ -- new .. okay?
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setfield(prev,"replace",fontkern(leftkern)) -- maybe also leftkern
+ end
end
end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
end
end
prevdisc = nil
prevglyph = current
+ elseif char == false then
+ prevdisc = nil
+ prevglyph = current
elseif id == disc_code then
pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
local done = false
if pre then
-- left|pre glyphs|right
- for n in traverse_char(pre) do
+ for n in nextchar, pre do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"preinjections")
local i = p.injections or p.preinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- pre = insert_node_before(pre,n,newkern(leftkern))
+ pre = insert_node_before(pre,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done = true
end
end
@@ -855,24 +908,23 @@ local function inject_pairs_only(head,where)
end
if post then
-- left|post glyphs|right
- for n in traverse_char(post) do
+ for n in nextchar, post do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"postinjections")
local i = p.injections or p.postinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- post = insert_node_before(post,n,newkern(leftkern))
+ post = insert_node_before(post,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done = true
end
end
@@ -881,24 +933,23 @@ local function inject_pairs_only(head,where)
end
if replace then
-- left|replace glyphs|right
- for n in traverse_char(replace) do
+ for n in nextchar, replace do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"replaceinjections")
local i = p.injections or p.replaceinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- replace = insert_node_before(replace,n,newkern(leftkern))
+ replace = insert_node_before(replace,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done = true
end
end
@@ -909,13 +960,12 @@ local function inject_pairs_only(head,where)
if pre then
local p = rawget(properties,prevglyph)
if p then
- -- local i = rawget(p,"preinjections")
local i = p.preinjections
if i then
-- glyph|pre glyphs
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- pre = insert_node_before(pre,pre,newkern(rightkern))
+ pre = insert_node_before(pre,pre,fontkern(rightkern))
done = true
end
end
@@ -924,13 +974,12 @@ local function inject_pairs_only(head,where)
if replace then
local p = rawget(properties,prevglyph)
if p then
- -- local i = rawget(p,"replaceinjections")
local i = p.replaceinjections
if i then
-- glyph|replace glyphs
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- replace = insert_node_before(replace,replace,newkern(rightkern))
+ replace = insert_node_before(replace,replace,fontkern(rightkern))
done = true
end
end
@@ -953,43 +1002,22 @@ local function inject_pairs_only(head,where)
if keepregisteredcounts then
keepregisteredcounts = false
else
- nofregisteredkerns = 0
+ nofregisteredpositions = 0
+ end
+ if trace_injections then
+ show_result(head)
end
- return tonode(head), true
+ return head
end
--- local function showoffset(n,flag)
--- local ox = getfield(n,"xoffset")
--- local oy = getfield(n,"yoffset")
--- if flag then
--- if ox == 0 then
--- setcolor(n,oy == 0 and "darkgray" or "darkgreen")
--- else
--- setcolor(n,oy == 0 and "darkblue" or "darkred")
--- end
--- else
--- if ox == 0 then
--- setcolor(n,oy == 0 and "gray" or "green")
--- else
--- setcolor(n,oy == 0 and "blue" or "red")
--- end
--- end
--- end
-
local function showoffset(n,flag)
- local o = getfield(n,"xoffset")
- if o == 0 then
- o = getfield(n,"yoffset")
- end
- if o ~= 0 then
- setcolor(n,flag and "darkred" or "darkgreen")
- else
- resetcolor(n)
+ local x, y = getoffsets(n)
+ if x ~= 0 or y ~= 0 then
+ setcolor(n,"darkgray")
end
end
local function inject_everything(head,where)
- head = tonut(head)
if trace_injections then
trace(head,"everything")
end
@@ -998,8 +1026,6 @@ local function inject_everything(head,where)
--
local current = head
local last = nil
- local font = font
- local markdata = nil
local prev = nil
local next = nil
local prevdisc = nil
@@ -1018,262 +1044,333 @@ local function inject_everything(head,where)
local marks = { }
local nofmarks = 0
--
+ -- local applyfix = hascursives and fix_cursive_marks
+ --
-- move out
--
local function processmark(p,n,pn) -- p = basenode
- local px = getfield(p,"xoffset")
+ local px, py = getoffsets(p)
+ local nx, ny = getoffsets(n)
local ox = 0
local rightkern = nil
local pp = rawget(properties,p)
if pp then
- -- pp = rawget(pp,"injections")
pp = pp.injections
if pp then
rightkern = pp.rightkern
end
end
+ local markdir = pn.markdir
if rightkern then -- x and w ~= 0
- if pn.markdir < 0 then
+ ox = px - (pn.markx or 0) - rightkern
+ if markdir and markdir < 0 then
-- kern(w-x) glyph(p) kern(x) mark(n)
- ox = px - pn.markx - rightkern
- -- report_injections("r2l case 1: %p",ox)
+ if not pn.markmark then
+ ox = ox + (pn.leftkern or 0)
+ end
else
-- kern(x) glyph(p) kern(w-x) mark(n)
- -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
--
-- According to Kai we don't need to handle leftkern here but I'm
-- pretty sure I've run into a case where it was needed so maybe
-- some day we need something more clever here.
--
+ -- maybe we need to apply both then
+ --
if false then
- -- a mark with kerning
+ -- a mark with kerning (maybe husayni needs it )
local leftkern = pp.leftkern
if leftkern then
- ox = px - pn.markx - leftkern
- else
- ox = px - pn.markx
+ ox = ox - leftkern
end
- else
- ox = px - pn.markx
end
end
else
- -- if pn.markdir < 0 then
- -- ox = px - pn.markx
- -- -- report_injections("r2l case 3: %p",ox)
- -- else
- -- -- ox = px - getfield(p,"width") + pn.markx
- ox = px - pn.markx
- -- report_injections("l2r case 3: %p",ox)
- -- end
+ ox = px - (pn.markx or 0)
+ if markdir and markdir < 0 then
+ if not pn.markmark then
+ local leftkern = pn.leftkern
+ if leftkern then
+ ox = ox + leftkern -- husayni needs it
+ end
+ end
+ end
if pn.checkmark then
- local wn = getfield(n,"width") -- in arial marks have widths
- if wn ~= 0 then
+ local wn = getwidth(n) -- in arial marks have widths
+ if wn and wn ~= 0 then
wn = wn/2
if trace_injections then
report_injections("correcting non zero width mark %C",getchar(n))
end
-- -- bad: we should center
+ --
-- pn.leftkern = -wn
-- pn.rightkern = -wn
- -- -- we're too late anyway as kerns are already injected so
- -- -- we do it the ugly way (no checking if the previous is
- -- -- already a kern) .. maybe we should fix the font instead
- insert_node_before(n,n,newkern(-wn))
- insert_node_after(n,n,newkern(-wn))
+ --
+ -- -- we're too late anyway as kerns are already injected so we do it the
+ -- -- ugly way (no checking if the previous is already a kern) .. maybe we
+ -- -- should fix the font instead
+ --
+ -- todo: head and check for prev / next kern
+ --
+ insert_node_before(n,n,fontkern(-wn))
+ insert_node_after(n,n,fontkern(-wn))
end
end
end
- local oy = getfield(n,"yoffset") + getfield(p,"yoffset") + pn.marky
- setfield(n,"xoffset",ox)
- setfield(n,"yoffset",oy)
+ local oy = ny + py + (pn.marky or 0)
+ if not pn.markmark then
+ local yoffset = pn.yoffset
+ if yoffset then
+ oy = oy + yoffset -- husayni needs it
+ end
+ end
+ setoffsets(n,ox,oy)
if trace_marks then
showoffset(n,true)
end
end
- -- todo: marks in disc
+ -- begin of temp fix --
+ -- local base = nil -- bah, some arabic fonts have no mark anchoring
+ -- end of temp fix --
while current do
- local id = getid(current)
local next = getnext(current)
- if id == glyph_code then
- if getsubtype(current) < 256 then
- local p = rawget(properties,current)
- if p then
- -- local i = rawget(p,"injections")
- local i = p.injections
- if i then
- local pm = i.markbasenode
- if pm then
- nofmarks = nofmarks + 1
- marks[nofmarks] = current
- else
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(current,"yoffset",yoffset)
- end
- if hascursives then
- local cursivex = i.cursivex
- if cursivex then
- if cursiveanchor then
- if cursivex ~= 0 then
- i.leftkern = (i.leftkern or 0) + cursivex
- end
- if maxc == 0 then
- minc = 1
- maxc = 1
- glyphs[1] = cursiveanchor
- else
- maxc = maxc + 1
- glyphs[maxc] = cursiveanchor
- end
- properties[cursiveanchor].cursivedy = i.cursivey -- cursiveprops
- last = current
+ local char, id = ischar(current)
+ if char then
+ local p = rawget(properties,current)
+ -- begin of temp fix --
+ -- if applyfix then
+ -- if not p then
+ -- local m = fontmarks[getfont(current)]
+ -- if m and m[char] then
+ -- if base then
+ -- p = { injections = { markbasenode = base } }
+ -- nofmarks = nofmarks + 1
+ -- marks[nofmarks] = current
+ -- properties[current] = p
+ -- hasmarks = true
+ -- end
+ -- else
+ -- base = current
+ -- end
+ -- end
+ -- end
+ -- end of temp fix
+ if p then
+ local i = p.injections
+ -- begin of temp fix --
+ -- if applyfix then
+ -- if not i then
+ -- local m = fontmarks[getfont(current)]
+ -- if m and m[char] then
+ -- if base then
+ -- i = { markbasenode = base }
+ -- nofmarks = nofmarks + 1
+ -- marks[nofmarks] = current
+ -- p.injections = i
+ -- hasmarks = true
+ -- end
+ -- else
+ -- base = current
+ -- end
+ -- end
+ -- end
+ -- end of temp fix --
+ if i then
+ local pm = i.markbasenode
+ -- begin of temp fix --
+ -- if applyfix then
+ -- if not pm then
+ -- local m = fontmarks[getfont(current)]
+ -- if m and m[char] then
+ -- if base then
+ -- pm = base
+ -- i.markbasenode = pm
+ -- hasmarks = true
+ -- end
+ -- else
+ -- base = current
+ -- end
+ -- else
+ -- base = current
+ -- end
+ -- end
+ -- end of temp fix --
+ if pm then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = current
+ else
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setoffsets(current,false,yoffset)
+ end
+ if hascursives then
+ local cursivex = i.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex ~= 0 then
+ i.leftkern = (i.leftkern or 0) + cursivex
+ end
+ if maxc == 0 then
+ minc = 1
+ maxc = 1
+ glyphs[1] = cursiveanchor
else
- maxc = 0
+ maxc = maxc + 1
+ glyphs[maxc] = cursiveanchor
end
- elseif maxc > 0 then
- local ny = getfield(current,"yoffset")
+ properties[cursiveanchor].cursivedy = i.cursivey -- cursiveprops
+ last = current
+ else
+ maxc = 0
+ end
+ elseif maxc > 0 then
+ local nx, ny = getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setoffsets(ti,false,ny) -- why not add ?
+ if trace_cursive then
+ showoffset(ti)
+ end
+ end
+ maxc = 0
+ cursiveanchor = nil
+ end
+ if i.cursiveanchor then
+ cursiveanchor = current -- no need for both now
+ else
+ if maxc > 0 then
+ local nx, ny = getoffsets(current)
for i=maxc,minc,-1 do
local ti = glyphs[i]
ny = ny + properties[ti].cursivedy
- setfield(ti,"yoffset",ny) -- why not add ?
+ setoffsets(ti,false,ny) -- why not add ?
if trace_cursive then
showoffset(ti)
end
end
maxc = 0
- cursiveanchor = nil
- end
- if i.cursiveanchor then
- cursiveanchor = current -- no need for both now
- else
- if maxc > 0 then
- local ny = getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti = glyphs[i]
- ny = ny + properties[ti].cursivedy
- setfield(ti,"yoffset",ny) -- why not add ?
- if trace_cursive then
- showoffset(ti)
- end
- end
- maxc = 0
- end
- cursiveanchor = nil
end
+ cursiveanchor = nil
end
- -- left|glyph|right
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_before(head,current,newkern(leftkern))
- end
- local rightkern = i.rightkern
- if rightkern and rightkern ~= 0 then
- insert_node_after(head,current,newkern(rightkern))
+ end
+ -- left|glyph|right
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if leftkern and leftkern ~= 0 then
+ if rightkern and leftkern == -rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern = 0
+ else
+ head = insert_node_before(head,current,fontkern(leftkern))
end
end
- else
- -- local i = rawget(p,"emptyinjections")
- local i = p.emptyinjections
- if i then
- -- glyph|disc|glyph (special case)
- -- okay?
- local rightkern = i.rightkern
- if rightkern and rightkern ~= 0 then
- if next and getid(next) == disc_code then
- if replace then
- -- error, we expect an empty one
- else
- setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern
- end
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ if next and getid(next) == disc_code then
+ if replace then
+ -- error, we expect an empty one
+ else
+ setfield(next,"replace",fontkern(rightkern)) -- maybe also leftkern
end
end
end
end
- if prevdisc then
- if p then
- local done = false
- if post then
- -- local i = rawget(p,"postinjections")
- local i = p.postinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done = true
- end
+ end
+ if prevdisc then
+ if p then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(leftkern))
+ done = true
end
end
- if replace then
- -- local i = rawget(p,"replaceinjections")
- local i = p.replaceinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done = true
- end
- end
- else
- -- local i = rawget(p,"emptyinjections")
- local i = p.emptyinjections
- if i then
- local leftkern = i.leftkern
- if leftkern and leftkern ~= 0 then
- setfield(prev,"replace",newkern(leftkern)) -- maybe also leftkern
- end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(leftkern))
+ done = true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i = p.emptyinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setfield(prev,"replace",fontkern(leftkern)) -- maybe also leftkern
+ end
end
end
- end
- else
- -- cursive
- if hascursives and maxc > 0 then
- local ny = getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti = glyphs[i]
- ny = ny + properties[ti].cursivedy
- setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- can be mark
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
- maxc = 0
- cursiveanchor = nil
end
end
+ else
+ -- cursive
+ if hascursives and maxc > 0 then
+ local nx, ny = getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ local xi, yi = getoffsets(ti)
+ setoffsets(ti,xi,yi + ny) -- can be mark, we could use properties
+ end
+ maxc = 0
+ cursiveanchor = nil
+ end
end
prevdisc = nil
prevglyph = current
+ elseif char == false then
+ -- base = nil
+ prevdisc = nil
+ prevglyph = current
elseif id == disc_code then
+ -- base = nil
pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
local done = false
if pre then
-- left|pre glyphs|right
- for n in traverse_char(pre) do
+ for n in nextchar, pre do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"preinjections")
local i = p.injections or p.preinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- pre = insert_node_before(pre,n,newkern(leftkern))
+ pre = insert_node_before(pre,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done = true
end
if hasmarks then
local pm = i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -1282,30 +1379,29 @@ local function inject_everything(head,where)
end
if post then
-- left|post glyphs|right
- for n in traverse_char(post) do
+ for n in nextchar, post do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"postinjections")
local i = p.injections or p.postinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- post = insert_node_before(post,n,newkern(leftkern))
+ post = insert_node_before(post,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done = true
end
if hasmarks then
local pm = i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -1314,30 +1410,29 @@ local function inject_everything(head,where)
end
if replace then
-- left|replace glyphs|right
- for n in traverse_char(replace) do
+ for n in nextchar, replace do
local p = rawget(properties,n)
if p then
- -- local i = rawget(p,"injections") or rawget(p,"replaceinjections")
local i = p.injections or p.replaceinjections
if i then
local yoffset = i.yoffset
if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- replace = insert_node_before(replace,n,newkern(leftkern))
+ replace = insert_node_before(replace,n,fontkern(leftkern))
done = true
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done = true
end
if hasmarks then
local pm = i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -1348,13 +1443,12 @@ local function inject_everything(head,where)
if pre then
local p = rawget(properties,prevglyph)
if p then
- -- local i = rawget(p,"preinjections")
local i = p.preinjections
if i then
-- glyph|pre glyphs
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- pre = insert_node_before(pre,pre,newkern(rightkern))
+ pre = insert_node_before(pre,pre,fontkern(rightkern))
done = true
end
end
@@ -1363,13 +1457,12 @@ local function inject_everything(head,where)
if replace then
local p = rawget(properties,prevglyph)
if p then
- -- local i = rawget(p,"replaceinjections")
local i = p.replaceinjections
if i then
-- glyph|replace glyphs
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
- replace = insert_node_before(replace,replace,newkern(rightkern))
+ replace = insert_node_before(replace,replace,fontkern(rightkern))
done = true
end
end
@@ -1382,6 +1475,7 @@ local function inject_everything(head,where)
prevglyph = nil
prevdisc = current
else
+ -- base = nil
prevglyph = nil
prevdisc = nil
end
@@ -1390,11 +1484,11 @@ local function inject_everything(head,where)
end
-- cursive
if hascursives and maxc > 0 then
- local ny = getfield(last,"yoffset")
+ local nx, ny = getoffsets(last)
for i=maxc,minc,-1 do
local ti = glyphs[i]
ny = ny + properties[ti].cursivedy
- setfield(ti,"yoffset",ny) -- why not add ?
+ setoffsets(ti,false,ny) -- why not add ?
if trace_cursive then
showoffset(ti)
end
@@ -1405,7 +1499,6 @@ local function inject_everything(head,where)
for i=1,nofmarks do
local m = marks[i]
local p = rawget(properties,m)
- -- local i = rawget(p,"injections")
local i = p.injections
local b = i.markbasenode
processmark(b,m,i)
@@ -1417,12 +1510,15 @@ local function inject_everything(head,where)
if keepregisteredcounts then
keepregisteredcounts = false
else
- nofregisteredkerns = 0
- nofregisteredpairs = 0
- nofregisteredmarks = 0
- nofregisteredcursives = 0
+ nofregisteredkerns = 0
+ nofregisteredpositions = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
end
- return tonode(head), true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
-- space triggers
@@ -1470,21 +1566,49 @@ end
injections.getthreshold = getthreshold
-function injections.isspace(n,threshold)
- if getid(n) == glue_code then
- local w = getfield(n,"width")
+function injections.isspace(n,threshold,id)
+ if (id or getid(n)) == glue_code then
+ local w = getwidth(n)
if threshold and w > threshold then -- was >=
return 32
end
end
end
+-- We have a plugin so that Kai can use the next in plain. Such a plugin is rather application
+-- specific.
+--
+-- local getboth = nodes.direct.getboth
+-- local getid = nodes.direct.getid
+-- local getprev = nodes.direct.getprev
+-- local getnext = nodes.direct.getnext
+--
+-- local whatsit_code = nodes.nodecodes.whatsit
+-- local glyph_code = nodes.nodecodes.glyph
+--
+-- local function getspaceboth(n) -- fragile: what it prev/next has no width field
+-- local prev, next = getboth(n)
+-- while prev and (getid(prev) == whatsit_code or (getwidth(prev) == 0 and getid(prev) ~= glyph_code)) do
+-- prev = getprev(prev)
+-- end
+-- while next and (getid(next) == whatsit_code or (getwidth(next) == 0 and getid(next) ~= glyph_code)) do
+-- next = getnext(next)
+-- end
+-- end
+--
+-- injections.installgetspaceboth(getspaceboth)
+
+local getspaceboth = getboth
+
+function injections.installgetspaceboth(gb)
+ getspaceboth = gb or getboth
+end
+
local function injectspaces(head)
if not triggers then
- return head, false
+ return head
end
-
local lastfont = nil
local spacekerns = nil
local leftkerns = nil
@@ -1502,10 +1626,10 @@ local function injectspaces(head)
factor = getthreshold(font)
end
- for n in traverse_id(glue_code,tonut(head)) do
- local prev, next = getboth(n)
- local prevchar = ischar(prev)
- local nextchar = ischar(next)
+ for n in nextglue, head do
+ local prev, next = getspaceboth(n)
+ local prevchar = prev and ischar(prev)
+ local nextchar = next and ischar(next)
if nextchar then
local font = getfont(next)
local trig = triggers[font]
@@ -1531,39 +1655,66 @@ local function injectspaces(head)
end
end
if leftkern then
- local old = getfield(n,"width")
+ local old = getwidth(n)
if old > threshold then
if rightkern then
- local new = old + (leftkern + rightkern) * factor
- if trace_spaces then
- report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ if useitalickerns then
+ local lnew = leftkern * factor
+ local rnew = rightkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
+ end
+ head = insert_node_before(head,n,italickern(lnew))
+ insert_node_after(head,n,italickern(rnew))
+ else
+ local new = old + (leftkern + rightkern) * factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
- leftkern = false
+ rightkern = false
else
- local new = old + leftkern * factor
- if trace_spaces then
- report_spaces("%C [%p -> %p]",prevchar,old,new)
+ if useitalickerns then
+ local new = leftkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",prevchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new)) -- tricky with traverse but ok
+ else
+ local new = old + leftkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p]",prevchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
end
leftkern = false
elseif rightkern then
- local old = getfield(n,"width")
+ local old = getwidth(n)
if old > threshold then
- local new = old + rightkern * factor
- if trace_spaces then
- report_spaces("[%p -> %p] %C",nextchar,old,new)
+ if useitalickerns then
+ local new = rightkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",nextchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ local new = old + rightkern * factor
+ if trace_spaces then
+ report_spaces("[%p -> %p] %C",nextchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
rightkern = false
end
end
triggers = false
- return head, true
+
+ return head
end
--
@@ -1578,17 +1729,17 @@ function injections.handler(head,where)
report_injections("injection variant %a","everything")
end
return inject_everything(head,where)
- elseif nofregisteredpairs > 0 then
+ elseif nofregisteredpositions > 0 then
if trace_injections then
- report_injections("injection variant %a","pairs")
+ report_injections("injection variant %a","positions")
end
- return inject_pairs_only(head,where)
+ return inject_positions_only(head,where)
elseif nofregisteredkerns > 0 then
if trace_injections then
report_injections("injection variant %a","kerns")
end
return inject_kerns_only(head,where)
else
- return head, false
+ return head
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua
index d4eaed763ba..abb0ebd148c 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua
@@ -23,7 +23,7 @@ if not modules then modules = { } end modules ['font-otl'] = {
-- todo: less tounicodes
-local gmatch, find, match, lower, strip = string.gmatch, string.find, string.match, string.lower, string.strip
+local lower = string.lower
local type, next, tonumber, tostring, unpack = type, next, tonumber, tostring, unpack
local abs = math.abs
local derivetable = table.derive
@@ -52,12 +52,14 @@ local report_otf = logs.reporter("fonts","otf loading")
local fonts = fonts
local otf = fonts.handlers.otf
-otf.version = 3.027 -- beware: also sync font-mis.lua and in mtx-fonts
-otf.cache = containers.define("fonts", "otl", otf.version, true)
-otf.svgcache = containers.define("fonts", "svg", otf.version, true)
-otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
+otf.version = 3.104 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.cache = containers.define("fonts", "otl", otf.version, true)
+otf.svgcache = containers.define("fonts", "svg", otf.version, true)
+otf.sbixcache = containers.define("fonts", "sbix", otf.version, true)
+otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
otf.svgenabled = false
+otf.sbixenabled = false
local otfreaders = otf.readers
@@ -77,6 +79,8 @@ local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M)
local syncspace = true
local forcenotdef = false
+local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF
+
local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
local wildcard = "*"
@@ -93,31 +97,43 @@ registerdirective("fonts.otf.loader.force", function(v) forceload =
registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end)
registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
--- local function load_featurefile(raw,featurefile)
--- if featurefile and featurefile ~= "" then
--- if trace_loading then
--- report_otf("using featurefile %a", featurefile)
--- end
--- -- TODO: apply_featurefile(raw, featurefile)
--- end
--- end
-
-- otfenhancers.patch("before","migrate metadata","cambria",function() end)
registerotfenhancer("check extra features", function() end) -- placeholder
-function otf.load(filename,sub,featurefile) -- second argument (format) is gone !
- --
- local featurefile = nil -- not supported (yet)
- --
+-- Kai has memory problems on osx so here is an experiment (I only tested on windows as
+-- my test mac is old and gets no updates and is therefore rather useless.):
+
+local checkmemory = utilities.lua and utilities.lua.checkmemory
+local threshold = 100 -- MB
+local tracememory = false
+
+registertracker("fonts.otf.loader.memory",function(v) tracememory = v end)
+
+if not checkmemory then -- we need a generic plug (this code might move):
+
+ local collectgarbage = collectgarbage
+
+ checkmemory = function(previous,threshold) -- threshold in MB
+ local current = collectgarbage("count")
+ if previous then
+ local checked = (threshold or 64)*1024
+ if current - previous > checked then
+ collectgarbage("collect")
+ current = collectgarbage("count")
+ end
+ end
+ return current
+ end
+
+end
+
+function otf.load(filename,sub,instance)
local base = file.basename(file.removesuffix(filename))
- local name = file.removesuffix(base)
+ local name = file.removesuffix(base) -- already no suffix
local attr = lfs.attributes(filename)
local size = attr and attr.size or 0
local time = attr and attr.modification or 0
- if featurefile then
- name = name .. "@" .. file.removesuffix(file.basename(featurefile))
- end
-- sub can be number of string
if sub == "" then
sub = false
@@ -126,71 +142,30 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
if sub then
hash = hash .. "-" .. sub
end
- hash = containers.cleanname(hash)
- local featurefiles
- if featurefile then
- featurefiles = { }
- for s in gmatch(featurefile,"[^,]+") do
- local name = resolvers.findfile(file.addsuffix(s,'fea'),'fea') or ""
- if name == "" then
- report_otf("loading error, no featurefile %a",s)
- else
- local attr = lfs.attributes(name)
- featurefiles[#featurefiles+1] = {
- name = name,
- size = attr and attr.size or 0,
- time = attr and attr.modification or 0,
- }
- end
- end
- if #featurefiles == 0 then
- featurefiles = nil
- end
+ if instance then
+ hash = hash .. "-" .. instance
end
+ hash = containers.cleanname(hash)
local data = containers.read(otf.cache,hash)
local reload = not data or data.size ~= size or data.time ~= time or data.tableversion ~= otfreaders.tableversion
if forceload then
report_otf("forced reload of %a due to hard coded flag",filename)
reload = true
end
- -- if not reload then
- -- local featuredata = data.featuredata
- -- if featurefiles then
- -- if not featuredata or #featuredata ~= #featurefiles then
- -- reload = true
- -- else
- -- for i=1,#featurefiles do
- -- local fi, fd = featurefiles[i], featuredata[i]
- -- if fi.name ~= fd.name or fi.size ~= fd.size or fi.time ~= fd.time then
- -- reload = true
- -- break
- -- end
- -- end
- -- end
- -- elseif featuredata then
- -- reload = true
- -- end
- -- if reload then
- -- report_otf("loading: forced reload due to changed featurefile specification %a",featurefile)
- -- end
- -- end
if reload then
report_otf("loading %a, hash %a",filename,hash)
--
starttiming(otfreaders)
- data = otfreaders.loadfont(filename,sub or 1) -- we can pass the number instead (if it comes from a name search)
- --
- -- if featurefiles then
- -- for i=1,#featurefiles do
- -- load_featurefile(data,featurefiles[i].name)
- -- end
- -- end
- --
- --
+ data = otfreaders.loadfont(filename,sub or 1,instance) -- we can pass the number instead (if it comes from a name search)
if data then
- --
- local resources = data.resources
- local svgshapes = resources.svgshapes
+ -- todo: make this a plugin
+ local used = checkmemory()
+ local resources = data.resources
+ local svgshapes = resources.svgshapes
+ local sbixshapes = resources.sbixshapes
+ if cleanup == 0 then
+ checkmemory(used,threshold,tracememory)
+ end
if svgshapes then
resources.svgshapes = nil
if otf.svgenabled then
@@ -205,18 +180,51 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
timestamp = timestamp,
}
end
+ if cleanup > 1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
+ end
+ if sbixshapes then
+ resources.sbixshapes = nil
+ if otf.sbixenabled then
+ local timestamp = os.date()
+ -- work in progress ... a bit boring to do
+ containers.write(otf.sbixcache,hash, {
+ sbixshapes = sbixshapes,
+ timestamp = timestamp,
+ })
+ data.properties.sbix = {
+ hash = hash,
+ timestamp = timestamp,
+ }
+ end
+ if cleanup > 1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
end
--
otfreaders.compact(data)
+ if cleanup == 0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.rehash(data,"unicodes")
otfreaders.addunicodetable(data)
otfreaders.extend(data)
+ if cleanup == 0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
data = containers.write(otf.cache, hash, data)
if cleanup > 1 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
stoptiming(otfreaders)
if elapsedtime then
@@ -224,10 +232,14 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
end
if cleanup > 3 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
data = containers.read(otf.cache,hash) -- this frees the old table and load the sparse one
if cleanup > 2 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
else
data = nil
@@ -243,15 +255,30 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
otfreaders.expand(data) -- inline tables
otfreaders.addunicodetable(data) -- only when not done yet
--
- otfenhancers.apply(data,filename,data)
+ otfenhancers.apply(data,filename,data) -- in context one can also use treatments
--
-- constructors.addcoreunicodes(data.resources.unicodes) -- still needed ?
--
if applyruntimefixes then
- applyruntimefixes(filename,data)
+ applyruntimefixes(filename,data) -- e.g. see treatments.lfg
end
--
data.metadata.math = data.resources.mathconstants
+ --
+ -- delayed tables (experiment)
+ --
+ local classes = data.resources.classes
+ if not classes then
+ local descriptions = data.descriptions
+ classes = setmetatableindex(function(t,k)
+ local d = descriptions[k]
+ local v = (d and d.class or "base") or false
+ t[k] = v
+ return v
+ end)
+ data.resources.classes = classes
+ end
+ --
end
return data
@@ -313,7 +340,7 @@ local function copytotfm(data,cache_id)
end
if mathspecs then
for unicode, character in next, characters do
- local d = descriptions[unicode]
+ local d = descriptions[unicode] -- we could use parent table here
local m = d.math
if m then
-- watch out: luatex uses horiz_variants for the parts
@@ -378,6 +405,7 @@ local function copytotfm(data,cache_id)
local fontname = metadata.fontname
local fullname = metadata.fullname or fontname
local psname = fontname or fullname
+ local subfont = metadata.subfontindex
local units = metadata.units or 1000
--
if units == 0 then -- catch bugs in fonts
@@ -472,10 +500,13 @@ local function copytotfm(data,cache_id)
properties.fullname = fullname
properties.psname = psname
properties.name = filename or fullname
+ properties.subfont = subfont
--
-- properties.name = specification.name
-- properties.sub = specification.sub
--
+ properties.private = properties.private or data.private or privateoffset
+ --
return {
characters = characters,
descriptions = descriptions,
@@ -535,7 +566,8 @@ local function otftotfm(specification)
local subindex = specification.subindex
local filename = specification.filename
local features = specification.features.normal
- local rawdata = otf.load(filename,sub,features and features.featurefile)
+ local instance = specification.instance or (features and features.axis)
+ local rawdata = otf.load(filename,sub,instance)
if rawdata and next(rawdata) then
local descriptions = rawdata.descriptions
rawdata.lookuphash = { } -- to be done
@@ -585,7 +617,7 @@ local function checkmathsize(tfmdata,mathsize)
local parameters = tfmdata.parameters
parameters.scriptpercentage = mathdata.ScriptPercentScaleDown
parameters.scriptscriptpercentage = mathdata.ScriptScriptPercentScaleDown
- parameters.mathsize = mathsize
+ parameters.mathsize = mathsize -- only when a number !
end
end
@@ -795,6 +827,7 @@ otf.coverup = {
multiple = justset,
kern = justset,
pair = justset,
+ single = justset,
ligature = function(coverage,unicode,ligature)
local first = ligature[1]
local tree = coverage[first]
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua
index 13568799b75..4b986bd3b66 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua
@@ -6,10 +6,6 @@ if not modules then modules = { } end modules ['font-oto'] = { -- original tex
license = "see context related readme files"
}
--- This is a version of font-otb adapted to the new fontloader code. We used to have two
--- base initialization methods but now we have only one. This means that instead of the
--- old default (independent) we now use the one more similar to node node (shared).
-
local concat, unpack = table.concat, table.unpack
local insert, remove = table.insert, table.remove
local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
@@ -34,6 +30,8 @@ local registerotffeature = otffeatures.register
otf.defaultbasealternate = "none" -- first last
+local getprivate = fonts.constructors.getprivate
+
local wildcard = "*"
local default = "dflt"
@@ -71,21 +69,32 @@ local function cref(feature,sequence)
return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
end
-
-local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
- report_prepare("%s: base alternate %s => %s (%S => %S)",
- cref(feature,sequence),
- gref(descriptions,unicode),
- replacement and gref(descriptions,replacement),
- value,
- comment)
+local function report_substitution(feature,sequence,descriptions,unicode,substitution)
+ if unicode == substitution then
+ report_prepare("%s: base substitution %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base substitution %s => %S",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ gref(descriptions,substitution))
+ end
end
-local function report_substitution(feature,sequence,descriptions,unicode,substitution)
- report_prepare("%s: base substitution %s => %S",
- cref(feature,sequence),
- gref(descriptions,unicode),
- gref(descriptions,substitution))
+local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
+ if unicode == replacement then
+ report_prepare("%s: base alternate %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base alternate %s => %s (%S => %S)",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ replacement and gref(descriptions,replacement),
+ value,
+ comment)
+ end
end
local function report_ligature(feature,sequence,descriptions,unicode,ligature)
@@ -158,13 +167,11 @@ end
-- messy if we need to take that into account.
local function makefake(tfmdata,name,present)
- local resources = tfmdata.resources
- local private = resources.private
+ local private = getprivate(tfmdata)
local character = { intermediate = true, ligatures = { } }
resources.unicodes[name] = private
tfmdata.characters[private] = character
tfmdata.descriptions[private] = { name = name }
- resources.private = private + 1
present[name] = private
return character
end
@@ -225,6 +232,9 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local trace_alternatives = trace_baseinit and trace_alternatives
local trace_ligatures = trace_baseinit and trace_ligatures
+ -- A chain of changes is handled in font-con which is clesner because
+ -- we can have shared changes and such.
+
if not changed then
changed = { }
tfmdata.changed = changed
@@ -237,39 +247,44 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
if kind == "gsub_single" then
for i=1,#steps do
for unicode, data in next, steps[i].coverage do
- -- if not changed[unicode] then -- fails for multiple subs in some math fonts
- if trace_singles then
- report_substitution(feature,sequence,descriptions,unicode,data)
- end
+ if unicode ~= data then
changed[unicode] = data
- -- end
+ end
+ if trace_singles then
+ report_substitution(feature,sequence,descriptions,unicode,data)
+ end
end
end
elseif kind == "gsub_alternate" then
for i=1,#steps do
for unicode, data in next, steps[i].coverage do
- if not changed[unicode] then
- local replacement = data[alternate]
- if replacement then
+ local replacement = data[alternate]
+ if replacement then
+ if unicode ~= replacement then
changed[unicode] = replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
- end
- elseif defaultalt == "first" then
- replacement = data[1]
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
+ end
+ elseif defaultalt == "first" then
+ replacement = data[1]
+ if unicode ~= replacement then
+ changed[unicode] = replacement
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ elseif defaultalt == "last" then
+ replacement = data[#data]
+ if unicode ~= replacement then
changed[unicode] = replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- elseif defaultalt == "last" then
- replacement = data[#data]
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- else
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
- end
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ else
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
end
end
end
@@ -289,7 +304,6 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
local nofligatures = #ligatures
if nofligatures > 0 then
-
local characters = tfmdata.characters
local present = { }
local done = trace_baseinit and trace_ligatures and { }
@@ -324,8 +338,9 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
local format = sequence.format
if kind == "gpos_pair" then
for i=1,#steps do
- local step = steps[i]
- if step.format == "kern" then
+ local step = steps[i]
+ local format = step.format
+ if format == "kern" or format == "move" then
for unicode, data in next, steps[i].coverage do
local character = characters[unicode]
local kerns = character.kerns
@@ -353,9 +368,13 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
local character = characters[unicode]
local kerns = character.kerns
for otherunicode, kern in next, data do
- if not kern[2] and not (kerns and kerns[otherunicode]) then
+ -- kern[2] is true (all zero) or a table
+ local other = kern[2]
+ if other == true or (not other and not (kerns and kerns[otherunicode])) then
local kern = kern[1]
- if kern[1] ~= 0 or kern[2] ~= 0 or kern[4] ~= 0 then
+ if kern == true then
+ -- all zero
+ elseif kern[1] ~= 0 or kern[2] ~= 0 or kern[4] ~= 0 then
-- a complex pair not suitable for basemode
else
kern = kern[3]
@@ -385,6 +404,53 @@ local function initializehashes(tfmdata)
-- already done
end
+local function checkmathreplacements(tfmdata,fullname,fixitalics)
+ if tfmdata.mathparameters then
+ local characters = tfmdata.characters
+ local changed = tfmdata.changed
+ if next(changed) then
+ if trace_preparing or trace_baseinit then
+ report_prepare("checking math replacements for %a",fullname)
+ end
+ for unicode, replacement in next, changed do
+ local u = characters[unicode]
+ local r = characters[replacement]
+ local n = u.next
+ local v = u.vert_variants
+ local h = u.horiz_variants
+ if fixitalics then
+ -- quite some warnings on stix ...
+ local ui = u.italic
+ if ui and not r.italic then
+ if trace_preparing then
+ report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+ end
+ r.italic = ui -- print(ui,ri)
+ end
+ end
+ if n and not r.next then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
+ end
+ r.next = n
+ end
+ if v and not r.vert_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+ end
+ r.vert_variants = v
+ end
+ if h and not r.horiz_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+ end
+ r.horiz_variants = h
+ end
+ end
+ end
+ end
+end
+
local function featuresinitializer(tfmdata,value)
if true then -- value then
local starttime = trace_preparing and os.clock()
@@ -401,6 +467,8 @@ local function featuresinitializer(tfmdata,value)
local rawfeatures = rawresources and rawresources.features
local basesubstitutions = rawfeatures and rawfeatures.gsub
local basepositionings = rawfeatures and rawfeatures.gpos
+ local substitutionsdone = false
+ local positioningsdone = false
--
if basesubstitutions or basepositionings then
local sequences = tfmdata.resources.sequences
@@ -423,12 +491,14 @@ local function featuresinitializer(tfmdata,value)
end
preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ substitutionsdone = true
elseif basepositionings and basepositionings[feature] then
if trace_preparing then
report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value)
end
preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ positioningsdone = true
end
end
end
@@ -437,6 +507,10 @@ local function featuresinitializer(tfmdata,value)
end
end
--
+ if substitutionsdone then
+ checkmathreplacements(tfmdata,fullname,features.fixitalics)
+ end
+ --
registerbasehash(tfmdata)
end
if trace_preparing then
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua
index a9d3a8b2931..c7438dd4305 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua
@@ -65,24 +65,27 @@ if not modules then modules = { } end modules ['font-otr'] = {
-- require("char-ini")
-- end
-local next, type, unpack = next, type, unpack
-local byte, lower, char, strip, gsub = string.byte, string.lower, string.char, string.strip, string.gsub
-local bittest = bit32.btest
-local concat, remove, unpack, fastcopy = table.concat, table.remov, table.unpack, table.fastcopy
-local floor, abs, sqrt, round = math.floor, math.abs, math.sqrt, math.round
+local next, type, tonumber = next, type, tonumber
+local byte, lower, char, gsub = string.byte, string.lower, string.char, string.gsub
+local floor, round = math.floor, math.round
local 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
local lpegmatch = lpeg.match
+local rshift = bit32.rshift
local setmetatableindex = table.setmetatableindex
local formatters = string.formatters
local sortedkeys = table.sortedkeys
local sortedhash = table.sortedhash
-local stripstring = string.strip
+local stripstring = string.nospaces
local utf16_to_utf8_be = utf.utf16_to_utf8_be
local report = logs.reporter("otf reader")
local trace_cmap = false -- only for checking issues
+local trace_cmap_detail = false -- only for checking issues
+
+-- local trace_cmap = true
+-- local trace_cmap_detail = true
fonts = fonts or { }
local handlers = fonts.handlers or { }
@@ -92,8 +95,8 @@ handlers.otf = otf
local readers = otf.readers or { }
otf.readers = readers
------ streamreader = utilities.streams -- faster on big files
-local streamreader = utilities.files -- faster on identify
+----- streamreader = utilities.streams -- faster on big files (not true any longer)
+local streamreader = utilities.files -- faster on identify (also uses less memory)
local streamwriter = utilities.files
readers.streamreader = streamreader
@@ -109,20 +112,56 @@ local readstring = streamreader.readstring
local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
-local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
+local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer
----- readchar = streamreader.readinteger1 -- 8-bit signed integer
local readshort = streamreader.readinteger2 -- 16-bit signed integer
-local readlong = streamreader.readinteger4 -- 24-bit unsigned integer
+local readlong = streamreader.readinteger4 -- 32-bit unsigned integer
local readfixed = streamreader.readfixed4
+local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
local readfword = readshort -- 16-bit signed integer that describes a quantity in FUnits
local readufword = readushort -- 16-bit unsigned integer that describes a quantity in FUnits
local readoffset = readushort
-local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
+local readcardinaltable = streamreader.readcardinaltable
+local readintegertable = streamreader.readintegertable
function streamreader.readtag(f)
- return lower(strip(readstring(f,4)))
+ return lower(stripstring(readstring(f,4)))
end
+local short = 2
+local ushort = 2
+local ulong = 4
+
+directives.register("fonts.streamreader",function()
+
+ streamreader = utilities.streams
+
+ openfile = streamreader.open
+ closefile = streamreader.close
+ setposition = streamreader.setposition
+ skipshort = streamreader.skipshort
+ readbytes = streamreader.readbytes
+ readstring = streamreader.readstring
+ readbyte = streamreader.readcardinal1
+ readushort = streamreader.readcardinal2
+ readuint = streamreader.readcardinal3
+ readulong = streamreader.readcardinal4
+ readshort = streamreader.readinteger2
+ readlong = streamreader.readinteger4
+ readfixed = streamreader.readfixed4
+ read2dot14 = streamreader.read2dot14
+ readfword = readshort
+ readufword = readushort
+ readoffset = readushort
+ readcardinaltable = streamreader.readcardinaltable
+ readintegertable = streamreader.readintegertable
+
+ function streamreader.readtag(f)
+ return lower(stripstring(readstring(f,4)))
+ end
+
+end)
+
-- date represented in number of seconds since 12:00 midnight, January 1, 1904. The value is represented as a
-- signed 64-bit integer
@@ -134,15 +173,6 @@ end
local tableversion = 0.004
readers.tableversion = tableversion
local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF
-local reportedskipped = { }
-
-
-local function reportskippedtable(tag)
- if not reportedskipped[tag] then
- report("loading of table %a skipped (reported once only)",tag)
- reportedskipped[tag] = true
- end
-end
-- We have quite some data tables. We are somewhat ff compatible with names but as I used
-- the information from the microsoft site there can be differences. Eventually I might end
@@ -174,6 +204,7 @@ local reservednames = { [0] =
"wwssubfamily",
"lightbackgroundpalette",
"darkbackgroundpalette",
+ "variationspostscriptnameprefix",
}
-- more at: https://www.microsoft.com/typography/otspec/name.htm
@@ -666,12 +697,10 @@ local widths = {
setmetatableindex(weights, function(t,k)
local r = floor((k + 50) / 100) * 100
local v = (r > 900 and "black") or rawget(t,r) or "normal"
--- print("weight:",k,r,v)
return v
end)
setmetatableindex(widths,function(t,k)
--- print("width:",k)
return "normal"
end)
@@ -704,6 +733,44 @@ local panosewidths = {
-- We implement a reader per table.
+-- helper
+
+local helpers = { }
+readers.helpers = helpers
+
+local function gotodatatable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable = fontdata.tables[tag]
+ if datatable then
+ local tableoffset = datatable.offset
+ setposition(f,tableoffset)
+ return tableoffset
+ end
+ end
+end
+
+local function reportskippedtable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable = fontdata.tables[tag]
+ if datatable then
+ report("loading of table %a skipped",tag)
+ end
+ end
+end
+
+local function setvariabledata(fontdata,tag,data)
+ local variabledata = fontdata.variabledata
+ if variabledata then
+ variabledata[tag] = data
+ else
+ fontdata.variabledata = { [tag] = data }
+ end
+end
+
+helpers.gotodatatable = gotodatatable
+helpers.setvariabledata = setvariabledata
+helpers.reportskippedtable = reportskippedtable
+
-- The name table is probably the first one to load. After all this one provides
-- useful information about what we deal with. The complication is that we need
-- to filter the best one available.
@@ -719,14 +786,13 @@ local platformnames = {
}
function readers.name(f,fontdata,specification)
- local datatable = fontdata.tables.name
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset = gotodatatable(f,fontdata,"name",true)
+ if tableoffset then
local format = readushort(f)
local nofnames = readushort(f)
local offset = readushort(f)
-- we can also provide a raw list as extra, todo as option
- local start = datatable.offset + offset
+ local start = tableoffset + offset
local namelists = {
unicode = { },
windows = { },
@@ -747,19 +813,17 @@ function readers.name(f,fontdata,specification)
local encoding = encodings[encoding]
local language = languages[language]
if encoding and language then
- local name = reservednames[readushort(f)]
- if name then
- namelist[#namelist+1] = {
- platform = platform,
- encoding = encoding,
- language = language,
- name = name,
- length = readushort(f),
- offset = start + readushort(f),
- }
- else
- skipshort(f,2)
- end
+ local index = readushort(f)
+ local name = reservednames[index]
+ namelist[#namelist+1] = {
+ platform = platform,
+ encoding = encoding,
+ language = language,
+ name = name,
+ index = index,
+ length = readushort(f),
+ offset = start + readushort(f),
+ }
else
skipshort(f,3)
end
@@ -783,8 +847,9 @@ function readers.name(f,fontdata,specification)
--
-- we need to choose one we like, for instance an unicode one
--
- local names = { }
- local done = { }
+ local names = { }
+ local done = { }
+ local extras = { }
--
-- there is quite some logic in ff ... hard to follow so we start simple
-- and extend when we run into it (todo: proper reverse hash) .. we're only
@@ -795,7 +860,8 @@ function readers.name(f,fontdata,specification)
for i=1,#namelist do
local name = namelist[i]
local nametag = name.name
- if not done[nametag] then
+ local index = name.index
+ if not done[nametag or i] then
local encoding = name.encoding
local language = name.language
if (not e or encoding == e) and (not l or language == l) then
@@ -808,13 +874,16 @@ function readers.name(f,fontdata,specification)
if decoder then
content = decoder(content)
end
- names[nametag] = {
- content = content,
- platform = platform,
- encoding = encoding,
- language = language,
- }
- done[nametag] = true
+ if nametag then
+ names[nametag] = {
+ content = content,
+ platform = platform,
+ encoding = encoding,
+ language = language,
+ }
+ end
+ extras[index] = content
+ done[nametag or i] = true
end
end
end
@@ -827,7 +896,8 @@ function readers.name(f,fontdata,specification)
filter("macintosh")
filter("unicode")
--
- fontdata.names = names
+ fontdata.names = names
+ fontdata.extras = extras
--
if specification.platformnames then
local collected = { }
@@ -884,9 +954,8 @@ end
-- properties table afterwards.
readers["os/2"] = function(f,fontdata)
- local datatable = fontdata.tables["os/2"]
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset = gotodatatable(f,fontdata,"os/2",true)
+ if tableoffset then
local version = readushort(f)
local windowsmetrics = {
version = version,
@@ -945,9 +1014,8 @@ readers["os/2"] = function(f,fontdata)
end
readers.head = function(f,fontdata)
- local datatable = fontdata.tables.head
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset = gotodatatable(f,fontdata,"head",true)
+ if tableoffset then
local fontheader = {
version = readfixed(f),
revision = readfixed(f),
@@ -978,68 +1046,60 @@ end
-- variables are not used but nofmetrics is quite important.
readers.hhea = function(f,fontdata,specification)
- if specification.details then
- local datatable = fontdata.tables.hhea
- if datatable then
- setposition(f,datatable.offset)
- fontdata.horizontalheader = {
- version = readfixed(f), -- two ushorts: major minor
- ascender = readfword(f),
- descender = readfword(f),
- linegap = readfword(f),
- maxadvancewidth = readufword(f),
- minleftsidebearing = readfword(f),
- minrightsidebearing = readfword(f),
- maxextent = readfword(f),
- caretsloperise = readshort(f),
- caretsloperun = readshort(f),
- caretoffset = readshort(f),
- reserved_1 = readshort(f),
- reserved_2 = readshort(f),
- reserved_3 = readshort(f),
- reserved_4 = readshort(f),
- metricdataformat = readshort(f),
- nofmetrics = readushort(f),
- }
- else
- fontdata.horizontalheader = {
- nofmetrics = 0,
- }
- end
+ local tableoffset = gotodatatable(f,fontdata,"hhea",specification.details)
+ if tableoffset then
+ fontdata.horizontalheader = {
+ version = readfixed(f), -- two ushorts: major minor
+ ascender = readfword(f),
+ descender = readfword(f),
+ linegap = readfword(f),
+ maxadvancewidth = readufword(f),
+ minleftsidebearing = readfword(f),
+ minrightsidebearing = readfword(f),
+ maxextent = readfword(f),
+ caretsloperise = readshort(f),
+ caretsloperun = readshort(f),
+ caretoffset = readshort(f),
+ reserved_1 = readshort(f),
+ reserved_2 = readshort(f),
+ reserved_3 = readshort(f),
+ reserved_4 = readshort(f),
+ metricdataformat = readshort(f),
+ nofmetrics = readushort(f),
+ }
+ else
+ fontdata.horizontalheader = {
+ nofmetrics = 0,
+ }
end
end
readers.vhea = function(f,fontdata,specification)
- if specification.details then
- local datatable = fontdata.tables.vhea
- if datatable then
- setposition(f,datatable.offset)
- local version = readfixed(f)
- fontdata.verticalheader = {
- version = version,
- ascender = readfword(f),
- descender = readfword(f),
- linegap = readfword(f),
- maxadvanceheight = readufword(f),
- mintopsidebearing = readfword(f),
- minbottomsidebearing = readfword(f),
- maxextent = readfword(f),
- caretsloperise = readshort(f),
- caretsloperun = readshort(f),
- caretoffset = readshort(f),
- reserved_1 = readshort(f),
- reserved_2 = readshort(f),
- reserved_3 = readshort(f),
- reserved_4 = readshort(f),
- metricdataformat = readshort(f),
- nofmetrics = readushort(f),
- }
--- inspect(fontdata.verticalheader)
- else
- fontdata.verticalheader = {
- nofmetrics = 0,
- }
- end
+ local tableoffset = gotodatatable(f,fontdata,"vhea",specification.details)
+ if tableoffset then
+ fontdata.verticalheader = {
+ version = readfixed(f),
+ ascender = readfword(f),
+ descender = readfword(f),
+ linegap = readfword(f),
+ maxadvanceheight = readufword(f),
+ mintopsidebearing = readfword(f),
+ minbottomsidebearing = readfword(f),
+ maxextent = readfword(f),
+ caretsloperise = readshort(f),
+ caretsloperun = readshort(f),
+ caretoffset = readshort(f),
+ reserved_1 = readshort(f),
+ reserved_2 = readshort(f),
+ reserved_3 = readshort(f),
+ reserved_4 = readshort(f),
+ metricdataformat = readshort(f),
+ nofmetrics = readushort(f),
+ }
+ else
+ fontdata.verticalheader = {
+ nofmetrics = 0,
+ }
end
end
@@ -1049,44 +1109,40 @@ end
-- fontdata.maximumprofile can be bad
readers.maxp = function(f,fontdata,specification)
- if specification.details then
- local datatable = fontdata.tables.maxp
- if datatable then
- setposition(f,datatable.offset)
- local version = readfixed(f)
- local nofglyphs = readushort(f)
- fontdata.nofglyphs = nofglyphs
- if version == 0.5 then
- fontdata.maximumprofile = {
- version = version,
- nofglyphs = nofglyphs,
- }
- return
- elseif version == 1.0 then
- fontdata.maximumprofile = {
- version = version,
- nofglyphs = nofglyphs,
- points = readushort(f),
- contours = readushort(f),
- compositepoints = readushort(f),
- compositecontours = readushort(f),
- zones = readushort(f),
- twilightpoints = readushort(f),
- storage = readushort(f),
- functiondefs = readushort(f),
- instructiondefs = readushort(f),
- stackelements = readushort(f),
- sizeofinstructions = readushort(f),
- componentelements = readushort(f),
- componentdepth = readushort(f),
- }
- return
- end
+ local tableoffset = gotodatatable(f,fontdata,"maxp",specification.details)
+ if tableoffset then
+ local version = readfixed(f)
+ local nofglyphs = readushort(f)
+ fontdata.nofglyphs = nofglyphs
+ if version == 0.5 then
+ fontdata.maximumprofile = {
+ version = version,
+ nofglyphs = nofglyphs,
+ }
+ elseif version == 1.0 then
+ fontdata.maximumprofile = {
+ version = version,
+ nofglyphs = nofglyphs,
+ points = readushort(f),
+ contours = readushort(f),
+ compositepoints = readushort(f),
+ compositecontours = readushort(f),
+ zones = readushort(f),
+ twilightpoints = readushort(f),
+ storage = readushort(f),
+ functiondefs = readushort(f),
+ instructiondefs = readushort(f),
+ stackelements = readushort(f),
+ sizeofinstructions = readushort(f),
+ componentelements = readushort(f),
+ componentdepth = readushort(f),
+ }
+ else
+ fontdata.maximumprofile = {
+ version = version,
+ nofglyphs = 0,
+ }
end
- fontdata.maximumprofile = {
- version = version,
- nofglyphs = 0,
- }
end
end
@@ -1094,87 +1150,78 @@ end
-- course).
readers.hmtx = function(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.hmtx
- if datatable then
- setposition(f,datatable.offset)
- local horizontalheader = fontdata.horizontalheader
- local nofmetrics = horizontalheader.nofmetrics
- local glyphs = fontdata.glyphs
- local nofglyphs = fontdata.nofglyphs
- local width = 0 -- advance
- local leftsidebearing = 0
- for i=0,nofmetrics-1 do
- local glyph = glyphs[i]
- width = readshort(f)
- leftsidebearing = readshort(f)
- if width ~= 0 then
- glyph.width = width
- end
- -- if leftsidebearing ~= 0 then
- -- glyph.lsb = leftsidebearing
- -- end
+ local tableoffset = gotodatatable(f,fontdata,"hmtx",specification.glyphs)
+ if tableoffset then
+ local horizontalheader = fontdata.horizontalheader
+ local nofmetrics = horizontalheader.nofmetrics
+ local glyphs = fontdata.glyphs
+ local nofglyphs = fontdata.nofglyphs
+ local width = 0 -- advance
+ local leftsidebearing = 0
+ for i=0,nofmetrics-1 do
+ local glyph = glyphs[i]
+ width = readshort(f)
+ leftsidebearing = readshort(f)
+ if width ~= 0 then
+ glyph.width = width
end
- -- The next can happen in for instance a monospace font or in a cjk font
- -- with fixed widths.
- for i=nofmetrics,nofglyphs-1 do
- local glyph = glyphs[i]
- if width ~= 0 then
- glyph.width = width
- end
- -- if leftsidebearing ~= 0 then
- -- glyph.lsb = leftsidebearing
- -- end
+-- for now
+-- if leftsidebearing ~= 0 then
+-- glyph.lsb = leftsidebearing
+-- end
+ end
+ -- The next can happen in for instance a monospace font or in a cjk font
+ -- with fixed widths.
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph = glyphs[i]
+ if width ~= 0 then
+ glyph.width = width
end
+ -- if leftsidebearing ~= 0 then
+ -- glyph.lsb = leftsidebearing
+ -- end
end
+ -- hm, there can be a lsb here
end
end
readers.vmtx = function(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.vmtx
- if datatable then
- setposition(f,datatable.offset)
- local verticalheader = fontdata.verticalheader
- local nofmetrics = verticalheader.nofmetrics
- local glyphs = fontdata.glyphs
- local nofglyphs = fontdata.nofglyphs
- local vheight = 0
- local vdefault = verticalheader.ascender + verticalheader.descender
- local topsidebearing = 0
- for i=0,nofmetrics-1 do
- local glyph = glyphs[i]
- vheight = readshort(f)
- topsidebearing = readshort(f)
- if vheight ~= 0 and vheight ~= vdefault then
- glyph.vheight = vheight
- end
- -- if topsidebearing ~= 0 then
- -- glyph.tsb = topsidebearing
- -- end
+ local tableoffset = gotodatatable(f,fontdata,"vmtx",specification.glyphs)
+ if tableoffset then
+ local verticalheader = fontdata.verticalheader
+ local nofmetrics = verticalheader.nofmetrics
+ local glyphs = fontdata.glyphs
+ local nofglyphs = fontdata.nofglyphs
+ local vheight = 0
+ local vdefault = verticalheader.ascender + verticalheader.descender
+ local topsidebearing = 0
+ for i=0,nofmetrics-1 do
+ local glyph = glyphs[i]
+ vheight = readshort(f)
+ topsidebearing = readshort(f)
+ if vheight ~= 0 and vheight ~= vdefault then
+ glyph.vheight = vheight
end
- -- The next can happen in for instance a monospace font or in a cjk font
- -- with fixed heights.
- for i=nofmetrics,nofglyphs-1 do
- local glyph = glyphs[i]
- if vheight ~= 0 and vheight ~= vdefault then
- glyph.vheight = vheight
- end
- -- if topsidebearing ~= 0 then
- -- glyph.tsb = topsidebearing
- -- end
+ -- if topsidebearing ~= 0 then
+ -- glyph.tsb = topsidebearing
+ -- end
+ end
+ -- The next can happen in for instance a monospace font or in a cjk font
+ -- with fixed heights.
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph = glyphs[i]
+ if vheight ~= 0 and vheight ~= vdefault then
+ glyph.vheight = vheight
end
+ -- if topsidebearing ~= 0 then
+ -- glyph.tsb = topsidebearing
+ -- end
end
end
end
readers.vorg = function(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.vorg
- if datatable then
- report("todo: %s","vorg")
- end
- end
+ reportskippedtable(f,fontdata,"vorg",specification.glyphs)
end
-- The post table relates to postscript (printing) but has some relevant properties for other
@@ -1182,9 +1229,8 @@ end
-- description is somewhat fuzzy but it is a hybrid with overloads.
readers.post = function(f,fontdata,specification)
- local datatable = fontdata.tables.post
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset = gotodatatable(f,fontdata,"post",true)
+ if tableoffset then
local version = readfixed(f)
fontdata.postscript = {
version = version,
@@ -1213,7 +1259,7 @@ readers.post = function(f,fontdata,specification)
for i=0,nofglyphs-1 do
local nameindex = readushort(f)
if nameindex >= 258 then
- maxnames = maxnames + 1
+ maxnames = maxnames + 1
nameindex = nameindex - 257
indices[nameindex] = i
else
@@ -1226,7 +1272,7 @@ readers.post = function(f,fontdata,specification)
report("quit post name fetching at %a of %a: %s",i,maxnames,"no index")
break
else
- local length = readbyte(f)
+ local length = readbyte(f)
if length > 0 then
glyphs[mapping].name = readstring(f,length)
else
@@ -1246,9 +1292,7 @@ readers.post = function(f,fontdata,specification)
end
readers.cff = function(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cff")
- end
+ reportskippedtable(f,fontdata,"cff",specification.glyphs)
end
-- Not all cmaps make sense .. e.g. dfont is obsolete and probably more are not relevant. Let's see
@@ -1270,6 +1314,7 @@ local sequence = {
-- variants
{ 0, 5, 14 },
-- last resort ranges
+{ 0, 4, 12 },
{ 3, 10, 13 },
}
@@ -1288,7 +1333,8 @@ local sequence = {
local supported = { }
for i=1,#sequence do
- local sp, se, sf = unpack(sequence[i])
+ local si = sequence[i]
+ local sp, se, sf = si[1], si[2], si[3]
local p = supported[sp]
if not p then
p = { }
@@ -1311,34 +1357,18 @@ formatreaders[4] = function(f,fontdata,offset)
--
skipshort(f,3) -- searchrange entryselector rangeshift
--
- local endchars = { }
- local startchars = { }
- local deltas = { }
- local offsets = { }
- local indices = { }
local mapping = fontdata.mapping
local glyphs = fontdata.glyphs
local duplicates = fontdata.duplicates
local nofdone = 0
- --
- for i=1,nofsegments do
- endchars[i] = readushort(f)
- end
- local reserved = readushort(f) -- 0
- for i=1,nofsegments do
- startchars[i] = readushort(f)
- end
- for i=1,nofsegments do
- deltas[i] = readshort(f)
- end
- for i=1,nofsegments do
- offsets[i] = readushort(f)
- end
+ local endchars = readcardinaltable(f,nofsegments,ushort)
+ local reserved = readushort(f) -- 0
+ local startchars = readcardinaltable(f,nofsegments,ushort)
+ local deltas = readcardinaltable(f,nofsegments,ushort)
+ local offsets = readcardinaltable(f,nofsegments,ushort)
-- format length language nofsegments searchrange entryselector rangeshift 4-tables
- local size = (length - 2 * 2 - 5 * 2 - 4 * nofsegments * 2) / 2
- for i=1,size-1 do
- indices[i] = readushort(f)
- end
+ local size = (length - 2 * 2 - 5 * 2 - 4 * 2 * nofsegments) / 2
+ local indices = readcardinaltable(f,size-1,ushort)
--
for segment=1,nofsegments do
local startchar = startchars[segment]
@@ -1352,7 +1382,7 @@ formatreaders[4] = function(f,fontdata,offset)
elseif offset == 0xFFFF then
-- bad encoding
elseif offset == 0 then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar + delta) % 65536)
end
for unicode=startchar,endchar do
@@ -1385,7 +1415,7 @@ formatreaders[4] = function(f,fontdata,offset)
end
else
local shift = (segment-nofsegments+offset/2) - startchar
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar + delta) % 65536)
end
for unicode=startchar,endchar do
@@ -1435,7 +1465,7 @@ formatreaders[6] = function(f,fontdata,offset)
local count = readushort(f)
local stop = start+count-1
local nofdone = 0
- if trace_cmap then
+ if trace_cmap_detail then
report("format 6 from %C to %C",2,start,stop)
end
for unicode=start,stop do
@@ -1472,7 +1502,7 @@ formatreaders[12] = function(f,fontdata,offset)
local first = readulong(f)
local last = readulong(f)
local index = readulong(f)
- if trace_cmap then
+ if trace_cmap_detail then
report("format 12 from %C to %C starts at index %i",first,last,index)
end
for unicode=first,last do
@@ -1503,7 +1533,7 @@ end
formatreaders[13] = function(f,fontdata,offset)
--
- -- this fector is only used for simple fallback fonts
+ -- this vector is only used for simple fallback fonts
--
setposition(f,offset+2+2+4+4) -- skip format reserved length language
local mapping = fontdata.mapping
@@ -1516,7 +1546,7 @@ formatreaders[13] = function(f,fontdata,offset)
local last = readulong(f)
local index = readulong(f)
if first < privateoffset then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 13 from %C to %C get index %i",first,last,index)
end
local glyph = glyphs[index]
@@ -1622,76 +1652,82 @@ local function checkcmap(f,fontdata,records,platform,encoding,format)
local p = platforms[platform]
local e = encodings[p]
local n = reader(f,fontdata,data) or 0
- report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ if trace_cmap then
+ report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ end
return n
end
function readers.cmap(f,fontdata,specification)
- if specification.glyphs then
- local datatable = fontdata.tables.cmap
- if datatable then
- local tableoffset = datatable.offset
- setposition(f,tableoffset)
- local version = readushort(f)
- local noftables = readushort(f)
- local records = { }
- local unicodecid = false
- local variantcid = false
- local variants = { }
- local duplicates = fontdata.duplicates or { }
- fontdata.duplicates = duplicates
- for i=1,noftables do
- local platform = readushort(f)
- local encoding = readushort(f)
- local offset = readulong(f)
- local record = records[platform]
- if not record then
- records[platform] = {
- [encoding] = {
- offsets = { offset },
- formats = { },
- }
+ local tableoffset = gotodatatable(f,fontdata,"cmap",specification.glyphs)
+ if tableoffset then
+ local version = readushort(f)
+ local noftables = readushort(f)
+ local records = { }
+ local unicodecid = false
+ local variantcid = false
+ local variants = { }
+ local duplicates = fontdata.duplicates or { }
+ fontdata.duplicates = duplicates
+ for i=1,noftables do
+ local platform = readushort(f)
+ local encoding = readushort(f)
+ local offset = readulong(f)
+ local record = records[platform]
+ if not record then
+ records[platform] = {
+ [encoding] = {
+ offsets = { offset },
+ formats = { },
+ }
+ }
+ else
+ local subtables = record[encoding]
+ if not subtables then
+ record[encoding] = {
+ offsets = { offset },
+ formats = { },
}
else
- local subtables = record[encoding]
- if not subtables then
- record[encoding] = {
- offsets = { offset },
- formats = { },
- }
- else
- local offsets = subtables.offsets
- offsets[#offsets+1] = offset
- end
+ local offsets = subtables.offsets
+ offsets[#offsets+1] = offset
end
end
+ end
+ if trace_cmap then
report("found cmaps:")
- for platform, record in sortedhash(records) do
- local p = platforms[platform]
- local e = encodings[p]
- local sp = supported[platform]
- local ps = p or "?"
+ end
+ for platform, record in sortedhash(records) do
+ local p = platforms[platform]
+ local e = encodings[p]
+ local sp = supported[platform]
+ local ps = p or "?"
+ if trace_cmap then
if sp then
report(" platform %i: %s",platform,ps)
else
report(" platform %i: %s (unsupported)",platform,ps)
end
- for encoding, subtables in sortedhash(record) do
- local se = sp and sp[encoding]
- local es = e and e[encoding] or "?"
+ end
+ for encoding, subtables in sortedhash(record) do
+ local se = sp and sp[encoding]
+ local es = e and e[encoding] or "?"
+ if trace_cmap then
if se then
report(" encoding %i: %s",encoding,es)
else
report(" encoding %i: %s (unsupported)",encoding,es)
end
- local offsets = subtables.offsets
- local formats = subtables.formats
- for i=1,#offsets do
- local offset = tableoffset + offsets[i]
- setposition(f,offset)
- formats[readushort(f)] = offset
- end
- record[encoding] = formats
+ end
+ local offsets = subtables.offsets
+ local formats = subtables.formats
+ for i=1,#offsets do
+ local offset = tableoffset + offsets[i]
+ setposition(f,offset)
+ formats[readushort(f)] = offset
+ end
+ record[encoding] = formats
+ if trace_cmap then
local list = sortedkeys(formats)
for i=1,#list do
if not (se and se[list[i]]) then
@@ -1701,26 +1737,27 @@ function readers.cmap(f,fontdata,specification)
report(" formats: % t",list)
end
end
- --
- local ok = false
- for i=1,#sequence do
- local sp, se, sf = unpack(sequence[i])
- if checkcmap(f,fontdata,records,sp,se,sf) > 0 then
- ok = true
- end
- end
- if not ok then
- report("no useable unicode cmap found")
+ end
+ --
+ local ok = false
+ for i=1,#sequence do
+ local si = sequence[i]
+ local sp, se, sf = si[1], si[2], si[3]
+ if checkcmap(f,fontdata,records,sp,se,sf) > 0 then
+ ok = true
end
- --
- fontdata.cidmaps = {
- version = version,
- noftables = noftables,
- records = records,
- }
- else
- fontdata.cidmaps = { }
end
+ if not ok then
+ report("no useable unicode cmap found")
+ end
+ --
+ fontdata.cidmaps = {
+ version = version,
+ noftables = noftables,
+ records = records,
+ }
+ else
+ fontdata.cidmaps = { }
end
end
@@ -1729,111 +1766,120 @@ end
-- although we not need it in our usage (yet). We can remove the locations table when we're done.
function readers.loca(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("loca")
- end
+ reportskippedtable(f,fontdata,"loca",specification.glyphs)
end
function readers.glyf(f,fontdata,specification) -- part goes to cff module
- if specification.glyphs then
- reportskippedtable("glyf")
- end
+ reportskippedtable(f,fontdata,"glyf",specification.glyphs)
end
--- Experimental (we need fonts).
+-- The MicroSoft variant is pretty clean and is supported (implemented elsewhere)
+-- just because I wanted to see how such a font looks like.
function readers.colr(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("colr")
- end
+ reportskippedtable(f,fontdata,"colr",specification.glyphs)
end
-
function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cpal")
- end
+ reportskippedtable(f,fontdata,"cpal",specification.glyphs)
end
+-- This one is also supported, if only because I could locate a proper font for
+-- testing.
+
function readers.svg(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("svg")
- end
+ reportskippedtable(f,fontdata,"svg",specification.glyphs)
+end
+
+-- There is a font from apple to test the next one. Will there be more? Anyhow,
+-- it's relatively easy to support, so I did it.
+
+function readers.sbix(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"sbix",specification.glyphs)
+end
+
+-- I'm only willing to look into the next variant if I see a decent and complete (!)
+-- font and more can show up. It makes no sense to waste time on ideas. Okay, the
+-- apple font also has these tables.
+
+function readers.cbdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cbdt",specification.glyphs)
+end
+function readers.cblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cblc",specification.glyphs)
+end
+function readers.ebdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebdt",specification.glyphs)
+end
+function readers.ebsc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebsc",specification.glyphs)
+end
+function readers.eblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"eblc",specification.glyphs)
end
-- Here we have a table that we really need for later processing although a more advanced gpos table
-- can also be available. Todo: we need a 'fake' lookup for this (analogue to ff).
function readers.kern(f,fontdata,specification)
- if specification.kerns then
- local datatable = fontdata.tables.kern
- if datatable then
- setposition(f,datatable.offset)
- local version = readushort(f)
- local noftables = readushort(f)
- for i=1,noftables do
- local version = readushort(f)
- local length = readushort(f)
- local coverage = readushort(f)
- -- bit 8-15 of coverage: format 0 or 2
- local format = bit32.rshift(coverage,8) -- is this ok?
- if format == 0 then
- local nofpairs = readushort(f)
- local searchrange = readushort(f)
- local entryselector = readushort(f)
- local rangeshift = readushort(f)
- local kerns = { }
- local glyphs = fontdata.glyphs
- for i=1,nofpairs do
- local left = readushort(f)
- local right = readushort(f)
- local kern = readfword(f)
- local glyph = glyphs[left]
- local kerns = glyph.kerns
- if kerns then
- kerns[right] = kern
- else
- glyph.kerns = { [right] = kern }
- end
+ local tableoffset = gotodatatable(f,fontdata,"kern",specification.kerns)
+ if tableoffset then
+ local version = readushort(f)
+ local noftables = readushort(f)
+ for i=1,noftables do
+ local version = readushort(f)
+ local length = readushort(f)
+ local coverage = readushort(f)
+ -- bit 8-15 of coverage: format 0 or 2
+ local format = rshift(coverage,8) -- is this ok?
+ if format == 0 then
+ local nofpairs = readushort(f)
+ local searchrange = readushort(f)
+ local entryselector = readushort(f)
+ local rangeshift = readushort(f)
+ local kerns = { }
+ local glyphs = fontdata.glyphs
+ for i=1,nofpairs do
+ local left = readushort(f)
+ local right = readushort(f)
+ local kern = readfword(f)
+ local glyph = glyphs[left]
+ local kerns = glyph.kerns
+ if kerns then
+ kerns[right] = kern
+ else
+ glyph.kerns = { [right] = kern }
end
- elseif format == 2 then
- report("todo: kern classes")
- else
- report("todo: kerns")
end
+ elseif format == 2 then
+ report("todo: kern classes")
+ else
+ report("todo: kerns")
end
end
end
end
function readers.gdef(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gdef")
- end
+ reportskippedtable(f,fontdata,"gdef",specification.details)
end
function readers.gsub(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gsub")
- end
+ reportskippedtable(f,fontdata,"gsub",specification.details)
end
function readers.gpos(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gpos")
- end
+ reportskippedtable(f,fontdata,"gpos",specification.details)
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("math")
- end
+ reportskippedtable(f,fontdata,"math",specification.details)
end
-- Now comes the loader. The order of reading these matters as we need to know
-- some properties in order to read following tables. When details is true we also
-- initialize the glyphs data.
-local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
+local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames)
local fontdata = sub and maindata.subfonts and maindata.subfonts[sub] or maindata
local names = fontdata.names
local info = nil
@@ -1858,6 +1904,25 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
if not familyname then familyname = family end
if not subfamilyname then subfamilyname = subfamily end
end
+ if platformnames then
+ platformnames = fontdata.platformnames
+ end
+ if instancenames then
+ local variabledata = fontdata.variabledata
+ if variabledata then
+ local instances = variabledata and variabledata.instances
+ if instances then
+ instancenames = { }
+ for i=1,#instances do
+ instancenames[i] = lower(stripstring(instances[i].subfamily))
+ end
+ else
+ instancenames = nil
+ end
+ else
+ instancenames = nil
+ end
+ end
info = { -- we inherit some inconsistencies/choices from ff
subfontindex = fontdata.subfontindex or sub or 0,
-- filename = filename,
@@ -1888,7 +1953,8 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
capheight = metrics.capheight, -- not always present and probably crap
ascender = metrics.typoascender,
descender = metrics.typodescender,
- platformnames = platformnames and fontdata.platformnames or nil,
+ platformnames = platformnames or nil,
+ instancenames = instancenames or nil,
}
if metricstoo then
local keys = {
@@ -1946,6 +2012,7 @@ local function loadtables(f,specification,offset)
entryselector = readushort(f), -- not needed
rangeshift = readushort(f), -- not needed
tables = tables,
+ foundtables = false,
}
for i=1,fontdata.noftables do
local tag = lower(stripstring(readstring(f,4)))
@@ -1961,7 +2028,8 @@ local function loadtables(f,specification,offset)
length = length,
}
end
- if tables.cff then
+ fontdata.foundtables = sortedkeys(tables)
+ if tables.cff or tables.cff2 then
fontdata.format = "opentype"
else
fontdata.format = "truetype"
@@ -1982,14 +2050,35 @@ local function prepareglyps(fontdata)
fontdata.mapping = { }
end
+local function readtable(tag,f,fontdata,specification,...)
+ local reader = readers[tag]
+ if reader then
+ -- local t = os.clock()
+ reader(f,fontdata,specification,...)
+ -- report("reading table %a took %0.4f seconds",tag,os.clock()-t)
+ end
+end
+
+local variablefonts_supported = (context and true) or (logs and logs.application and true) or false
+
local function readdata(f,offset,specification)
+
local fontdata = loadtables(f,specification,offset)
+
if specification.glyphs then
prepareglyps(fontdata)
end
- --
- readers["name"](f,fontdata,specification)
- --
+
+ if not variablefonts_supported then
+ specification.instance = nil
+ specification.variable = nil
+ specification.factors = nil
+ end
+
+ fontdata.temporary = { }
+
+ readtable("name",f,fontdata,specification)
+
local askedname = specification.askedname
if askedname then
local fullname = getname(fontdata,"fullname") or ""
@@ -1999,35 +2088,124 @@ local function readdata(f,offset,specification)
return -- keep searching
end
end
- --
- --
- readers["os/2"](f,fontdata,specification)
- readers["head"](f,fontdata,specification)
- readers["maxp"](f,fontdata,specification)
- readers["hhea"](f,fontdata,specification)
- readers["vhea"](f,fontdata,specification)
- readers["hmtx"](f,fontdata,specification)
- readers["vmtx"](f,fontdata,specification)
- readers["vorg"](f,fontdata,specification)
- readers["post"](f,fontdata,specification)
- readers["cff" ](f,fontdata,specification)
- readers["cmap"](f,fontdata,specification)
- readers["loca"](f,fontdata,specification)
- readers["glyf"](f,fontdata,specification)
- readers["colr"](f,fontdata,specification)
- readers["cpal"](f,fontdata,specification)
- readers["svg" ](f,fontdata,specification)
- readers["kern"](f,fontdata,specification)
- readers["gdef"](f,fontdata,specification)
- readers["gsub"](f,fontdata,specification)
- readers["gpos"](f,fontdata,specification)
- readers["math"](f,fontdata,specification)
- --
+
+ readtable("stat",f,fontdata,specification)
+ readtable("avar",f,fontdata,specification)
+ readtable("fvar",f,fontdata,specification)
+
+ if variablefonts_supported then
+
+ local variabledata = fontdata.variabledata
+
+ if variabledata then
+ local instances = variabledata.instances
+ local axis = variabledata.axis
+ if axis and (not instances or #instances == 0) then
+ instances = { }
+ variabledata.instances = instances
+ local function add(n,subfamily,value)
+ local values = { }
+ for i=1,#axis do
+ local a = axis[i]
+ values[i] = {
+ axis = a.tag,
+ value = i == n and value or a.default,
+ }
+ end
+ instances[#instances+1] = {
+ subfamily = subfamily,
+ values = values,
+ }
+ end
+ for i=1,#axis do
+ local a = axis[i]
+ local tag = a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
+ end
+ -- report("%i fake instances added",#instances)
+ end
+ end
+
+ if not specification.factors then
+ local instance = specification.instance
+ if type(instance) == "string" then
+ local factors = helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ fontdata.instance = instance
+ report("user instance: %s, factors: % t",instance,factors)
+ else
+ report("user instance: %s, bad factors",instance)
+ end
+ end
+ end
+
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors = helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors = factors
+ fontdata.factors = factors
+ -- report("factors: % t",factors)
+ -- else
+ -- report("bad factors")
+ end
+ else
+ -- report("unknown instance")
+ end
+ end
+
+ end
+
+ readtable("os/2",f,fontdata,specification)
+ readtable("head",f,fontdata,specification)
+ readtable("maxp",f,fontdata,specification)
+ readtable("hhea",f,fontdata,specification)
+ readtable("vhea",f,fontdata,specification)
+ readtable("hmtx",f,fontdata,specification)
+ readtable("vmtx",f,fontdata,specification)
+ readtable("vorg",f,fontdata,specification)
+ readtable("post",f,fontdata,specification)
+
+ readtable("mvar",f,fontdata,specification)
+ readtable("hvar",f,fontdata,specification)
+ readtable("vvar",f,fontdata,specification)
+
+ readtable("gdef",f,fontdata,specification)
+
+ readtable("cff" ,f,fontdata,specification)
+ readtable("cff2",f,fontdata,specification)
+
+ readtable("cmap",f,fontdata,specification)
+ readtable("loca",f,fontdata,specification) -- maybe load it in glyf
+ readtable("glyf",f,fontdata,specification) -- loads gvar
+
+ readtable("colr",f,fontdata,specification)
+ readtable("cpal",f,fontdata,specification)
+
+ readtable("svg" ,f,fontdata,specification)
+
+ readtable("sbix",f,fontdata,specification)
+
+ readtable("cbdt",f,fontdata,specification)
+ readtable("cblc",f,fontdata,specification)
+ readtable("ebdt",f,fontdata,specification)
+ readtable("eblc",f,fontdata,specification)
+
+ readtable("kern",f,fontdata,specification)
+ readtable("gsub",f,fontdata,specification)
+ readtable("gpos",f,fontdata,specification)
+
+ readtable("math",f,fontdata,specification)
+
fontdata.locations = nil
fontdata.tables = nil
fontdata.cidmaps = nil
fontdata.dictionaries = nil
- -- fontdata.cff = nil
+ -- fontdata.cff = nil
return fontdata
end
@@ -2051,12 +2229,9 @@ local function loadfontdata(specification)
fontdata = readdata(f,0,specification)
elseif version == "ttcf" then
local subfont = tonumber(specification.subfont)
- local offsets = { }
local ttcversion = readulong(f)
local nofsubfonts = readulong(f)
- for i=1,nofsubfonts do
- offsets[i] = readulong(f)
- end
+ local offsets = readcardinaltable(f,nofsubfonts,ulong)
if subfont then -- a number of not
if subfont >= 1 and subfont <= nofsubfonts then
fontdata = readdata(f,offsets[subfont],specification)
@@ -2102,7 +2277,7 @@ local function loadfontdata(specification)
end
end
-local function loadfont(specification,n)
+local function loadfont(specification,n,instance)
if type(specification) == "string" then
specification = {
filename = specification,
@@ -2111,11 +2286,13 @@ local function loadfont(specification,n)
glyphs = true,
shapes = true,
kerns = true,
+ variable = true,
globalkerns = true,
lookups = true,
-- true or number:
subfont = n or true,
tounicode = false,
+ instance = instance
}
end
-- if shapes only then
@@ -2131,6 +2308,10 @@ local function loadfont(specification,n)
if specification.platformnames then
specification.platformnames = true -- not really used any more
end
+ if specification.instance or instance then
+ specification.variable = true
+ specification.instance = specification.instance or instance
+ end
local function message(str)
report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback())
end
@@ -2142,11 +2323,14 @@ end
-- we need even less, but we can have a 'detail' variant
-function readers.loadshapes(filename,n)
+function readers.loadshapes(filename,n,instance,streams)
local fontdata = loadfont {
filename = filename,
shapes = true,
+ streams = streams,
+ variable = true,
subfont = n,
+ instance = instance,
}
if fontdata then
-- easier on luajit but still we can hit the 64 K stack constants issue
@@ -2171,18 +2355,19 @@ function readers.loadshapes(filename,n)
}
end
-function readers.loadfont(filename,n)
+function readers.loadfont(filename,n,instance)
local fontdata = loadfont {
filename = filename,
glyphs = true,
shapes = false,
lookups = true,
+ variable = true,
-- kerns = true,
-- globalkerns = true, -- only for testing, e.g. cambria has different gpos and kern
subfont = n,
+ instance = instance,
}
if fontdata then
- --
return {
tableversion = tableversion,
creator = "context mkiv",
@@ -2192,11 +2377,13 @@ function readers.loadfont(filename,n)
descriptions = fontdata.descriptions,
format = fontdata.format,
goodies = { },
- metadata = getinfo(fontdata,n,false,false,true), -- no platformnames here !
+ metadata = getinfo(fontdata,n,false,false,true,true), -- no platformnames here !
properties = {
hasitalics = fontdata.hasitalics or false,
maxcolorclass = fontdata.maxcolorclass,
hascolor = fontdata.hascolor or false,
+ instance = fontdata.instance,
+ factors = fontdata.factors,
},
resources = {
-- filename = fontdata.filename,
@@ -2215,6 +2402,9 @@ function readers.loadfont(filename,n)
mathconstants = fontdata.mathconstants,
colorpalettes = fontdata.colorpalettes,
svgshapes = fontdata.svgshapes,
+ sbixshapes = fontdata.sbixshapes,
+ variabledata = fontdata.variabledata,
+ foundtables = fontdata.foundtables,
},
}
end
@@ -2226,6 +2416,7 @@ function readers.getinfo(filename,specification) -- string, nil|number|table
local subfont = nil
local platformnames = false
local rawfamilynames = false
+ local instancenames = true
if type(specification) == "table" then
subfont = tonumber(specification.subfont)
platformnames = specification.platformnames
@@ -2237,20 +2428,21 @@ function readers.getinfo(filename,specification) -- string, nil|number|table
filename = filename,
details = true,
platformnames = platformnames,
+ instancenames = true,
-- rawfamilynames = rawfamilynames,
}
if fontdata then
local subfonts = fontdata.subfonts
if not subfonts then
- return getinfo(fontdata,nil,platformnames,rawfamilynames)
+ return getinfo(fontdata,nil,platformnames,rawfamilynames,false,instancenames)
elseif not subfont then
local info = { }
for i=1,#subfonts do
- info[i] = getinfo(fontdata,i,platformnames,rawfamilynames)
+ info[i] = getinfo(fontdata,i,platformnames,rawfamilynames,false,instancenames)
end
return info
elseif subfont >= 1 and subfont <= #subfonts then
- return getinfo(fontdata,subfont,platformnames,rawfamilynames)
+ return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames)
else
return {
filename = filename,
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua
index 1f84214812f..e3389b9daf7 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua
@@ -6,73 +6,45 @@ if not modules then modules = { } end modules ['font-ots'] = { -- sequences
license = "see context related readme files",
}
--- to be checked: discrun doesn't seem to do something useful now (except run the
--- check again) so if we need it again we'll do a zwnjrun or so
-
--- components will go away and be replaced by a property table which simplifies
--- code (also more efficient)
-
--- beware, on my development machine we test a slightly a more optimized version
-
--- assumptions:
---
--- cursives don't cross discretionaries
--- marks precede bases
---
--- pitfalls:
---
--- when we append to a dics field we need to set the field in order to update tail
---
--- This is a version of font-otn.lua adapted to the new font loader code. It
--- is a context version which can contain experimental code, but when we
--- have serious patches we will backport to the font-otn files. The plain
--- loader that ships with context also uses this now.
---
--- todo: looks like we have a leak somewhere (probably in ligatures)
--- todo: copy attributes to disc
--- todo: get rid of components, better use the tounicode entry if needed (at all)
---
--- we do some disc juggling where we need to keep in mind that the
--- pre, post and replace fields can have prev pointers to a nesting
--- node ... i wonder if that is still needed
---
--- not possible:
---
--- \discretionary {alpha-} {betagammadelta}
--- {\discretionary {alphabeta-} {gammadelta}
--- {\discretionary {alphabetagamma-} {delta}
--- {alphabetagammadelta}}}
-
--[[ldx--
<p>This module is a bit more split up that I'd like but since we also want to test
with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/>
and discussion about improvements and functionality mostly happens on the
<l n='context'/> mailing list.</p>
-<p>The specification of OpenType is kind of vague. Apart from a lack of a proper
-free specifications there's also the problem that Microsoft and Adobe
-may have their own interpretation of how and in what order to apply features.
-In general the Microsoft website has more detailed specifications and is a
-better reference. There is also some information in the FontForge help files.</p>
+<p>The specification of OpenType is (or at least a decade ago was) kind of vague.
+Apart from a lack of a proper free specifications there's also the problem that
+Microsoft and Adobe may have their own interpretation of how and in what order to
+apply features. In general the Microsoft website has more detailed specifications
+and is a better reference. There is also some information in the FontForge help
+files. In the end we rely most on the Microsoft specification.</p>
<p>Because there is so much possible, fonts might contain bugs and/or be made to
work with certain rederers. These may evolve over time which may have the side
-effect that suddenly fonts behave differently.</p>
+effect that suddenly fonts behave differently. We don't want to catch all font
+issues.</p>
-<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
-implementation. Of course all errors are mine and of course the code can be
-improved. There are quite some optimizations going on here and processing speed
-is currently acceptable. Not all functions are implemented yet, often because I
-lack the fonts for testing. Many scripts are not yet supported either, but I will
-look into them as soon as <l n='context'/> users ask for it.</p>
+<p>After a lot of experiments (mostly by Taco, me and Idris) the first implementation
+becaus quite useful. When it did most of what we wanted, a more optimized version
+evolved. Of course all errors are mine and of course the code can be improved. There
+are quite some optimizations going on here and processing speed is currently quite
+acceptable and has been improved over time. Many complex scripts are not yet supported
+yet, but I will look into them as soon as <l n='context'/> users ask for it.</p>
-<p>The specification leaves room for interpretation. In case of doubt the microsoft
+<p>The specification leaves room for interpretation. In case of doubt the Microsoft
implementation is the reference as it is the most complete one. As they deal with
lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and
their suggestions help improve the code. I'm aware that not all border cases can be
taken care of, unless we accept excessive runtime, and even then the interference
with other mechanisms (like hyphenation) are not trivial.</p>
+<p>Especially discretionary handling has been improved much by Kai Eigner who uses complex
+(latin) fonts. The current implementation is a compromis between his patches and my code
+and in the meantime performance is quite ok. We cannot check all border cases without
+compromising speed but so far we're okay. Given good test cases we can probably improve
+it here and there. Especially chain lookups are non trivial with discretionaries but
+things got much better over time thanks to Kai.</p>
+
<p>Glyphs are indexed not by unicode but in their own way. This is because there is no
relationship with unicode at all, apart from the fact that a font might cover certain
ranges of characters. One character can have multiple shapes. However, at the
@@ -84,81 +56,128 @@ then in the output eventually.</p>
that different from the one produced by <l n='fontforge'/> but we uses hashes instead.
In <l n='context'/> that table is packed (similar tables are shared) and cached on disk
so that successive runs can use the optimized table (after loading the table is
-unpacked). The flattening code used later is a prelude to an even more compact table
-format (and as such it keeps evolving).</p>
+unpacked).</p>
-<p>This module is sparsely documented because it is a moving target. The table format
-of the reader changes and we experiment a lot with different methods for supporting
-features.</p>
-
-<p>As with the <l n='afm'/> code, we may decide to store more information in the
-<l n='otf'/> table.</p>
+<p>This module is sparsely documented because it is has been a moving target. The
+table format of the reader changed a bit over time and we experiment a lot with
+different methods for supporting features. By now the structures are quite stable</p>
<p>Incrementing the version number will force a re-cache. We jump the number by one
-when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that
-results in different tables.</p>
+when there's a fix in the reader or processing code that can result in different
+results.</p>
+
+<p>This code is also used outside context but in context it has to work with other
+mechanisms. Both put some constraints on the code here.</p>
+
--ldx]]--
+-- Remark: We assume that cursives don't cross discretionaries which is okay because it
+-- is only used in semitic scripts.
+--
+-- Remark: We assume that marks precede base characters.
+--
+-- Remark: When complex ligatures extend into discs nodes we can get side effects. Normally
+-- this doesn't happen; ff\d{l}{l}{l} in lm works but ff\d{f}{f}{f}.
+--
+-- Todo: check if we copy attributes to disc nodes if needed.
+--
+-- Todo: it would be nice if we could get rid of components. In other places we can use
+-- the unicode properties.
+--
+-- Remark: We do some disc juggling where we need to keep in mind that the pre, post and
+-- replace fields can have prev pointers to a nesting node ... I wonder if that is still
+-- needed.
+--
+-- Remark: This is not possible:
+--
+-- \discretionary {alpha-} {betagammadelta}
+-- {\discretionary {alphabeta-} {gammadelta}
+-- {\discretionary {alphabetagamma-} {delta}
+-- {alphabetagammadelta}}}
+--
+-- Remark: Something is messed up: we have two mark / ligature indices, one at the
+-- injection end and one here ... this is based on KE's patches but there is something
+-- fishy there as I'm pretty sure that for husayni we need some connection (as it's much
+-- more complex than an average font) but I need proper examples of all cases, not of
+-- only some.
+--
+-- Remark: I wonder if indexed would be faster than unicoded. It would be a major
+-- rewrite to have char being unicode + an index field in glyph nodes. Also more
+-- assignments have to be made in order to keep things in sync. So, it's a no-go.
+--
+-- Remark: We can provide a fast loop when there are no disc nodes (tests show a 1%
+-- gain). Smaller functions might perform better cache-wise. But ... memory becomes
+-- faster anyway, so ...
+--
+-- Remark: Some optimizations made sense for 5.2 but seem less important for 5.3 but
+-- anyway served their purpose.
+--
+-- Todo: just (0=l2r and 1=r2l) or maybe (r2l = true)
+
local type, next, tonumber = type, next, tonumber
local random = math.random
local formatters = string.formatters
local insert = table.insert
-local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes
-
-local registertracker = trackers.register
-local registerdirective = directives.register
-
-local fonts = fonts
-local otf = fonts.handlers.otf
-
-local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end)
-local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end)
-local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end)
-local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end)
-local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end)
-local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end)
-local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end)
-local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end)
-local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end)
-local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end)
-local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end)
-local trace_details = false registertracker("otf.details", function(v) trace_details = v end)
------ trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end)
-local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end)
-local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
-local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end)
-local trace_plugins = false registertracker("otf.plugins", function(v) trace_plugins = v end)
-
-local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end)
-local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end)
-local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
-local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end)
-
------ zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
-local optimizekerns = true
-local alwaysdisc = true registerdirective("otf.alwaysdisc", function(v) alwaysdisc = v end)
-
-local report_direct = logs.reporter("fonts","otf direct")
-local report_subchain = logs.reporter("fonts","otf subchain")
-local report_chain = logs.reporter("fonts","otf chain")
-local report_process = logs.reporter("fonts","otf process")
-local report_warning = logs.reporter("fonts","otf warning")
-local report_run = logs.reporter("fonts","otf run")
-
-registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
-registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
-registertracker("otf.actions","otf.replacements,otf.positions")
-registertracker("otf.injections","nodes.injections")
-
-registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+local registertracker = trackers.register
+
+local logs = logs
+local trackers = trackers
+local nodes = nodes
+local attributes = attributes
+local fonts = fonts
+
+local otf = fonts.handlers.otf
+local tracers = nodes.tracers
+
+local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end)
+local trace_details = false registertracker("otf.details", function(v) trace_details = v end)
+local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end)
+local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end)
+local trace_plugins = false registertracker("otf.plugins", function(v) trace_plugins = v end)
+local trace_chains = false registertracker("otf.chains", function(v) trace_chains = v end)
+
+local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end)
+----- trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end)
+local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end)
+local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end)
+
+local forcediscretionaries = false
+local forcepairadvance = false -- for testing
+
+directives.register("otf.forcediscretionaries",function(v)
+ forcediscretionaries = v
+end)
+
+directives.register("otf.forcepairadvance",function(v)
+ forcepairadvance = v
+end)
+
+local report_direct = logs.reporter("fonts","otf direct")
+local report_subchain = logs.reporter("fonts","otf subchain")
+local report_chain = logs.reporter("fonts","otf chain")
+local report_process = logs.reporter("fonts","otf process")
+local report_warning = logs.reporter("fonts","otf warning")
+local report_run = logs.reporter("fonts","otf run")
+
+registertracker("otf.substitutions", "otf.singles","otf.multiples","otf.alternatives","otf.ligatures")
+registertracker("otf.positions", "otf.marks","otf.kerns","otf.cursive")
+registertracker("otf.actions", "otf.substitutions","otf.positions")
+registertracker("otf.sample", "otf.steps","otf.substitutions","otf.positions","otf.analyzing")
+registertracker("otf.sample.silent", "otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing")
local nuts = nodes.nuts
-local tonode = nuts.tonode
-local tonut = nuts.tonut
local getfield = nuts.getfield
-local setfield = nuts.setfield
local getnext = nuts.getnext
local setnext = nuts.setnext
local getprev = nuts.getprev
@@ -178,26 +197,37 @@ local setchar = nuts.setchar
local getdisc = nuts.getdisc
local setdisc = nuts.setdisc
local setlink = nuts.setlink
+local getcomponents = nuts.getcomponents -- the original one, not yet node-aux
+local setcomponents = nuts.setcomponents -- the original one, not yet node-aux
+local getdir = nuts.getdir
+local getwidth = nuts.getwidth
local ischar = nuts.is_char
+local usesfont = nuts.uses_font
local insert_node_after = nuts.insert_after
local copy_node = nuts.copy
local copy_node_list = nuts.copy_list
+local remove_node = nuts.remove
local find_node_tail = nuts.tail
local flush_node_list = nuts.flush_list
local flush_node = nuts.flush_node
local end_of_math = nuts.end_of_math
-local traverse_nodes = nuts.traverse
-local traverse_id = nuts.traverse_id
-local remove_node = nuts.remove
-
+----- traverse_nodes = nuts.traverse
+----- traverse_id = nuts.traverse_id
+local set_components = nuts.set_components
+local take_components = nuts.take_components
+local count_components = nuts.count_components
+local copy_no_components = nuts.copy_no_components
+local copy_only_glyphs = nuts.copy_only_glyphs
+
+local setmetatable = setmetatable
local setmetatableindex = table.setmetatableindex
-local zwnj = 0x200C
-local zwj = 0x200D
-local wildcard = "*"
-local default = "dflt"
+local nextnode = nuts.traversers.node
+
+----- zwnj = 0x200C
+----- zwj = 0x200D
local nodecodes = nodes.nodecodes
local glyphcodes = nodes.glyphcodes
@@ -213,31 +243,22 @@ local localpar_code = nodecodes.localpar
local discretionary_code = disccodes.discretionary
local ligature_code = glyphcodes.ligature
-local privateattribute = attributes.private
-
--- Something is messed up: we have two mark / ligature indices, one at the injection
--- end and one here ... this is based on KE's patches but there is something fishy
--- there as I'm pretty sure that for husayni we need some connection (as it's much
--- more complex than an average font) but I need proper examples of all cases, not
--- of only some.
-
-local a_state = privateattribute('state')
+local a_state = attributes.private('state')
+local a_noligature = attributes.private("noligature")
local injections = nodes.injections
local setmark = injections.setmark
local setcursive = injections.setcursive
local setkern = injections.setkern
-local setpair = injections.setpair
+local setmove = injections.setmove
+local setposition = injections.setposition
local resetinjection = injections.reset
local copyinjection = injections.copy
local setligaindex = injections.setligaindex
local getligaindex = injections.getligaindex
-local cursonce = true
-
-local fonthashes = fonts.hashes
-local fontdata = fonthashes.identifiers
-local fontfeatures = fonthashes.features
+local fontdata = fonts.hashes.identifiers
+local fontfeatures = fonts.hashes.features
local otffeatures = fonts.constructors.features.otf
local registerotffeature = otffeatures.register
@@ -248,48 +269,51 @@ local getrandom = utilities and utilities.randomizer and utilities.rand
otf.defaultnodealternate = "none" -- first last
--- We use a few global variables. The handler can be called nested but this assumes that the
--- same font is used. Nested calls are normally not needed (only for devanagari).
+-- We use a few semi-global variables. The handler can be called nested but this assumes
+-- that the same font is used.
-local tfmdata = false
-local characters = false
-local descriptions = false
-local marks = false
-local currentfont = false
-local factor = 0
-local threshold = 0
-local checkmarks = false
+local tfmdata = false
+local characters = false
+local descriptions = false
+local marks = false
+local classes = false
+local currentfont = false
+local factor = 0
+local threshold = 0
+local checkmarks = false
-local sweepnode = nil
-local sweepprev = nil
-local sweepnext = nil
-local sweephead = { }
+local discs = false
+local spaces = false
-local notmatchpre = { }
-local notmatchpost = { }
-local notmatchreplace = { }
+local sweepnode = nil
+local sweephead = { } -- we don't nil entries but false them (no collection and such)
-local handlers = { }
+local notmatchpre = { } -- to be checked: can we use false instead of nil / what if a == b tests
+local notmatchpost = { } -- to be checked: can we use false instead of nil / what if a == b tests
+local notmatchreplace = { } -- to be checked: can we use false instead of nil / what if a == b tests
-local isspace = injections.isspace
-local getthreshold = injections.getthreshold
+local handlers = { }
--- we use this for special testing and documentation
+local isspace = injections.isspace
+local getthreshold = injections.getthreshold
-local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
-local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
-local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+local checkstep = (tracers and tracers.steppers.check) or function() end
+local registerstep = (tracers and tracers.steppers.register) or function() end
+local registermessage = (tracers and tracers.steppers.message) or function() end
-local function checkdisccontent(d)
- local pre, post, replace = getdisc(d)
- if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end
- if post then for n in traverse_id(glue_code,post) do print("pos",nodes.idstostring(post)) break end end
- if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
-end
+-- local function checkdisccontent(d)
+-- local pre, post, replace = getdisc(d)
+-- if pre then for n in traverse_id(glue_code,pre) do report("pre: %s",nodes.idstostring(pre)) break end end
+-- if post then for n in traverse_id(glue_code,post) do report("pos: %s",nodes.idstostring(post)) break end end
+-- if replace then for n in traverse_id(glue_code,replace) do report("rep: %s",nodes.idstostring(replace)) break end end
+-- end
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_direct(...)
end
@@ -298,59 +322,77 @@ local function logwarning(...)
report_direct(...)
end
-local f_unicode = formatters["%U"]
-local f_uniname = formatters["%U (%s)"]
-local f_unilist = formatters["% t (% t)"]
+local gref do
-local function gref(n) -- currently the same as in font-otb
- if type(n) == "number" then
- local description = descriptions[n]
- local name = description and description.name
- if name then
- return f_uniname(n,name)
- else
- return f_unicode(n)
- end
- elseif n then
- local num, nam = { }, { }
- for i=1,#n do
- local ni = n[i]
- if tonumber(ni) then -- later we will start at 2
- local di = descriptions[ni]
- num[i] = f_unicode(ni)
- nam[i] = di and di.name or "-"
+ local f_unicode = formatters["U+%X"] -- was ["%U"]
+ local f_uniname = formatters["U+%X (%s)"] -- was ["%U (%s)"]
+ local f_unilist = formatters["% t"]
+
+ gref = function(n) -- currently the same as in font-otb
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return f_uniname(n,name)
+ else
+ return f_unicode(n)
+ end
+ elseif n then
+ local t = { }
+ for i=1,#n do
+ local ni = n[i]
+ if tonumber(ni) then -- later we will start at 2
+ local di = descriptions[ni]
+ local nn = di and di.name
+ if nn then
+ t[#t+1] = f_uniname(ni,nn)
+ else
+ t[#t+1] = f_unicode(ni)
+ end
+ end
end
+ return f_unilist(t)
+ else
+ return "<error in node mode tracing>"
end
- return f_unilist(num,nam)
- else
- return "<error in node mode tracing>"
end
+
end
local function cref(dataset,sequence,index)
if not dataset then
return "no valid dataset"
- elseif index then
- return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index)
+ end
+ local merged = sequence.merged and "merged " or ""
+ if index then
+ return formatters["feature %a, type %a, %schain lookup %a, index %a"](
+ dataset[4],sequence.type,merged,sequence.name,index)
else
- return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %schain lookup %a"](
+ dataset[4],sequence.type,merged,sequence.name)
end
end
local function pref(dataset,sequence)
- return formatters["feature %a, type %a, lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %slookup %a"](
+ dataset[4],sequence.type,sequence.merged and "merged " or "",sequence.name)
end
local function mref(rlmode)
- if not rlmode or rlmode == 0 then
- return "---"
- elseif rlmode == -1 or rlmode == "+TRT" then
- return "r2l"
- else
+ if not rlmode or rlmode >= 0 then
return "l2r"
+ else
+ return "r2l"
end
end
+-- The next code is somewhat complicated by the fact that some fonts can have ligatures made
+-- from ligatures that themselves have marks. This was identified by Kai in for instance
+-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes
+-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next
+-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
+-- third component.
+
-- We can assume that languages that use marks are not hyphenated. We can also assume
-- that at most one discretionary is present.
@@ -360,21 +402,6 @@ end
-- However, for arabic we need to keep them around for the sake of mark placement
-- and indices.
-local function copy_glyph(g) -- next and prev are untouched !
- local components = getfield(g,"components")
- if components then
- setfield(g,"components")
- local n = copy_node(g)
- copyinjection(n,g) -- we need to preserve the lig indices
- setfield(g,"components",components)
- return n
- else
- local n = copy_node(g)
- copyinjection(n,g) -- we need to preserve the lig indices
- return n
- end
-end
-
local function flattendisk(head,disc)
local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
local prev, next = getboth(disc)
@@ -396,7 +423,7 @@ local function flattendisk(head,disc)
elseif next then
return next, next
else
- return -- maybe warning
+ -- return -- maybe warning
end
else
if replace then
@@ -419,18 +446,40 @@ local function appenddisc(disc,list)
if post then
setlink(posttail,posthead)
else
- post = phead
+ post = posthead
end
if replace then
setlink(replacetail,replacehead)
else
- replace = rhead
+ replace = replacehead
end
setdisc(disc,pre,post,replace)
end
-- start is a mark and we need to keep that one
+local take_components = getcomponents -- we overload here (for now)
+local set_components = setcomponents -- we overload here (for now)
+----- get_components = getcomponents -- we overload here (for now)
+
+local function count_components(start,marks)
+ if getid(start) ~= glyph_code then
+ return 0
+ elseif getsubtype(start) == ligature_code then
+ local i = 0
+ local components = getcomponents(start)
+ while components do
+ i = i + count_components(components,marks)
+ components = getnext(components)
+ end
+ return i
+ elseif not marks[getchar(start)] then
+ return 1
+ else
+ return 0
+ end
+end
+
local function markstoligature(head,start,stop,char)
if start == stop and getchar(start) == char then
return head, start
@@ -439,48 +488,28 @@ local function markstoligature(head,start,stop,char)
local next = getnext(stop)
setprev(start)
setnext(stop)
- local base = copy_glyph(start)
+ local base = copy_no_components(start,copyinjection)
if head == start then
head = base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",start)
- setlink(prev,base)
- setlink(base,next)
+ set_components(base,start)
+ setlink(prev,base,next)
return head, base
end
end
--- The next code is somewhat complicated by the fact that some fonts can have ligatures made
--- from ligatures that themselves have marks. This was identified by Kai in for instance
--- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes
--- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next
--- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
--- third component.
-
-local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents)
- if getid(start) ~= glyph_code then -- and then get rid of all components
- return 0
- elseif getsubtype(start) == ligature_code then
- local i = 0
- local components = getfield(start,"components")
- while components do
- i = i + getcomponentindex(components)
- components = getnext(components)
- end
- return i
- elseif not marks[getchar(start)] then
- return 1
- else
- return 0
- end
-end
-
-local a_noligature = attributes.private("noligature")
+-- Remark for Kai: (some arabic fonts do mark + mark = other mark and such)
+--
+-- The hasmarks is needed for ligatures of marks that are part of a ligature in
+-- which case we assume that we can delete the marks anyway (we can always become
+-- more clever if needed) .. in fact the whole logic here should be redone. We're
+-- in the not discfound branch then. We now have skiphash too so we can be more
+-- selective if needed (todo).
-local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head
+local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) -- brr head
if getattr(start,a_noligature) == 1 then
-- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first)
return head, start
@@ -490,53 +519,43 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setchar(start,char)
return head, start
end
- -- needs testing (side effects):
- local components = getfield(start,"components")
- if components then
- -- we get a double free .. needs checking
- -- flush_node_list(components)
- end
- --
local prev = getprev(start)
local next = getnext(stop)
local comp = start
setprev(start)
setnext(stop)
- local base = copy_glyph(start)
+ local base = copy_no_components(start,copyinjection)
if start == head then
head = base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",comp) -- start can have components ... do we need to flush?
- if prev then
- setnext(prev,base)
- end
- if next then
- setprev(next,base)
- end
- setboth(base,prev,next)
+ set_components(base,comp)
+ setlink(prev,base,next)
if not discfound then
- local deletemarks = markflag ~= "mark"
+ local deletemarks = not skiphash or hasmarks
local components = start
local baseindex = 0
local componentindex = 0
local head = base
local current = base
- -- first we loop over the glyphs in start .. stop
+ -- first we loop over the glyphs in start ... stop
while start do
local char = getchar(start)
if not marks[char] then
baseindex = baseindex + componentindex
- componentindex = getcomponentindex(start)
- elseif not deletemarks then -- quite fishy
+ componentindex = count_components(start,marks)
+ -- we can be more clever here: "not deletemarks or (skiphash and not skiphash[char])"
+ -- and such:
+ elseif not deletemarks then
+ -- we can get a loop when the font expects otherwise (i.e. unexpected deletemarks)
setligaindex(start,baseindex + getligaindex(start,componentindex))
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
end
local n = copy_node(start)
- copyinjection(n,start)
+ copyinjection(n,start) -- is this ok ? we position later anyway
head, current = insert_node_after(head,current,n) -- unlikely that mark has components
elseif trace_marks then
logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -544,11 +563,11 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
start = getnext(start)
end
-- we can have one accent as part of a lookup and another following
- -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added)
local start = getnext(current)
while start do
local char = ischar(start)
if char then
+ -- also something skiphash here?
if marks[char] then
setligaindex(start,baseindex + getligaindex(start,componentindex))
if trace_marks then
@@ -570,27 +589,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
-- \- can give problems as there we can have a negative char but that won't match
-- anyway
local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true)
- if not replace then -- todo: signal simple hyphen
- local prev = getprev(base)
- local current = comp
- local previous = nil
- local copied = nil
- while current do
- if getid(current) == glyph_code then
- local n = copy_node(current)
- if copied then
- setlink(previous,n)
- else
- copied = n
- end
- previous = n
- end
- current = getnext(current)
- end
- setprev(discnext) -- also blocks funny assignments
- setnext(discprev) -- also blocks funny assignments
+ if not replace then
+ local prev = getprev(base)
+ local comp = take_components(base)
+ local copied = copy_only_glyphs(comp)
if pre then
setlink(discprev,pre)
+ else
+ setnext(discprev) -- also blocks funny assignments
end
pre = comp
if post then
@@ -598,20 +604,26 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setprev(post)
else
post = discnext
+ setprev(discnext) -- also blocks funny assignments
end
- setlink(prev,discfound)
- setlink(discfound,next)
+ setlink(prev,discfound,next)
setboth(base)
- setfield(base,"components",copied)
- setdisc(discfound,pre,post,base) -- was discretionary_code
- base = prev -- restart
+ -- here components have a pointer so we can't free it!
+ set_components(base,copied)
+ replace = base
+ if forcediscretionaries then
+ setdisc(discfound,pre,post,replace,discretionary_code)
+ else
+ setdisc(discfound,pre,post,replace)
+ end
+ base = prev
end
end
end
return head, base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks,what)
+local function multiple_glyphs(head,start,multiple,skiphash,what,stop) -- what to do with skiphash matches here
local nofmultiples = #multiple
if nofmultiples > 0 then
resetinjection(start)
@@ -654,7 +666,11 @@ end
local function get_alternative_glyph(start,alternatives,value)
local n = #alternatives
- if value == "random" then
+ if n == 1 then
+ -- we could actually change that into a gsub and save some memory in the
+ -- font loader but it makes tracing more messy
+ return alternatives[1], trace_alternatives and "1 (only one present)"
+ elseif value == "random" then
local r = getrandom and getrandom("glyph",1,n) or random(1,n)
return alternatives[r], trace_alternatives and formatters["value %a, taking %a"](value,r)
elseif value == "first" then
@@ -719,21 +735,25 @@ function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
return head, start, true
end
-function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
+function handlers.gsub_multiple(head,start,dataset,sequence,multiple,rlmode,skiphash)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
+ return multiple_glyphs(head,start,multiple,skiphash,dataset[1])
end
-function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
+-- Don't we deal with disc otherwise now? I need to check if the next one can be
+-- simplified. Anyway, it can be way messier: marks that get removed as well as
+-- marks that are kept.
+
+function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skiphash)
local current = getnext(start)
if not current then
return head, start, false, nil
end
local stop = nil
local startchar = getchar(start)
- if marks[startchar] then
+ if skiphash and skiphash[startchar] then
while current do
local char = ischar(current,currentfont)
if char then
@@ -764,15 +784,16 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
-- ok, goto next lookup
end
end
- else
- local skipmark = sequence.flags[1]
+ else -- is the check for disc still valid here ? and why only replace then
local discfound = false
local lastdisc = nil
+ local hasmarks = marks[startchar]
while current do
local char, id = ischar(current,currentfont)
if char then
- if skipmark and marks[char] then
+ if skiphash and skiphash[char] then
current = getnext(current)
+ -- if stop then stop = current end -- ?
else -- ligature is a tree
local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font
if lg then
@@ -780,6 +801,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
discfound = lastdisc
lastdisc = nil
end
+ if marks[char] then
+ hasmarks = true
+ end
stop = current -- needed for fake so outside then
ligature = lg
current = getnext(current)
@@ -791,8 +815,20 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
-- kind of weird
break
elseif id == disc_code then
- -- tricky .. we also need to do pre here
- local replace = getfield(current,"replace")
+ --
+ -- Kai: see chainprocs, we probably could do the same here or was there a reason
+ -- why we kept the replace check here.
+ --
+ -- if not discfound then
+ -- discfound = current
+ -- end
+ -- if current == stop then
+ -- break -- okay? or before the disc
+ -- else
+ -- current = getnext(current)
+ -- end
+ --
+ local replace = getfield(current,"replace") -- hm: pre and post
if replace then
-- of{f-}{}{f}e o{f-}{}{f}fe o{-}{}{ff}e (oe and ff ligature)
-- we can end up here when we have a start run .. testruns start at a disc but
@@ -802,6 +838,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
if char then
local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font
if lg then
+ if marks[char] then
+ hasmarks = true -- very unlikely
+ end
ligature = lg
replace = getnext(replace)
else
@@ -824,10 +863,10 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
if stop then
if trace_ligatures then
local stopchar = getchar(stop)
- head, start = toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
else
- head, start = toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head, start = toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
end
else
-- weird but happens (in some arabic font)
@@ -845,84 +884,81 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
return head, start, false, discfound
end
-function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local startchar = getchar(start)
- if step.format == "pair" then
- local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns,injection)
+ local format = step.format
+ if format == "single" or type(kerns) == "table" then -- the table check can go
+ local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
end
else
- -- needs checking .. maybe no kerns format for single
- local k = setkern(start,factor,rlmode,kerns,injection)
+ local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k)
end
end
- return head, start, false
+ return head, start, true
end
-function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local snext = getnext(start)
if not snext then
return head, start, false
else
local prev = start
- local done = false
while snext do
local nextchar = ischar(snext,currentfont)
if nextchar then
- local krn = kerns[nextchar]
- if not krn and marks[nextchar] then
- prev = snext
+ if skiphash and skiphash[nextchar] then -- includes marks too when flag
+ prev = snext
snext = getnext(snext)
- elseif not krn then
- break
- elseif step.format == "pair" then
- local a, b = krn[1], krn[2]
- if optimizekerns then
- -- this permits a mixed table, but we could also decide to optimize this
- -- in the loader and use format 'kern'
- if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
- local k = setkern(snext,factor,rlmode,a[3],injection)
+ else
+ local krn = kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format = step.format
+ if format == "pair" then
+ local a, b = krn[1], krn[2]
+ if a == true then
+ -- zero
+ elseif a then -- #a > 0
+ local x, y, w, h = setposition(1,start,factor,rlmode,a,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
+ local startchar = getchar(start)
+ 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")
end
- done = true
- break
end
- end
- if a and #a > 0 then
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection)
- if trace_kerns then
- local startchar = getchar(start)
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ if b == true then
+ -- zero
+ start = snext -- cf spec
+ elseif b then -- #b > 0
+ local x, y, w, h = setposition(2,snext,factor,rlmode,b,injection)
+ if trace_kerns then
+ local startchar = getchar(start)
+ 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")
+ end
+ start = snext -- cf spec
+ elseif forcepairadvance then
+ start = snext -- for testing, not cf spec
end
- end
- if b and #b > 0 then
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
+ return head, start, true
+ elseif krn ~= 0 then
+ local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn,injection)
if trace_kerns then
- local startchar = getchar(snext)
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections")
end
+ return head, start, true
+ else -- can't happen
+ break
end
- done = true
- break
- elseif krn ~= 0 then
- local k = setkern(snext,factor,rlmode,krn,injection)
- if trace_kerns then
- logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections")
- end
- done = true
- break
- else -- can't happen
- break
end
else
break
end
end
- return head, start, done
+ return head, start, false
end
end
@@ -931,7 +967,7 @@ end
we need to explicitly test for basechar, baselig and basemark entries.</p>
--ldx]]--
-function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar = getchar(start)
if marks[markchar] then
local base = getprev(start) -- [glyph] [start=mark]
@@ -966,10 +1002,13 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
local ma = markanchors[2]
local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head, start, true
+ elseif trace_bugs then
+ -- onetimemessage(currentfont,basechar,"no base anchors",report_fonts)
+ logwarning("%s: mark %s is not anchored to %s",pref(dataset,sequence),gref(markchar),gref(basechar))
end
elseif trace_bugs then
logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1)
@@ -983,7 +1022,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
return head, start, false
end
-function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar = getchar(start)
if marks[markchar] then
local base = getprev(start) -- [glyph] [optional marks] [start=mark]
@@ -1022,8 +1061,8 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
if ba then
local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ logprocess("%s, index %s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ pref(dataset,sequence),index,bound,gref(markchar),gref(basechar),index,dx,dy)
end
return head, start, true
else
@@ -1048,7 +1087,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
return head, start, false
end
-function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar = getchar(start)
if marks[markchar] then
local base = getprev(start) -- [glyph] [basemark] [start=mark]
@@ -1071,8 +1110,8 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
local ma = markanchors[2]
local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head, start, true
end
@@ -1084,8 +1123,7 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
return head, start, false
end
-function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i) -- to be checked
- local done = false
+function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step) -- to be checked
local startchar = getchar(start)
if marks[startchar] then
if trace_cursive then
@@ -1093,12 +1131,11 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
else
local nxt = getnext(start)
- while not done and nxt do
+ while nxt do
local nextchar = ischar(nxt,currentfont)
if not nextchar then
break
- elseif marks[nextchar] then
- -- should not happen (maybe warning)
+ elseif marks[nextchar] then -- always sequence.flags[1]
nxt = getnext(nxt)
else
local exit = exitanchors[3]
@@ -1107,11 +1144,12 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
if entry then
entry = entry[2]
if entry then
- local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local r2lflag = sequence.flags[4] -- mentioned in the standard
+ local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ 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))
end
- done = true
+ return head, start, true
end
end
end
@@ -1119,7 +1157,7 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
end
end
- return head, start, done
+ return head, start, false
end
--[[ldx--
@@ -1132,6 +1170,9 @@ local chainprocs = { }
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_subchain(...)
end
@@ -1141,6 +1182,9 @@ local logwarning = report_subchain
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_chain(...)
end
@@ -1154,7 +1198,7 @@ local logwarning = report_chain
-- in a bit weird way. There is no lookup and the replacement comes from the lookup
-- itself. It is meant mostly for dealing with Urdu.
-local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
+local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode,skiphash)
local char = getchar(start)
local replacement = replacements[char]
if replacement then
@@ -1196,66 +1240,76 @@ as less as needed but that would also make the code even more messy.</p>
-- this is messy: do we need this disc checking also in alternaties?
+local function reportzerosteps(dataset,sequence)
+ logwarning("%s: no steps",cref(dataset,sequence))
+end
+
local function reportmoresteps(dataset,sequence)
logwarning("%s: more than 1 step",cref(dataset,sequence))
end
-function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,chainindex)
+-- local function reportbadsteps(dataset,sequence)
+-- logwarning("%s: bad step, no proper return values",cref(dataset,sequence))
+-- end
+
+local function getmapping(dataset,sequence,currentlookup)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
- end
- local current = start
- while current do
- local currentchar = ischar(current)
- if currentchar then
- local replacement = steps[1].coverage[currentchar]
- if not replacement or replacement == "" then
- if trace_bugs then
- logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
- end
- else
- if trace_singles then
- logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
- end
- resetinjection(current)
- setchar(current,replacement)
- end
- return head, start, true
- elseif currentchar == false then
- -- can't happen
- break
- elseif current == stop then
- break
- else
- current = getnext(current)
+ if nofsteps == 0 then
+ reportzerosteps(dataset,sequence)
+ currentlookup.mapping = false
+ return false
+ else
+ if nofsteps > 1 then
+ reportmoresteps(dataset,sequence)
end
+ local mapping = steps[1].coverage
+ currentlookup.mapping = mapping
+ currentlookup.format = steps[1].format
+ return mapping
end
- return head, start, false
end
---[[ldx--
-<p>Here we replace start by a sequence of new glyphs.</p>
---ldx]]--
+function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ if trace_chains then
+ logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start)))
+ end
+ head, start = remove_node(head,start,true)
+ return head, getprev(start), true
+end
-function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local startchar = getchar(start)
- local replacement = steps[1].coverage[startchar]
- if not replacement or replacement == "" then
- if trace_bugs then
- logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
- end
- else
- if trace_multiples then
- logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ if mapping then
+ local current = start
+ while current do
+ local currentchar = ischar(current)
+ if currentchar then
+ local replacement = mapping[currentchar]
+ if not replacement or replacement == "" then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
+ end
+ resetinjection(current)
+ setchar(current,replacement)
+ end
+ return head, start, true
+ elseif currentchar == false then
+ -- can't happen
+ break
+ elseif current == stop then
+ break
+ else
+ current = getnext(current)
+ end
end
- return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
end
return head, start, false
end
@@ -1272,42 +1326,69 @@ end
-- marks come last anyway
-- are there cases where we need to delete the mark
-function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local kind = dataset[4]
- local what = dataset[1]
- local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx
- local current = start
- while current do
- local currentchar = ischar(current)
- if currentchar then
- local alternatives = steps[1].coverage[currentchar]
- if alternatives then
- local choice, comment = get_alternative_glyph(current,alternatives,value)
- if choice then
- if trace_alternatives then
- logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment)
- end
- resetinjection(start)
- setchar(start,choice)
- else
- if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment)
+ if mapping then
+ local kind = dataset[4]
+ local what = dataset[1]
+ local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx
+ local current = start
+ while current do
+ local currentchar = ischar(current)
+ if currentchar then
+ local alternatives = mapping[currentchar]
+ if alternatives then
+ local choice, comment = get_alternative_glyph(current,alternatives,value)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(currentchar),choice,gref(choice),comment)
+ end
+ resetinjection(start)
+ setchar(start,choice)
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(currentchar),comment)
+ end
end
end
+ return head, start, true
+ elseif currentchar == false then
+ -- can't happen
+ break
+ elseif current == stop then
+ break
+ else
+ current = getnext(current)
+ end
+ end
+ end
+ return head, start, false
+end
+
+--[[ldx--
+<p>Here we replace start by a sequence of new glyphs.</p>
+--ldx]]--
+
+function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local startchar = getchar(start)
+ local replacement = mapping[startchar]
+ if not replacement or replacement == "" then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
end
- return head, start, true
- elseif currentchar == false then
- -- can't happen
- break
- elseif current == stop then
- break
else
- current = getnext(current)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ end
+ return multiple_glyphs(head,start,replacement,skiphash,dataset[1],stop)
end
end
return head, start, false
@@ -1319,419 +1400,423 @@ this function (move code inline and handle the marks by a separate function). We
assume rather stupid ligatures (no complex disc nodes).</p>
--ldx]]--
-function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,chainindex)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+-- compare to handlers.gsub_ligature which is more complex ... why
+
+function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local startchar = getchar(start)
- local ligatures = steps[1].coverage[startchar]
- if not ligatures then
- if trace_bugs then
- logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
- end
- else
- local current = getnext(start)
- local discfound = false
- local last = stop
- local nofreplacements = 1
- local skipmark = currentlookup.flags[1] -- sequence.flags?
- while current do
- -- todo: ischar ... can there really be disc nodes here?
- local id = getid(current)
- if id == disc_code then
- if not discfound then
- discfound = current
- end
- if current == stop then
- break -- okay? or before the disc
- else
- current = getnext(current)
- end
- else
- local schar = getchar(current)
- if skipmark and marks[schar] then -- marks
- -- if current == stop then -- maybe add this
- -- break
- -- else
+ if mapping then
+ local startchar = getchar(start)
+ local ligatures = mapping[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
+ end
+ else
+ local hasmarks = marks[startchar]
+ local current = getnext(start)
+ local discfound = false
+ local last = stop
+ local nofreplacements = 1
+ while current do
+ -- todo: ischar ... can there really be disc nodes here?
+ local id = getid(current)
+ if id == disc_code then
+ if not discfound then
+ discfound = current
+ end
+ if current == stop then
+ break -- okay? or before the disc
+ else
current = getnext(current)
- -- end
+ end
else
- local lg = ligatures[schar]
- if lg then
- ligatures = lg
- last = current
- nofreplacements = nofreplacements + 1
- if current == stop then
- break
- else
+ local schar = getchar(current)
+ if skiphash and skiphash[schar] then -- marks
+ -- if current == stop then -- maybe add this
+ -- break
+ -- else
current = getnext(current)
- end
+ -- end
else
- break
+ local lg = ligatures[schar]
+ if lg then
+ ligatures = lg
+ last = current
+ nofreplacements = nofreplacements + 1
+ if marks[char] then
+ hasmarks = true
+ end
+ if current == stop then
+ break
+ else
+ current = getnext(current)
+ end
+ else
+ break
+ end
end
end
end
- end
- local ligature = ligatures.ligature
- if ligature then
- if chainindex then
- stop = last
- end
- if trace_ligatures then
+ local ligature = ligatures.ligature
+ if ligature then
+ if chainindex then
+ stop = last
+ end
+ if trace_ligatures then
+ if start == stop then
+ logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ end
+ end
+ head, start = toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
+ return head, start, true, nofreplacements, discfound
+ elseif trace_bugs then
if start == stop then
- logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
else
- logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
end
end
- head, start = toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound)
- return head, start, true, nofreplacements, discfound
- elseif trace_bugs then
- if start == stop then
- logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
- else
- logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
- end
end
end
return head, start, false, 0, false
end
-function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local startchar = getchar(start)
- local step = steps[1]
- local kerns = step.coverage[startchar]
- if not kerns then
- -- skip
- elseif step.format == "pair" then
- local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns) -- currentlookup.flags ?
- if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h)
- end
- else -- needs checking .. maybe no kerns format for single
- local k = setkern(start,factor,rlmode,kerns,injection)
- if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ if mapping then
+ local startchar = getchar(start)
+ local kerns = mapping[startchar]
+ if kerns then
+ local format = currentlookup.format
+ if format == "single" then
+ local dx, dy, w, h = setposition(0,start,factor,rlmode,kerns) -- currentlookup.flags ?
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
+ end
+ else -- needs checking .. maybe no kerns format for single
+ local k = (format == "move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k)
+ end
+ end
+ return head, start, true
end
end
return head, start, false
end
-function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex) -- todo: injections ?
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex) -- todo: injections ?
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local snext = getnext(start)
- if snext then
- local startchar = getchar(start)
- local step = steps[1]
- local kerns = step.coverage[startchar] -- always 1 step
- if kerns then
- local prev = start
- local done = false
- while snext do
- local nextchar = ischar(snext,currentfont)
- if not nextchar then
- break
- end
- local krn = kerns[nextchar]
- if not krn and marks[nextchar] then
- prev = snext
- snext = getnext(snext)
- elseif not krn then
- break
- elseif step.format == "pair" then
- local a, b = krn[1], krn[2]
- if optimizekerns then
- -- this permits a mixed table, but we could also decide to optimize this
- -- in the loader and use format 'kern'
- if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
- local k = setkern(snext,factor,rlmode,a[3],"injections")
+ if mapping then
+ local snext = getnext(start)
+ if snext then
+ local startchar = getchar(start)
+ local kerns = mapping[startchar] -- always 1 step
+ if kerns then
+ local prev = start
+ while snext do
+ local nextchar = ischar(snext,currentfont)
+ if not nextchar then
+ break
+ end
+ if skiphash and skiphash[nextchar] then
+ prev = snext
+ snext = getnext(snext)
+ else
+ local krn = kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format = currentlookup.format
+ if format == "pair" then
+ local a, b = krn[1], krn[2]
+ if a == true then
+ -- zero
+ elseif a then
+ local x, y, w, h = setposition(1,start,factor,rlmode,a,"injections") -- currentlookups flags?
+ if trace_kerns then
+ local startchar = getchar(start)
+ 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)
+ end
+ end
+ if b == true then
+ -- zero
+ start = snext -- cf spec
+ elseif b then -- #b > 0
+ local x, y, w, h = setposition(2,snext,factor,rlmode,b,"injections")
+ if trace_kerns then
+ local startchar = getchar(start)
+ 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)
+ end
+ start = snext -- cf spec
+ elseif forcepairadvance then
+ start = snext -- for testing, not cf spec
+ end
+ return head, start, true
+ elseif krn ~= 0 then
+ local k = (format == "move" and setmove or setkern)(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar))
end
- done = true
+ return head, start, true
+ else
break
end
end
- if a and #a > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,"injections") -- currentlookups flags?
- if trace_kerns then
- 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)
- end
- end
- if b and #b > 0 then
- local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
- if trace_kerns then
- 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)
- end
- end
- done = true
- break
- elseif krn ~= 0 then
- local k = setkern(snext,factor,rlmode,krn)
- if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar))
- end
- done = true
- break
- else
- break
end
end
- return head, start, done
end
end
return head, start, false
end
-function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local markchar = getchar(start)
- if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
- if markanchors then
- local base = getprev(start) -- [glyph] [start=mark]
- if base then
- local basechar = ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base = getprev(base)
- if base then
- local basechar = ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+ if mapping then
+ local markchar = getchar(start)
+ if marks[markchar] then
+ local markanchors = mapping[markchar] -- always 1 step
+ if markanchors then
+ local base = getprev(start) -- [glyph] [start=mark]
+ if base then
+ local basechar = ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base = getprev(base)
+ if base then
+ local basechar = ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ end
+ return head, start, false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
end
return head, start, false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
- end
- return head, start, false
end
end
- end
- local ba = markanchors[1][basechar]
- if ba then
- local ma = markanchors[2]
- if ma then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ local ba = markanchors[1][basechar]
+ if ba then
+ local ma = markanchors[2]
+ if ma then
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
end
- return head, start, true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head, start, false
end
-function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local markchar = getchar(start)
- if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
- if markanchors then
- local base = getprev(start) -- [glyph] [optional marks] [start=mark]
- if base then
- local basechar = ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base = getprev(base)
- if base then
- local basechar = ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+ if mapping then
+ local markchar = getchar(start)
+ if marks[markchar] then
+ local markanchors = mapping[markchar] -- always 1 step
+ if markanchors then
+ local base = getprev(start) -- [glyph] [optional marks] [start=mark]
+ if base then
+ local basechar = ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base = getprev(base)
+ if base then
+ local basechar = ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ end
+ return head, start, false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
end
return head, start, false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
- end
- return head, start, false
end
end
- end
- local ba = markanchors[1][basechar]
- if ba then
- local ma = markanchors[2]
- if ma then
- local index = getligaindex(start)
- ba = ba[index]
- if ba then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ local ba = markanchors[1][basechar]
+ if ba then
+ local ma = markanchors[2]
+ if ma then
+ local index = getligaindex(start)
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ cref(dataset,sequence),a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return head, start, true
end
- return head, start, true
end
end
+ elseif trace_bugs then
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head, start, false
end
-function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local markchar = getchar(start)
- if marks[markchar] then
- local markanchors = steps[1].coverage[markchar] -- always 1 step
- if markanchors then
- local base = getprev(start) -- [glyph] [basemark] [start=mark]
- local slc = getligaindex(start)
- if slc then -- a rather messy loop ... needs checking with husayni
- while base do
- local blc = getligaindex(base)
- if blc and blc ~= slc then
- base = getprev(base)
- else
- break
+ if mapping then
+ local markchar = getchar(start)
+ if marks[markchar] then
+ local markanchors = mapping[markchar] -- always 1 step
+ if markanchors then
+ local base = getprev(start) -- [glyph] [basemark] [start=mark]
+ local slc = getligaindex(start)
+ if slc then -- a rather messy loop ... needs checking with husayni
+ while base do
+ local blc = getligaindex(base)
+ if blc and blc ~= slc then
+ base = getprev(base)
+ else
+ break
+ end
end
end
- end
- if base then -- subtype test can go
- local basechar = ischar(base,currentfont)
- if basechar then
- local ba = markanchors[1][basechar]
- if ba then
- local ma = markanchors[2]
- if ma then
- local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ if base then -- subtype test can go
+ local basechar = ischar(base,currentfont)
+ if basechar then
+ local ba = markanchors[1][basechar]
+ if ba then
+ local ma = markanchors[2]
+ if ma then
+ local dx, dy, bound = setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head, start, true
end
- return head, start, true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head, start, false
end
-function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps = currentlookup.steps
- local nofsteps = currentlookup.nofsteps
- if nofsteps > 1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping = currentlookup.mapping
+ if mapping == nil then
+ mapping = getmapping(dataset,sequence,currentlookup)
end
- local startchar = getchar(start)
- local exitanchors = steps[1].coverage[startchar] -- always 1 step
- if exitanchors then
- local done = false
- if marks[startchar] then
- if trace_cursive then
- logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
- end
- else
- local nxt = getnext(start)
- while not done and nxt do
- local nextchar = ischar(nxt,currentfont)
- if not nextchar then
- break
- elseif marks[nextchar] then
- -- should not happen (maybe warning)
- nxt = getnext(nxt)
- else
- local exit = exitanchors[3]
- if exit then
- local entry = exitanchors[1][nextchar]
- if entry then
- entry = entry[2]
+ if mapping then
+ local startchar = getchar(start)
+ local exitanchors = mapping[startchar] -- always 1 step
+ if exitanchors then
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
+ end
+ else
+ local nxt = getnext(start)
+ while nxt do
+ local nextchar = ischar(nxt,currentfont)
+ if not nextchar then
+ break
+ elseif marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = getnext(nxt)
+ else
+ local exit = exitanchors[3]
+ if exit then
+ local entry = exitanchors[1][nextchar]
if entry then
- local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
- if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ entry = entry[2]
+ if entry then
+ local r2lflag = sequence.flags[4] -- mentioned in the standard
+ local dx, dy, bound = setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
+ if trace_cursive then
+ 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))
+ end
+ return head, start, true
end
- done = true
- break
end
+ elseif trace_bugs then
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
- elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ break
end
- break
end
end
- end
- return head, start, done
- else
- if trace_cursive and trace_details then
+ elseif trace_cursive and trace_details then
logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone)
end
- return head, start, false
end
+ return head, start, false
end
-- what pointer to return, spec says stop
@@ -1745,36 +1830,50 @@ end
-- A previous version had disc collapsing code in the (single sub) handler plus some
-- checking in the main loop, but that left the pre/post sequences undone. The best
-- solution is to add some checking there and backtrack when a replace/post matches
--- but it takes a bit of work to figure out an efficient way (this is what the sweep*
--- names refer to). I might look into that variant one day again as it can replace
--- some other code too. In that approach we can have a special version for gub and pos
--- which gains some speed. This method does the test and passes info to the handlers
--- (sweepnode, sweepmode, sweepprev, sweepnext, etc). Here collapsing is handled in the
--- main loop which also makes code elsewhere simpler (i.e. no need for the other special
--- runners and disc code in ligature building). I also experimented with pushing preceding
--- glyphs sequences in the replace/pre fields beforehand which saves checking afterwards
--- but at the cost of duplicate glyphs (memory) but it's too much overhead (runtime).
+-- but it takes a bit of work to figure out an efficient way (this is what the
+-- sweep* names refer to). I might look into that variant one day again as it can
+-- replace some other code too. In that approach we can have a special version for
+-- gub and pos which gains some speed. This method does the test and passes info to
+-- the handlers. Here collapsing is handled in the main loop which also makes code
+-- elsewhere simpler (i.e. no need for the other special runners and disc code in
+-- ligature building). I also experimented with pushing preceding glyphs sequences
+-- in the replace/pre fields beforehand which saves checking afterwards but at the
+-- cost of duplicate glyphs (memory) but it's too much overhead (runtime).
--
--- In the meantime Kai had moved the code from the single chain into a more general handler
--- and this one (renamed to chaindisk) is used now. I optimized the code a bit and brought
--- it in sycn with the other code. Hopefully I didn't introduce errors. Note: this somewhat
--- complex approach is meant for fonts that implement (for instance) ligatures by character
--- replacement which to some extend is not that suitable for hyphenation. I also use some
--- helpers. This method passes some states but reparses the list. There is room for a bit of
--- speed up but that will be done in the context version. (In fact a partial rewrite of all
--- code can bring some more efficientry.)
+-- In the meantime Kai had moved the code from the single chain into a more general
+-- handler and this one (renamed to chaindisk) is used now. I optimized the code a
+-- bit and brought it in sycn with the other code. Hopefully I didn't introduce
+-- errors. Note: this somewhat complex approach is meant for fonts that implement
+-- (for instance) ligatures by character replacement which to some extend is not
+-- that suitable for hyphenation. I also use some helpers. This method passes some
+-- states but reparses the list. There is room for a bit of speed up but that will
+-- be done in the context version. (In fact a partial rewrite of all code can bring
+-- some more efficiency.)
--
--- I didn't test it with extremes but successive disc nodes still can give issues but in
--- order to handle that we need more complex code which also slows down even more. The main
--- loop variant could deal with that: test, collapse, backtrack.
+-- I didn't test it with extremes but successive disc nodes still can give issues
+-- but in order to handle that we need more complex code which also slows down even
+-- more. The main loop variant could deal with that: test, collapse, backtrack.
+
+local userkern = nuts.pool and nuts.pool.newkern -- context
+
+do if not userkern then -- generic
+
+ local thekern = nuts.new("kern",1) -- userkern
+ local setkern = nuts.setkern -- not injections.setkern
+
+ userkern = function(k)
+ local n = copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
-local new_kern = nuts.pool.kern
+end end
local function checked(head)
local current = head
while current do
if getid(current) == glue_code then
- local kern = new_kern(getfield(current,"width"))
+ local kern = userkern(getwidth(current))
if head == current then
local next = getnext(current)
if next then
@@ -1785,8 +1884,7 @@ local function checked(head)
current = next
else
local prev, next = getboth(current)
- setlink(prev,kern)
- setlink(kern,next)
+ setlink(prev,kern,next)
flush_node(current)
current = next
end
@@ -1804,7 +1902,131 @@ local function setdiscchecked(d,pre,post,replace)
setdisc(d,pre,post,replace)
end
-local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
+local noflags = { false, false, false, false }
+
+local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+
+ local size = ck[5] - ck[4] + 1
+ local chainlookups = ck[6]
+ local done = false
+
+ -- current match
+ if chainlookups then
+ -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and
+ -- #lookups can be less than #current
+
+ if size == 1 then
+
+ -- if nofchainlookups > size then
+ -- -- bad rules
+ -- end
+
+ local chainlookup = chainlookups[1]
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local chainkind = chainstep.type
+ local chainproc = chainprocs[chainkind]
+ if chainproc then
+ local ok
+ head, start, ok = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ if ok then
+ done = true
+ end
+ else
+ logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
+ end
+ end
+
+ else
+
+ -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The
+ -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if
+ -- we have a ligature. Cf the spec we then need to advance one character but we
+ -- really need to test it as there are fonts out there that are fuzzy and have
+ -- too many lookups:
+ --
+ -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes
+ --
+ -- Even worse are these family emoji shapes as they can have multiple lookups
+ -- per slot (probably only for gpos).
+
+ -- It's very unlikely that we will have skip classes here but still ... we seldom
+ -- enter this branch anyway.
+
+ local i = 1
+ local laststart = start
+ local nofchainlookups = #chainlookups -- useful?
+ while start do
+ if skiphash then -- hm, so we know we skip some
+ while start do
+ local char = ischar(start,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ start = getnext(start)
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ end
+ local chainlookup = chainlookups[i]
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep = chainlookup[j]
+ local chainkind = chainstep.type
+ local chainproc = chainprocs[chainkind]
+ if chainproc then
+ local ok, n
+ head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i)
+ -- messy since last can be changed !
+ if ok then
+ done = true
+ if n and n > 1 and i + n > nofchainlookups then
+ -- this is a safeguard, we just ignore the rest of the lookups
+ i = size -- prevents an advance
+ break
+ end
+ end
+ else
+ -- actually an error
+ logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
+ end
+ end
+ else
+ -- we skip but we could also delete as option .. what does an empty lookup actually mean
+ -- in opentype ... anyway, we could map it onto gsub_remove if needed
+ end
+ i = i + 1
+ if i > size or not start then
+ break
+ elseif start then
+ laststart = start
+ start = getnext(start)
+ end
+ end
+ if not start then
+ start = laststart
+ end
+
+ end
+ else
+ -- todo: needs checking for holes in the replacements
+ local replacements = ck[7]
+ if replacements then
+ head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode,skiphash)
+ else
+ done = true
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(dataset,sequence))
+ end
+ end
+ end
+ return head, start, done
+end
+
+local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
if not start then
return head, start, false
@@ -1819,7 +2041,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local sweepnode = sweepnode
local sweeptype = sweeptype
local sweepoverflow = false
- local checkdisc = getprev(head) -- hm bad name head
local keepdisc = not sweepnode
local lookaheaddisc = nil
local backtrackdisc = nil
@@ -1845,19 +2066,23 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
hasglue = true
elseif id == disc_code then
if keepdisc then
- keepdisc = false
- if notmatchpre[current] ~= notmatchreplace[current] then
- lookaheaddisc = current
- end
+ keepdisc = false
+ lookaheaddisc = current
local replace = getfield(current,"replace")
- while replace and i <= l do
- if getid(replace) == glyph_code then
- i = i + 1
+ if not replace then
+ sweepoverflow = true
+ sweepnode = current
+ current = getnext(current)
+ else
+ while replace and i <= l do
+ if getid(replace) == glyph_code then
+ i = i + 1
+ end
+ replace = getnext(replace)
end
- replace = getnext(replace)
+ current = getnext(replace)
end
- last = current
- current = getnext(c)
+ last = current
else
head, current = flattendisk(head,current)
end
@@ -1868,7 +2093,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if current then
-- go on
elseif sweepoverflow then
- -- we already are folling up on sweepnode
+ -- we already are following up on sweepnode
break
elseif sweeptype == "post" or sweeptype == "replace" then
current = getnext(sweepnode)
@@ -1919,7 +2144,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if notmatchpre[current] ~= notmatchreplace[current] then
lookaheaddisc = current
end
- local replace = getfield(c,"replace")
+ -- we assume a simple text only replace (we could use nuts.count)
+ local replace = getfield(current,"replace")
while replace and i < s do
if getid(replace) == glyph_code then
i = i + 1
@@ -1964,6 +2190,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if notmatchpost[current] ~= notmatchreplace[current] then
backtrackdisc = current
end
+ -- we assume a simple text only replace (we could use nuts.count)
local replace = getfield(current,"replace")
while replace and i > 1 do
if getid(replace) == glyph_code then
@@ -1981,8 +2208,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
end
end
end
+ local done = false
- local ok = false
if lookaheaddisc then
local cf = start
@@ -2001,38 +2228,44 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
-
- setprev(lookaheaddisc,cprev)
- if cprev then
- setnext(cprev,lookaheaddisc)
- end
+ setlink(cprev,lookaheaddisc)
setprev(cf)
setnext(cl)
if startishead then
head = lookaheaddisc
end
local pre, post, replace = getdisc(lookaheaddisc)
- local new = copy_node_list(cf)
+ local new = copy_node_list(cf) -- br, how often does that happen
local cnew = new
+ if pre then
+ setlink(find_node_tail(cf),pre)
+ end
+ if replace then
+ local tail = find_node_tail(new)
+ setlink(tail,replace)
+ end
for i=1,insertedmarks do
cnew = getnext(cnew)
end
+ cl = start
local clast = cnew
for i=f,l do
+ cl = getnext(cl)
clast = getnext(clast)
end
if not notmatchpre[lookaheaddisc] then
- cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok = false
+ cf, start, ok = chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done = true
+ end
end
if not notmatchreplace[lookaheaddisc] then
- new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
- end
- if pre then
- setlink(cl,pre)
- end
- if replace then
- local tail = find_node_tail(new)
- setlink(tail,replace)
+ local ok = false
+ new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done = true
+ end
end
if hasglue then
setdiscchecked(lookaheaddisc,cf,post,new)
@@ -2040,8 +2273,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(lookaheaddisc,cf,post,new)
end
start = getprev(lookaheaddisc)
- sweephead[cf] = getnext(clast)
- sweephead[new] = getnext(last)
+ sweephead[cf] = getnext(clast) or false
+ sweephead[new] = getnext(cl) or false
elseif backtrackdisc then
@@ -2060,10 +2293,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
- if cnext then
- setprev(cnext,backtrackdisc)
- end
- setnext(backtrackdisc,cnext)
+ setlink(backtrackdisc,cnext)
setprev(cf)
setnext(cl)
local pre, post, replace, pretail, posttail, replacetail = getdisc(backtrackdisc,true)
@@ -2077,10 +2307,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
clast = getnext(clast)
end
if not notmatchpost[backtrackdisc] then
- cf, start, ok = chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok = false
+ cf, start, ok = chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done = true
+ end
end
if not notmatchreplace[backtrackdisc] then
- new, cnew, ok = chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
+ local ok = false
+ new, cnew, ok = chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done = true
+ end
end
if post then
setlink(posttail,cf)
@@ -2098,539 +2336,486 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(backtrackdisc,pre,post,replace)
end
start = getprev(backtrackdisc)
- sweephead[post] = getnext(clast)
- sweephead[replace] = getnext(last)
+ sweephead[post] = getnext(clast) or false
+ sweephead[replace] = getnext(last) or false
else
- head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok = false
+ head, start, ok = chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done = true
+ end
end
- return head, start, ok
+ return head, start, done
end
-local noflags = { false, false, false, false }
+local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode)
+ local rule = ck[1]
+ local lookuptype = ck[8] or ck[2]
+ local nofseq = #ck[3]
+ local first = ck[4]
+ local last = ck[5]
+ local char = getchar(start)
+ logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping",
+ cref(dataset,sequence),rule,match and "matches" or "nomatch",
+ gref(char),first-1,last-first+1,nofseq-last,lookuptype,
+ discseen and "" or "no ", sweepnode and "" or "not ")
+end
+
+-- The next one is quite optimized but still somewhat slow, fonts like ebgaramond
+-- are real torture tests because they have many steps with one context (having
+-- multiple contexts makes more sense) also because we (can) reduce them. Instead of
+-- a match boolean variable and check for that I decided to use a goto with labels
+-- instead. This is one of the cases where it makes the code more readable and we
+-- might even gain a bit performance.
-local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
+-- when we have less replacements (lookups) then current matches we can push too much into
+-- the previous disc .. such be it (<before><disc><current=fl><after> with only f done)
+
+local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
+ -- optimizing for rlmode gains nothing
local sweepnode = sweepnode
local sweeptype = sweeptype
+ local postreplace
+ local prereplace
+ local checkdisc
+ local discseen -- = false
+ if sweeptype then
+ if sweeptype == "replace" then
+ postreplace = true
+ prereplace = true
+ else
+ postreplace = sweeptype == "post"
+ prereplace = sweeptype == "pre"
+ end
+ checkdisc = getprev(head)
+ end
local currentfont = currentfont
- local diskseen = false
- local checkdisc = getprev(head)
- local flags = sequence.flags or noflags
- local done = false
- local skipmark = flags[1]
- local skipligature = flags[2]
- local skipbase = flags[3]
- local markclass = sequence.markclass
- local skipped = false
- for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu)
- local match = true
+
+ local skipped -- = false
+
+ local startprev,
+ startnext = getboth(start)
+ local done -- = false
+
+ -- we can have multiple hits and as we scan (currently) all we need to check
+ -- if we have a match ... contextchains have no real coverage table (with
+ -- unique entries)
+
+ -- fonts can have many steps (each doing one check) or many contexts
+
+ -- todo: make a per-char cache so that we have small contexts (when we have a context
+ -- n == 1 and otherwise it can be more so we can even distingish n == 1 or more)
+
+ local nofcontexts = contexts.n -- #contexts
+
+ local startchar = nofcontext == 1 or ischar(start,currentfont) -- only needed in a chain
+
+ for k=1,nofcontexts do -- does this disc mess work well with n > 1
+
+ local ck = contexts[k]
+ local seq = ck[3]
+ local f = ck[4] -- first current
+ if not startchar or not seq[f][startchar] then
+ -- report("no hit in %a at %i of %i contexts",sequence.type,k,nofcontexts)
+ goto next
+ end
+ local s = seq.n -- or #seq
+ local l = ck[5] -- last current
local current = start
local last = start
- local ck = contexts[k]
- local seq = ck[3]
- local s = #seq
- local size = 1
- -- f..l = mid string
- if s == 1 then
- -- this seldom happens as it makes no sense (bril, ebgaramond, husayni, minion)
- local char = ischar(current,currentfont)
- if char then
- match = seq[1][char]
- end
- else
- -- maybe we need a better space check (maybe check for glue or category or combination)
- -- we cannot optimize for n=2 because there can be disc nodes
- local f = ck[4]
- local l = ck[5]
- -- current match
- size = l - f + 1
- if size > 1 then
- -- before/current/after | before/current | current/after
- local discfound = nil
- local n = f + 1
- last = getnext(last) -- the second in current (first already matched)
- while n <= l do
- if not last and (sweeptype == "post" or sweeptype == "replace") then
- last = getnext(sweepnode)
- sweeptype = nil
- end
- if last then
- local char, id = ischar(last,currentfont)
- if char then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class or "base"
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- skipped = true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- last = getnext(last)
- elseif seq[n][char] then
- if n < l then
- last = getnext(last)
- end
- n = n + 1
- else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
- else
- match = false
- end
- break
- end
+
+ -- current match
+
+ if l > f then
+ -- before/current/after | before/current | current/after
+ local discfound -- = nil
+ local n = f + 1
+ last = startnext -- the second in current (first already matched)
+ while n <= l do
+ if postreplace and not last then
+ last = getnext(sweepnode)
+ sweeptype = nil
+ end
+ if last then
+ local char, id = ischar(last,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ last = getnext(last)
+ elseif seq[n][char] then
+ if n < l then
+ last = getnext(last)
+ end
+ n = n + 1
+ elseif discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
- else
- match = false
- end
break
end
- elseif char == false then
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
else
- match = false
+ break
end
- break
- elseif id == disc_code then
- diskseen = true
- discfound = last
- notmatchpre[last] = nil
- notmatchpost[last] = true
- notmatchreplace[last] = nil
- local pre, post, replace = getdisc(last)
- if pre then
- local n = n
- while pre do
- if seq[n][getchar(pre)] then
- n = n + 1
- pre = getnext(pre)
- if n > l then
- break
- end
- else
- notmatchpre[last] = true
+ else
+ goto next
+ end
+ elseif id == disc_code then
+ -- elseif id == disc_code and (not discs or discs[last]) then
+ discseen = true
+ discfound = last
+ notmatchpre[last] = nil
+ notmatchpost[last] = true
+ notmatchreplace[last] = nil
+ local pre, post, replace = getdisc(last)
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ if n > l then
break
end
- end
- if n <= l then
+ pre = getnext(pre)
+ else
notmatchpre[last] = true
+ break
end
- else
- notmatchpre[last] = true
end
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
- replace = getnext(replace)
- if n > l then
- break
- end
+ -- commented, for Kai to check
+ -- if n <= l then
+ -- notmatchpre[last] = true
+ -- end
+ else
+ notmatchpre[last] = true
+ end
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ if n > l then
+ break
+ end
+ replace = getnext(replace)
+ else
+ notmatchreplace[last] = true
+ if notmatchpre[last] then
+ goto next
else
- notmatchreplace[last] = true
- match = not notmatchpre[last]
break
end
end
- match = not notmatchpre[last]
end
- -- maybe only if match
- last = getnext(last)
- else
- match = false
- break
+ -- why here again
+ if notmatchpre[last] then
+ goto next
+ end
end
+ -- maybe only if match
+ last = getnext(last)
else
- match = false
- break
+ goto next
end
+ else
+ goto next
end
end
- -- before
- if match and f > 1 then
- local prev = getprev(start)
+ end
+
+ -- before
+
+ if f > 1 then
+ if startprev then
+ local prev = startprev
+ if prereplace and prev == checkdisc then
+ prev = getprev(sweepnode)
+ end
if prev then
- if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then
- prev = getprev(sweepnode)
- -- sweeptype = nil
- end
- if prev then
- local discfound = nil
- local n = f - 1
- while n >= 1 do
- if prev then
- local char, id = ischar(prev,currentfont)
- if char then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- skipped = true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- prev = getprev(prev) -- moved here
- elseif seq[n][char] then
- if n > 1 then -- new test
- prev = getprev(prev) -- moved here
- end
- n = n - 1
- else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpost[discfound]
- else
- match = false
- end
- break
- end
+ local discfound -- = nil
+ local n = f - 1
+ while n >= 1 do
+ if prev then
+ local char, id = ischar(prev,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ prev = getprev(prev)
+ elseif seq[n][char] then
+ if n > 1 then
+ prev = getprev(prev)
+ end
+ n = n - 1
+ elseif discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpost[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpost[discfound]
- else
- match = false
- end
break
end
- -- prev = getprev(prev) -- moved up
- elseif char == false then
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpost[discfound]
- else
- match = false
+ else
+ goto next
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpost[discfound] then
+ goto next
end
- break
- elseif id == disc_code then
- -- the special case: f i where i becomes dottless i ..
- diskseen = true
- discfound = prev
- notmatchpre[prev] = true
- notmatchpost[prev] = nil
- notmatchreplace[prev] = nil
- local pre, post, replace, pretail, posttail, replacetail = getdisc(prev,true)
- if pre ~= start and post ~= start and replace ~= start then
- if post then
- local n = n
- while posttail do
- if seq[n][getchar(posttail)] then
- n = n - 1
- if posttail == post then
- break
- else
- posttail = getprev(posttail)
- if n < 1 then
- break
- end
- end
- else
- notmatchpost[prev] = true
+ else
+ goto next
+ end
+ break
+ elseif id == disc_code then
+ -- elseif id == disc_code and (not discs or discs[prev]) then
+ -- the special case: f i where i becomes dottless i ..
+ discseen = true
+ discfound = prev
+ notmatchpre[prev] = true
+ notmatchpost[prev] = nil
+ notmatchreplace[prev] = nil
+ local pre, post, replace, pretail, posttail, replacetail = getdisc(prev,true)
+ -- weird test: needs checking
+ if pre ~= start and post ~= start and replace ~= start then
+ if post then
+ local n = n
+ while posttail do
+ if seq[n][getchar(posttail)] then
+ n = n - 1
+ if posttail == post or n < 1 then
break
+ else
+ posttail = getprev(posttail)
end
- end
- if n >= 1 then
+ else
notmatchpost[prev] = true
+ break
end
- else
+ end
+ if n >= 1 then
notmatchpost[prev] = true
end
- if replace then
- -- we seldom enter this branch (e.g. on brill efficient)
- while replacetail do
- if seq[n][getchar(replacetail)] then
- n = n - 1
- if replacetail == replace then
- break
- else
- replacetail = getprev(replacetail)
- if n < 1 then
- break
- end
- end
+ else
+ notmatchpost[prev] = true
+ end
+ if replace then
+ -- we seldom enter this branch (e.g. on brill efficient)
+ while replacetail do
+ if seq[n][getchar(replacetail)] then
+ n = n - 1
+ if replacetail == replace or n < 1 then
+ break
+ else
+ replacetail = getprev(replacetail)
+ end
+ else
+ notmatchreplace[prev] = true
+ if notmatchpost[prev] then
+ goto next
else
- notmatchreplace[prev] = true
- match = not notmatchpost[prev]
break
end
end
- if not match then
- break
- end
end
+ else
+ notmatchreplace[prev] = true -- new, for Kai to check
end
- -- maybe only if match
- prev = getprev(prev)
- elseif seq[n][32] and isspace(prev,threshold) then
+ end
+ prev = getprev(prev)
+ -- elseif id == glue_code and seq[n][32] and isspace(prev,threshold,id) then
+ -- elseif seq[n][32] and spaces[prev] then
+ -- n = n - 1
+ -- prev = getprev(prev)
+ elseif id == glue_code then
+ local sn = seq[n]
+ if (sn[32] and spaces[prev]) or sn[0xFFFC] then
n = n - 1
prev = getprev(prev)
else
- match = false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n = n - 1
+ prev = getprev(prev)
else
- match = false
- break
+ goto next
end
+ else
+ goto next
end
- else
- match = false
end
else
- match = false
+ goto next
end
+ else
+ goto next
end
- -- after
- if match and s > l then
- local current = last and getnext(last)
- if not current then
- if sweeptype == "post" or sweeptype == "replace" then
- current = getnext(sweepnode)
- -- sweeptype = nil
- end
- end
- if current then
- local discfound = nil
- -- removed optimization for s-l == 1, we have to deal with marks anyway
- local n = l + 1
- while n <= s do
- if current then
- local char, id = ischar(current,currentfont)
- if char then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- skipped = true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- current = getnext(current) -- was absent
- elseif seq[n][char] then
- if n < s then -- new test
- current = getnext(current) -- was absent
- end
- n = n + 1
- else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
- else
- match = false
- end
- break
- end
+ end
+
+ -- after
+
+ if s > l then
+ local current = last and getnext(last)
+ if not current and postreplace then
+ current = getnext(sweepnode)
+ end
+ if current then
+ local discfound -- = nil
+ local n = l + 1
+ while n <= s do
+ if current then
+ local char, id = ischar(current,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped = true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ current = getnext(current) -- was absent
+ elseif seq[n][char] then
+ if n < s then -- new test
+ current = getnext(current) -- was absent
+ end
+ n = n + 1
+ elseif discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
- else
- match = false
- end
break
end
- elseif char == false then
- if discfound then
- notmatchreplace[discfound] = true
- match = not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char == false then
+ if discfound then
+ notmatchreplace[discfound] = true
+ if notmatchpre[discfound] then
+ goto next
else
- match = false
+ break
end
- break
- elseif id == disc_code then
- diskseen = true
- discfound = current
- notmatchpre[current] = nil
- notmatchpost[current] = true
- notmatchreplace[current] = nil
- local pre, post, replace = getdisc(current)
- if pre then
- local n = n
- while pre do
- if seq[n][getchar(pre)] then
- n = n + 1
- pre = getnext(pre)
- if n > s then
- break
- end
- else
- notmatchpre[current] = true
+ else
+ goto next
+ end
+ elseif id == disc_code then
+ -- elseif id == disc_code and (not discs or discs[current]) then
+ discseen = true
+ discfound = current
+ notmatchpre[current] = nil
+ notmatchpost[current] = true
+ notmatchreplace[current] = nil
+ local pre, post, replace = getdisc(current)
+ if pre then
+ local n = n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n = n + 1
+ if n > s then
break
+ else
+ pre = getnext(pre)
end
- end
- if n <= s then
+ else
notmatchpre[current] = true
+ break
end
- else
+ end
+ if n <= s then
notmatchpre[current] = true
end
- if replace then
- -- so far we never entered this branch
- while replace do
- if seq[n][getchar(replace)] then
- n = n + 1
+ else
+ notmatchpre[current] = true
+ end
+ if replace then
+ -- so far we never entered this branch
+ while replace do
+ if seq[n][getchar(replace)] then
+ n = n + 1
+ if n > s then
+ break
+ else
replace = getnext(replace)
- if n > s then
- break
- end
+ end
+ else
+ notmatchreplace[current] = true
+ if notmatchpre[current] then
+ goto next
else
- notmatchreplace[current] = true
- match = notmatchpre[current]
break
end
end
- if not match then
- break
- end
- else
- -- skip 'm
end
- -- maybe only if match
- current = getnext(current)
- elseif seq[n][32] and isspace(current,threshold) then
+ else
+ notmatchreplace[current] = true -- new, for Kai to check
+ end
+ current = getnext(current)
+ elseif id == glue_code then
+ local sn = seq[n]
+ if (sn[32] and spaces[current]) or sn[0xFFFC] then
n = n + 1
current = getnext(current)
else
- match = false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n = n + 1
+ current = getnext(current)
else
- match = false
- break
- end
- end
- else
- match = false
- end
- end
- end
- if match then
- -- Can lookups be of a different type?
- local diskchain = diskseen or sweepnode
- if trace_contexts then
- local rule = ck[1]
- local lookuptype = ck[8] or ck[2]
- local first = ck[4]
- local last = ck[5]
- local char = getchar(start)
- logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
- cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype)
- end
- local chainlookups = ck[6]
- if chainlookups then
- local nofchainlookups = #chainlookups
- -- Lookups can be like { 1, false, 3 } or { false, 2 } or basically anything and
- -- #lookups can be less than #current
- if size == 1 then
- -- if nofchainlookups > size then
- -- -- bad rules
- -- end
- local chainlookup = chainlookups[1]
- local chainkind = chainlookup.type
- local chainproc = chainprocs[chainkind]
- if chainproc then
- local ok
- if diskchain then
- head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc)
- else
- head, start, ok = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
- end
- if ok then
- done = true
+ goto next
end
else
- logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
- end
- else
- -- See LookupType 5: Contextual Substitution Subtable. Now it becomes messy. The
- -- easiest case is where #current maps on #lookups i.e. one-to-one. But what if
- -- we have a ligature. Cf the spec we then need to advance one character but we
- -- really need to test it as there are fonts out there that are fuzzy and have
- -- too many lookups:
- --
- -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes
- --
- local i = 1
- while start do
- if skipped then
- while start do -- todo: use properties
- local char = getchar(start)
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class or "base"
- if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then
- start = getnext(start)
- else
- break
- end
- else
- break
- end
- end
- end
- local chainlookup = chainlookups[i]
- if chainlookup then
- local chainkind = chainlookup.type
- local chainproc = chainprocs[chainkind]
- if chainproc then
- local ok, n
- if diskchain then
- head, start, ok = chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc)
- else
- head, start, ok, n = chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
- end
- -- messy since last can be changed !
- if ok then
- done = true
- if n and n > 1 and i + n > nofchainlookups then
- -- this is a safeguard, we just ignore the rest of the lookups
- break
- end
- end
- else
- -- actually an error
- logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
- end
- end
- i = i + 1
- if i > size or not start then
- break
- elseif start then
- start = getnext(start)
- end
+ goto next
end
end
else
- -- todo: needs checking for holes in the replacements
- local replacements = ck[7]
- if replacements then
- head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode)
- else
- done = true
- if trace_contexts then
- logprocess("%s: skipping match",cref(dataset,sequence))
- end
- end
- end
- if done then
- break -- out of contexts (new, needs checking)
+ goto next
end
end
+
+ if trace_contexts then
+ chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true,discseen,sweepnode)
+ end
+ if discseen or sweepnode then
+ head, start, done = chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck)
+ else
+ head, start, done = chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck)
+ end
+ if done then
+ break
+ -- else
+ -- next context
+ end
+ ::next::
+ -- if trace_chains then
+ -- chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,false,discseen,sweepnode)
+ -- end
end
- if diskseen then
+ if discseen then
notmatchpre = { }
notmatchpost = { }
notmatchreplace = { }
+ -- notmatchpre = { a = 1, b = 1 } notmatchpre .a = nil notmatchpre .b = nil
+ -- notmatchpost = { a = 1, b = 1 } notmatchpost .a = nil notmatchpost .b = nil
+ -- notmatchreplace = { a = 1, b = 1 } notmatchreplace.a = nil notmatchreplace.b = nil
end
return head, start, done
end
@@ -2643,13 +2828,19 @@ handlers.gpos_context = handle_contextchain
-- this needs testing
-local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode)
+local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
local steps = currentlookup.steps
local nofsteps = currentlookup.nofsteps
if nofsteps > 1 then
reportmoresteps(dataset,sequence)
end
- return handle_contextchain(head,start,dataset,sequence,currentlookup,rlmode)
+ -- probably wrong
+ local l = steps[1].coverage[getchar(start)]
+ if l then
+ return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash)
+ else
+ return head, start, false
+ end
end
chainprocs.gsub_context = chained_contextchain
@@ -2658,28 +2849,40 @@ chainprocs.gsub_reversecontextchain = chained_contextchain
chainprocs.gpos_contextchain = chained_contextchain
chainprocs.gpos_context = chained_contextchain
-local missing = setmetatableindex("table")
+------------------------------
+
+-- experiment (needs no handler in font-otc so not now):
+--
+-- function otf.registerchainproc(name,f)
+-- -- chainprocs[name] = f
+-- chainprocs[name] = function(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
+-- local done = currentlookup.nofsteps > 0
+-- if not done then
+-- reportzerosteps(dataset,sequence)
+-- else
+-- head, start, done = f(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
+-- if not head or not start then
+-- reportbadsteps(dataset,sequence)
+-- end
+-- end
+-- return head, start, done
+-- end
+-- end
+
+local missing = setmetatableindex("table")
+local logwarning = report_process
+local resolved = { } -- we only resolve a font,script,language pair once
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps == "silent" then
+ return
+ end
end
report_process(...)
end
-local logwarning = report_process
-
-local function report_missing_coverage(dataset,sequence)
- local t = missing[currentfont]
- if not t[sequence] then
- t[sequence] = true
- logwarning("missing coverage for feature %a, lookup %a, type %a, font %a, name %a",
- dataset[4],sequence.name,sequence.type,currentfont,tfmdata.properties.fullname)
- end
-end
-
-local resolved = { } -- we only resolve a font,script,language pair once
-
-- todo: pass all these 'locals' in a table
local sequencelists = setmetatableindex(function(t,font)
@@ -2693,81 +2896,96 @@ end)
-- fonts.hashes.sequences = sequencelists
-local autofeatures = fonts.analyzers.features
-local featuretypes = otf.tables.featuretypes
-local defaultscript = otf.features.checkeddefaultscript
-local defaultlanguage = otf.features.checkeddefaultlanguage
-
-local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
- local features = sequence.features
- if features then
- local order = sequence.order
- if order then
- local featuretype = featuretypes[sequence.type or "unknown"]
- for i=1,#order do
- local kind = order[i]
- local valid = enabled[kind]
- if valid then
- local scripts = features[kind]
- local languages = scripts and (
- scripts[script] or
- scripts[wildcard] or
- (autoscript and defaultscript(featuretype,autoscript,scripts))
- )
- local enabled = languages and (
- languages[language] or
- languages[wildcard] or
- (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
- )
- if enabled then
- return { valid, autofeatures[kind] or false, sequence, kind }
+do -- overcome local limit
+
+ local autofeatures = fonts.analyzers.features
+ local featuretypes = otf.tables.featuretypes
+ local defaultscript = otf.features.checkeddefaultscript
+ local defaultlanguage = otf.features.checkeddefaultlanguage
+
+ local wildcard = "*"
+ local default = "dflt"
+
+ local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
+ local features = sequence.features
+ if features then
+ local order = sequence.order
+ if order then
+ local featuretype = featuretypes[sequence.type or "unknown"]
+ for i=1,#order do
+ local kind = order[i]
+ local valid = enabled[kind]
+ if valid then
+ local scripts = features[kind]
+ local languages = scripts and (
+ scripts[script] or
+ scripts[wildcard] or
+ (autoscript and defaultscript(featuretype,autoscript,scripts))
+ )
+ local enabled = languages and (
+ languages[language] or
+ languages[wildcard] or
+ (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
+ )
+ if enabled then
+ return { valid, autofeatures[kind] or false, sequence, kind }
+ end
end
end
+ else
+ -- can't happen
end
- else
- -- can't happen
end
+ return false
end
- return false
-end
-function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
- local shared = tfmdata.shared
- local properties = tfmdata.properties
- local language = properties.language or "dflt"
- local script = properties.script or "dflt"
- local enabled = shared.features
- local autoscript = enabled and enabled.autoscript
- local autolanguage = enabled and enabled.autolanguage
- local res = resolved[font]
- if not res then
- res = { }
- resolved[font] = res
- end
- local rs = res[script]
- if not rs then
- rs = { }
- res[script] = rs
- end
- local rl = rs[language]
- if not rl then
- rl = {
- -- indexed but we can also add specific data by key
- }
- rs[language] = rl
- local sequences = tfmdata.resources.sequences
- if sequences then
- for s=1,#sequences do
- local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
- if v then
- rl[#rl+1] = v
+ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context
+ local shared = tfmdata.shared
+ local properties = tfmdata.properties
+ local language = properties.language or "dflt"
+ local script = properties.script or "dflt"
+ local enabled = shared.features
+ local autoscript = enabled and enabled.autoscript
+ local autolanguage = enabled and enabled.autolanguage
+ local res = resolved[font]
+ if not res then
+ res = { }
+ resolved[font] = res
+ end
+ local rs = res[script]
+ if not rs then
+ rs = { }
+ res[script] = rs
+ end
+ local rl = rs[language]
+ if not rl then
+ rl = {
+ -- indexed but we can also add specific data by key
+ }
+ rs[language] = rl
+ local sequences = tfmdata.resources.sequences
+ if sequences then
+ for s=1,#sequences do
+ local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
+ if v then
+ rl[#rl+1] = v
+ end
end
end
end
+ return rl
end
- return rl
+
end
+-- Functions like kernrun, comprun etc evolved over time and in the end look rather
+-- complex. It's a bit of a compromis between extensive copying and creating subruns.
+-- The logic has been improved a lot by Kai and Ivo who use complex fonts which
+-- really helped to identify border cases on the one hand and get insight in the diverse
+-- ways fonts implement features (not always that consistent and efficient). At the same
+-- time I tried to keep the code relatively efficient so that the overhead in runtime
+-- stays acceptable.
+
local function report_disc(what,n)
report_run("%s: %s > %s",what,n,languages.serializediscretionary(n))
end
@@ -2815,14 +3033,12 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
if prev then
- local nest = getprev(pre)
setlink(prev,pre)
if k_run(prevmarks,"preinjections",pre,font,attr,...) then -- or prev?
done = true
end
- setprev(pre,nest)
--- setprev(pre)
- setnext(prev,disc)
+ setprev(pre)
+ setlink(prev,disc)
end
end
--
@@ -2836,7 +3052,7 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
setnext(posttail)
- setprev(next,disc)
+ setlink(disc,next)
end
end
--
@@ -2845,14 +3061,12 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
if prev then
- local nest = getprev(replace)
setlink(prev,replace)
if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then -- getnext(replace))
done = true
end
- setprev(replace,nest)
--- setprev(replace)
- setnext(prev,disc)
+ setprev(replace)
+ setlink(prev,disc)
end
if next then
setlink(replacetail,next)
@@ -2860,20 +3074,25 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
setnext(replacetail)
- setprev(next,disc)
+ setlink(disc,next)
end
elseif prev and next then
setlink(prev,next)
if k_run(prevmarks,"emptyinjections",next,font,attr,...) then
done = true
end
- setlink(prev,disc)
- setlink(disc,next)
+ setlink(prev,disc,next)
+ end
+ if done and trace_testruns then
+ report_disc("done",disc)
end
return nextstart, done
end
-local function comprun(disc,c_run,...)
+-- fonts like ebgaramond do ligatures this way (less efficient than e.g. dejavu which
+-- will do the testrun variant)
+
+local function comprun(disc,c_run,...) -- vararg faster than the whole list
if trace_compruns then
report_disc("comp",disc)
end
@@ -2883,7 +3102,7 @@ local function comprun(disc,c_run,...)
--
if pre then
sweepnode = disc
- sweeptype = "pre" -- in alternative code preinjections is uc_c_sed (also used then for proeprties, saves a variable)
+ sweeptype = "pre" -- in alternative code preinjections is used (also used then for properties, saves a variable)
local new, done = c_run(pre,...)
if done then
pre = new
@@ -2914,12 +3133,18 @@ local function comprun(disc,c_run,...)
sweepnode = nil
sweeptype = nil
if renewed then
+ if trace_testruns then
+ report_disc("done",disc)
+ end
setdisc(disc,pre,post,replace)
end
--
return getnext(disc), renewed
end
+-- if we can hyphenate in a lig then unlikely a lig so we
+-- could have a option here to ignore lig
+
local function testrun(disc,t_run,c_run,...)
if trace_testruns then
report_disc("test",disc)
@@ -2930,32 +3155,72 @@ local function testrun(disc,t_run,c_run,...)
return
end
local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
- local done = false
- if replace and prev then
- -- this is a bit strange as we only do replace here and not post
- -- anyway, we only look ahead ... the idea is that we discard a
- -- disc when there is a ligature crossing the replace boundary
- setlink(replacetail,next)
- local ok, overflow = t_run(replace,next,...)
- if ok and overflow then
- -- so, we can have crossed the boundary
- setfield(disc,"replace")
- setlink(prev,replace)
- -- setlink(replacetail,next)
- setboth(disc)
- flush_node_list(disc)
- return replace, true -- restart .. tricky !
+ local renewed = false
+ if (post or replace) and prev then
+ if post then
+ setlink(posttail,next)
+ else
+ post = next
+ end
+ if replace then
+ setlink(replacetail,next)
+ else
+ replace = next
+ end
+ local d_post = t_run(post,next,...)
+ local d_replace = t_run(replace,next,...)
+ if d_post > 0 or d_replace > 0 then
+ local d = d_replace > d_post and d_replace or d_post
+ local head = getnext(disc) -- is: next
+ local tail = head
+ for i=1,d do
+ local nx = getnext(tail)
+ local id = getid(nx)
+ if id == disc_code then
+ head, tail = flattendisk(head,nx)
+ elseif id == glyph_code then
+ tail = nx
+ else
+ -- we can have overrun into a glue
+ break
+ end
+ end
+ next = getnext(tail)
+ setnext(tail)
+ setprev(head)
+ local new = copy_node_list(head)
+ if posttail then
+ setlink(posttail,head)
+ else
+ post = head
+ end
+ if replacetail then
+ setlink(replacetail,new)
+ else
+ replace = new
+ end
else
-- we stay inside the disc
- setnext(replacetail)
- setprev(next,disc)
+ if posttail then
+ setnext(posttail)
+ else
+ post = nil
+ end
+ if replacetail then
+ setnext(replacetail)
+ else
+ replace = nil
+ end
end
+ setlink(disc,next)
-- pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
end
--
-- like comprun
--
- local renewed = false
+ if trace_testruns then
+ report_disc("more",disc)
+ end
--
if pre then
sweepnode = disc
@@ -2991,47 +3256,14 @@ local function testrun(disc,t_run,c_run,...)
sweeptype = nil
if renewed then
setdisc(disc,pre,post,replace)
- return next, true
- else
- return next, done
+ if trace_testruns then
+ report_disc("done",disc)
+ end
end
+ -- next can have changed (copied list)
+ return getnext(disc), renewed
end
--- A discrun happens when we have a zwnj. We're gpossing so it is unlikely that
--- there has been a match changing the character. Now, as we check again here
--- the question is: why do we do this ... needs checking as drun seems useless
--- ... maybe that code can go away
-
--- local function discrun(disc,drun,krun)
--- local prev, next = getboth(disc)
--- if trace_discruns then
--- report_disc("disc",disc)
--- end
--- if next and prev then
--- setnext(prev,next)
--- -- setprev(next,prev)
--- drun(prev)
--- setnext(prev,disc)
--- -- setprev(next,disc)
--- end
--- --
--- if krun then -- currently always false
--- local pre = getfield(disc,"pre")
--- if not pre then
--- -- go on
--- elseif prev then
--- local nest = getprev(pre)
--- setlink(prev,pre)
--- krun(prev,"preinjections")
--- setprev(pre,nest)
--- setnext(prev,disc)
--- else
--- krun(pre,"preinjections")
--- end
--- end
--- return next
--- end
-
-- We can make some assumptions with respect to discretionaries. First of all it is very
-- unlikely that some of the analysis related attributes applies. Then we can also assume
-- that the ConTeXt specific dynamic attribute is different, although we do use explicit
@@ -3059,24 +3291,28 @@ end
local nesting = 0
-local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
local done = false
local sweep = sweephead[head]
if sweep then
start = sweep
- sweephead[head] = nil
+ -- sweephead[head] = nil
+ sweephead[head] = false
else
start = head
end
while start do
- local char = ischar(start,font)
+ local char, id = ischar(start,font)
if char then
- local a = attr and getattr(start,0)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(start,0)
+ end
if not a or (a == attr) then
local lookupmatch = lookupcache[char]
if lookupmatch then
local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
if ok then
done = true
end
@@ -3101,67 +3337,103 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm
return head, done
end
+-- only replace?
+
local function t_run_single(start,stop,font,attr,lookupcache)
+ local lastd = nil
while start ~= stop do
local char = ischar(start,font)
if char then
- local a = attr and getattr(start,0)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(start,0)
+ end
+ local startnext = getnext(start)
if not a or (a == attr) then
local lookupmatch = lookupcache[char]
if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check
-- if we need more than ligatures we can outline the code and use functions
- local s = getnext(start)
+ local s = startnext
+ local ss = nil
+ local sstop = s == stop
+ if not s then
+ s = ss
+ ss = nil
+ end
+ -- a bit weird: why multiple ... anyway we can't have a disc in a disc
+ -- how about post ... we can probably merge this into the while
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
+ if not s then
+ s = ss
+ ss = nil
+ end
+ end
local l = nil
local d = 0
while s do
- if s == stop then
- d = 1
- elseif d > 0 then
- d = d + 1
- end
- local lg = lookupmatch[getchar(s)]
- if lg then
- l = lg
- s = getnext(s)
+ local char = ischar(s,font)
+ if char then
+ local lg = lookupmatch[char]
+ if lg then
+ if sstop then
+ d = 1
+ elseif d > 0 then
+ d = d + 1
+ end
+ l = lg
+ s = getnext(s)
+ sstop = s == stop
+ if not s then
+ s = ss
+ ss = nil
+ end
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
+ if not s then
+ s = ss
+ ss = nil
+ end
+ end
+ else
+ break
+ end
else
break
end
end
- if l and l.ligature then
- return true, d > 1
+ if l and l.ligature then -- so we test for ligature
+ lastd = d
end
+-- why not: if not l then break elseif l.ligature then return d end
+ else
+-- why not: break
+ -- no match (yet)
end
else
-- go on can be a mixed one
+-- why not: break
end
- start = getnext(start)
+ if lastd then
+ return lastd
+ end
+ start = startnext
else
break
end
end
+ return 0
end
--- local function d_run_single(prev,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
--- local a = attr and getattr(prev,0)
--- if not a or (a == attr) then
--- local char = ischar(prev) -- can be disc
--- if char then
--- local lookupmatch = lookupcache[char]
--- if lookupmatch then
--- local h, d, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
--- if ok then
--- done = true
--- success = true
--- end
--- end
--- end
--- end
--- end
-
-local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- local a = attr and getattr(sub,0)
+local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(sub,0)
+ end
if not a or (a == attr) then
- for n in traverse_nodes(sub) do -- only gpos
+ for n in nextnode, sub do -- only gpos
if n == last then
break
end
@@ -3169,7 +3441,7 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
if char then
local lookupmatch = lookupcache[char]
if lookupmatch then
- local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection)
+ local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
if ok then
return true
end
@@ -3179,39 +3451,39 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
end
end
-local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
+local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
local done = false
local sweep = sweephead[head]
if sweep then
start = sweep
- sweephead[head] = nil
+ -- sweephead[head] = nil
+ sweephead[head] = false
else
start = head
end
while start do
local char = ischar(start,font)
if char then
- local a = attr and getattr(start,0)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(start,0)
+ end
if not a or (a == attr) then
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done = true
- break
- elseif not start then
- -- don't ask why ... shouldn't happen
- break
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ done = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -3236,83 +3508,97 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
end
local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
+ local lastd = nil
while start ~= stop do
local char = ischar(start,font)
if char then
- local a = attr and getattr(start,0)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(start,0)
+ end
+ local startnext = getnext(start)
if not a or (a == attr) then
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- if we need more than ligatures we can outline the code and use functions
- local s = getnext(start)
- local l = nil
- local d = 0
- while s do
- if s == stop then
- d = 1
- elseif d > 0 then
- d = d + 1
- end
- local lg = lookupmatch[getchar(s)]
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- if we need more than ligatures we can outline the code and use functions
+ local s = startnext
+ local ss = nil
+ local sstop = s == stop
+ if not s then
+ s = ss
+ ss = nil
+ end
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
+ if not s then
+ s = ss
+ ss = nil
+ end
+ end
+ local l = nil
+ local d = 0
+ while s do
+ local char = ischar(s)
+ if char then
+ local lg = lookupmatch[char]
if lg then
+ if sstop then
+ d = 1
+ elseif d > 0 then
+ d = d + 1
+ end
l = lg
s = getnext(s)
+ sstop = s == stop
+ if not s then
+ s = ss
+ ss = nil
+ end
+ while getid(s) == disc_code do
+ ss = getnext(s)
+ s = getfield(s,"replace")
+ if not s then
+ s = ss
+ ss = nil
+ end
+ end
else
break
end
- end
- if l and l.ligature then
- return true, d > 1
+ else
+ break
end
end
- else
- report_missing_coverage(dataset,sequence)
+ if l and l.ligature then
+ lastd = d
+ end
end
end
else
-- go on can be a mixed one
end
- start = getnext(start)
+ if lastd then
+ return lastd
+ end
+ start = startnext
else
break
end
end
+ return 0
end
--- local function d_run_multiple(prev,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
--- local a = attr and getattr(prev,0)
--- if not a or (a == attr) then
--- local char = ischar(prev) -- can be disc
--- if char then
--- for i=1,nofsteps do
--- local step = steps[i]
--- local lookupcache = step.coverage
--- if lookupcache then
--- local lookupmatch = lookupcache[char]
--- if lookupmatch then
--- -- we could move all code inline but that makes things even more unreadable
--- local h, d, ok = handler(head,prev,dataset,sequence,lookupmatch,rlmode,step,i)
--- if ok then
--- done = true
--- break
--- end
--- end
--- else
--- report_missing_coverage(dataset,sequence)
--- end
--- end
--- end
--- end
--- end
-
-local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- local a = attr and getattr(sub,0)
+local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(sub,0)
+ end
if not a or (a == attr) then
- for n in traverse_nodes(sub) do -- only gpos
+ for n in nextnode, sub do -- only gpos
if n == last then
break
end
@@ -3321,16 +3607,12 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
for i=1,nofsteps do
local step = steps[i]
local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection)
- if ok then
- return true
- end
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection) -- sub was head
+ if ok then
+ return true
end
- else
- report_missing_coverage(dataset,sequence)
end
end
end
@@ -3341,230 +3623,374 @@ end
-- to be checked, nowadays we probably can assume properly matched directions
-- so maybe we no longer need a stack
+-- local function txtdirstate(start,stack,top,rlparmode)
+-- local dir = getdir(start)
+-- local new = 1
+-- if dir == "+TRT" then
+-- top = top + 1
+-- stack[top] = dir
+-- new = -1
+-- elseif dir == "+TLT" then
+-- top = top + 1
+-- stack[top] = dir
+-- elseif dir == "-TRT" or dir == "-TLT" then
+-- if top == 1 then
+-- top = 0
+-- new = rlparmode
+-- else
+-- top = top - 1
+-- if stack[top] == "+TRT" then
+-- new = -1
+-- end
+-- end
+-- else
+-- new = rlparmode
+-- end
+-- return getnext(start), top, new
+-- end
+--
+-- local function pardirstate(start)
+-- local dir = getdir(start)
+-- local new = 0
+-- if dir == "TLT" then
+-- new = 1
+-- elseif dir == "TRT" then
+-- new = -1
+-- end
+-- return getnext(start), new, new
+-- end
+
local function txtdirstate(start,stack,top,rlparmode)
- local dir = getfield(start,"dir")
- local new = 1
+ local nxt = getnext(start)
+ local dir = getdir(start)
if dir == "+TRT" then
top = top + 1
stack[top] = dir
- new = -1
+ return nxt, top, -1
elseif dir == "+TLT" then
top = top + 1
stack[top] = dir
+ return nxt, top, 1
elseif dir == "-TRT" or dir == "-TLT" then
- top = top - 1
- if stack[top] == "+TRT" then
- new = -1
+ if top == 1 then
+ return nxt, 0, rlparmode
+ else
+ top = top - 1
+ if stack[top] == "+TRT" then
+ return nxt, top, -1
+ else
+ return nxt, top, 1
+ end
end
else
- new = rlparmode
+ return nxt, top, rlparmode
end
- if trace_directions then
- report_process("directions after txtdir %a: parmode %a, txtmode %a, level %a",dir,mref(rlparmode),mref(new),top)
- end
- return getnext(start), top, new
end
local function pardirstate(start)
- local dir = getfield(start,"dir")
- local new = 0
+ local nxt = getnext(start)
+ local dir = getdir(start)
if dir == "TLT" then
- new = 1
+ return nxt, 1, 1
elseif dir == "TRT" then
- new = -1
- end
- if trace_directions then
- report_process("directions after pardir %a: parmode %a",dir,mref(new))
+ return nxt, -1, -1
+ else
+ return nxt, 0, 0
end
- return getnext(start), new, new
end
+-- -- this will become:
+--
+-- local getdirection = nuts.getdirection
+--
+-- local function txtdirstate1(start,stack,top,rlparmode)
+-- local nxt = getnext(start)
+-- local dir, sub = getdirection(start)
+-- if sub then
+-- if top == 1 then
+-- return nxt, 0, rlparmode
+-- elseif dir < 2 then
+-- top = top - 1
+-- if stack[top] == 1 then
+-- return nxt, top, -1
+-- else
+-- return nxt, top, 1
+-- end
+-- else
+-- return nxt, top, rlparmode
+-- end
+-- elseif dir == 1 then
+-- top = top + 1
+-- stack[top] = 1
+-- return nxt, top, -1
+-- elseif dir == 0 then
+-- top = top + 1
+-- stack[top] = 0
+-- return nxt, top, 1
+-- else
+-- return nxt, top, rlparmode
+-- end
+-- end
+--
+-- local function pardirstate1(start)
+-- local nxt = getnext(start)
+-- local dir = getdirection(start)
+-- if dir == 0 then
+-- return nxt, 1, 1
+-- elseif dir == 1 then
+-- return nxt, -1, -1
+-- else
+-- return nxt, 0, 0
+-- end
+-- end
+
otf.helpers = otf.helpers or { }
otf.helpers.txtdirstate = txtdirstate
otf.helpers.pardirstate = pardirstate
-local function featuresprocessor(head,font,attr)
+-- This is the main loop. We run over the node list dealing with a specific font. The
+-- attribute is a context specific thing. We could work on sub start-stop ranges instead
+-- but I wonder if there is that much speed gain (experiments showed that it made not
+-- much sense) and we need to keep track of directions anyway. Also at some point I
+-- want to play with font interactions and then we do need the full sweeps. Apart from
+-- optimizations the principles of processing the features hasn't changed much since
+-- the beginning.
- local sequences = sequencelists[font] -- temp hack
+do
- if not sequencelists then
- return head, false
- end
-
- nesting = nesting + 1
-
- if nesting == 1 then
-
- currentfont = font
- tfmdata = fontdata[font]
- descriptions = tfmdata.descriptions
- characters = tfmdata.characters
- marks = tfmdata.resources.marks
- threshold,
- factor = getthreshold(font)
- checkmarks = tfmdata.properties.checkmarks
-
- elseif currentfont ~= font then
+ -- reference:
+ --
+ -- local a = attr and getattr(start,0)
+ -- if a then
+ -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
+ -- else
+ -- a = not attribute or getprop(start,a_state) == attribute
+ -- end
+ --
+ -- used:
+ --
+ -- local a -- happens often so no assignment is faster
+ -- if attr then
+ -- if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ -- a = true
+ -- end
+ -- elseif not attribute or getprop(start,a_state) == attribute then
+ -- a = true
+ -- end
+
+ -- This is a measurable experimental speedup (only with hyphenated text and multiple
+ -- fonts per processor call), especially for fonts with lots of contextual lookups.
+
+ local fastdisc = true
+ local testdics = false
+
+ directives.register("otf.fastdisc",function(v) fastdisc = v end) -- normally enabled
+
+ -- using a merged combined hash as first test saves some 30% on ebgaramond and
+ -- about 15% on arabtype .. then moving the a test also saves a bit (even when
+ -- often a is not set at all so that one is a bit debatable
+
+ local otfdataset = nil -- todo: make an installer
+
+ local getfastdisc = { __index = function(t,k)
+ local v = usesfont(k,currentfont)
+ t[k] = v
+ return v
+ end }
+
+ local getfastspace = { __index = function(t,k)
+ -- we don't pass the id so that one can overload isspace
+ local v = isspace(k,threshold) or false
+ t[k] = v
+ return v
+ end }
+
+ function otf.featuresprocessor(head,font,attr,direction,n)
+
+ local sequences = sequencelists[font] -- temp hack
+
+ nesting = nesting + 1
+
+ if nesting == 1 then
+ currentfont = font
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions -- only needed in gref so we could pass node there instead
+ characters = tfmdata.characters -- but this branch is not entered that often anyway
+ local resources = tfmdata.resources
+ marks = resources.marks
+ classes = resources.classes
+ threshold,
+ factor = getthreshold(font)
+ checkmarks = tfmdata.properties.checkmarks
+
+ if not otfdataset then
+ otfdataset = otf.dataset
+ end
- report_warning("nested call with a different font, level %s, quitting",nesting)
- nesting = nesting - 1
- return head, false
+ discs = fastdisc and n and n > 1 and setmetatable({},getfastdisc) -- maybe inline
+ spaces = setmetatable({},getfastspace)
- end
+ elseif currentfont ~= font then
- -- some 10% faster when no dynamics but hardly measureable on real runs .. but: it only
- -- works when we have no other dynamics as otherwise the zero run will be applied to the
- -- whole stream for which we then need to pass another variable which we won't
+ report_warning("nested call with a different font, level %s, quitting",nesting)
+ nesting = nesting - 1
+ return head, false
- -- if attr == 0 then
- -- attr = false
- -- end
+ end
- head = tonut(head)
+ -- some 10% faster when no dynamics but hardly measureable on real runs .. but: it only
+ -- works when we have no other dynamics as otherwise the zero run will be applied to the
+ -- whole stream for which we then need to pass another variable which we won't
- if trace_steps then
- checkstep(head)
- end
+ -- if attr == 0 then
+ -- attr = false
+ -- end
- local rlmode = 0
+ if trace_steps then
+ checkstep(head)
+ end
- local done = false
- local datasets = otf.dataset(tfmdata,font,attr)
-
- local forcedisc = alwaysdisc or not attr
-
- local dirstack = { } -- could move outside function but we can have local runs
-
- sweephead = { }
-
- -- We could work on sub start-stop ranges instead but I wonder if there is that
- -- much speed gain (experiments showed that it made not much sense) and we need
- -- to keep track of directions anyway. Also at some point I want to play with
- -- font interactions and then we do need the full sweeps.
-
- -- Keeping track of the headnode is needed for devanagari (I generalized it a bit
- -- so that multiple cases are also covered.)
-
- -- We don't goto the next node when a disc node is created so that we can then treat
- -- the pre, post and replace. It's a bit of a hack but works out ok for most cases.
-
- for s=1,#datasets do
- local dataset = datasets[s]
- ----- featurevalue = dataset[1] -- todo: pass to function instead of using a global
- local attribute = dataset[2]
- local sequence = dataset[3] -- sequences[s] -- also dataset[5]
- local rlparmode = 0
- local topstack = 0
- local success = false
- local typ = sequence.type
- local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset
- local handler = handlers[typ]
- local steps = sequence.steps
- local nofsteps = sequence.nofsteps
- if not steps then
- -- this permits injection, watch the different arguments
- local h, d, ok = handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
- if ok then
- success = true
- if h then
+ local initialrl = direction == "TRT" and -1 or 0
+ -- local initialrl = (direction == 1 or direction == "TRT") and -1 or 0
+
+ -- local done = false
+ local datasets = otfdataset(tfmdata,font,attr)
+ local dirstack = { nil } -- could move outside function but we can have local runs
+ sweephead = { }
+ -- sweephead = { a = 1, b = 1 } sweephead.a = nil sweephead.b = nil
+
+ -- Keeping track of the headnode is needed for devanagari. (I generalized it a bit
+ -- so that multiple cases are also covered.) We could prepend a temp node.
+
+ -- We don't goto the next node when a disc node is created so that we can then treat
+ -- the pre, post and replace. It's a bit of a hack but works out ok for most cases.
+
+ for s=1,#datasets do
+ local dataset = datasets[s]
+ local attribute = dataset[2]
+ local sequence = dataset[3] -- sequences[s] -- also dataset[5]
+ local rlparmode = initialrl
+ local topstack = 0
+ local typ = sequence.type
+ local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset
+ local forcetestrun = typ == "gsub_ligature" -- testrun is only for ligatures
+ local handler = handlers[typ] -- store in dataset
+ local steps = sequence.steps
+ local nofsteps = sequence.nofsteps
+ local skiphash = sequence.skiphash
+
+ if not steps then
+ -- This permits injection, watch the different arguments. Watch out, the arguments passed
+ -- are not frozen as we might extend or change this. Is this used at all apart from some
+ -- experiments?
+ local h, ok = handler(head,dataset,sequence,initialrl,font,attr) -- less arguments now
+ -- if ok then
+ -- done = true
+ -- end
+ if h and h ~= head then
head = h
end
- end
- elseif typ == "gsub_reversecontextchain" then
- -- this is a limited case, no special treatments like 'init' etc
- local start = find_node_tail(head)
- while start do
- local char = ischar(start,font)
- if char then
- local a = attr and getattr(start,0)
- if not a or (a == attr) then
- for i=1,nofsteps do
- local step = steps[i]
- local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- todo: disc?
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success = true
- break
+ elseif typ == "gsub_reversecontextchain" then
+ --
+ -- This might need a check: if we have #before or #after > 0 then we might need to reverse
+ -- the before and after lists in the loader. But first I need to see a font that uses multiple
+ -- matches.
+ --
+ local start = find_node_tail(head)
+ local rlmode = 0 -- how important is this .. do we need to check for dir?
+ local merged = steps.merged
+ while start do
+ local char = ischar(start,font)
+ if char then
+ local m = merged[char]
+ if m then
+ local a -- happens often so no assignment is faster
+ if attr then
+ a = getattr(start,0)
+ end
+ if not a or (a == attr) then
+ for i=m[1],m[2] do
+ local step = steps[i]
+ -- for i=1,#m do
+ -- local step = m[i]
+ local lookupcache = step.coverage
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ -- done = true
+ break
+ end
end
end
+ if start then
+ start = getprev(start)
+ end
else
- report_missing_coverage(dataset,sequence)
+ start = getprev(start)
end
- end
- if start then
+ else
start = getprev(start)
end
else
start = getprev(start)
end
- else
- start = getprev(start)
end
- end
- else
- local start = head -- local ?
- rlmode = 0 -- to be checked ?
- if nofsteps == 1 then -- happens often
- local step = steps[1]
- local lookupcache = step.coverage
- if not lookupcache then
- report_missing_coverage(dataset,sequence)
- else
+ else
+ local start = head
+ local rlmode = initialrl
+ if nofsteps == 1 then -- happens often
+ local step = steps[1]
+ local lookupcache = step.coverage
while start do
local char, id = ischar(start,font)
if char then
- local a = attr and getattr(start,0)
- if a then
- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
+ if skiphash and skiphash[char] then -- we never needed it here but let's try
+ start = getnext(start)
else
- a = not attribute or getprop(start,a_state) == attribute
- end
- if a then
local lookupmatch = lookupcache[char]
if lookupmatch then
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
- if ok then
- success = true
- -- elseif gpossing and zwnjruns and char == zwnj then
- -- discrun(start,d_run,font,attr,lookupcache)
+ local a -- happens often so no assignment is faster
+ if attr then
+ if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ a = true
+ end
+ elseif not attribute or getprop(start,a_state) == attribute then
+ a = true
end
- -- elseif gpossing and zwnjruns and char == zwnj then
- -- discrun(start,d_run,font,attr,lookupcache)
- end
- if start then
- start = getnext(start)
+ if a then
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ -- if ok then
+ -- done = true
+ -- end
+ if start then
+ start = getnext(start)
+ end
+ else
+ start = getnext(start)
+ end
+ else
+ start = getnext(start)
end
- else
- start = getnext(start)
end
- elseif char == false then
- -- whatever glyph
- start = getnext(start)
+ elseif char == false or id == glue_code then
+ -- a different font|state or glue (happens often)
+ start = getnext(start)
elseif id == disc_code then
- -- ctx: we could assume the same attr as the surrounding glyphs but then we loose
- -- the option to have interesting disc nodes (we gain upto 10% on extreme tests);
- -- if a disc would have a font field we could even be more strict (see oldstyle test
- -- case)
- local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr
- if a then
- -- local attr = false
+ if not discs or discs[start] == true then
local ok
if gpossing then
- start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- elseif typ == "gsub_ligature" then
- start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ start, ok = kernrun(start,k_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start, ok = testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
else
- start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- end
- if ok then
- success = true
+ start, ok = comprun(start,c_run_single, font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
end
+ -- if ok then
+ -- done = true
+ -- end
else
start = getnext(start)
end
@@ -3578,97 +4004,199 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
end
- end
-
- else
-
- while start do
- local char, id = ischar(start,font)
- if char then
- local a = attr and getattr(start,0)
- if a then
- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
- else
- a = not attribute or getprop(start,a_state) == attribute
- end
- if a then
- for i=1,nofsteps do
- local step = steps[i]
- local lookupcache = step.coverage
- if lookupcache then
- local lookupmatch = lookupcache[char]
- if lookupmatch then
- -- we could move all code inline but that makes things even more unreadable
- local ok
- head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success = true
- break
- elseif not start then
- -- don't ask why ... shouldn't happen
- break
- -- elseif gpossing and zwnjruns and char == zwnj then
- -- discrun(start,d_run,font,attr,steps,nofsteps)
+ else
+ local merged = steps.merged
+ while start do
+ local char, id = ischar(start,font)
+ if char then
+ if skiphash and skiphash[char] then -- we never needed it here but let's try
+ start = getnext(start)
+ else
+ local m = merged[char]
+ if m then
+ local a -- happens often so no assignment is faster
+ if attr then
+ if getattr(start,0) == attr and (not attribute or getprop(start,a_state) == attribute) then
+ a = true
end
- -- elseif gpossing and zwnjruns and char == zwnj then
- -- discrun(start,d_run,font,attr,steps,nofsteps)
+ elseif not attribute or getprop(start,a_state) == attribute then
+ a = true
+ end
+ if a then
+ for i=m[1],m[2] do
+ local step = steps[i]
+ -- for i=1,#m do
+ -- local step = m[i]
+ local lookupcache = step.coverage
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ -- done = true
+ break
+ elseif not start then
+ -- don't ask why ... shouldn't happen
+ break
+ end
+ end
+ end
+ if start then
+ start = getnext(start)
+ end
+ else
+ start = getnext(start)
end
else
- report_missing_coverage(dataset,sequence)
+ start = getnext(start)
end
end
- if start then
- start = getnext(start)
- end
- else
+ elseif char == false or id == glue_code then
+ -- a different font|state or glue (happens often)
start = getnext(start)
- end
- elseif char == false then
- start = getnext(start)
- elseif id == disc_code then
- -- see comment above
- local a = forcedisc or getsubtype(start) == discretionary_code or getattr(start,0) == attr
- if a then
- local ok
- if gpossing then
- start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- elseif typ == "gsub_ligature" then
- start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
+ elseif id == disc_code then
+ if not discs or discs[start] == true then
+ local ok
+ if gpossing then
+ start, ok = kernrun(start,k_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start, ok = testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ else
+ start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ end
+ -- if ok then
+ -- done = true
+ -- end
else
- start, ok = comprun(start,c_run_multiple, font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- end
- if ok then
- success = true
+ start = getnext(start)
end
+ elseif id == math_code then
+ start = getnext(end_of_math(start))
+ elseif id == dir_code then
+ start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id == localpar_code then
+ start, rlparmode, rlmode = pardirstate(start)
else
start = getnext(start)
end
- elseif id == math_code then
- start = getnext(end_of_math(start))
- elseif id == dir_code then
- start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
- elseif id == localpar_code then
- start, rlparmode, rlmode = pardirstate(start)
- else
- start = getnext(start)
end
end
end
+
+ if trace_steps then -- ?
+ registerstep(head)
+ end
+
end
- if success then
- done = true
+ nesting = nesting - 1
+
+ -- return head, done
+ return head
+ end
+
+ -- This is not an official helper and used for tracing experiments. It can be changed as I like
+ -- at any moment. At some point it might be used in a module that can help font development.
+
+ function otf.datasetpositionprocessor(head,font,direction,dataset)
+
+ currentfont = font
+ tfmdata = fontdata[font]
+ descriptions = tfmdata.descriptions -- only needed in gref so we could pass node there instead
+ characters = tfmdata.characters -- but this branch is not entered that often anyway
+ local resources = tfmdata.resources
+ marks = resources.marks
+ classes = resources.classes
+ threshold,
+ factor = getthreshold(font)
+ checkmarks = tfmdata.properties.checkmarks
+
+ if type(dataset) == "number" then
+ dataset = otfdataset(tfmdata,font,0)[dataset]
end
- if trace_steps then -- ?
- registerstep(head)
+
+ local sequence = dataset[3] -- sequences[s] -- also dataset[5]
+ local typ = sequence.type
+ -- local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- store in dataset
+
+ -- gpos_contextchain gpos_context
+
+ -- if not gpossing then
+ -- return head, false
+ -- end
+
+ local handler = handlers[typ] -- store in dataset
+ local steps = sequence.steps
+ local nofsteps = sequence.nofsteps
+
+ local done = false
+ local dirstack = { nil } -- could move outside function but we can have local runs (maybe a few more nils)
+ local start = head
+ local initialrl = direction == "TRT" and -1 or 0
+ -- local initialrl = (direction == 1 or direction == "TRT") and -1 or 0
+ local rlmode = initialrl
+ local rlparmode = initialrl
+ local topstack = 0
+ local merged = steps.merged
+
+ -- local matches = false
+ local position = 0
+
+ while start do
+ local char, id = ischar(start,font)
+ if char then
+ position = position + 1
+ local m = merged[char]
+ if m then
+ if skiphash and skiphash[char] then -- we never needed it here but let's try
+ start = getnext(start)
+ else
+ for i=m[1],m[2] do
+ local step = steps[i]
+ local lookupcache = step.coverage
+ local lookupmatch = lookupcache[char]
+ if lookupmatch then
+ local ok
+ head, start, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ -- if matches then
+ -- matches[position] = i
+ -- else
+ -- matches = { [position] = i }
+ -- end
+ break
+ elseif not start then
+ break
+ end
+ end
+ end
+ if start then
+ start = getnext(start)
+ end
+ end
+ else
+ start = getnext(start)
+ end
+ elseif char == false or id == glue_code then
+ -- a different font|state or glue (happens often)
+ start = getnext(start)
+ elseif id == math_code then
+ start = getnext(end_of_math(start))
+ elseif id == dir_code then
+ start, topstack, rlmode = txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id == localpar_code then
+ start, rlparmode, rlmode = pardirstate(start)
+ else
+ start = getnext(start)
+ end
end
+ return head
end
- nesting = nesting - 1
- head = tonode(head)
+ -- end of experiment
- return head, done
end
-- so far
@@ -3676,32 +4204,49 @@ end
local plugins = { }
otf.plugins = plugins
+local report = logs.reporter("fonts")
+
function otf.registerplugin(name,f)
if type(name) == "string" and type(f) == "function" then
plugins[name] = { name, f }
+ report()
+ report("plugin %a has been loaded, please be aware of possible side effects",name)
+ report()
+ if logs.pushtarget then
+ logs.pushtarget("log")
+ end
+ report("Plugins are not officially supported unless stated otherwise. This is because")
+ report("they bypass the regular font handling and therefore some features in ConTeXt")
+ report("(especially those related to fonts) might not work as expected or might not work")
+ report("at all. Some plugins are for testing and development only and might change")
+ report("whenever we feel the need for it.")
+ report()
+ if logs.poptarget then
+ logs.poptarget()
+ end
end
end
-local function plugininitializer(tfmdata,value)
+function otf.plugininitializer(tfmdata,value)
if type(value) == "string" then
tfmdata.shared.plugin = plugins[value]
end
end
-local function pluginprocessor(head,font)
+function otf.pluginprocessor(head,font,attr,direction) -- n
local s = fontdata[font].shared
local p = s and s.plugin
if p then
if trace_plugins then
report_process("applying plugin %a",p[1])
end
- return p[2](head,font)
+ return p[2](head,font,attr,direction)
else
return head, false
end
end
-local function featuresinitializer(tfmdata,value)
+function otf.featuresinitializer(tfmdata,value)
-- nothing done here any more
end
@@ -3711,67 +4256,113 @@ registerotffeature {
default = true,
initializers = {
position = 1,
- node = featuresinitializer,
- plug = plugininitializer,
+ node = otf.featuresinitializer,
+ plug = otf.plugininitializer,
},
processors = {
- node = featuresprocessor,
- plug = pluginprocessor,
+ node = otf.featuresprocessor,
+ plug = otf.pluginprocessor,
}
}
-otf.nodemodeinitializer = featuresinitializer
-otf.featuresprocessor = featuresprocessor
-
--- This can be used for extra handlers, but should be used with care!
-
-otf.handlers = handlers -- used in devanagari
+-- This can be used for extra handlers, but should be used with care! We implement one
+-- here but some more can be found in the osd (script devanagary) file. Now watch out:
+-- when a handlers has steps, it is called as the other ones, but when we have no steps,
+-- we use a different call:
+--
+-- function(head,dataset,sequence,initialrl,font,attr)
+-- return head, done
+-- end
+--
+-- Also see (!!).
--- We implement one here:
+otf.handlers = handlers
local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end
+local tag = "kern" -- maybe some day a merge
+
if fontfeatures then
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local features = fontfeatures[font]
- local enabled = features and features.spacekern and features.kern
+ local enabled = features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head, start, enabled
+ return head, enabled
end
else -- generic (no hashes)
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local shared = fontdata[font].shared
local features = shared and shared.features
- local enabled = features and features.spacekern and features.kern
+ local enabled = features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head, start, enabled
+ return head, enabled
end
end
+-- There are fonts out there that change the space but we don't do that kind of
+-- things in TeX.
+
local function hasspacekerns(data)
- local sequences = data.resources.sequences
- for i=1,#sequences do
- local sequence = sequences[i]
- local steps = sequence.steps
- if steps and sequence.features.kern then
- for i=1,#steps do
- local coverage = steps[i].coverage
- if not coverage then
- -- maybe an issue
- elseif coverage[32] then
- return true
- else
- for k, v in next, coverage do
- if v[32] then
- return true
+ local resources = data.resources
+ local sequences = resources.sequences
+ local validgpos = resources.features.gpos
+ if validgpos and sequences then
+ for i=1,#sequences do
+ local sequence = sequences[i]
+ local steps = sequence.steps
+ if steps and sequence.features[tag] then
+ local kind = sequence.type
+ if kind == "gpos_pair" or kind == "gpos_single" then
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ local rules = step.rules
+ if rules then
+ -- not now: analyze (simple) rules
+ elseif not coverage then
+ -- nothing to do
+ elseif kind == "gpos_single" then
+ -- maybe a message that we ignore
+ elseif kind == "gpos_pair" then
+ local format = step.format
+ if format == "move" or format == "kern" then
+ local kerns = coverage[32]
+ if kerns then
+ return true
+ end
+ for k, v in next, coverage do
+ if v[32] then
+ return true
+ end
+ end
+ elseif format == "pair" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ local one = v[1]
+ if one and one ~= true then
+ return true
+ end
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ local one = kern[1]
+ if one and one ~= true then
+ return true
+ end
+ end
+ end
+ end
end
end
end
@@ -3788,112 +4379,120 @@ otf.readers.registerextender {
end
}
--- we merge the lookups but we still honor the language / script
-
local function spaceinitializer(tfmdata,value) -- attr
local resources = tfmdata.resources
local spacekerns = resources and resources.spacekerns
- local properties = tfmdata.properties
if value and spacekerns == nil then
+ local rawdata = tfmdata.shared and tfmdata.shared.rawdata
+ local properties = rawdata.properties
if properties and properties.hasspacekerns then
local sequences = resources.sequences
- local left = { }
- local right = { }
- local last = 0
- local feat = nil
- for i=1,#sequences do
- local sequence = sequences[i]
- local steps = sequence.steps
- if steps then
- local kern = sequence.features.kern
- if kern then
- if feat then
- for script, languages in next, kern do
- local f = feat[script]
- if f then
- for l in next, languages do
- f[l] = true
- end
- else
- feat[script] = languages
- end
- end
- else
- feat = kern
- end
- for i=1,#steps do
- local step = steps[i]
- local coverage = step.coverage
- local rules = step.rules
- local format = step.format
- if rules then
- -- not now: analyze (simple) rules
- elseif coverage then
- -- what to do if we have no [1] but only [2]
- local single = format == gpos_single
- local kerns = coverage[32]
- if kerns then
- for k, v in next, kerns do
- if type(v) ~= "table" then
- right[k] = v
- elseif single then
- right[k] = v[3]
- else
- local one = v[1]
- if one then
- right[k] = one[3]
+ local validgpos = resources.features.gpos
+ if validgpos and sequences then
+ local left = { }
+ local right = { }
+ local last = 0
+ local feat = nil
+ for i=1,#sequences do
+ local sequence = sequences[i]
+ local steps = sequence.steps
+ if steps then
+ -- we don't support space kerns in other features
+ local kern = sequence.features[tag]
+ if kern then
+ local kind = sequence.type
+ if kind == "gpos_pair" or kind == "gpos_single" then
+ if feat then
+ for script, languages in next, kern do
+ local f = feat[script]
+ if f then
+ for l in next, languages do
+ f[l] = true
end
+ else
+ feat[script] = languages
end
end
+ else
+ feat = kern
end
- for k, v in next, coverage do
- local kern = v[32]
- if kern then
- if type(kern) ~= "table" then
- left[k] = kern
- elseif single then
- left[k] = v[3]
- else
- local one = v[1]
- if one then
- left[k] = one[3]
+ for i=1,#steps do
+ local step = steps[i]
+ local coverage = step.coverage
+ local rules = step.rules
+ if rules then
+ -- not now: analyze (simple) rules
+ elseif not coverage then
+ -- nothng to do
+ elseif kind == "gpos_single" then
+ -- makes no sense in TeX
+ elseif kind == "gpos_pair" then
+ local format = step.format
+ if format == "move" or format == "kern" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ right[k] = v
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ left[k] = kern
+ end
+ end
+ elseif format == "pair" then
+ local kerns = coverage[32]
+ if kerns then
+ for k, v in next, kerns do
+ local one = v[1]
+ if one and one ~= true then
+ right[k] = one[3]
+ end
+ end
+ end
+ for k, v in next, coverage do
+ local kern = v[32]
+ if kern then
+ local one = kern[1]
+ if one and one ~= true then
+ left[k] = one[3]
+ end
+ end
end
end
end
end
+ last = i
end
+ else
+ -- no steps ... needed for old one ... we could use the basekerns
+ -- instead
end
- last = i
end
- else
- -- no steps ... needed for old one ... we could use the basekerns
- -- instead
- end
- end
- left = next(left) and left or false
- right = next(right) and right or false
- if left or right then
- spacekerns = {
- left = left,
- right = right,
- }
- if last > 0 then
- local triggersequence = {
- features = { kern = feat or { dflt = { dflt = true, } } },
- flags = noflags,
- name = "trigger_space_kerns",
- order = { "kern" },
- type = "trigger_space_kerns",
- left = left,
- right = right,
+ end
+ left = next(left) and left or false
+ right = next(right) and right or false
+ if left or right then
+ spacekerns = {
+ left = left,
+ right = right,
}
- insert(sequences,last,triggersequence)
+ if last > 0 then
+ local triggersequence = {
+ -- no steps, see (!!)
+ features = { [tag] = feat or { dflt = { dflt = true, } } },
+ flags = noflags,
+ name = "trigger_space_kerns",
+ order = { tag },
+ type = "trigger_space_kerns",
+ left = left,
+ right = right,
+ }
+ insert(sequences,last,triggersequence)
+ end
end
- else
- spacekerns = false
end
- else
- spacekerns = false
end
resources.spacekerns = spacekerns
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ott.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ott.lua
new file mode 100644
index 00000000000..88da136ac70
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ott.lua
@@ -0,0 +1,1159 @@
+if not modules then modules = { } end modules ["font-ott"] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ -- dataonly = true,
+}
+
+local type, next, tonumber, tostring, rawget, rawset = type, next, tonumber, tostring, rawget, rawset
+local gsub, lower, format, match, gmatch, find = string.gsub, string.lower, string.format, string.match, string.gmatch, string.find
+local sequenced = table.sequenced
+local is_boolean = string.is_boolean
+
+local setmetatableindex = table.setmetatableindex
+local setmetatablenewindex = table.setmetatablenewindex
+local allocate = utilities.storage.allocate
+
+local fonts = fonts
+local otf = fonts.handlers.otf
+local otffeatures = otf.features
+
+local tables = otf.tables or { }
+otf.tables = tables
+
+local statistics = otf.statistics or { }
+otf.statistics = statistics
+
+local scripts = allocate {
+ ["arab"] = "arabic",
+ ["armi"] = "imperial aramaic",
+ ["armn"] = "armenian",
+ ["avst"] = "avestan",
+ ["bali"] = "balinese",
+ ["bamu"] = "bamum",
+ ["batk"] = "batak",
+ ["beng"] = "bengali",
+ ["bng2"] = "bengali variant 2",
+ ["bopo"] = "bopomofo",
+ ["brah"] = "brahmi",
+ ["brai"] = "braille",
+ ["bugi"] = "buginese",
+ ["buhd"] = "buhid",
+ ["byzm"] = "byzantine music",
+ ["cakm"] = "chakma",
+ ["cans"] = "canadian syllabics",
+ ["cari"] = "carian",
+ ["cham"] = "cham",
+ ["cher"] = "cherokee",
+ ["copt"] = "coptic",
+ ["cprt"] = "cypriot syllabary",
+ ["cyrl"] = "cyrillic",
+ ["deva"] = "devanagari",
+ ["dev2"] = "devanagari variant 2",
+ ["dsrt"] = "deseret",
+ ["egyp"] = "egyptian heiroglyphs",
+ ["ethi"] = "ethiopic",
+ ["geor"] = "georgian",
+ ["glag"] = "glagolitic",
+ ["goth"] = "gothic",
+ ["grek"] = "greek",
+ ["gujr"] = "gujarati",
+ ["gjr2"] = "gujarati variant 2",
+ ["guru"] = "gurmukhi",
+ ["gur2"] = "gurmukhi variant 2",
+ ["hang"] = "hangul",
+ ["hani"] = "cjk ideographic",
+ ["hano"] = "hanunoo",
+ ["hebr"] = "hebrew",
+ ["ital"] = "old italic",
+ ["jamo"] = "hangul jamo",
+ ["java"] = "javanese",
+ ["kali"] = "kayah li",
+ ["kana"] = "hiragana and katakana",
+ ["khar"] = "kharosthi",
+ ["khmr"] = "khmer",
+ ["knda"] = "kannada",
+ ["knd2"] = "kannada variant 2",
+ ["kthi"] = "kaithi",
+ ["lana"] = "tai tham",
+ ["lao" ] = "lao",
+ ["latn"] = "latin",
+ ["lepc"] = "lepcha",
+ ["limb"] = "limbu",
+ ["linb"] = "linear b",
+ ["lisu"] = "lisu",
+ ["lyci"] = "lycian",
+ ["lydi"] = "lydian",
+ ["mand"] = "mandaic and mandaean",
+ ["math"] = "mathematical alphanumeric symbols",
+ ["merc"] = "meroitic cursive",
+ ["mero"] = "meroitic hieroglyphs",
+ ["mlym"] = "malayalam",
+ ["mlm2"] = "malayalam variant 2",
+ ["mong"] = "mongolian",
+ ["mtei"] = "meitei Mayek",
+ ["musc"] = "musical symbols",
+ ["mym2"] = "myanmar variant 2",
+ ["mymr"] = "myanmar",
+ ["nko" ] = 'n"ko',
+ ["ogam"] = "ogham",
+ ["olck"] = "ol chiki",
+ ["orkh"] = "old turkic and orkhon runic",
+ ["orya"] = "oriya",
+ ["ory2"] = "odia variant 2",
+ ["osma"] = "osmanya",
+ ["phag"] = "phags-pa",
+ ["phli"] = "inscriptional pahlavi",
+ ["phnx"] = "phoenician",
+ ["prti"] = "inscriptional parthian",
+ ["rjng"] = "rejang",
+ ["runr"] = "runic",
+ ["samr"] = "samaritan",
+ ["sarb"] = "old south arabian",
+ ["saur"] = "saurashtra",
+ ["shaw"] = "shavian",
+ ["shrd"] = "sharada",
+ ["sinh"] = "sinhala",
+ ["sora"] = "sora sompeng",
+ ["sund"] = "sundanese",
+ ["sylo"] = "syloti nagri",
+ ["syrc"] = "syriac",
+ ["tagb"] = "tagbanwa",
+ ["takr"] = "takri",
+ ["tale"] = "tai le",
+ ["talu"] = "tai lu",
+ ["taml"] = "tamil",
+ ["tavt"] = "tai viet",
+ ["telu"] = "telugu",
+ ["tel2"] = "telugu variant 2",
+ ["tfng"] = "tifinagh",
+ ["tglg"] = "tagalog",
+ ["thaa"] = "thaana",
+ ["thai"] = "thai",
+ ["tibt"] = "tibetan",
+ ["tml2"] = "tamil variant 2",
+ ["ugar"] = "ugaritic cuneiform",
+ ["vai" ] = "vai",
+ ["xpeo"] = "old persian cuneiform",
+ ["xsux"] = "sumero-akkadian cuneiform",
+ ["yi" ] = "yi",
+}
+
+local languages = allocate {
+ ["aba" ] = "abaza",
+ ["abk" ] = "abkhazian",
+ ["ach" ] = "acholi",
+ ["acr" ] = "achi",
+ ["ady" ] = "adyghe",
+ ["afk" ] = "afrikaans",
+ ["afr" ] = "afar",
+ ["agw" ] = "agaw",
+ ["aio" ] = "aiton",
+ ["aka" ] = "akan",
+ ["als" ] = "alsatian",
+ ["alt" ] = "altai",
+ ["amh" ] = "amharic",
+ ["ang" ] = "anglo-saxon",
+ ["apph"] = "phonetic transcription—americanist conventions",
+ ["ara" ] = "arabic",
+ ["arg" ] = "aragonese",
+ ["ari" ] = "aari",
+ ["ark" ] = "rakhine",
+ ["asm" ] = "assamese",
+ ["ast" ] = "asturian",
+ ["ath" ] = "athapaskan",
+ ["avr" ] = "avar",
+ ["awa" ] = "awadhi",
+ ["aym" ] = "aymara",
+ ["azb" ] = "torki",
+ ["aze" ] = "azerbaijani",
+ ["bad" ] = "badaga",
+ ["bad0"] = "banda",
+ ["bag" ] = "baghelkhandi",
+ ["bal" ] = "balkar",
+ ["ban" ] = "balinese",
+ ["bar" ] = "bavarian",
+ ["bau" ] = "baulé",
+ ["bbc" ] = "batak toba",
+ ["bbr" ] = "berber",
+ ["bch" ] = "bench",
+ ["bcr" ] = "bible cree",
+ ["bdy" ] = "bandjalang",
+ ["bel" ] = "belarussian",
+ ["bem" ] = "bemba",
+ ["ben" ] = "bengali",
+ ["bgc" ] = "haryanvi",
+ ["bgq" ] = "bagri",
+ ["bgr" ] = "bulgarian",
+ ["bhi" ] = "bhili",
+ ["bho" ] = "bhojpuri",
+ ["bik" ] = "bikol",
+ ["bil" ] = "bilen",
+ ["bis" ] = "bislama",
+ ["bjj" ] = "kanauji",
+ ["bkf" ] = "blackfoot",
+ ["bli" ] = "baluchi",
+ ["blk" ] = "pa'o karen",
+ ["bln" ] = "balante",
+ ["blt" ] = "balti",
+ ["bmb" ] = "bambara (bamanankan)",
+ ["bml" ] = "bamileke",
+ ["bos" ] = "bosnian",
+ ["bpy" ] = "bishnupriya manipuri",
+ ["bre" ] = "breton",
+ ["brh" ] = "brahui",
+ ["bri" ] = "braj bhasha",
+ ["brm" ] = "burmese",
+ ["brx" ] = "bodo",
+ ["bsh" ] = "bashkir",
+ ["bti" ] = "beti",
+ ["bts" ] = "batak simalungun",
+ ["bug" ] = "bugis",
+ ["cak" ] = "kaqchikel",
+ ["cat" ] = "catalan",
+ ["cbk" ] = "zamboanga chavacano",
+ ["ceb" ] = "cebuano",
+ ["cgg" ] = "chiga",
+ ["cha" ] = "chamorro",
+ ["che" ] = "chechen",
+ ["chg" ] = "chaha gurage",
+ ["chh" ] = "chattisgarhi",
+ ["chi" ] = "chichewa (chewa, nyanja)",
+ ["chk" ] = "chukchi",
+ ["chk0"] = "chuukese",
+ ["cho" ] = "choctaw",
+ ["chp" ] = "chipewyan",
+ ["chr" ] = "cherokee",
+ ["chu" ] = "chuvash",
+ ["chy" ] = "cheyenne",
+ ["cmr" ] = "comorian",
+ ["cop" ] = "coptic",
+ ["cor" ] = "cornish",
+ ["cos" ] = "corsican",
+ ["cpp" ] = "creoles",
+ ["cre" ] = "cree",
+ ["crr" ] = "carrier",
+ ["crt" ] = "crimean tatar",
+ ["csb" ] = "kashubian",
+ ["csl" ] = "church slavonic",
+ ["csy" ] = "czech",
+ ["ctg" ] = "chittagonian",
+ ["cuk" ] = "san blas kuna",
+ ["dan" ] = "danish",
+ ["dar" ] = "dargwa",
+ ["dax" ] = "dayi",
+ ["dcr" ] = "woods cree",
+ ["deu" ] = "german",
+ ["dgo" ] = "dogri",
+ ["dgr" ] = "dogri",
+ ["dhg" ] = "dhangu",
+ ["dhv" ] = "divehi (dhivehi, maldivian)",
+ ["diq" ] = "dimli",
+ ["div" ] = "divehi (dhivehi, maldivian)",
+ ["djr" ] = "zarma",
+ ["djr0"] = "djambarrpuyngu",
+ ["dng" ] = "dangme",
+ ["dnj" ] = "dan",
+ ["dnk" ] = "dinka",
+ ["dri" ] = "dari",
+ ["duj" ] = "dhuwal",
+ ["dun" ] = "dungan",
+ ["dzn" ] = "dzongkha",
+ ["ebi" ] = "ebira",
+ ["ecr" ] = "eastern cree",
+ ["edo" ] = "edo",
+ ["efi" ] = "efik",
+ ["ell" ] = "greek",
+ ["emk" ] = "eastern maninkakan",
+ ["eng" ] = "english",
+ ["erz" ] = "erzya",
+ ["esp" ] = "spanish",
+ ["esu" ] = "central yupik",
+ ["eti" ] = "estonian",
+ ["euq" ] = "basque",
+ ["evk" ] = "evenki",
+ ["evn" ] = "even",
+ ["ewe" ] = "ewe",
+ ["fan" ] = "french antillean",
+ ["fan0"] = " fang",
+ ["far" ] = "persian",
+ ["fat" ] = "fanti",
+ ["fin" ] = "finnish",
+ ["fji" ] = "fijian",
+ ["fle" ] = "dutch (flemish)",
+ ["fne" ] = "forest nenets",
+ ["fon" ] = "fon",
+ ["fos" ] = "faroese",
+ ["fra" ] = "french",
+ ["frc" ] = "cajun french",
+ ["fri" ] = "frisian",
+ ["frl" ] = "friulian",
+ ["frp" ] = "arpitan",
+ ["fta" ] = "futa",
+ ["ful" ] = "fulah",
+ ["fuv" ] = "nigerian fulfulde",
+ ["gad" ] = "ga",
+ ["gae" ] = "scottish gaelic (gaelic)",
+ ["gag" ] = "gagauz",
+ ["gal" ] = "galician",
+ ["gar" ] = "garshuni",
+ ["gaw" ] = "garhwali",
+ ["gez" ] = "ge'ez",
+ ["gih" ] = "githabul",
+ ["gil" ] = "gilyak",
+ ["gil0"] = "kiribati (gilbertese)",
+ ["gkp" ] = "kpelle (guinea)",
+ ["glk" ] = "gilaki",
+ ["gmz" ] = "gumuz",
+ ["gnn" ] = "gumatj",
+ ["gog" ] = "gogo",
+ ["gon" ] = "gondi",
+ ["grn" ] = "greenlandic",
+ ["gro" ] = "garo",
+ ["gua" ] = "guarani",
+ ["guc" ] = "wayuu",
+ ["guf" ] = "gupapuyngu",
+ ["guj" ] = "gujarati",
+ ["guz" ] = "gusii",
+ ["hai" ] = "haitian (haitian creole)",
+ ["hal" ] = "halam",
+ ["har" ] = "harauti",
+ ["hau" ] = "hausa",
+ ["haw" ] = "hawaiian",
+ ["hay" ] = "haya",
+ ["haz" ] = "hazaragi",
+ ["hbn" ] = "hammer-banna",
+ ["her" ] = "herero",
+ ["hil" ] = "hiligaynon",
+ ["hin" ] = "hindi",
+ ["hma" ] = "high mari",
+ ["hmn" ] = "hmong",
+ ["hmo" ] = "hiri motu",
+ ["hnd" ] = "hindko",
+ ["ho" ] = "ho",
+ ["hri" ] = "harari",
+ ["hrv" ] = "croatian",
+ ["hun" ] = "hungarian",
+ ["hye" ] = "armenian",
+ ["hye0"] = "armenian east",
+ ["iba" ] = "iban",
+ ["ibb" ] = "ibibio",
+ ["ibo" ] = "igbo",
+ ["ido" ] = "ido",
+ ["ijo" ] = "ijo languages",
+ ["ile" ] = "interlingue",
+ ["ilo" ] = "ilokano",
+ ["ina" ] = "interlingua",
+ ["ind" ] = "indonesian",
+ ["ing" ] = "ingush",
+ ["inu" ] = "inuktitut",
+ ["ipk" ] = "inupiat",
+ ["ipph"] = "phonetic transcription—ipa conventions",
+ ["iri" ] = "irish",
+ ["irt" ] = "irish traditional",
+ ["isl" ] = "icelandic",
+ ["ism" ] = "inari sami",
+ ["ita" ] = "italian",
+ ["iwr" ] = "hebrew",
+ ["jam" ] = "jamaican creole",
+ ["jan" ] = "japanese",
+ ["jav" ] = "javanese",
+ ["jbo" ] = "lojban",
+ ["jii" ] = "yiddish",
+ ["jud" ] = "ladino",
+ ["jul" ] = "jula",
+ ["kab" ] = "kabardian",
+ ["kab0"] = "kabyle",
+ ["kac" ] = "kachchi",
+ ["kal" ] = "kalenjin",
+ ["kan" ] = "kannada",
+ ["kar" ] = "karachay",
+ ["kat" ] = "georgian",
+ ["kaz" ] = "kazakh",
+ ["kde" ] = "makonde",
+ ["kea" ] = "kabuverdianu (crioulo)",
+ ["keb" ] = "kebena",
+ ["kek" ] = "kekchi",
+ ["kge" ] = "khutsuri georgian",
+ ["kha" ] = "khakass",
+ ["khk" ] = "khanty-kazim",
+ ["khm" ] = "khmer",
+ ["khs" ] = "khanty-shurishkar",
+ ["kht" ] = "khamti shan",
+ ["khv" ] = "khanty-vakhi",
+ ["khw" ] = "khowar",
+ ["kik" ] = "kikuyu (gikuyu)",
+ ["kir" ] = "kirghiz (kyrgyz)",
+ ["kis" ] = "kisii",
+ ["kiu" ] = "kirmanjki",
+ ["kjd" ] = "southern kiwai",
+ ["kjp" ] = "eastern pwo karen",
+ ["kkn" ] = "kokni",
+ ["klm" ] = "kalmyk",
+ ["kmb" ] = "kamba",
+ ["kmn" ] = "kumaoni",
+ ["kmo" ] = "komo",
+ ["kms" ] = "komso",
+ ["knr" ] = "kanuri",
+ ["kod" ] = "kodagu",
+ ["koh" ] = "korean old hangul",
+ ["kok" ] = "konkani",
+ ["kom" ] = "komi",
+ ["kon" ] = "kikongo",
+ ["kon0"] = "kongo",
+ ["kop" ] = "komi-permyak",
+ ["kor" ] = "korean",
+ ["kos" ] = "kosraean",
+ ["koz" ] = "komi-zyrian",
+ ["kpl" ] = "kpelle",
+ ["kri" ] = "krio",
+ ["krk" ] = "karakalpak",
+ ["krl" ] = "karelian",
+ ["krm" ] = "karaim",
+ ["krn" ] = "karen",
+ ["krt" ] = "koorete",
+ ["ksh" ] = "kashmiri",
+ ["ksh0"] = "ripuarian",
+ ["ksi" ] = "khasi",
+ ["ksm" ] = "kildin sami",
+ ["ksw" ] = "s’gaw karen",
+ ["kua" ] = "kuanyama",
+ ["kui" ] = "kui",
+ ["kul" ] = "kulvi",
+ ["kum" ] = "kumyk",
+ ["kur" ] = "kurdish",
+ ["kuu" ] = "kurukh",
+ ["kuy" ] = "kuy",
+ ["kyk" ] = "koryak",
+ ["kyu" ] = "western kayah",
+ ["lad" ] = "ladin",
+ ["lah" ] = "lahuli",
+ ["lak" ] = "lak",
+ ["lam" ] = "lambani",
+ ["lao" ] = "lao",
+ ["lat" ] = "latin",
+ ["laz" ] = "laz",
+ ["lcr" ] = "l-cree",
+ ["ldk" ] = "ladakhi",
+ ["lez" ] = "lezgi",
+ ["lij" ] = "ligurian",
+ ["lim" ] = "limburgish",
+ ["lin" ] = "lingala",
+ ["lis" ] = "lisu",
+ ["ljp" ] = "lampung",
+ ["lki" ] = "laki",
+ ["lma" ] = "low mari",
+ ["lmb" ] = "limbu",
+ ["lmo" ] = "lombard",
+ ["lmw" ] = "lomwe",
+ ["lom" ] = "loma",
+ ["lrc" ] = "luri",
+ ["lsb" ] = "lower sorbian",
+ ["lsm" ] = "lule sami",
+ ["lth" ] = "lithuanian",
+ ["ltz" ] = "luxembourgish",
+ ["lua" ] = "luba-lulua",
+ ["lub" ] = "luba-katanga",
+ ["lug" ] = "ganda",
+ ["luh" ] = "luyia",
+ ["luo" ] = "luo",
+ ["lvi" ] = "latvian",
+ ["mad" ] = "madura",
+ ["mag" ] = "magahi",
+ ["mah" ] = "marshallese",
+ ["maj" ] = "majang",
+ ["mak" ] = "makhuwa",
+ ["mal" ] = "malayalam reformed",
+ ["mam" ] = "mam",
+ ["man" ] = "mansi",
+ ["map" ] = "mapudungun",
+ ["mar" ] = "marathi",
+ ["maw" ] = "marwari",
+ ["mbn" ] = "mbundu",
+ ["mch" ] = "manchu",
+ ["mcr" ] = "moose cree",
+ ["mde" ] = "mende",
+ ["mdr" ] = "mandar",
+ ["men" ] = "me'en",
+ ["mer" ] = "meru",
+ ["mfe" ] = "morisyen",
+ ["min" ] = "minangkabau",
+ ["miz" ] = "mizo",
+ ["mkd" ] = "macedonian",
+ ["mkr" ] = "makasar",
+ ["mkw" ] = "kituba",
+ ["mle" ] = "male",
+ ["mlg" ] = "malagasy",
+ ["mln" ] = "malinke",
+ ["mly" ] = "malay",
+ ["mnd" ] = "mandinka",
+ ["mng" ] = "mongolian",
+ ["mni" ] = "manipuri",
+ ["mnk" ] = "maninka",
+ ["mnx" ] = "manx",
+ ["moh" ] = "mohawk",
+ ["mok" ] = "moksha",
+ ["mol" ] = "moldavian",
+ ["mon" ] = "mon",
+ ["mor" ] = "moroccan",
+ ["mos" ] = "mossi",
+ ["mri" ] = "maori",
+ ["mth" ] = "maithili",
+ ["mts" ] = "maltese",
+ ["mun" ] = "mundari",
+ ["mus" ] = "muscogee",
+ ["mwl" ] = "mirandese",
+ ["mww" ] = "hmong daw",
+ ["myn" ] = "mayan",
+ ["mzn" ] = "mazanderani",
+ ["nag" ] = "naga-assamese",
+ ["nah" ] = "nahuatl",
+ ["nan" ] = "nanai",
+ ["nap" ] = "neapolitan",
+ ["nas" ] = "naskapi",
+ ["nau" ] = "nauruan",
+ ["nav" ] = "navajo",
+ ["ncr" ] = "n-cree",
+ ["ndb" ] = "ndebele",
+ ["ndc" ] = "ndau",
+ ["ndg" ] = "ndonga",
+ ["nds" ] = "low saxon",
+ ["nep" ] = "nepali",
+ ["new" ] = "newari",
+ ["nga" ] = "ngbaka",
+ ["ngr" ] = "nagari",
+ ["nhc" ] = "norway house cree",
+ ["nis" ] = "nisi",
+ ["niu" ] = "niuean",
+ ["nkl" ] = "nyankole",
+ ["nko" ] = "n'ko",
+ ["nld" ] = "dutch",
+ ["noe" ] = "nimadi",
+ ["nog" ] = "nogai",
+ ["nor" ] = "norwegian",
+ ["nov" ] = "novial",
+ ["nsm" ] = "northern sami",
+ ["nso" ] = "sotho, northern",
+ ["nta" ] = "northern tai",
+ ["nto" ] = "esperanto",
+ ["nym" ] = "nyamwezi",
+ ["nyn" ] = "norwegian nynorsk",
+ ["oci" ] = "occitan",
+ ["ocr" ] = "oji-cree",
+ ["ojb" ] = "ojibway",
+ ["ori" ] = "odia",
+ ["oro" ] = "oromo",
+ ["oss" ] = "ossetian",
+ ["paa" ] = "palestinian aramaic",
+ ["pag" ] = "pangasinan",
+ ["pal" ] = "pali",
+ ["pam" ] = "pampangan",
+ ["pan" ] = "punjabi",
+ ["pap" ] = "palpa",
+ ["pap0"] = "papiamentu",
+ ["pas" ] = "pashto",
+ ["pau" ] = "palauan",
+ ["pcc" ] = "bouyei",
+ ["pcd" ] = "picard",
+ ["pdc" ] = "pennsylvania german",
+ ["pgr" ] = "polytonic greek",
+ ["phk" ] = "phake",
+ ["pih" ] = "norfolk",
+ ["pil" ] = "filipino",
+ ["plg" ] = "palaung",
+ ["plk" ] = "polish",
+ ["pms" ] = "piemontese",
+ ["pnb" ] = "western panjabi",
+ ["poh" ] = "pocomchi",
+ ["pon" ] = "pohnpeian",
+ ["pro" ] = "provencal",
+ ["ptg" ] = "portuguese",
+ ["pwo" ] = "western pwo karen",
+ ["qin" ] = "chin",
+ ["quc" ] = "k’iche’",
+ ["quh" ] = "quechua (bolivia)",
+ ["quz" ] = "quechua",
+ ["qvi" ] = "quechua (ecuador)",
+ ["qwh" ] = "quechua (peru)",
+ ["raj" ] = "rajasthani",
+ ["rar" ] = "rarotongan",
+ ["rbu" ] = "russian buriat",
+ ["rcr" ] = "r-cree",
+ ["rej" ] = "rejang",
+ ["ria" ] = "riang",
+ ["rif" ] = "tarifit",
+ ["rit" ] = "ritarungo",
+ ["rkw" ] = "arakwal",
+ ["rms" ] = "romansh",
+ ["rmy" ] = "vlax romani",
+ ["rom" ] = "romanian",
+ ["roy" ] = "romany",
+ ["rsy" ] = "rusyn",
+ ["rtm" ] = "rotuman",
+ ["rua" ] = "kinyarwanda",
+ ["run" ] = "rundi",
+ ["rup" ] = "aromanian",
+ ["rus" ] = "russian",
+ ["sad" ] = "sadri",
+ ["san" ] = "sanskrit",
+ ["sas" ] = "sasak",
+ ["sat" ] = "santali",
+ ["say" ] = "sayisi",
+ ["scn" ] = "sicilian",
+ ["sco" ] = "scots",
+ ["sek" ] = "sekota",
+ ["sel" ] = "selkup",
+ ["sga" ] = "old irish",
+ ["sgo" ] = "sango",
+ ["sgs" ] = "samogitian",
+ ["shi" ] = "tachelhit",
+ ["shn" ] = "shan",
+ ["sib" ] = "sibe",
+ ["sid" ] = "sidamo",
+ ["sig" ] = "silte gurage",
+ ["sks" ] = "skolt sami",
+ ["sky" ] = "slovak",
+ ["sla" ] = "slavey",
+ ["slv" ] = "slovenian",
+ ["sml" ] = "somali",
+ ["smo" ] = "samoan",
+ ["sna" ] = "sena",
+ ["sna0"] = "shona",
+ ["snd" ] = "sindhi",
+ ["snh" ] = "sinhala (sinhalese)",
+ ["snk" ] = "soninke",
+ ["sog" ] = "sodo gurage",
+ ["sop" ] = "songe",
+ ["sot" ] = "sotho, southern",
+ ["sqi" ] = "albanian",
+ ["srb" ] = "serbian",
+ ["srd" ] = "sardinian",
+ ["srk" ] = "saraiki",
+ ["srr" ] = "serer",
+ ["ssl" ] = "south slavey",
+ ["ssm" ] = "southern sami",
+ ["stq" ] = "saterland frisian",
+ ["suk" ] = "sukuma",
+ ["sun" ] = "sundanese",
+ ["sur" ] = "suri",
+ ["sva" ] = "svan",
+ ["sve" ] = "swedish",
+ ["swa" ] = "swadaya aramaic",
+ ["swk" ] = "swahili",
+ ["swz" ] = "swati",
+ ["sxt" ] = "sutu",
+ ["sxu" ] = "upper saxon",
+ ["syl" ] = "sylheti",
+ ["syr" ] = "syriac",
+ ["szl" ] = "silesian",
+ ["tab" ] = "tabasaran",
+ ["taj" ] = "tajiki",
+ ["tam" ] = "tamil",
+ ["tat" ] = "tatar",
+ ["tcr" ] = "th-cree",
+ ["tdd" ] = "dehong dai",
+ ["tel" ] = "telugu",
+ ["tet" ] = "tetum",
+ ["tgl" ] = "tagalog",
+ ["tgn" ] = "tongan",
+ ["tgr" ] = "tigre",
+ ["tgy" ] = "tigrinya",
+ ["tha" ] = "thai",
+ ["tht" ] = "tahitian",
+ ["tib" ] = "tibetan",
+ ["tiv" ] = "tiv",
+ ["tkm" ] = "turkmen",
+ ["tmh" ] = "tamashek",
+ ["tmn" ] = "temne",
+ ["tna" ] = "tswana",
+ ["tne" ] = "tundra nenets",
+ ["tng" ] = "tonga",
+ ["tod" ] = "todo",
+ ["tod0"] = "toma",
+ ["tpi" ] = "tok pisin",
+ ["trk" ] = "turkish",
+ ["tsg" ] = "tsonga",
+ ["tua" ] = "turoyo aramaic",
+ ["tul" ] = "tulu",
+ ["tuv" ] = "tuvin",
+ ["tvl" ] = "tuvalu",
+ ["twi" ] = "twi",
+ ["tyz" ] = "tày",
+ ["tzm" ] = "tamazight",
+ ["tzo" ] = "tzotzil",
+ ["udm" ] = "udmurt",
+ ["ukr" ] = "ukrainian",
+ ["umb" ] = "umbundu",
+ ["urd" ] = "urdu",
+ ["usb" ] = "upper sorbian",
+ ["uyg" ] = "uyghur",
+ ["uzb" ] = "uzbek",
+ ["vec" ] = "venetian",
+ ["ven" ] = "venda",
+ ["vit" ] = "vietnamese",
+ ["vol" ] = "volapük",
+ ["vro" ] = "võro",
+ ["wa" ] = "wa",
+ ["wag" ] = "wagdi",
+ ["war" ] = "waray-waray",
+ ["wcr" ] = "west-cree",
+ ["wel" ] = "welsh",
+ ["wlf" ] = "wolof",
+ ["wln" ] = "walloon",
+ ["xbd" ] = "lü",
+ ["xhs" ] = "xhosa",
+ ["xjb" ] = "minjangbal",
+ ["xog" ] = "soga",
+ ["xpe" ] = "kpelle (liberia)",
+ ["yak" ] = "sakha",
+ ["yao" ] = "yao",
+ ["yap" ] = "yapese",
+ ["yba" ] = "yoruba",
+ ["ycr" ] = "y-cree",
+ ["yic" ] = "yi classic",
+ ["yim" ] = "yi modern",
+ ["zea" ] = "zealandic",
+ ["zgh" ] = "standard morrocan tamazigh",
+ ["zha" ] = "zhuang",
+ ["zhh" ] = "chinese, hong kong sar",
+ ["zhp" ] = "chinese phonetic",
+ ["zhs" ] = "chinese simplified",
+ ["zht" ] = "chinese traditional",
+ ["znd" ] = "zande",
+ ["zul" ] = "zulu",
+ ["zza" ] = "zazaki",
+}
+
+local features = allocate {
+ ["aalt"] = "access all alternates",
+ ["abvf"] = "above-base forms",
+ ["abvm"] = "above-base mark positioning",
+ ["abvs"] = "above-base substitutions",
+ ["afrc"] = "alternative fractions",
+ ["akhn"] = "akhands",
+ ["blwf"] = "below-base forms",
+ ["blwm"] = "below-base mark positioning",
+ ["blws"] = "below-base substitutions",
+ ["c2pc"] = "petite capitals from capitals",
+ ["c2sc"] = "small capitals from capitals",
+ ["calt"] = "contextual alternates",
+ ["case"] = "case-sensitive forms",
+ ["ccmp"] = "glyph composition/decomposition",
+ ["cfar"] = "conjunct form after ro",
+ ["cjct"] = "conjunct forms",
+ ["clig"] = "contextual ligatures",
+ ["cpct"] = "centered cjk punctuation",
+ ["cpsp"] = "capital spacing",
+ ["cswh"] = "contextual swash",
+ ["curs"] = "cursive positioning",
+ ["dflt"] = "default processing",
+ ["dist"] = "distances",
+ ["dlig"] = "discretionary ligatures",
+ ["dnom"] = "denominators",
+ ["dtls"] = "dotless forms", -- math
+ ["expt"] = "expert forms",
+ ["falt"] = "final glyph alternates",
+ ["fin2"] = "terminal forms #2",
+ ["fin3"] = "terminal forms #3",
+ ["fina"] = "terminal forms",
+ ["flac"] = "flattened accents over capitals", -- math
+ ["frac"] = "fractions",
+ ["fwid"] = "full width",
+ ["half"] = "half forms",
+ ["haln"] = "halant forms",
+ ["halt"] = "alternate half width",
+ ["hist"] = "historical forms",
+ ["hkna"] = "horizontal kana alternates",
+ ["hlig"] = "historical ligatures",
+ ["hngl"] = "hangul",
+ ["hojo"] = "hojo kanji forms",
+ ["hwid"] = "half width",
+ ["init"] = "initial forms",
+ ["isol"] = "isolated forms",
+ ["ital"] = "italics",
+ ["jalt"] = "justification alternatives",
+ ["jp04"] = "jis2004 forms",
+ ["jp78"] = "jis78 forms",
+ ["jp83"] = "jis83 forms",
+ ["jp90"] = "jis90 forms",
+ ["kern"] = "kerning",
+ ["lfbd"] = "left bounds",
+ ["liga"] = "standard ligatures",
+ ["ljmo"] = "leading jamo forms",
+ ["lnum"] = "lining figures",
+ ["locl"] = "localized forms",
+ ["ltra"] = "left-to-right alternates",
+ ["ltrm"] = "left-to-right mirrored forms",
+ ["mark"] = "mark positioning",
+ ["med2"] = "medial forms #2",
+ ["medi"] = "medial forms",
+ ["mgrk"] = "mathematical greek",
+ ["mkmk"] = "mark to mark positioning",
+ ["mset"] = "mark positioning via substitution",
+ ["nalt"] = "alternate annotation forms",
+ ["nlck"] = "nlc kanji forms",
+ ["nukt"] = "nukta forms",
+ ["numr"] = "numerators",
+ ["onum"] = "old style figures",
+ ["opbd"] = "optical bounds",
+ ["ordn"] = "ordinals",
+ ["ornm"] = "ornaments",
+ ["palt"] = "proportional alternate width",
+ ["pcap"] = "petite capitals",
+ ["pkna"] = "proportional kana",
+ ["pnum"] = "proportional figures",
+ ["pref"] = "pre-base forms",
+ ["pres"] = "pre-base substitutions",
+ ["pstf"] = "post-base forms",
+ ["psts"] = "post-base substitutions",
+ ["pwid"] = "proportional widths",
+ ["qwid"] = "quarter widths",
+ ["rand"] = "randomize",
+ ["rclt"] = "required contextual alternates",
+ ["rkrf"] = "rakar forms",
+ ["rlig"] = "required ligatures",
+ ["rphf"] = "reph form",
+ ["rtbd"] = "right bounds",
+ ["rtla"] = "right-to-left alternates",
+ ["rtlm"] = "right to left mirrored forms",
+ ["rvrn"] = "required variation alternates",
+ ["ruby"] = "ruby notation forms",
+ ["salt"] = "stylistic alternates",
+ ["sinf"] = "scientific inferiors",
+ ["size"] = "optical size", -- now stat table
+ ["smcp"] = "small capitals",
+ ["smpl"] = "simplified forms",
+ -- ["ss01"] = "stylistic set 1",
+ -- ["ss02"] = "stylistic set 2",
+ -- ["ss03"] = "stylistic set 3",
+ -- ["ss04"] = "stylistic set 4",
+ -- ["ss05"] = "stylistic set 5",
+ -- ["ss06"] = "stylistic set 6",
+ -- ["ss07"] = "stylistic set 7",
+ -- ["ss08"] = "stylistic set 8",
+ -- ["ss09"] = "stylistic set 9",
+ -- ["ss10"] = "stylistic set 10",
+ -- ["ss11"] = "stylistic set 11",
+ -- ["ss12"] = "stylistic set 12",
+ -- ["ss13"] = "stylistic set 13",
+ -- ["ss14"] = "stylistic set 14",
+ -- ["ss15"] = "stylistic set 15",
+ -- ["ss16"] = "stylistic set 16",
+ -- ["ss17"] = "stylistic set 17",
+ -- ["ss18"] = "stylistic set 18",
+ -- ["ss19"] = "stylistic set 19",
+ -- ["ss20"] = "stylistic set 20",
+ ["ssty"] = "script style", -- math
+ ["stch"] = "stretching glyph decomposition",
+ ["subs"] = "subscript",
+ ["sups"] = "superscript",
+ ["swsh"] = "swash",
+ ["titl"] = "titling",
+ ["tjmo"] = "trailing jamo forms",
+ ["tnam"] = "traditional name forms",
+ ["tnum"] = "tabular figures",
+ ["trad"] = "traditional forms",
+ ["twid"] = "third widths",
+ ["unic"] = "unicase",
+ ["valt"] = "alternate vertical metrics",
+ ["vatu"] = "vattu variants",
+ ["vert"] = "vertical writing",
+ ["vhal"] = "alternate vertical half metrics",
+ ["vjmo"] = "vowel jamo forms",
+ ["vkna"] = "vertical kana alternates",
+ ["vkrn"] = "vertical kerning",
+ ["vpal"] = "proportional alternate vertical metrics",
+ ["vrt2"] = "vertical rotation",
+ ["zero"] = "slashed zero",
+
+ ["trep"] = "traditional tex replacements",
+ ["tlig"] = "traditional tex ligatures",
+
+ ["ss.."] = "stylistic set ..",
+ ["cv.."] = "character variant ..",
+ ["js.."] = "justification ..",
+
+ ["dv.."] = "devanagari ..",
+ ["ml.."] = "malayalam ..",
+}
+
+local baselines = allocate {
+ ["hang"] = "hanging baseline",
+ ["icfb"] = "ideographic character face bottom edge baseline",
+ ["icft"] = "ideographic character face tope edige baseline",
+ ["ideo"] = "ideographic em-box bottom edge baseline",
+ ["idtp"] = "ideographic em-box top edge baseline",
+ ["math"] = "mathematical centered baseline",
+ ["romn"] = "roman baseline"
+}
+
+tables.scripts = scripts
+tables.languages = languages
+tables.features = features
+tables.baselines = baselines
+
+local acceptscripts = true directives.register("otf.acceptscripts", function(v) acceptscripts = v end)
+local acceptlanguages = true directives.register("otf.acceptlanguages", function(v) acceptlanguages = v end)
+
+local report_checks = logs.reporter("fonts","checks")
+
+-- hm, we overload the metatables
+
+if otffeatures.features then
+ for k, v in next, otffeatures.features do
+ features[k] = v
+ end
+ otffeatures.features = features
+end
+
+local function swapped(h)
+ local r = { }
+ for k, v in next, h do
+ r[gsub(v,"[^a-z0-9]","")] = k -- is already lower
+ end
+ return r
+end
+
+local verbosescripts = allocate(swapped(scripts ))
+local verboselanguages = allocate(swapped(languages))
+local verbosefeatures = allocate(swapped(features ))
+local verbosebaselines = allocate(swapped(baselines))
+
+-- lets forget about trailing spaces
+
+local function resolve(t,k)
+ if k then
+ k = gsub(lower(k),"[^a-z0-9]","")
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ end
+end
+
+setmetatableindex(verbosescripts, resolve)
+setmetatableindex(verboselanguages, resolve)
+setmetatableindex(verbosefeatures, resolve)
+setmetatableindex(verbosebaselines, resolve)
+
+-- We could optimize the next lookups by using an extra metatable and storing
+-- already found values but in practice there are not that many lookups so
+-- it's never a bottleneck.
+
+setmetatableindex(scripts, function(t,k)
+ if k then
+ k = lower(k)
+ if k == "dflt" then
+ return k
+ end
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ k = gsub(k," ","")
+ v = rawget(t,v)
+ if v then
+ return v
+ elseif acceptscripts then
+ report_checks("registering extra script %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+
+setmetatableindex(languages, function(t,k)
+ if k then
+ k = lower(k)
+ if k == "dflt" then
+ return k
+ end
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ k = gsub(k," ","")
+ v = rawget(t,v)
+ if v then
+ return v
+ elseif acceptlanguages then
+ report_checks("registering extra language %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+
+if setmetatablenewindex then
+
+ setmetatablenewindex(languages, "ignore")
+ setmetatablenewindex(scripts, "ignore")
+ setmetatablenewindex(baselines, "ignore")
+
+end
+
+local function resolve(t,k)
+ if k then
+ k = lower(k)
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ k = gsub(k," ","")
+ local v = rawget(t,k)
+ if v then
+ return v
+ end
+ local tag, dd = match(k,"(..)(%d+)")
+ if tag and dd then
+ local v = rawget(t,tag)
+ if v then
+ return v -- return format(v,tonumber(dd)) -- old way
+ else
+ local v = rawget(t,tag.."..") -- nicer in overview
+ if v then
+ return (gsub(v,"%.%.",tonumber(dd))) -- new way
+ end
+ end
+ end
+ end
+ return k -- "dflt"
+end
+
+setmetatableindex(features, resolve)
+
+local function assign(t,k,v)
+ if k and v then
+ v = lower(v)
+ rawset(t,k,v) -- rawset ?
+ -- rawset(features,gsub(v,"[^a-z0-9]",""),k) -- why ? old code
+ end
+end
+
+if setmetatablenewindex then
+
+ setmetatablenewindex(features, assign)
+
+end
+
+local checkers = {
+ rand = function(v)
+ return v == true and "random" or v
+ end
+}
+
+-- Keep this:
+--
+-- function otf.features.normalize(features)
+-- if features then
+-- local h = { }
+-- for k, v in next, features do
+-- k = lower(k)
+-- if k == "language" then
+-- v = gsub(lower(v),"[^a-z0-9]","")
+-- h.language = rawget(verboselanguages,v) or (languages[v] and v) or "dflt" -- auto adds
+-- elseif k == "script" then
+-- v = gsub(lower(v),"[^a-z0-9]","")
+-- h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
+-- else
+-- if type(v) == "string" then
+-- local b = is_boolean(v)
+-- if type(b) == "nil" then
+-- v = tonumber(v) or lower(v)
+-- else
+-- v = b
+-- end
+-- end
+-- if not rawget(features,k) then
+-- k = rawget(verbosefeatures,k) or k
+-- end
+-- local c = checkers[k]
+-- h[k] = c and c(v) or v
+-- end
+-- end
+-- return h
+-- end
+-- end
+
+-- inspect(fonts.handlers.otf.statistics.usedfeatures)
+
+if not storage then
+ return
+end
+
+local usedfeatures = statistics.usedfeatures or { }
+statistics.usedfeatures = usedfeatures
+
+table.setmetatableindex(usedfeatures, function(t,k) if k then local v = { } t[k] = v return v end end) -- table.autotable
+
+storage.register("fonts/otf/usedfeatures", usedfeatures, "fonts.handlers.otf.statistics.usedfeatures" )
+
+local normalizedaxis = otf.readers.helpers.normalizedaxis or function(s) return s end
+
+function otffeatures.normalize(features)
+ if features then
+ local h = { }
+ for key, value in next, features do
+ local k = lower(key)
+ if k == "language" then
+ local v = gsub(lower(value),"[^a-z0-9]","")
+ h.language = rawget(verboselanguages,v) or (languages[v] and v) or "dflt" -- auto adds
+ elseif k == "script" then
+ local v = gsub(lower(value),"[^a-z0-9]","")
+ h.script = rawget(verbosescripts,v) or (scripts[v] and v) or "dflt" -- auto adds
+ elseif k == "axis" then
+ h[k] = normalizedaxis(value)
+ if not callbacks.supported.glyph_stream_provider then
+ h.variableshapes = true -- for the moment
+ end
+ else
+ local uk = usedfeatures[key]
+ local uv = uk[value]
+ if uv then
+ -- report_checks("feature value %a first seen at %a",value,key)
+ else
+ uv = tonumber(value) -- before boolean as there we also handle 0/1
+ if uv then
+ -- we're okay
+ elseif type(value) == "string" then
+ local b = is_boolean(value)
+ if type(b) == "nil" then
+ -- we do this elsewhere
+ --
+ -- if find(value,"=") then
+ -- local t = { }
+ -- for k, v in gmatch(value,"([^%s,=]+)%s*=%s*([^%s,=]+)") do
+ -- t[k] = tonumber(v) or v
+ -- end
+ -- if next(t) then
+ -- value = sequenced(t,",")
+ -- end
+ -- end
+ uv = lower(value)
+ else
+ uv = b
+ end
+ elseif type(value) == "table" then
+ uv = sequenced(t,",")
+ else
+ uv = value
+ end
+ if not rawget(features,k) then
+ k = rawget(verbosefeatures,k) or k
+ end
+ local c = checkers[k]
+ if c then
+ uv = c(uv) or vc
+ end
+ uk[value] = uv
+ end
+ h[k] = uv
+ end
+ end
+ return h
+ end
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua
index cfa90c7944a..562d7561d94 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua
@@ -15,6 +15,7 @@ local formatters = string.formatters
local sortedkeys = table.sortedkeys
local sortedhash = table.sortedhash
local tohash = table.tohash
+local setmetatableindex = table.setmetatableindex
local report = logs.reporter("otf reader")
@@ -29,8 +30,8 @@ local f_index = formatters["I%05X"]
local f_character_y = formatters["%C"]
local f_character_n = formatters["[ %C ]"]
-local check_duplicates = true -- can become an option (pseudo feature) / aways needed anyway
-local check_soft_hyphen = false -- can become an option (pseudo feature) / needed for tagging
+local check_duplicates = true -- can become an option (pseudo feature) / aways needed anyway
+local check_soft_hyphen = true -- can become an option (pseudo feature) / needed for tagging
directives.register("otf.checksofthyphen",function(v)
check_soft_hyphen = v
@@ -370,6 +371,7 @@ local function copyduplicates(fontdata)
local duplicates = resources.duplicates
if check_soft_hyphen then
-- ebgaramond has a zero width empty soft hyphen
+ -- antykwatorunsks lacks a soft hyphen
local ds = descriptions[0xAD]
if not ds or ds.width == 0 then
if ds then
@@ -621,7 +623,7 @@ local function checklookups(fontdata,missing,nofmissing)
end
end
if next(done) then
- report("not unicoded: % t",table.sortedkeys(done))
+ report("not unicoded: % t",sortedkeys(done))
end
end
end
@@ -632,7 +634,6 @@ local function unifymissing(fontdata)
require("font-agl")
end
local unicodes = { }
- local private = fontdata.private
local resources = fontdata.resources
resources.unicodes = unicodes
for unicode, d in next, fontdata.descriptions do
@@ -673,7 +674,8 @@ local function unifyglyphs(fontdata,usenames)
for index=1,#glyphs do
local glyph = glyphs[index]
local unicode = glyph.unicode -- this is the primary one
- if not unicode then
+ -- if not unicode then -- some fonts use the private space
+ if not unicode or unicode >= private or (unicode >= 0xE000 and unicode <= 0xF8FF) or unicode == 0xFFFE or unicode == 0xFFFF then
-- report("assigning private unicode %U to glyph indexed %05X (%s)",private,index,"unset")
unicode = private
-- glyph.unicode = -1
@@ -812,9 +814,9 @@ function readers.getcomponents(fontdata) -- handy for resolving ligatures when n
end
for i=1,#steps do
-- we actually had/have this in base mode
- local coverage = steps[i].coverage
- if coverage then
- for k, v in next, coverage do
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
traverse(k,k,v)
end
end
@@ -891,7 +893,7 @@ function readers.rehash(fontdata,hashmethod) -- TODO: combine loops in one
unifymissing(fontdata)
-- stripredundant(fontdata)
else
- fontdata.hashmethod = "unicode"
+ fontdata.hashmethod = "unicodes"
local indices = unifyglyphs(fontdata)
unifyresources(fontdata,indices)
copyduplicates(fontdata)
@@ -908,10 +910,10 @@ function readers.checkhash(fontdata)
elseif hashmethod == "names" and fontdata.names then
unifyresources(fontdata,fontdata.names)
copyduplicates(fontdata)
- fontdata.hashmethod = "unicode"
+ fontdata.hashmethod = "unicodes"
fontdata.names = nil -- no need for it
else
- readers.rehash(fontdata,"unicode")
+ readers.rehash(fontdata,"unicodes")
end
end
@@ -1066,13 +1068,14 @@ function readers.pack(data)
end
end
- local function pack_flat(v)
- local tag = tabstr_flat(v)
+ local function pack_normal_cc(v)
+ local tag = tabstr_normal(v)
local ht = h[tag]
if ht then
c[ht] = c[ht] + 1
return ht
else
+ v[1] = 0
nt = nt + 1
t[nt] = v
h[tag] = nt
@@ -1081,8 +1084,8 @@ function readers.pack(data)
end
end
- local function pack_boolean(v)
- local tag = tabstr_boolean(v)
+ local function pack_flat(v)
+ local tag = tabstr_flat(v)
local ht = h[tag]
if ht then
c[ht] = c[ht] + 1
@@ -1126,6 +1129,84 @@ function readers.pack(data)
end
end
+ -- saves a lot on noto sans
+
+ -- can be made more clever
+
+ local function pack_boolean(v)
+ local tag = tabstr_boolean(v)
+ local ht = h[tag]
+ if ht then
+ c[ht] = c[ht] + 1
+ return ht
+ else
+ nt = nt + 1
+ t[nt] = v
+ h[tag] = nt
+ c[nt] = 1
+ return nt
+ end
+ end
+
+ -- -- This was an experiment to see if we can bypass the luajit limits but loading is
+ -- -- still an issue due to other limits so we don't use this ... actually it can
+ -- -- prevent a luajittex crash but i don't care too much about that as we can't use
+ -- -- that engine anyway then.
+ --
+ -- local function check(t)
+ -- if type(t) == "table" then
+ -- local s = sortedkeys(t)
+ -- local n = #s
+ -- if n <= 10 then
+ -- return
+ -- end
+ -- local ranges = { }
+ -- local first, last
+ -- for i=1,#s do
+ -- local ti = s[i]
+ -- if not first then
+ -- first = ti
+ -- last = ti
+ -- elseif ti == last + 1 then
+ -- last = ti
+ -- elseif last - first < 10 then
+ -- -- we could permits a few exceptions
+ -- return
+ -- else
+ -- ranges[#ranges+1] = { first, last }
+ -- first, last = nil, nil
+ -- end
+ -- end
+ -- if #ranges > 0 then
+ -- return {
+ -- ranges = ranges
+ -- }
+ -- end
+ -- end
+ -- end
+ --
+ -- local function pack_boolean(v)
+ -- local tag
+ -- local r = check(v)
+ -- if r then
+ -- v = r
+ -- tag = tabstr_normal(v)
+ -- else
+ -- tag = tabstr_boolean(v)
+ -- end
+ -- local ht = h[tag]
+ -- if ht then
+ -- c[ht] = c[ht] + 1
+ -- return ht
+ -- else
+ -- nt = nt + 1
+ -- t[nt] = v
+ -- h[tag] = nt
+ -- c[nt] = 1
+ -- return nt
+ -- end
+ -- end
+
local function pack_final(v)
-- v == number
if c[v] <= criterium then
@@ -1145,6 +1226,25 @@ function readers.pack(data)
end
end
+ local function pack_final_cc(v)
+ -- v == number
+ if c[v] <= criterium then
+ return t[v]
+ else
+ -- compact hash
+ local hv = hh[v]
+ if hv then
+ return hv
+ else
+ ntt = ntt + 1
+ tt[ntt] = t[v]
+ hh[v] = ntt
+ cc[ntt] = c[v]
+ return ntt
+ end
+ end
+ end
+
local function success(stage,pass)
if nt == 0 then
if trace_loading or trace_packing then
@@ -1191,9 +1291,9 @@ function readers.pack(data)
local function packers(pass)
if pass == 1 then
- return pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed
+ return pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed, pack_normal_cc
else
- return pack_final, pack_final, pack_final, pack_final, pack_final
+ return pack_final, pack_final, pack_final, pack_final, pack_final, pack_final_cc
end
end
@@ -1202,6 +1302,7 @@ function readers.pack(data)
local sublookups = resources.sublookups
local features = resources.features
local palettes = resources.colorpalettes
+ local variable = resources.variabledata
local chardata = characters and characters.data
local descriptions = data.descriptions or data.glyphs
@@ -1210,15 +1311,13 @@ function readers.pack(data)
return
end
- --
-
for pass=1,2 do
if trace_packing then
report_otf("start packing: stage 1, pass %s",pass)
end
- local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed, pack_normal_cc = packers(pass)
for unicode, description in next, descriptions do
local boundingbox = description.boundingbox
@@ -1258,28 +1357,30 @@ function readers.pack(data)
if kind == "gpos_pair" then
local c = step.coverage
if c then
- if step.format == "kern" then
+ if step.format == "pair" then
for g1, d1 in next, c do
- c[g1] = pack_normal(d1)
+ for g2, d2 in next, d1 do
+ local f = d2[1] if f and f ~= true then d2[1] = pack_indexed(f) end
+ local s = d2[2] if s and s ~= true then d2[2] = pack_indexed(s) end
+ end
end
else
for g1, d1 in next, c do
- for g2, d2 in next, d1 do
- local f = d2[1] if f then d2[1] = pack_indexed(f) end
- local s = d2[2] if s then d2[2] = pack_indexed(s) end
- end
+ c[g1] = pack_normal(d1)
end
end
end
elseif kind == "gpos_single" then
local c = step.coverage
if c then
- if step.format == "kern" then
- step.coverage = pack_normal(c)
- else
+ if step.format == "single" then
for g1, d1 in next, c do
- c[g1] = pack_indexed(d1)
+ if d1 and d1 ~= true then
+ c[g1] = pack_indexed(d1)
+ end
end
+ else
+ step.coverage = pack_normal(c)
end
end
elseif kind == "gpos_cursive" then
@@ -1331,7 +1432,7 @@ function readers.pack(data)
local r = rule.before if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
local r = rule.after if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
local r = rule.current if r then for i=1,#r do r[i] = pack_boolean(r[i]) end end
- local r = rule.lookups if r then rule.lookups = pack_mixed (r) end
+ -- local r = rule.lookups if r then rule.lookups = pack_mixed (r) end
local r = rule.replacements if r then rule.replacements = pack_flat (r) end
end
end
@@ -1377,6 +1478,53 @@ function readers.pack(data)
end
+ if variable then
+
+ -- todo: segments
+
+ local instances = variable.instances
+ if instances then
+ for i=1,#instances do
+ local v = instances[i].values
+ for j=1,#v do
+ v[j] = pack_normal(v[j])
+ end
+ end
+ end
+
+ local function packdeltas(main)
+ if main then
+ local deltas = main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di = deltas[i]
+ local d = di.deltas
+ -- local r = di.regions
+ for j=1,#d do
+ d[j] = pack_indexed(d[j])
+ end
+ di.regions = pack_indexed(di.regions)
+ end
+ end
+ local regions = main.regions
+ if regions then
+ for i=1,#regions do
+ local r = regions[i]
+ for j=1,#r do
+ r[j] = pack_normal(r[j])
+ end
+ end
+ end
+ end
+ end
+
+ packdeltas(variable.global)
+ packdeltas(variable.horizontal)
+ packdeltas(variable.vertical)
+ packdeltas(variable.metrics)
+
+ end
+
if not success(1,pass) then
return
end
@@ -1391,7 +1539,7 @@ function readers.pack(data)
report_otf("start packing: stage 2, pass %s",pass)
end
- local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed, pack_normal_cc = packers(pass)
for unicode, description in next, descriptions do
local math = description.math
@@ -1415,9 +1563,7 @@ function readers.pack(data)
if kind == "gpos_pair" then
local c = step.coverage
if c then
- if step.format == "kern" then
- -- todo !
- else
+ if step.format == "pair" then
for g1, d1 in next, c do
for g2, d2 in next, d1 do
d1[g2] = pack_normal(d2)
@@ -1425,11 +1571,22 @@ function readers.pack(data)
end
end
end
--- elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" or kind == "gpos_mark2ligature" then
--- local c = step.baseclasses
--- for k, v in next, c do
--- c[k] = pack_normal(v)
--- end
+ -- elseif kind == "gpos_cursive" then
+ -- local c = step.coverage -- new
+ -- if c then
+ -- for g1, d1 in next, c do
+ -- c[g1] = pack_normal_cc(d1)
+ -- end
+ -- end
+ elseif kind == "gpos_mark2ligature" then
+ local c = step.baseclasses -- new
+ if c then
+ for g1, d1 in next, c do
+ for g2, d2 in next, d1 do
+ d1[g2] = pack_normal(d2)
+ end
+ end
+ end
end
local rules = step.rules
if rules then
@@ -1453,10 +1610,23 @@ function readers.pack(data)
if sublookups then
packthem(sublookups)
end
- -- features
- if not success(2,pass) then
- -- return
+ if variable then
+ local function unpackdeltas(main)
+ if main then
+ local regions = main.regions
+ if regions then
+ main.regions = pack_normal(regions)
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
end
+ -- if not success(2,pass) then
+ -- -- return
+ -- end
end
for pass=1,2 do
@@ -1464,7 +1634,7 @@ function readers.pack(data)
report_otf("start packing: stage 3, pass %s",pass)
end
- local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed = packers(pass)
+ local pack_normal, pack_indexed, pack_flat, pack_boolean, pack_mixed, pack_normal_cc = packers(pass)
local function packthem(sequences)
for i=1,#sequences do
@@ -1478,18 +1648,23 @@ function readers.pack(data)
if kind == "gpos_pair" then
local c = step.coverage
if c then
- if step.format == "kern" then
- -- todo !
- else
+ if step.format == "pair" then
for g1, d1 in next, c do
c[g1] = pack_normal(d1)
end
end
end
+ elseif kind == "gpos_cursive" then
+ local c = step.coverage
+ if c then
+ for g1, d1 in next, c do
+ c[g1] = pack_normal_cc(d1)
+ end
+ end
end
end
end
- end
+ end
end
if sequences then
@@ -1525,6 +1700,7 @@ function readers.unpack(data)
local sublookups = resources.sublookups
local features = resources.features
local palettes = resources.colorpalettes
+ local variable = resources.variabledata
local unpacked = { }
setmetatable(unpacked,unpacked_mt)
for unicode, description in next, descriptions do
@@ -1564,6 +1740,15 @@ function readers.unpack(data)
-- end
end
+ -- local function expandranges(t,ranges)
+ -- for i=1,#ranges do
+ -- local r = ranges[i]
+ -- for k=r[1],r[2] do
+ -- t[k] = true
+ -- end
+ -- end
+ -- end
+
local function unpackthem(sequences)
for i=1,#sequences do
local sequence = sequences[i]
@@ -1573,20 +1758,26 @@ function readers.unpack(data)
local features = sequence.features
local flags = sequence.flags
local markclass = sequence.markclass
+ if features then
+ local tv = tables[features]
+ if tv then
+ sequence.features = tv
+ features = tv
+ end
+ for script, feature in next, features do
+ local tv = tables[feature]
+ if tv then
+ features[script] = tv
+ end
+ end
+ end
if steps then
for i=1,#steps do
local step = steps[i]
if kind == "gpos_pair" then
local c = step.coverage
if c then
- if step.format == "kern" then
- for g1, d1 in next, c do
- local tv = tables[d1]
- if tv then
- c[g1] = tv
- end
- end
- else
+ if step.format == "pair" then
for g1, d1 in next, c do
local tv = tables[d1]
if tv then
@@ -1603,29 +1794,41 @@ function readers.unpack(data)
local s = tables[d2[2]] if s then d2[2] = s end
end
end
+ else
+ for g1, d1 in next, c do
+ local tv = tables[d1]
+ if tv then
+ c[g1] = tv
+ end
+ end
end
end
elseif kind == "gpos_single" then
local c = step.coverage
if c then
- if step.format == "kern" then
- local tv = tables[c]
- if tv then
- step.coverage = tv
- end
- else
+ if step.format == "single" then
for g1, d1 in next, c do
local tv = tables[d1]
if tv then
c[g1] = tv
end
end
+ else
+ local tv = tables[c]
+ if tv then
+ step.coverage = tv
+ end
end
end
elseif kind == "gpos_cursive" then
local c = step.coverage
if c then
for g1, d1 in next, c do
+ local tv = tables[d1]
+ if tv then
+ d1 = tv
+ c[g1] = d1
+ end
local f = tables[d1[2]] if f then d1[2] = f end
local s = tables[d1[3]] if s then d1[3] = s end
end
@@ -1633,12 +1836,6 @@ function readers.unpack(data)
elseif kind == "gpos_mark2base" or kind == "gpos_mark2mark" then
local c = step.baseclasses
if c then
--- for k, v in next, c do
--- local tv = tables[v]
--- if tv then
--- c[k] = tv
--- end
--- end
for g1, d1 in next, c do
for g2, d2 in next, d1 do
local tv = tables[d2]
@@ -1660,14 +1857,13 @@ function readers.unpack(data)
elseif kind == "gpos_mark2ligature" then
local c = step.baseclasses
if c then
--- for k, v in next, c do
--- local tv = tables[v]
--- if tv then
--- c[k] = tv
--- end
--- end
for g1, d1 in next, c do
for g2, d2 in next, d1 do
+ local tv = tables[d2] -- new
+ if tv then
+ d2 = tv
+ d1[g2] = d2
+ end
for g3, d3 in next, d2 do
local tv = tables[d2[g3]]
if tv then
@@ -1704,6 +1900,18 @@ function readers.unpack(data)
before[i] = tv
end
end
+ -- for i=1,#before do
+ -- local bi = before[i]
+ -- local tv = tables[bi]
+ -- if tv then
+ -- bi = tv
+ -- before[i] = bi
+ -- end
+ -- local ranges = bi.ranges
+ -- if ranges then
+ -- expandranges(bi,ranges)
+ -- end
+ -- end
end
local after = rule.after
if after then
@@ -1718,6 +1926,18 @@ function readers.unpack(data)
after[i] = tv
end
end
+ -- for i=1,#after do
+ -- local ai = after[i]
+ -- local tv = tables[ai]
+ -- if tv then
+ -- ai = tv
+ -- after[i] = ai
+ -- end
+ -- local ranges = ai.ranges
+ -- if ranges then
+ -- expandranges(ai,ranges)
+ -- end
+ -- end
end
local current = rule.current
if current then
@@ -1732,14 +1952,26 @@ function readers.unpack(data)
current[i] = tv
end
end
+ -- for i=1,#current do
+ -- local ci = current[i]
+ -- local tv = tables[ci]
+ -- if tv then
+ -- ci = tv
+ -- current[i] = ci
+ -- end
+ -- local ranges = ci.ranges
+ -- if ranges then
+ -- expandranges(ci,ranges)
+ -- end
+ -- end
end
- local lookups = rule.lookups
- if lookups then
- local tv = tables[lookups]
- if tv then
- rule.lookups = tv
- end
- end
+ -- local lookups = rule.lookups
+ -- if lookups then
+ -- local tv = tables[lookups]
+ -- if tv then
+ -- rule.lookups = tv
+ -- end
+ -- end
local replacements = rule.replacements
if replacements then
local tv = tables[replacements]
@@ -1751,19 +1983,6 @@ function readers.unpack(data)
end
end
end
- if features then
- local tv = tables[features]
- if tv then
- sequence.features = tv
- features = tv
- end
- for script, feature in next, features do
- local tv = tables[feature]
- if tv then
- features[script] = tv
- end
- end
- end
if order then
local tv = tables[order]
if tv then
@@ -1810,6 +2029,70 @@ function readers.unpack(data)
end
end
+ if variable then
+
+ -- todo: segments
+
+ local instances = variable.instances
+ if instances then
+ for i=1,#instances do
+ local v = instances[i].values
+ for j=1,#v do
+ local tv = tables[v[j]]
+ if tv then
+ v[j] = tv
+ end
+ end
+ end
+ end
+
+ local function unpackdeltas(main)
+ if main then
+ local deltas = main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di = deltas[i]
+ local d = di.deltas
+ local r = di.regions
+ for j=1,#d do
+ local tv = tables[d[j]]
+ if tv then
+ d[j] = tv
+ end
+ end
+ local tv = di.regions
+ if tv then
+ di.regions = tv
+ end
+ end
+ end
+ local regions = main.regions
+ if regions then
+ local tv = tables[regions]
+ if tv then
+ main.regions = tv
+ regions = tv
+ end
+ for i=1,#regions do
+ local r = regions[i]
+ for j=1,#r do
+ local tv = tables[r[j]]
+ if tv then
+ r[j] = tv
+ end
+ end
+ end
+ end
+ end
+ end
+
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
+
+ end
+
data.tables = nil
end
end
@@ -1851,9 +2134,12 @@ local function mergesteps_1(lookup,strict)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target = first.coverage
for i=2,nofsteps do
- for k, v in next, steps[i].coverage do
- if not target[k] then
- target[k] = v
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
+ if not target[k] then
+ target[k] = v
+ end
end
end
end
@@ -1863,8 +2149,10 @@ local function mergesteps_1(lookup,strict)
return nofsteps - 1
end
-
-local function mergesteps_2(lookup,strict) -- pairs
+local function mergesteps_2(lookup) -- pairs
+ -- this can be tricky as we can have a match on a mark with no marks skip flag
+ -- in which case with multiple steps a hit can prevent a next step while in the
+ -- merged case we can hit differently (a messy font then anyway)
local steps = lookup.steps
local nofsteps = lookup.nofsteps
local first = steps[1]
@@ -1880,71 +2168,68 @@ local function mergesteps_2(lookup,strict) -- pairs
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target = first.coverage
for i=2,nofsteps do
- for k, v in next, steps[i].coverage do
- local tk = target[k]
- if tk then
- for k, v in next, v do
- if not tk[k] then
- tk[k] = v
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
+ local tk = target[k]
+ if tk then
+ for kk, vv in next, v do
+ if tk[kk] == nil then
+ tk[kk] = vv
+ end
end
+ else
+ target[k] = v
end
- else
- target[k] = v
end
end
end
lookup.nofsteps = 1
- lookup.steps = { first }
+ lookup.merged = true
+ lookup.steps = { first }
return nofsteps - 1
end
+-- we could have a coverage[first][second] = { } already here (because eventually
+-- we also have something like that after loading)
local function mergesteps_3(lookup,strict) -- marks
local steps = lookup.steps
local nofsteps = lookup.nofsteps
- local first = steps[1]
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- local baseclasses = { }
- local coverage = { }
- local used = { }
+ -- check first
+ local coverage = { }
for i=1,nofsteps do
- local offset = i*10
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
+ local tk = coverage[k] -- { class, { x, y } }
+ if tk then
+ report("quitting merge due to multiple checks")
+ return nofsteps
+ else
+ coverage[k] = v
+ end
+ end
+ end
+ end
+ -- merge indeed
+ local first = steps[1]
+ local baseclasses = { } -- let's assume sparse step.baseclasses
+ for i=1,nofsteps do
+ local offset = i*10 -- we assume max 10 classes per step
local step = steps[i]
for k, v in sortedhash(step.baseclasses) do
baseclasses[offset+k] = v
end
for k, v in next, step.coverage do
- local tk = coverage[k]
- if tk then
- for k, v in next, v do
- if not tk[k] then
- tk[k] = v
- local c = offset + v[1]
- v[1] = c
- if not used[c] then
- used[c] = true
- end
- end
- end
- else
- coverage[k] = v
- local c = offset + v[1]
- v[1] = c
- if not used[c] then
- used[c] = true
- end
- end
- end
- end
- for k, v in next, baseclasses do
- if not used[k] then
- baseclasses[k] = nil
- report("discarding not used baseclass %i",k)
+ v[1] = offset + v[1]
end
end
first.baseclasses = baseclasses
first.coverage = coverage
lookup.nofsteps = 1
+ lookup.merged = true
lookup.steps = { first }
return nofsteps - 1
end
@@ -1973,12 +2258,15 @@ local function mergesteps_4(lookup) -- ligatures
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target = first.coverage
for i=2,nofsteps do
- for k, v in next, steps[i].coverage do
- local tk = target[k]
- if tk then
- nested(v,tk)
- else
- target[k] = v
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
+ local tk = target[k]
+ if tk then
+ nested(v,tk)
+ else
+ target[k] = v
+ end
end
end
end
@@ -1987,62 +2275,140 @@ local function mergesteps_4(lookup) -- ligatures
return nofsteps - 1
end
+-- so we assume only one cursive entry and exit and even then the first one seems
+-- to win anyway: no exit or entry quite the lookup match and then we take the
+-- next step; this means that we can as well merge them
+
+local function mergesteps_5(lookup) -- cursive
+ local steps = lookup.steps
+ local nofsteps = lookup.nofsteps
+ local first = steps[1]
+ report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ local target = first.coverage
+ local hash = nil
+ for k, v in next, target do
+ hash = v[1]
+ break
+ end
+ for i=2,nofsteps do
+ local c = steps[i].coverage
+ if c then
+ for k, v in next, c do
+ local tk = target[k]
+ if tk then
+ if not tk[2] then
+ tk[2] = v[2]
+ end
+ if not tk[3] then
+ tk[3] = v[3]
+ end
+ else
+ target[k] = v
+ v[1] = hash
+ end
+ end
+ end
+ end
+ lookup.nofsteps = 1
+ lookup.merged = true
+ lookup.steps = { first }
+ return nofsteps - 1
+end
+
local function checkkerns(lookup)
local steps = lookup.steps
local nofsteps = lookup.nofsteps
+ local kerned = 0
for i=1,nofsteps do
local step = steps[i]
if step.format == "pair" then
local coverage = step.coverage
local kerns = true
for g1, d1 in next, coverage do
- if d1[1] ~= 0 or d1[2] ~= 0 or d1[4] ~= 0 then
+ if d1 == true then
+ -- all zero
+ elseif not d1 then
+ -- null
+ elseif d1[1] ~= 0 or d1[2] ~= 0 or d1[4] ~= 0 then
kerns = false
break
end
end
if kerns then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
+ local c = { }
for g1, d1 in next, coverage do
- coverage[g1] = d1[3]
+ if d1 and d1 ~= true then
+ c[g1] = d1[3]
+ end
end
- step.format = "kern"
+ step.coverage = c
+ step.format = "move"
+ kerned = kerned + 1
end
end
end
+ return kerned
end
+-- There are several options to optimize but we have this somewhat fuzzy aspect of
+-- advancing (depending on the second of a pair) so we need to retain that information.
+--
+-- We can have:
+--
+-- true, nil|false
+--
+-- which effectively means: nothing to be done and advance to next (so not next of
+-- next) and because coverage should be not overlapping we can wipe these. However,
+-- checking for (true,nil) (false,nil) and omitting them doesn't gain much.
+
+-- Because we pack we cannot mix tables and numbers so we can only turn a whole set in
+-- format kern instead of pair.
+
local function checkpairs(lookup)
local steps = lookup.steps
local nofsteps = lookup.nofsteps
local kerned = 0
- for i=1,nofsteps do
- local step = steps[i]
- if step.format == "pair" then
- local coverage = step.coverage
- local kerns = true
- for g1, d1 in next, coverage do
- for g2, d2 in next, d1 do
- if d2[2] then
- kerns = false
- break
- else
- local v = d2[1]
- if v[1] ~= 0 or v[2] ~= 0 or v[4] ~= 0 then
- kerns = false
- break
- end
+
+ local function onlykerns(step)
+ local coverage = step.coverage
+ for g1, d1 in next, coverage do
+ for g2, d2 in next, d1 do
+ if d2[2] then
+ --- true or { a, b, c, d }
+ return false
+ else
+ local v = d2[1]
+ if v == true then
+ -- all zero
+ elseif v and (v[1] ~= 0 or v[2] ~= 0 or v[4] ~= 0) then
+ return false
end
end
end
- if kerns then
+ end
+ return coverage
+ end
+
+ for i=1,nofsteps do
+ local step = steps[i]
+ if step.format == "pair" then
+ local coverage = onlykerns(step)
+ if coverage then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
for g1, d1 in next, coverage do
+ local d = { }
for g2, d2 in next, d1 do
- d1[g2] = d2[1][3]
+ local v = d2[1]
+ if v == true then
+ -- ignore -- d1[g2] = nil
+ elseif v then
+ d[g2] = v[3] -- d1[g2] = v[3]
+ end
end
+ coverage[g1] = d
end
- step.format = "kern"
+ step.format = "move"
kerned = kerned + 1
end
end
@@ -2050,6 +2416,30 @@ local function checkpairs(lookup)
return kerned
end
+local compact_pairs = true
+local compact_singles = true
+
+local merge_pairs = true
+local merge_singles = true
+local merge_substitutions = true
+local merge_alternates = true
+local merge_multiples = true
+local merge_ligatures = true
+local merge_cursives = true
+local merge_marks = true
+
+directives.register("otf.compact.pairs", function(v) compact_pairs = v end)
+directives.register("otf.compact.singles", function(v) compact_singles = v end)
+
+directives.register("otf.merge.pairs", function(v) merge_pairs = v end)
+directives.register("otf.merge.singles", function(v) merge_singles = v end)
+directives.register("otf.merge.substitutions", function(v) merge_substitutions = v end)
+directives.register("otf.merge.alternates", function(v) merge_alternates = v end)
+directives.register("otf.merge.multiples", function(v) merge_multiples = v end)
+directives.register("otf.merge.ligatures", function(v) merge_ligatures = v end)
+directives.register("otf.merge.cursives", function(v) merge_cursives = v end)
+directives.register("otf.merge.marks", function(v) merge_marks = v end)
+
function readers.compact(data)
if not data or data.compacted then
return
@@ -2066,23 +2456,65 @@ function readers.compact(data)
for i=1,#lookups do
local lookup = lookups[i]
local nofsteps = lookup.nofsteps
+ local kind = lookup.type
allsteps = allsteps + nofsteps
if nofsteps > 1 then
- local kind = lookup.type
- if kind == "gsub_single" or kind == "gsub_alternate" or kind == "gsub_multiple" then
- merged = merged + mergesteps_1(lookup)
+ local merg = merged
+ if kind == "gsub_single" then
+ if merge_substitutions then
+ merged = merged + mergesteps_1(lookup)
+ end
+ elseif kind == "gsub_alternate" then
+ if merge_alternates then
+ merged = merged + mergesteps_1(lookup)
+ end
+ elseif kind == "gsub_multiple" then
+ if merge_multiples then
+ merged = merged + mergesteps_1(lookup)
+ end
elseif kind == "gsub_ligature" then
- merged = merged + mergesteps_4(lookup)
+ if merge_ligatures then
+ merged = merged + mergesteps_4(lookup)
+ end
elseif kind == "gpos_single" then
- merged = merged + mergesteps_1(lookup,true)
- checkkerns(lookup)
+ if merge_singles then
+ merged = merged + mergesteps_1(lookup,true)
+ end
+ if compact_singles then
+ kerned = kerned + checkkerns(lookup)
+ end
elseif kind == "gpos_pair" then
- merged = merged + mergesteps_2(lookup,true)
- kerned = kerned + checkpairs(lookup)
+ if merge_pairs then
+ merged = merged + mergesteps_2(lookup)
+ end
+ if compact_pairs then
+ kerned = kerned + checkpairs(lookup)
+ end
elseif kind == "gpos_cursive" then
- merged = merged + mergesteps_2(lookup)
+ if merge_cursives then
+ merged = merged + mergesteps_5(lookup)
+ end
elseif kind == "gpos_mark2mark" or kind == "gpos_mark2base" or kind == "gpos_mark2ligature" then
- merged = merged + mergesteps_3(lookup)
+ if merge_marks then
+ merged = merged + mergesteps_3(lookup)
+ end
+ end
+ if merg ~= merged then
+ lookup.merged = true
+ end
+ elseif nofsteps == 1 then
+ local kern = kerned
+ if kind == "gpos_single" then
+ if compact_singles then
+ kerned = kerned + checkkerns(lookup)
+ end
+ elseif kind == "gpos_pair" then
+ if compact_pairs then
+ kerned = kerned + checkpairs(lookup)
+ end
+ end
+ if kern ~= kerned then
+ -- lookup.kerned = true
end
end
end
@@ -2100,6 +2532,79 @@ function readers.compact(data)
end
end
+local function mergesteps(t,k)
+ if k == "merged" then
+ local merged = { }
+ for i=1,#t do
+ local step = t[i]
+ local coverage = step.coverage
+ for k in next, coverage do
+ local m = merged[k]
+ if m then
+ m[2] = i
+ -- m[#m+1] = step
+ else
+ merged[k] = { i, i }
+ -- merged[k] = { step }
+ end
+ end
+ end
+ t.merged = merged
+ return merged
+ end
+end
+
+local function checkmerge(sequence)
+ local steps = sequence.steps
+ if steps then
+ setmetatableindex(steps,mergesteps)
+ end
+end
+
+local function checkflags(sequence,resources)
+ if not sequence.skiphash then
+ local flags = sequence.flags
+ if flags then
+ local skipmark = flags[1]
+ local skipligature = flags[2]
+ local skipbase = flags[3]
+ local markclass = sequence.markclass
+ local skipsome = skipmark or skipligature or skipbase or markclass or false
+ if skipsome then
+ sequence.skiphash = setmetatableindex(function(t,k)
+ local c = resources.classes[k] -- delayed table
+ local v = c == skipmark
+ or (markclass and c == "mark" and not markclass[k])
+ or c == skipligature
+ or c == skipbase
+ or false
+ t[k] = v
+ return v
+ end)
+ else
+ sequence.skiphash = false
+ end
+ else
+ sequence.skiphash = false
+ end
+ end
+end
+
+local function checksteps(sequence)
+ local steps = sequence.steps
+ if steps then
+ for i=1,#steps do
+ steps[i].index = i
+ end
+ end
+end
+
+if fonts.helpers then
+ fonts.helpers.checkmerge = checkmerge
+ fonts.helpers.checkflags = checkflags
+ fonts.helpers.checksteps = checksteps -- has to happen last
+end
+
function readers.expand(data)
if not data or data.expanded then
return
@@ -2141,6 +2646,11 @@ function readers.expand(data)
end
end
end
+
+ -- using a merged combined hash as first test saves some 30% on ebgaramond and
+ -- about 15% on arabtype .. then moving the a test also saves a bit (even when
+ -- often a is not set at all so that one is a bit debatable
+
local function expandlookups(sequences)
if sequences then
-- we also need to do sublookups
@@ -2148,6 +2658,8 @@ function readers.expand(data)
local sequence = sequences[i]
local steps = sequence.steps
if steps then
+ local nofsteps = sequence.nofsteps
+
local kind = sequence.type
local markclass = sequence.markclass
if markclass then
@@ -2158,7 +2670,8 @@ function readers.expand(data)
sequence.markclass = markclasses[markclass]
end
end
- for i=1,sequence.nofsteps do
+
+ for i=1,nofsteps do
local step = steps[i]
local baseclasses = step.baseclasses
if baseclasses then
@@ -2174,13 +2687,14 @@ function readers.expand(data)
end
local rules = step.rules
if rules then
- local rulehash = { }
+ local rulehash = { n = 0 } -- is contexts in font-ots
local rulesize = 0
local coverage = { }
local lookuptype = sequence.type
+ local nofrules = #rules
step.coverage = coverage -- combined hits
- for nofrules=1,#rules do
- local rule = rules[nofrules]
+ for currentrule=1,nofrules do
+ local rule = rules[currentrule]
local current = rule.current
local before = rule.before
local after = rule.after
@@ -2208,23 +2722,27 @@ function readers.expand(data)
local lookups = rule.lookups or false
local subtype = nil
if lookups then
- -- is now indexed
- for k, v in next, lookups do
- local lookup = sublookups[v]
- if lookup then
- lookups[k] = lookup
- if not subtype then
- subtype = lookup.type
+ for i=1,#lookups do
+ local lookups = lookups[i]
+ if lookups then
+ for k, v in next, lookups do -- actually this one is indexed
+ local lookup = sublookups[v]
+ if lookup then
+ lookups[k] = lookup
+ if not subtype then
+ subtype = lookup.type
+ end
+ else
+ -- already expanded
+ end
end
- else
- -- already expanded
end
end
end
if sequence[1] then -- we merge coverage into one
- rulesize = rulesize + 1
- rulehash[rulesize] = {
- nofrules, -- 1
+ sequence.n = #sequence -- tiny speedup
+ local ruledata = {
+ currentrule, -- 1 -- original rule number, only use this for tracing!
lookuptype, -- 2
sequence, -- 3
start, -- 4
@@ -2233,20 +2751,61 @@ function readers.expand(data)
replacements, -- 7
subtype, -- 8
}
- for unic in next, sequence[start] do
- local cu = coverage[unic]
- if not cu then
- coverage[unic] = rulehash -- can now be done cleaner i think
+ --
+ -- possible optimization: per [unic] a rulehash, but beware:
+ -- contexts have unique coverage and chains can have multiple
+ -- hits (rules) per coverage entry
+ --
+ -- so: we can combine multiple steps as well as multiple rules
+ -- but that takes careful checking, in which case we can go the
+ -- step list approach and turn contexts into steps .. in fact,
+ -- if we turn multiple contexts into steps we're already ok as
+ -- steps gets a coverage hash by metatable
+ --
+ rulesize = rulesize + 1
+ rulehash[rulesize] = ruledata
+ rulehash.n = rulesize -- tiny speedup
+ --
+ if true then -- nofrules > 1
+
+ for unic in next, sequence[start] do
+ local cu = coverage[unic]
+ if cu then
+ local n = #cu+1
+ cu[n] = ruledata
+ cu.n = n
+ else
+ coverage[unic] = { ruledata, n = 1 }
+ end
end
+
+ else
+
+ for unic in next, sequence[start] do
+ local cu = coverage[unic]
+ if cu then
+ -- we can have a contextchains with many matches which we
+ -- can actually optimize
+ else
+ coverage[unic] = rulehash
+ end
+ end
+
end
end
end
end
end
+
+ checkmerge(sequence)
+ checkflags(sequence,resources)
+ checksteps(sequence)
+
end
end
end
end
+
expandlookups(sequences)
expandlookups(sublookups)
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua
index 6584190ce38..9f78f2c0a3d 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua
@@ -21,6 +21,7 @@ local setmetatableindex = table.setmetatableindex
local fonts = fonts
local handlers = fonts.handlers
+local helpers = fonts.helpers
local readers = fonts.readers
local constructors = fonts.constructors
local encodings = fonts.encodings
@@ -39,6 +40,8 @@ local registertfmfeature = tfmfeatures.register
local tfmenhancers = constructors.enhancers.tfm
local registertfmenhancer = tfmenhancers.register
+local charcommand = helpers.commands.char
+
constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua
fonts.formats.tfm = "type1" -- we need to have at least a value here
@@ -244,6 +247,8 @@ local function read_from_tfm(specification)
--
constructors.enhanceparameters(parameters) -- official copies for us
--
+ properties.private = properties.private or tfmdata.private or privateoffset
+ --
if newtfmdata then
--
-- We do nothing as we assume flat tfm files. It would become real messy
@@ -436,7 +441,7 @@ do
local originals = tfmdata.characters
local indices = { }
local parentfont = { "font", 1 }
- local private = fonts.constructors.privateoffset
+ local private = tfmdata or fonts.constructors.privateoffset
local reported = encdone[tfmfile][encfile]
-- create characters table
@@ -463,7 +468,7 @@ do
if backmap then
original.index = backmap[name]
else -- probably bitmap
- original.commands = { parentfont, { "char", index } }
+ original.commands = { parentfont, charcommand[index] } -- or "slot"
original.oindex = index
end
done[name] = true
@@ -514,6 +519,7 @@ do
tfmdata.tounicode = 1
tfmdata.embedding = "subset"
tfmdata.usedbitmap = bitmap and virtualid
+ tfmdata.private = private
return tfmdata
end
@@ -548,7 +554,9 @@ end
local flushstreamobject = lpdf and lpdf.flushstreamobject
local setfontattributes = pdf.setfontattributes
- if not flushstreamobject then
+ if flushstreamobject then
+ -- we're in context
+ else
flushstreamobject = function(data)
return pdf.obj {
immediate = true,
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua
index 6df339214b2..bdfa3e85906 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua
@@ -6,42 +6,108 @@ if not modules then modules = { } end modules ['font-ttf'] = {
license = "see context related readme files"
}
+-- This version is different from previous in the sense that we no longer store
+-- contours but keep points and contours (endpoints) separate for a while
+-- because later on we need to apply deltas and that is easier on a list of
+-- points.
+
+-- The code is a bit messy. I looked at the ff code but it's messy too. It has
+-- to do with the fact that we need to look at points on the curve and control
+-- points in between. This also means that we start at point 2 and have to look
+-- at point 1 when we're at the end. We still use a ps like storage with the
+-- operator last in an entry. It's typical code that evolves stepwise till a
+-- point of no comprehension.
+
+-- For deltas we need a rather complex loop over points that can have holes and
+-- be less than nofpoints and even can have duplicates and also the x and y value
+-- lists can be shorter than etc. I need fonts in order to complete this simply
+-- because I need to visualize in order to understand (what the standard tries
+-- to explain).
+
+-- 0 point then none applied
+-- 1 points then applied to all
+-- otherwise inferred deltas using nearest
+-- if no lower point then use highest referenced point
+-- if no higher point then use lowest referenced point
+-- factor = (target-left)/(right-left)
+-- delta = (1-factor)*left + factor * right
+
local next, type, unpack = next, type, unpack
-local bittest = bit32.btest
-local sqrt = math.sqrt
+local band, rshift = bit32.band, bit32.rshift
+local sqrt, round = math.sqrt, math.round
+local char = string.char
+local concat = table.concat
+
+local report = logs.reporter("otf reader","ttf")
+
+local trace_deltas = false
+
+local readers = fonts.handlers.otf.readers
+local streamreader = readers.streamreader
+
+local setposition = streamreader.setposition
+local getposition = streamreader.getposition
+local skipbytes = streamreader.skip
+local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
+local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
+local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
+local readchar = streamreader.readinteger1 -- 8-bit signed integer
+local readshort = streamreader.readinteger2 -- 16-bit signed integer
+local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
+local readinteger = streamreader.readinteger1
+local readcardinaltable = streamreader.readcardinaltable
+local readintegertable = streamreader.readintegertable
+
+directives.register("fonts.streamreader",function()
+
+ streamreader = utilities.streams
+
+ setposition = streamreader.setposition
+ getposition = streamreader.getposition
+ skipbytes = streamreader.skip
+ readbyte = streamreader.readcardinal1
+ readushort = streamreader.readcardinal2
+ readulong = streamreader.readcardinal4
+ readchar = streamreader.readinteger1
+ readshort = streamreader.readinteger2
+ read2dot14 = streamreader.read2dot14
+ readinteger = streamreader.readinteger1
+ readcardinaltable = streamreader.readcardinaltable
+ readintegertable = streamreader.readintegertable
-local report = logs.reporter("otf reader","ttf")
+end)
-local readers = fonts.handlers.otf.readers
-local streamreader = readers.streamreader
+local short = 2
+local ushort = 2
+local ulong = 4
-local setposition = streamreader.setposition
-local getposition = streamreader.getposition
-local skipbytes = streamreader.skip
-local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
-local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
-local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
-local readchar = streamreader.readinteger1 -- 8-bit signed integer
-local readshort = streamreader.readinteger2 -- 16-bit signed integer
-local read2dot14 = streamreader.read2dot14 -- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
+local helpers = readers.helpers
+local gotodatatable = helpers.gotodatatable
local function mergecomposites(glyphs,shapes)
+ -- todo : deltas
+
local function merge(index,shape,components)
local contours = { }
+ local points = { }
local nofcontours = 0
+ local nofpoints = 0
+ local offset = 0
+ local deltas = shape.deltas
for i=1,#components do
local component = components[i]
local subindex = component.index
local subshape = shapes[subindex]
local subcontours = subshape.contours
+ local subpoints = subshape.points
if not subcontours then
local subcomponents = subshape.components
if subcomponents then
- subcontours = merge(subindex,subshape,subcomponents)
+ subcontours, subpoints = merge(subindex,subshape,subcomponents)
end
end
- if subcontours then
+ if subpoints then
local matrix = component.matrix
local xscale = matrix[1]
local xrotate = matrix[2]
@@ -49,36 +115,39 @@ local function mergecomposites(glyphs,shapes)
local yscale = matrix[4]
local xoffset = matrix[5]
local yoffset = matrix[6]
+ for i=1,#subpoints do
+ local p = subpoints[i]
+ local x = p[1]
+ local y = p[2]
+ nofpoints = nofpoints + 1
+ points[nofpoints] = {
+ xscale * x + xrotate * y + xoffset,
+ yscale * y + yrotate * x + yoffset,
+ p[3]
+ }
+ end
for i=1,#subcontours do
- local points = subcontours[i]
- local result = { }
- for i=1,#points do
- local p = points[i]
- local x = p[1]
- local y = p[2]
- result[i] = {
- xscale * x + xrotate * y + xoffset,
- yscale * y + yrotate * x + yoffset,
- p[3]
- }
- end
nofcontours = nofcontours + 1
- contours[nofcontours] = result
+ contours[nofcontours] = offset + subcontours[i]
end
+ offset = offset + #subpoints
else
report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex)
end
end
+ shape.points = points -- todo : phantom points
shape.contours = contours
shape.components = nil
- return contours
+ return contours, points
end
for index=1,#glyphs do
- local shape = shapes[index]
- local components = shape.components
- if components then
- merge(index,shape,components)
+ local shape = shapes[index]
+ if shape then
+ local components = shape.components
+ if components then
+ merge(index,shape,components)
+ end
end
end
@@ -92,145 +161,561 @@ end
-- begin of converter
--- make paths: the ff code is quite complex but it looks like we need to deal
--- with all kind of on curve border cases
-
local function curveto(m_x,m_y,l_x,l_y,r_x,r_y) -- todo: inline this
- return {
+ return
l_x + 2/3 *(m_x-l_x), l_y + 2/3 *(m_y-l_y),
r_x + 2/3 *(m_x-r_x), r_y + 2/3 *(m_y-r_y),
- r_x, r_y, "c" -- "curveto"
- }
+ r_x, r_y, "c"
end
-- We could omit the operator which saves some 10%:
--
--- #2=lineto #4=quadratic #6=cubic #3=moveto (with "m")
+-- #2=lineto #4=quadratic #6=cubic #3=moveto (with "m")
--
--- For the moment we keep the original outlines but that default might change
--- in the future. In any case, a backend should support both.
+-- This is tricky ... something to do with phantom points .. however, the hvar
+-- and vvar tables should take care of the width .. the test font doesn't have
+-- those so here we go then (we need a flag for hvar).
--
--- The code is a bit messy. I looked at the ff code but it's messy too. It has
--- to do with the fact that we need to look at points on the curve and control
--- points in between. This also means that we start at point 2 and have to look at
--- point 1 when we're at the end. We still use a ps like storage with the operator
--- last in an entry. It's typical code that evolves stepwise till a point of no
--- comprehension.
-
-local function contours2outlines(glyphs,shapes)
- local quadratic = true
- -- local quadratic = false
+-- h-advance left-side-bearing v-advance top-side-bearing
+--
+-- We had two loops (going backward) but can do it in one loop .. but maybe we
+-- should only accept fonts with proper hvar tables.
+
+local function applyaxis(glyph,shape,deltas,dowidth)
+ local points = shape.points
+ if points then
+ local nofpoints = #points
+ local h = nofpoints + 2 -- weird, the example font seems to have left first
+ local l = nofpoints + 1
+ ----- v = nofpoints + 3
+ ----- t = nofpoints + 4
+ local dw = 0
+ local dl = 0
+ for i=1,#deltas do
+ local deltaset = deltas[i]
+ local xvalues = deltaset.xvalues
+ local yvalues = deltaset.yvalues
+ local dpoints = deltaset.points
+ local factor = deltaset.factor
+ if dpoints then
+ -- todo: interpolate
+ local nofdpoints = #dpoints
+ for i=1,nofdpoints do
+ local d = dpoints[i]
+ local p = points[d]
+ if p then
+ if xvalues then
+ local x = xvalues[i]
+ if x and x ~= 0 then
+ p[1] = p[1] + factor * x
+ end
+ end
+ if yvalues then
+ local y = yvalues[i]
+ if y and y ~= 0 then
+ p[2] = p[2] + factor * y
+ end
+ end
+ elseif dowidth then
+ -- we've now ran into phantom points which is a bit fuzzy because:
+ -- are there gaps in there?
+ --
+ -- todo: move this outside the loop (when we can be sure of all 4 being there)
+ if d == h then
+ -- we have a phantom point hadvance
+ local x = xvalues[i]
+ if x then
+ dw = dw + factor * x
+ end
+ elseif d == l then
+ local x = xvalues[i]
+ if x then
+ dl = dl + factor * x
+ end
+ end
+ end
+ end
+ else
+ for i=1,nofpoints do
+ local p = points[i]
+ if xvalues then
+ local x = xvalues[i]
+ if x and x ~= 0 then
+ p[1] = p[1] + factor * x
+ end
+ end
+ if yvalues then
+ local y = yvalues[i]
+ if y and y ~= 0 then
+ p[2] = p[2] + factor * y
+ end
+ end
+ end
+ if dowidth then
+ local x = xvalues[h]
+ if x then
+ dw = dw + factor * x
+ end
+ local x = xvalues[l]
+ if x then
+ dl = dl + factor * x
+ end
+ end
+ end
+ end
+ -- for i=1,nofpoints do
+ -- local p = points[i]
+ -- p[1] = round(p[1])
+ -- p[2] = round(p[2])
+ -- end
+ if dowidth then
+ local width = glyph.width or 0
+ -- local lsb = glyph.lsb or 0
+ glyph.width = width + dw - dl
+ end
+ else
+ report("no points for glyph %a",glyph.name)
+ end
+end
+
+-- round or not ?
+
+-- local quadratic = true -- both methods work, todo: install a directive
+local quadratic = false
+
+local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox overhead
for index=1,#glyphs do
- local glyph = glyphs[index]
- local shape = shapes[index]
- local contours = shape.contours
- if contours then
- local nofcontours = #contours
- local segments = { }
- local nofsegments = 0
- glyph.segments = segments
- if nofcontours > 0 then
- for i=1,nofcontours do
- local contour = contours[i]
- local nofcontour = #contour
- if nofcontour > 0 then
- local first_pt = contour[1]
- local first_on = first_pt[3]
- -- todo no new tables but reuse lineto and quadratic
- if nofcontour == 1 then
- -- this can influence the boundingbox
- first_pt[3] = "m" -- "moveto"
- nofsegments = nofsegments + 1
- segments[nofsegments] = first_pt
- else -- maybe also treat n == 2 special
- local first_on = first_pt[3]
- local last_pt = contour[nofcontour]
- local last_on = last_pt[3]
- local start = 1
- local control_pt = false
- if first_on then
- start = 2
- else
- if last_on then
- first_pt = last_pt
+ local shape = shapes[index]
+ if shape then
+ local glyph = glyphs[index]
+ local contours = shape.contours
+ local points = shape.points
+ if contours then
+ local nofcontours = #contours
+ local segments = { }
+ local nofsegments = 0
+ glyph.segments = segments
+ if nofcontours > 0 then
+ local px, py = 0, 0 -- we could use these in calculations which saves a copy
+ local first = 1
+ for i=1,nofcontours do
+ local last = contours[i]
+ if last >= first then
+ local first_pt = points[first]
+ local first_on = first_pt[3]
+ -- todo no new tables but reuse lineto and quadratic
+ if first == last then
+ first_pt[3] = "m" -- "moveto"
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = first_pt
+ else -- maybe also treat n == 2 special
+ local first_on = first_pt[3]
+ local last_pt = points[last]
+ local last_on = last_pt[3]
+ local start = 1
+ local control_pt = false
+ if first_on then
+ start = 2
else
- first_pt = { (first_pt[1]+last_pt[1])/2, (first_pt[2]+last_pt[2])/2, false }
+ if last_on then
+ first_pt = last_pt
+ else
+ first_pt = { (first_pt[1]+last_pt[1])/2, (first_pt[2]+last_pt[2])/2, false }
+ end
+ control_pt = first_pt
end
- control_pt = first_pt
- end
- nofsegments = nofsegments + 1
- segments[nofsegments] = { first_pt[1], first_pt[2], "m" } -- "moveto"
- local previous_pt = first_pt
- for i=start,nofcontour do
- local current_pt = contour[i]
- local current_on = current_pt[3]
- local previous_on = previous_pt[3]
- if previous_on then
- if current_on then
- -- both normal points
+ local x, y = first_pt[1], first_pt[2]
+ if not done then
+ xmin, ymin, xmax, ymax = x, y, x, y
+ done = true
+ end
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x, y, "m" } -- "moveto"
+ if not quadratic then
+ px, py = x, y
+ end
+ local previous_pt = first_pt
+ for i=first,last do
+ local current_pt = points[i]
+ local current_on = current_pt[3]
+ local previous_on = previous_pt[3]
+ if previous_on then
+ if current_on then
+ -- both normal points
+ local x, y = current_pt[1], current_pt[2]
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x, y, "l" } -- "lineto"
+ if not quadratic then
+ px, py = x, y
+ end
+ else
+ control_pt = current_pt
+ end
+ elseif current_on then
+ local x1, y1 = control_pt[1], control_pt[2]
+ local x2, y2 = current_pt[1], current_pt[2]
nofsegments = nofsegments + 1
- segments[nofsegments] = { current_pt[1], current_pt[2], "l" } -- "lineto"
+ if quadratic then
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ else
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ end
+ control_pt = false
else
+ local x2, y2 = (previous_pt[1]+current_pt[1])/2, (previous_pt[2]+current_pt[2])/2
+ local x1, y1 = control_pt[1], control_pt[2]
+ nofsegments = nofsegments + 1
+ if quadratic then
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ else
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ end
control_pt = current_pt
end
- elseif current_on then
- local ps = segments[nofsegments]
+ previous_pt = current_pt
+ end
+ if first_pt == last_pt then
+ -- we're already done, probably a simple curve
+ else
nofsegments = nofsegments + 1
- if quadratic then
- segments[nofsegments] = { control_pt[1], control_pt[2], current_pt[1], current_pt[2], "q" } -- "quadraticto"
+ local x2, y2 = first_pt[1], first_pt[2]
+ if not control_pt then
+ segments[nofsegments] = { x2, y2, "l" } -- "lineto"
+ elseif quadratic then
+ local x1, y1 = control_pt[1], control_pt[2]
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ else
+ local x1, y1 = control_pt[1], control_pt[2]
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ -- px, py = x2, y2
+ end
+ end
+ end
+ end
+ first = last + 1
+ end
+ end
+ end
+ end
+ end
+end
+
+local function contours2outlines_shaped(glyphs,shapes,keepcurve)
+ for index=1,#glyphs do
+ local shape = shapes[index]
+ if shape then
+ local glyph = glyphs[index]
+ local contours = shape.contours
+ local points = shape.points
+ if contours then
+ local nofcontours = #contours
+ local segments = keepcurve and { } or nil
+ local nofsegments = 0
+ if keepcurve then
+ glyph.segments = segments
+ end
+ if nofcontours > 0 then
+ local xmin, ymin, xmax, ymax, done = 0, 0, 0, 0, false
+ local px, py = 0, 0 -- we could use these in calculations which saves a copy
+ local first = 1
+ for i=1,nofcontours do
+ local last = contours[i]
+ if last >= first then
+ local first_pt = points[first]
+ local first_on = first_pt[3]
+ -- todo no new tables but reuse lineto and quadratic
+ if first == last then
+ -- this can influence the boundingbox
+ if keepcurve then
+ first_pt[3] = "m" -- "moveto"
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = first_pt
+ end
+ else -- maybe also treat n == 2 special
+ local first_on = first_pt[3]
+ local last_pt = points[last]
+ local last_on = last_pt[3]
+ local start = 1
+ local control_pt = false
+ if first_on then
+ start = 2
+ else
+ if last_on then
+ first_pt = last_pt
else
- local p = segments[nofsegments-1] local n = #p
- segments[nofsegments] = curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],current_pt[1],current_pt[2])
+ first_pt = { (first_pt[1]+last_pt[1])/2, (first_pt[2]+last_pt[2])/2, false }
end
- control_pt = false
+ control_pt = first_pt
+ end
+ local x, y = first_pt[1], first_pt[2]
+ if not done then
+ xmin, ymin, xmax, ymax = x, y, x, y
+ done = true
else
+ if x < xmin then xmin = x elseif x > xmax then xmax = x end
+ if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ end
+ if keepcurve then
nofsegments = nofsegments + 1
- local halfway_x = (previous_pt[1]+current_pt[1])/2
- local halfway_y = (previous_pt[2]+current_pt[2])/2
+ segments[nofsegments] = { x, y, "m" } -- "moveto"
+ end
+ if not quadratic then
+ px, py = x, y
+ end
+ local previous_pt = first_pt
+ for i=first,last do
+ local current_pt = points[i]
+ local current_on = current_pt[3]
+ local previous_on = previous_pt[3]
+ if previous_on then
+ if current_on then
+ -- both normal points
+ local x, y = current_pt[1], current_pt[2]
+ if x < xmin then xmin = x elseif x > xmax then xmax = x end
+ if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x, y, "l" } -- "lineto"
+ end
+ if not quadratic then
+ px, py = x, y
+ end
+ else
+ control_pt = current_pt
+ end
+ elseif current_on then
+ local x1, y1 = control_pt[1], control_pt[2]
+ local x2, y2 = current_pt[1], current_pt[2]
+ if quadratic then
+ if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
+ if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ end
+ else
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
+ if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
+ if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
+ if px < xmin then xmin = px elseif px > xmax then xmax = px end
+ if py < ymin then ymin = py elseif py > ymax then ymax = py end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ end
+ end
+ control_pt = false
+ else
+ local x2, y2 = (previous_pt[1]+current_pt[1])/2, (previous_pt[2]+current_pt[2])/2
+ local x1, y1 = control_pt[1], control_pt[2]
+ if quadratic then
+ if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
+ if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ end
+ else
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
+ if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
+ if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
+ if px < xmin then xmin = px elseif px > xmax then xmax = px end
+ if py < ymin then ymin = py elseif py > ymax then ymax = py end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ end
+ end
+ control_pt = current_pt
+ end
+ previous_pt = current_pt
+ end
+ if first_pt == last_pt then
+ -- we're already done, probably a simple curve
+ elseif not control_pt then
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { first_pt[1], first_pt[2], "l" } -- "lineto"
+ end
+ else
+ local x1, y1 = control_pt[1], control_pt[2]
+ local x2, y2 = first_pt[1], first_pt[2]
+ if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
+ if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
if quadratic then
- segments[nofsegments] = { control_pt[1], control_pt[2], halfway_x, halfway_y, "q" } -- "quadraticto"
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto"
+ end
else
- local p = segments[nofsegments-1] local n = #p
- segments[nofsegments] = curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],halfway_x,halfway_y)
+ x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2)
+ if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
+ if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
+ if px < xmin then xmin = px elseif px > xmax then xmax = px end
+ if py < ymin then ymin = py elseif py > ymax then ymax = py end
+ if keepcurve then
+ nofsegments = nofsegments + 1
+ segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto"
+ end
+ -- px, py = x2, y2
end
- control_pt = current_pt
end
- previous_pt = current_pt
end
- if first_pt == last_pt then
- -- we're already done, probably a simple curve
+ end
+ first = last + 1
+ end
+ glyph.boundingbox = { round(xmin), round(ymin), round(xmax), round(ymax) }
+ end
+ end
+ end
+ end
+end
+
+-- optimize for zero
+
+local c_zero = char(0)
+local s_zero = char(0,0)
+
+local function toushort(n)
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+
+local function toshort(n)
+ if n < 0 then
+ n = n + 0x10000
+ end
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+
+-- todo: we can reuse result, xpoints and ypoints
+
+local function repackpoints(glyphs,shapes)
+ local noboundingbox = { 0, 0, 0, 0 }
+ local result = { } -- reused
+ for index=1,#glyphs do
+ local shape = shapes[index]
+ if shape then
+ local r = 0
+ local glyph = glyphs[index]
+ if false then -- shape.type == "composite"
+ -- we merged them
+ else
+ local contours = shape.contours
+ local nofcontours = contours and #contours or 0
+ local boundingbox = glyph.boundingbox or noboundingbox
+ r = r + 1 result[r] = toshort(nofcontours)
+ r = r + 1 result[r] = toshort(boundingbox[1]) -- xmin
+ r = r + 1 result[r] = toshort(boundingbox[2]) -- ymin
+ r = r + 1 result[r] = toshort(boundingbox[3]) -- xmax
+ r = r + 1 result[r] = toshort(boundingbox[4]) -- ymax
+ if nofcontours > 0 then
+ for i=1,nofcontours do
+ r = r + 1 result[r] = toshort(contours[i]-1)
+ end
+ r = r + 1 result[r] = s_zero -- no instructions
+ local points = shape.points
+ local currentx = 0
+ local currenty = 0
+ local xpoints = { }
+ local ypoints = { }
+ local x = 0
+ local y = 0
+ local lastflag = nil
+ local nofflags = 0
+ for i=1,#points do
+ local pt = points[i]
+ local px = pt[1]
+ local py = pt[2]
+ local fl = pt[3] and 0x01 or 0x00
+ if px == currentx then
+ fl = fl + 0x10
+ else
+ local dx = round(px - currentx)
+ if dx < -255 or dx > 255 then
+ x = x + 1 xpoints[x] = toshort(dx)
+ elseif dx < 0 then
+ fl = fl + 0x02
+ x = x + 1 xpoints[x] = char(-dx)
+ elseif dx > 0 then
+ fl = fl + 0x12
+ x = x + 1 xpoints[x] = char(dx)
+ else
+ fl = fl + 0x02
+ x = x + 1 xpoints[x] = c_zero
+ end
+ end
+ if py == currenty then
+ fl = fl + 0x20
+ else
+ local dy = round(py - currenty)
+ if dy < -255 or dy > 255 then
+ y = y + 1 ypoints[y] = toshort(dy)
+ elseif dy < 0 then
+ fl = fl + 0x04
+ y = y + 1 ypoints[y] = char(-dy)
+ elseif dy > 0 then
+ fl = fl + 0x24
+ y = y + 1 ypoints[y] = char(dy)
else
- nofsegments = nofsegments + 1
- if not control_pt then
- segments[nofsegments] = { first_pt[1], first_pt[2], "l" } -- "lineto"
- elseif quadratic then
- segments[nofsegments] = { control_pt[1], control_pt[2], first_pt[1], first_pt[2], "q" } -- "quadraticto"
- else
- local p = last_pt local n = #p
- segments[nofsegments] = curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],first_pt[1],first_pt[2])
- end
+ fl = fl + 0x04
+ y = y + 1 ypoints[y] = c_zero
end
end
+ currentx = px
+ currenty = py
+ if lastflag == fl then
+ nofflags = nofflags + 1
+ else -- if > 255
+ if nofflags == 1 then
+ r = r + 1 result[r] = char(lastflag)
+ elseif nofflags == 2 then
+ r = r + 1 result[r] = char(lastflag,lastflag)
+ elseif nofflags > 2 then
+ lastflag = lastflag + 0x08
+ r = r + 1 result[r] = char(lastflag,nofflags-1)
+ end
+ nofflags = 1
+ lastflag = fl
+ end
+ end
+ if nofflags == 1 then
+ r = r + 1 result[r] = char(lastflag)
+ elseif nofflags == 2 then
+ r = r + 1 result[r] = char(lastflag,lastflag)
+ elseif nofflags > 2 then
+ lastflag = lastflag + 0x08
+ r = r + 1 result[r] = char(lastflag,nofflags-1)
end
+ r = r + 1 result[r] = concat(xpoints)
+ r = r + 1 result[r] = concat(ypoints)
end
end
+ glyph.stream = concat(result,"",1,r)
+ else
+ -- fatal
end
end
end
-- end of converter
-local function readglyph(f,nofcontours)
- local points = { }
- local endpoints = { }
- local instructions = { }
- local flags = { }
+local function readglyph(f,nofcontours) -- read deltas here, saves space
+ local points = { }
+ local instructions = { }
+ local flags = { }
+ local contours = { } -- readintegertable(f,nofcontours,short)
for i=1,nofcontours do
- endpoints[i] = readshort(f) + 1
+ contours[i] = readshort(f) + 1
end
- local nofpoints = endpoints[nofcontours]
+ local nofpoints = contours[nofcontours]
local nofinstructions = readushort(f)
--- f:seek("set",f:seek()+nofinstructions)
skipbytes(f,nofinstructions)
-- because flags can repeat we don't know the amount ... in fact this is
-- not that efficient (small files but more mem)
@@ -238,7 +723,7 @@ local function readglyph(f,nofcontours)
while i <= nofpoints do
local flag = readbyte(f)
flags[i] = flag
- if bittest(flag,0x0008) then
+ if band(flag,0x08) ~= 0 then
for j=1,readbyte(f) do
i = i + 1
flags[i] = flag
@@ -251,8 +736,8 @@ local function readglyph(f,nofcontours)
local x = 0
for i=1,nofpoints do
local flag = flags[i]
- local short = bittest(flag,0x0002)
- local same = bittest(flag,0x0010)
+ local short = band(flag,0x02) ~= 0
+ local same = band(flag,0x10) ~= 0
if short then
if same then
x = x + readbyte(f)
@@ -264,13 +749,13 @@ local function readglyph(f,nofcontours)
else
x = x + readshort(f)
end
- points[i] = { x, y, bittest(flag,0x0001) }
+ points[i] = { x, 0, band(flag,0x01) ~= 0 }
end
local y = 0
for i=1,nofpoints do
local flag = flags[i]
- local short = bittest(flag,0x0004)
- local same = bittest(flag,0x0020)
+ local short = band(flag,0x04) ~= 0
+ local same = band(flag,0x20) ~= 0
if short then
if same then
y = y + readbyte(f)
@@ -284,17 +769,11 @@ local function readglyph(f,nofcontours)
end
points[i][2] = y
end
- -- we could integrate this if needed
- local first = 1
- for i=1,#endpoints do
- local last = endpoints[i]
- endpoints[i] = { unpack(points,first,last) }
- first = last + 1
- end
return {
- type = "glyph",
- -- points = points,
- contours = endpoints,
+ type = "glyph",
+ points = points,
+ contours = contours,
+ nofpoints = nofpoints,
}
end
@@ -305,19 +784,19 @@ local function readcomposite(f)
while true do
local flags = readushort(f)
local index = readushort(f)
- ----- f_words = bittest(flags,0x0001)
- local f_xyarg = bittest(flags,0x0002)
- ----- f_round = bittest(flags,0x0004+0x0002)
- ----- f_scale = bittest(flags,0x0008)
- ----- f_reserved = bittest(flags,0x0010)
- ----- f_more = bittest(flags,0x0020)
- ----- f_xyscale = bittest(flags,0x0040)
- ----- f_matrix = bittest(flags,0x0080)
- ----- f_instruct = bittest(flags,0x0100)
- ----- f_usemine = bittest(flags,0x0200)
- ----- f_overlap = bittest(flags,0x0400)
- local f_offset = bittest(flags,0x0800)
- ----- f_uoffset = bittest(flags,0x1000)
+ ----- f_words = band(flags,0x0001) ~= 0
+ local f_xyarg = band(flags,0x0002) ~= 0
+ ----- f_round = band(flags,0x0006) ~= 0 -- 2 + 4
+ ----- f_scale = band(flags,0x0008) ~= 0
+ ----- f_reserved = band(flags,0x0010) ~= 0
+ ----- f_more = band(flags,0x0020) ~= 0
+ ----- f_xyscale = band(flags,0x0040) ~= 0
+ ----- f_matrix = band(flags,0x0080) ~= 0
+ ----- f_instruct = band(flags,0x0100) ~= 0
+ ----- f_usemine = band(flags,0x0200) ~= 0
+ ----- f_overlap = band(flags,0x0400) ~= 0
+ local f_offset = band(flags,0x0800) ~= 0
+ ----- f_uoffset = band(flags,0x1000) ~= 0
local xscale = 1
local xrotate = 0
local yrotate = 0
@@ -327,7 +806,7 @@ local function readcomposite(f)
local base = false
local reference = false
if f_xyarg then
- if bittest(flags,0x0001) then -- f_words
+ if band(flags,0x0001) ~= 0 then -- f_words
xoffset = readshort(f)
yoffset = readshort(f)
else
@@ -335,7 +814,7 @@ local function readcomposite(f)
yoffset = readchar(f) -- signed byte, stupid name
end
else
- if bittest(flags,0x0001) then -- f_words
+ if band(flags,0x0001) ~= 0 then -- f_words
base = readshort(f)
reference = readshort(f)
else
@@ -343,21 +822,21 @@ local function readcomposite(f)
reference = readchar(f) -- signed byte, stupid name
end
end
- if bittest(flags,0x0008) then -- f_scale
+ if band(flags,0x0008) ~= 0 then -- f_scale
xscale = read2dot14(f)
yscale = xscale
if f_xyarg and f_offset then
xoffset = xoffset * xscale
yoffset = yoffset * yscale
end
- elseif bittest(flags,0x0040) then -- f_xyscale
+ elseif band(flags,0x0040) ~= 0 then -- f_xyscale
xscale = read2dot14(f)
yscale = read2dot14(f)
if f_xyarg and f_offset then
xoffset = xoffset * xscale
yoffset = yoffset * yscale
end
- elseif bittest(flags,0x0080) then -- f_matrix
+ elseif band(flags,0x0080) ~= 0 then -- f_matrix
xscale = read2dot14(f)
xrotate = read2dot14(f)
yrotate = read2dot14(f)
@@ -370,22 +849,22 @@ local function readcomposite(f)
nofcomponents = nofcomponents + 1
components[nofcomponents] = {
index = index,
- usemine = bittest(flags,0x0200), -- f_usemine
- round = bittest(flags,0x0006), -- f_round,
+ usemine = band(flags,0x0200) ~= 0, -- f_usemine
+ round = band(flags,0x0006) ~= 0, -- f_round,
base = base,
reference = reference,
matrix = { xscale, xrotate, yrotate, yscale, xoffset, yoffset },
}
- if bittest(flags,0x0100) then
+ if band(flags,0x0100) ~= 0 then
instructions = true
end
- if not bittest(flags,0x0020) then -- f_more
+ if not band(flags,0x0020) ~= 0 then -- f_more
break
end
end
return {
- type = "composite",
- components = components,
+ type = "composite",
+ components = components,
}
end
@@ -407,15 +886,13 @@ function readers.loca(f,fontdata,specification)
local locations = { }
setposition(f,datatable.offset)
if format == 1 then
- local nofglyphs = datatable.length/4 - 1
- -1
+ local nofglyphs = datatable.length/4 - 2
for i=0,nofglyphs do
locations[i] = offset + readulong(f)
end
fontdata.nofglyphs = nofglyphs
else
- local nofglyphs = datatable.length/2 - 1
- -1
+ local nofglyphs = datatable.length/2 - 2
for i=0,nofglyphs do
locations[i] = offset + readushort(f) * 2
end
@@ -427,54 +904,374 @@ function readers.loca(f,fontdata,specification)
end
function readers.glyf(f,fontdata,specification) -- part goes to cff module
- if specification.glyphs then
- local datatable = fontdata.tables.glyf
- if datatable then
- local locations = fontdata.locations
- if locations then
- local glyphs = fontdata.glyphs
- local nofglyphs = fontdata.nofglyphs
- local filesize = fontdata.filesize
- local nothing = { 0, 0, 0, 0 }
- local shapes = { }
- local loadshapes = specification.shapes
- for index=0,nofglyphs do
- local location = locations[index]
- if location >= filesize then
- report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
- fontdata.nofglyphs = index - 1
- fontdata.badfont = true
- break
- elseif location > 0 then
- setposition(f,location)
- local nofcontours = readshort(f)
- glyphs[index].boundingbox = {
- readshort(f), -- xmin
- readshort(f), -- ymin
- readshort(f), -- xmax
- readshort(f), -- ymax
- }
- if not loadshapes then
- -- save space
- elseif nofcontours == 0 then
- shapes[index] = readnothing(f,nofcontours)
- elseif nofcontours > 0 then
- shapes[index] = readglyph(f,nofcontours)
+ local tableoffset = gotodatatable(f,fontdata,"glyf",specification.glyphs)
+ if tableoffset then
+ local locations = fontdata.locations
+ if locations then
+ local glyphs = fontdata.glyphs
+ local nofglyphs = fontdata.nofglyphs
+ local filesize = fontdata.filesize
+ local nothing = { 0, 0, 0, 0 }
+ local shapes = { }
+ local loadshapes = specification.shapes or specification.instance
+ for index=0,nofglyphs do
+ local location = locations[index]
+ if location >= filesize then
+ report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
+ fontdata.nofglyphs = index - 1
+ fontdata.badfont = true
+ break
+ elseif location > 0 then
+ setposition(f,location)
+ local nofcontours = readshort(f)
+ glyphs[index].boundingbox = {
+ readshort(f), -- xmin
+ readshort(f), -- ymin
+ readshort(f), -- xmax
+ readshort(f), -- ymax
+ }
+ if not loadshapes then
+ -- save space
+ elseif nofcontours == 0 then
+ shapes[index] = readnothing(f,nofcontours)
+ elseif nofcontours > 0 then
+ shapes[index] = readglyph(f,nofcontours)
+ else
+ shapes[index] = readcomposite(f,nofcontours)
+ end
+ else
+ if loadshapes then
+ shapes[index] = { }
+ end
+ glyphs[index].boundingbox = nothing
+ end
+ end
+ if loadshapes then
+ if readers.gvar then
+ readers.gvar(f,fontdata,specification,glyphs,shapes)
+ end
+ mergecomposites(glyphs,shapes)
+ if specification.instance then
+ if specification.streams then
+ repackpoints(glyphs,shapes)
+ else
+ contours2outlines_shaped(glyphs,shapes,specification.shapes)
+ end
+ elseif specification.shapes then
+ contours2outlines_normal(glyphs,shapes)
+ end
+ end
+ end
+ end
+end
+
+-- gvar is a bit crazy format and one can really wonder if the bit-jugling obscurity
+-- is still needed in these days .. cff is much nicer with these blends while the ttf
+-- coding variant looks quite horrible
+
+local function readtuplerecord(f,nofaxis)
+ local record = { }
+ for i=1,nofaxis do
+ record[i] = read2dot14(f)
+ end
+ return record
+end
+
+-- (1) the first is a real point the rest deltas
+-- (2) points can be present more than once (multiple deltas then)
+
+local function readpoints(f)
+ local count = readbyte(f)
+ if count == 0 then
+ -- second byte not used, deltas for all point numbers
+ return nil, 0 -- todo
+ else
+ if count < 128 then
+ -- no second byte, use count
+ elseif band(count,0x80) ~= 0 then
+ count = band(count,0x7F) * 256 + readbyte(f)
+ else
+ -- bad news
+ end
+ local points = { }
+ local p = 0
+ local n = 1 -- indices
+ while p < count do
+ local control = readbyte(f)
+ local runreader = band(control,0x80) ~= 0 and readushort or readbyte
+ local runlength = band(control,0x7F)
+ for i=1,runlength+1 do
+ n = n + runreader(f)
+ p = p + 1
+ points[p] = n
+ end
+ end
+ return points, p
+ end
+end
+
+local function readdeltas(f,nofpoints)
+ local deltas = { }
+ local p = 0
+ local z = 0
+ while nofpoints > 0 do
+ local control = readbyte(f)
+if not control then
+ break
+end
+ local allzero = band(control,0x80) ~= 0
+ local runlength = band(control,0x3F) + 1
+ if allzero then
+ z = z + runlength
+ else
+ local runreader = band(control,0x40) ~= 0 and readshort or readinteger
+ if z > 0 then
+ for i=1,z do
+ p = p + 1
+ deltas[p] = 0
+ end
+ z = 0
+ end
+ for i=1,runlength do
+ p = p + 1
+ deltas[p] = runreader(f)
+ end
+ end
+ nofpoints = nofpoints - runlength
+ end
+ -- saves space
+-- if z > 0 then
+-- for i=1,z do
+-- p = p + 1
+-- deltas[p] = 0
+-- end
+-- end
+ if p > 0 then
+ -- forget about trailing zeros
+ return deltas
+ else
+ -- forget about all zeros
+ end
+end
+
+local function readdeltas(f,nofpoints)
+ local deltas = { }
+ local p = 0
+ while nofpoints > 0 do
+ local control = readbyte(f)
+ if control then
+ local allzero = band(control,0x80) ~= 0
+ local runlength = band(control,0x3F) + 1
+ if allzero then
+ for i=1,runlength do
+ p = p + 1
+ deltas[p] = 0
+ end
+ else
+ local runreader = band(control,0x40) ~= 0 and readshort or readinteger
+ for i=1,runlength do
+ p = p + 1
+ deltas[p] = runreader(f)
+ end
+ end
+ nofpoints = nofpoints - runlength
+ else
+ -- it happens
+ break
+ end
+ end
+ -- saves space
+ if p > 0 then
+ return deltas
+ else
+ -- forget about all zeros
+ end
+end
+
+function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
+ -- this is one of the messiest tables
+ local instance = specification.instance
+ if not instance then
+ return
+ end
+ local factors = specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset = gotodatatable(f,fontdata,"gvar",specification.variable or specification.shapes)
+ if tableoffset then
+ local version = readulong(f) -- 1.0
+ local nofaxis = readushort(f)
+ local noftuples = readushort(f)
+ local tupleoffset = tableoffset + readulong(f)
+ local nofglyphs = readushort(f)
+ local flags = readushort(f)
+ local dataoffset = tableoffset + readulong(f)
+ local data = { }
+ local tuples = { }
+ local glyphdata = fontdata.glyphs
+ local dowidth = not fontdata.variabledata.hvarwidths
+ -- there is one more offset (so that one can calculate the size i suppose)
+ -- so we could test for overflows but we simply assume sane font files
+ if band(flags,0x0001) ~= 0 then
+ for i=1,nofglyphs+1 do
+ data[i] = dataoffset + readulong(f)
+ end
+ else
+ for i=1,nofglyphs+1 do
+ data[i] = dataoffset + 2*readushort(f)
+ end
+ end
+ --
+ if noftuples > 0 then
+ setposition(f,tupleoffset)
+ for i=1,noftuples do
+ tuples[i] = readtuplerecord(f,nofaxis)
+ end
+ end
+ local nextoffset = false
+ local startoffset = data[1]
+ for i=1,nofglyphs do -- hm one more cf spec
+ nextoffset = data[i+1]
+ local glyph = glyphdata[i-1]
+ local name = trace_deltas and glyph.name
+ if startoffset == nextoffset then
+ if name then
+ report("no deltas for glyph %a",name)
+ end
+ else
+ local shape = shapedata[i-1] -- todo 0
+ if not shape then
+ if name then
+ report("no shape for glyph %a",name)
+ end
+ else
+ lastoffset = startoffset
+ setposition(f,startoffset)
+ local flags = readushort(f)
+ local count = band(flags,0x0FFF)
+ local offset = startoffset + readushort(f) -- to serialized
+ local deltas = { }
+ local allpoints = (shape.nofpoints or 0) -- + 1
+ local shared = false
+ local nofshared = 0
+ if band(flags,0x8000) ~= 0 then -- has shared points
+ -- go to the packed stream (get them once)
+ local current = getposition(f)
+ setposition(f,offset)
+ shared, nofshared = readpoints(f)
+ offset = getposition(f)
+ setposition(f,current)
+ -- and back to the table
+ end
+ for j=1,count do
+ local size = readushort(f) -- check
+ local flags = readushort(f)
+ local index = band(flags,0x0FFF)
+ local haspeak = band(flags,0x8000) ~= 0
+ local intermediate = band(flags,0x4000) ~= 0
+ local private = band(flags,0x2000) ~= 0
+ local peak = nil
+ local start = nil
+ local stop = nil
+ local xvalues = nil
+ local yvalues = nil
+ local points = shared -- we default to shared
+ local nofpoints = nofshared -- we default to shared
+ -- local advance = 4
+ if haspeak then
+ peak = readtuplerecord(f,nofaxis)
+ -- advance = advance + 2*nofaxis
else
- shapes[index] = readcomposite(f,nofcontours)
+ if index+1 > #tuples then
+ report("error, bad tuple index",index)
+ end
+ peak = tuples[index+1] -- hm, needs checking, only peak?
end
- else
- if loadshapes then
- shapes[index] = { }
+ if intermediate then
+ start = readtuplerecord(f,nofaxis)
+ stop = readtuplerecord(f,nofaxis)
+ -- advance = advance + 4*nofaxis
+ end
+ -- get the deltas
+ if size > 0 then
+ local current = getposition(f)
+ -- goto the packed stream
+ setposition(f,offset)
+ if private then
+ points, nofpoints = readpoints(f)
+ end -- else
+ if nofpoints == 0 then
+ nofpoints = allpoints + 4
+ end
+ if nofpoints > 0 then
+ -- a nice test is to do only one
+ xvalues = readdeltas(f,nofpoints)
+ yvalues = readdeltas(f,nofpoints)
+ end
+ -- resync offset
+ offset = offset + size
+ -- back to the table
+ setposition(f,current)
+ end
+ if not xvalues and not yvalues then
+ points = nil
+ end
+ local s = 1
+ for i=1,nofaxis do
+ local f = factors[i]
+ local peak = peak and peak [i] or 0
+ -- local start = start and start[i] or 0
+ -- local stop = stop and stop [i] or 0
+ local start = start and start[i] or (peak < 0 and peak or 0)
+ local stop = stop and stop [i] or (peak > 0 and peak or 0)
+ -- do we really need these tests ... can't we assume sane values
+ if start > peak or peak > stop then
+ -- * 1
+ elseif start < 0 and stop > 0 and peak ~= 0 then
+ -- * 1
+ elseif peak == 0 then
+ -- * 1
+ elseif f < start or f > stop then
+ -- * 0
+ s = 0
+ break
+ elseif f < peak then
+-- s = - s * (f - start) / (peak - start)
+ s = s * (f - start) / (peak - start)
+ elseif f > peak then
+ s = s * (stop - f) / (stop - peak)
+ else
+ -- * 1
+ end
+ end
+ if s == 0 then
+ if name then
+ report("no deltas applied for glyph %a",name)
+ end
+ else
+ deltas[#deltas+1] = {
+ factor = s,
+ points = points,
+ xvalues = xvalues,
+ yvalues = yvalues,
+ }
end
- glyphs[index].boundingbox = nothing
end
- end
- if loadshapes then
- mergecomposites(glyphs,shapes)
- contours2outlines(glyphs,shapes)
+ if shape.type == "glyph" then
+-- if glyph.name == "u1f31d" then
+-- if glyph.unicode == 127773 then
+-- inspect(deltas)
+-- end
+ applyaxis(glyph,shape,deltas,dowidth)
+ else
+ -- todo: args_are_xy_values mess .. i have to be really bored
+ -- and motivated to deal with it
+ shape.deltas = deltas
+ end
end
end
+ startoffset = nextoffset
end
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-vfc.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-vfc.lua
new file mode 100644
index 00000000000..3e48422d621
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-vfc.lua
@@ -0,0 +1,99 @@
+if not modules then modules = { } end modules ['font-vfc'] = {
+ version = 1.001,
+ comment = "companion to font-ini.mkiv and hand-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local select = select
+local insert = table.insert
+
+local fonts = fonts
+local helpers = fonts.helpers
+
+local setmetatableindex = table.setmetatableindex
+local makeweak = table.makeweak
+
+-- Helpers dealing with virtual fonts: beware, these are final values so
+-- don't change the content of tables gotten this way!
+
+local push = { "push" }
+local pop = { "pop" }
+local dummy = { "comment" }
+
+function helpers.prependcommands(commands,...)
+ insert(commands,1,push)
+ for i=select("#",...),1,-1 do
+ local s = select(i,...)
+ if s then
+ insert(commands,1,s)
+ end
+ end
+ insert(commands,pop)
+ return commands
+end
+
+function helpers.appendcommands(commands,...)
+ insert(commands,1,push)
+ insert(commands,pop)
+ for i=1,select("#",...) do
+ local s = select(i,...)
+ if s then
+ insert(commands,s)
+ end
+ end
+ return commands
+end
+
+-- todo: maybe weak
+-- todo: maybe indirect so that we can't change them
+
+local char = setmetatableindex(function(t,k)
+ -- local v = { "char", k }
+ local v = { "slot", 0, k }
+ t[k] = v
+ return v
+end)
+
+local right = setmetatableindex(function(t,k)
+ local v = { "right", k }
+ t[k] = v
+ return v
+end)
+
+local left = setmetatableindex(function(t,k)
+ local v = { "right", -k }
+ t[k] = v
+ return v
+end)
+
+local down = setmetatableindex(function(t,k)
+ local v = { "down", k }
+ t[k] = v
+ return v
+end)
+
+local up = setmetatableindex(function(t,k)
+ local v = { "down", -k }
+ t[k] = v
+ return v
+end)
+
+-- makeweak(char)
+-- makeweak(right)
+-- makeweak(left)
+-- makeweak(up)
+-- makeweak(down)
+
+helpers.commands = utilities.storage.allocate {
+ char = char,
+ right = right,
+ left = left,
+ down = down,
+ up = up,
+ push = push,
+ pop = pop,
+ dummy = dummy,
+}
+
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-def.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-def.lua
new file mode 100644
index 00000000000..883451fb5e6
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-def.lua
@@ -0,0 +1,98 @@
+if not modules then modules = { } end modules ['luatex-fonts-def'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ os.exit()
+end
+
+local fonts = fonts
+
+-- A bit of tuning for definitions.
+
+fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
+
+-- tricky: we sort of bypass the parser and directly feed all into
+-- the sub parser
+
+function fonts.definers.getspecification(str)
+ return "", str, "", ":", str
+end
+
+-- the generic name parser (different from context!)
+
+local list = { } -- we could pass Carg but let's keep the old one
+
+local function issome () list.lookup = 'name' end -- xetex mode prefers name (not in context!)
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function iskey (k,v) list[k] = v end
+local function istrue (s) list[s] = true end
+local function isfalse(s) list[s] = false end
+
+local P, S, R, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs
+
+local spaces = P(" ")^0
+local namespec = Cs((P("{")/"") * (1-S("}"))^0 * (P("}")/"") + (1-S("/:("))^0)
+local crapspec = spaces * P("/") * (((1-P(":"))^0)/iscrap) * spaces
+local filename_1 = P("file:")/isfile * (namespec/thename)
+local filename_2 = P("[") * P(true)/isfile * (((1-P("]"))^0)/thename) * P("]")
+local fontname_1 = P("name:")/isname * (namespec/thename)
+local fontname_2 = P(true)/issome * (namespec/thename)
+local sometext = R("az","AZ","09")^1
+local somekey = R("az","AZ","09")^1
+local somevalue = (P("{")/"")*(1-P("}"))^0*(P("}")/"") + (1-S(";"))^1
+local truevalue = P("+") * spaces * (sometext/istrue)
+local falsevalue = P("-") * spaces * (sometext/isfalse)
+local keyvalue = (C(somekey) * spaces * P("=") * spaces * C(somevalue))/iskey
+local somevalue = sometext/istrue
+local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim
+local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
+local options = P(":") * spaces * (P(";")^0 * option)^0
+
+local pattern = (filename_1 + filename_2 + fontname_1 + fontname_2)
+ * subvalue^0 * crapspec^0 * options^0
+
+function fonts.definers.analyze(str,size)
+ local specification = fonts.definers.makespecification(str,nil,nil,nil,":",nil,size)
+ list = { }
+ lpeg.match(pattern,str)
+ list.crap = nil
+ if list.name then
+ specification.name = list.name
+ list.name = nil
+ end
+ if list.lookup then
+ specification.lookup = list.lookup
+ list.lookup = nil
+ end
+ if list.sub then
+ specification.sub = list.sub
+ list.sub = nil
+ end
+ specification.features.normal = fonts.handlers.otf.features.normalize(list)
+ list = nil
+ return specification
+end
+
+function fonts.definers.applypostprocessors(tfmdata)
+ local postprocessors = tfmdata.postprocessors
+ if postprocessors then
+ for i=1,#postprocessors do
+ local extrahash = postprocessors[i](tfmdata) -- after scaling etc
+ if type(extrahash) == "string" and extrahash ~= "" then
+ -- e.g. a reencoding needs this
+ extrahash = string.gsub(lower(extrahash),"[^a-z]","-")
+ tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash)
+ end
+ end
+ end
+ return tfmdata
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-demo-vf-1.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-demo-vf-1.lua
deleted file mode 100644
index 793526f7be3..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-demo-vf-1.lua
+++ /dev/null
@@ -1,52 +0,0 @@
-if not modules then modules = { } end modules ['luatex-fonts-demo-vf-1'] = {
- version = 1.001,
- comment = "companion to luatex-*.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local identifiers = fonts.hashes.identifiers
-
-return function(specification)
- local f1, id1 = fonts.constructors.readanddefine('lmroman10-regular', specification.size)
- local f2, id2 = fonts.constructors.readanddefine('lmsans10-regular', specification.size)
- local f3, id3 = fonts.constructors.readanddefine('lmtypewriter10-regular',specification.size)
- if f1 and f2 and f3 then
- f1.properties.name = specification.name
- f1.properties.virtualized = true
- f1.fonts = {
- { id = id1 },
- { id = id2 },
- { id = id3 },
- }
- local color = { [0] =
- { "special", "pdf:0 g" },
- { "special", "pdf:1 0 0 rg" },
- { "special", "pdf:0 1 0 rg" },
- { "special", "pdf:0 0 1 rg" },
- { "special", "pdf:0 0 1 rg" },
- }
- local chars = {
- identifiers[id1].characters,
- identifiers[id2].characters,
- identifiers[id3].characters,
- }
- for u, v in next, f1.characters do
- local n = math.floor(math.random(1,3)+0.5)
- local c = chars[n][u] or v
- v.commands = {
- color[n],
- { 'slot', n, u },
- color[0],
- { 'nop' }
- }
- v.kerns = nil
- v.width = c.width
- v.height = c.height
- v.depth = c.depth
- v.italic = nil
- end
- end
- return f1
-end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-enc.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-enc.lua
index c076d59477d..2bc6b71bf49 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-enc.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-enc.lua
@@ -7,7 +7,6 @@ if not modules then modules = { } end modules ['luatex-font-enc'] = {
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
@@ -19,7 +18,7 @@ encodings.known = { }
setmetatable(encodings.agl, { __index = function(t,k)
if k == "unicodes" then
- texio.write(" <loading (extended) adobe glyph list>")
+ logs.report("fonts","loading (extended) adobe glyph list")
local unicodes = dofile(resolvers.findfile("font-age.lua"))
encodings.agl = { unicodes = unicodes }
return unicodes
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-ext.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-ext.lua
index 0b61e27fd67..aee43ec4b30 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-ext.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-ext.lua
@@ -7,88 +7,54 @@ if not modules then modules = { } end modules ['luatex-fonts-ext'] = {
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
-local fonts = fonts
-local otffeatures = fonts.constructors.features.otf
-
--- A few generic extensions.
+local byte = string.byte
-local function initializeitlc(tfmdata,value)
- if value then
- -- the magic 40 and it formula come from Dohyun Kim but we might need another guess
- local parameters = tfmdata.parameters
- local italicangle = parameters.italicangle
- if italicangle and italicangle ~= 0 then
- local properties = tfmdata.properties
- local factor = tonumber(value) or 1
- properties.hasitalics = true
- properties.autoitalicamount = factor * (parameters.uwidth or 40)/2
- end
- end
-end
+local fonts = fonts
+local handlers = fonts.handlers
+local otf = handlers.otf
+local afm = handlers.afm
+local registerotffeature = otf.features.register
+local registerafmfeature = afm.features.register
-otffeatures.register {
- name = "itlc",
- description = "italic correction",
- initializers = {
- base = initializeitlc,
- node = initializeitlc,
- }
-}
+-- extra generic stuff
--- slant and extend
+function fonts.loggers.onetimemessage() end
-local function initializeslant(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 1 then
- value = 1
- elseif value < -1 then
- value = -1
- end
- tfmdata.parameters.slantfactor = value
-end
+-- done elsewhere
+--
+-- loadmodule('font-ext-imp-italic.lua')
+-- loadmodule('font-ext-imp-effect.lua')
+-- loadmodule('luatex-fonts-lig.lua')
-otffeatures.register {
- name = "slant",
- description = "slant glyphs",
- initializers = {
- base = initializeslant,
- node = initializeslant,
- }
-}
+-- protrusion (simplified version)
-local function initializeextend(tfmdata,value)
- value = tonumber(value)
- if not value then
- value = 0
- elseif value > 10 then
- value = 10
- elseif value < -10 then
- value = -10
- end
- tfmdata.parameters.extendfactor = value
-end
+fonts.protrusions = fonts.protrusions or { }
+fonts.protrusions.setups = fonts.protrusions.setups or { }
+local setups = fonts.protrusions.setups
-otffeatures.register {
- name = "extend",
- description = "scale glyphs horizontally",
- initializers = {
- base = initializeextend,
- node = initializeextend,
- }
-}
+setups['default'] = { -- demo vector
--- expansion and protrusion
+ factor = 1,
+ left = 1,
+ right = 1,
-fonts.protrusions = fonts.protrusions or { }
-fonts.protrusions.setups = fonts.protrusions.setups or { }
+ [0x002C] = { 0, 1 }, -- comma
+ [0x002E] = { 0, 1 }, -- period
+ [0x003A] = { 0, 1 }, -- colon
+ [0x003B] = { 0, 1 }, -- semicolon
+ [0x002D] = { 0, 1 }, -- hyphen
+ [0x2013] = { 0, 0.50 }, -- endash
+ [0x2014] = { 0, 0.33 }, -- emdash
+ [0x3001] = { 0, 1 }, -- ideographic comma 、
+ [0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
-local setups = fonts.protrusions.setups
+}
local function initializeprotrusion(tfmdata,value)
if value then
@@ -111,7 +77,7 @@ local function initializeprotrusion(tfmdata,value)
end
end
-otffeatures.register {
+local specification = {
name = "protrusion",
description = "shift characters into the left and or right margin",
initializers = {
@@ -120,10 +86,32 @@ otffeatures.register {
}
}
-fonts.expansions = fonts.expansions or { }
-fonts.expansions.setups = fonts.expansions.setups or { }
+registerotffeature(specification)
+registerafmfeature(specification)
+
+-- expansion (simplified version)
+
+fonts.expansions = fonts.expansions or { }
+fonts.expansions.setups = fonts.expansions.setups or { }
+local setups = fonts.expansions.setups
-local setups = fonts.expansions.setups
+setups['default'] = { -- demo vector
+
+ stretch = 2,
+ shrink = 2,
+ step = .5,
+ factor = 1,
+
+ [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
+ [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
+ [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
+ [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
+ [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
+ [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
+ [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
+ [byte('w')] = 0.7, [byte('z')] = 0.7,
+ [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
+}
local function initializeexpansion(tfmdata,value)
if value then
@@ -148,7 +136,7 @@ local function initializeexpansion(tfmdata,value)
end
end
-otffeatures.register {
+local specification = {
name = "expansion",
description = "apply hz optimization",
initializers = {
@@ -157,55 +145,20 @@ otffeatures.register {
}
}
--- left over
-
-function fonts.loggers.onetimemessage() end
-
--- example vectors
-
-local byte = string.byte
+registerotffeature(specification)
+registerafmfeature(specification)
-fonts.expansions.setups['default'] = {
+-- normalizer (generic only)
- stretch = 2, shrink = 2, step = .5, factor = 1,
-
- [byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
- [byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
- [byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
- [byte('S')] = 0.7, [byte('U')] = 0.7, [byte('W')] = 0.7, [byte('Z')] = 0.7,
- [byte('a')] = 0.7, [byte('b')] = 0.7, [byte('c')] = 0.7, [byte('d')] = 0.7, [byte('e')] = 0.7,
- [byte('g')] = 0.7, [byte('h')] = 0.7, [byte('k')] = 0.7, [byte('m')] = 0.7, [byte('n')] = 0.7,
- [byte('o')] = 0.7, [byte('p')] = 0.7, [byte('q')] = 0.7, [byte('s')] = 0.7, [byte('u')] = 0.7,
- [byte('w')] = 0.7, [byte('z')] = 0.7,
- [byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
-}
+if not otf.features.normalize then
-fonts.protrusions.setups['default'] = {
-
- factor = 1, left = 1, right = 1,
-
- [0x002C] = { 0, 1 }, -- comma
- [0x002E] = { 0, 1 }, -- period
- [0x003A] = { 0, 1 }, -- colon
- [0x003B] = { 0, 1 }, -- semicolon
- [0x002D] = { 0, 1 }, -- hyphen
- [0x2013] = { 0, 0.50 }, -- endash
- [0x2014] = { 0, 0.33 }, -- emdash
- [0x3001] = { 0, 1 }, -- ideographic comma 、
- [0x3002] = { 0, 1 }, -- ideographic full stop 。
- [0x060C] = { 0, 1 }, -- arabic comma ،
- [0x061B] = { 0, 1 }, -- arabic semicolon ؛
- [0x06D4] = { 0, 1 }, -- arabic full stop ۔
-
-}
-
--- normalizer
-
-fonts.handlers.otf.features.normalize = function(t)
- if t.rand then
- t.rand = "random"
+ otf.features.normalize = function(t)
+ if t.rand then
+ t.rand = "random"
+ end
+ return t
end
- return t
+
end
-- bonus
@@ -229,6 +182,8 @@ end
-- [110] = 109, -- n
-- }
+-- reencoding (generic only)
+
fonts.encodings = fonts.encodings or { }
local reencodings = { }
fonts.encodings.reencodings = reencodings
@@ -253,7 +208,7 @@ local function specialreencode(tfmdata,value)
end
end
-local function reencode(tfmdata,value)
+local function initialize(tfmdata,value)
tfmdata.postprocessors = tfmdata.postprocessors or { }
table.insert(tfmdata.postprocessors,
function(tfmdata)
@@ -262,26 +217,28 @@ local function reencode(tfmdata,value)
)
end
-otffeatures.register {
+registerotffeature {
name = "reencode",
description = "reencode characters",
manipulators = {
- base = reencode,
- node = reencode,
+ base = initialize,
+ node = initialize,
}
}
-local function ignore(tfmdata,key,value)
+-- math stuff (generic only)
+
+local function initialize(tfmdata,key,value)
if value then
tfmdata.mathparameters = nil
end
end
-otffeatures.register {
+registerotffeature {
name = "ignoremathconstants",
description = "ignore math constants table",
initializers = {
- base = ignore,
- node = ignore,
+ base = initialize,
+ node = initialize,
}
}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-gbn.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-gbn.lua
index 21c6061542d..53be41c7ed4 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-gbn.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-gbn.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['font-gbn'] = {
+if not modules then modules = { } end modules ['luatex-fonts-gbn'] = {
version = 1.001,
comment = "companion to luatex-*.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -9,10 +9,11 @@ if not modules then modules = { } end modules ['font-gbn'] = {
-- generic [base|node] mode handler
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
+local next = next
+
local fonts = fonts
local nodes = nodes
@@ -37,7 +38,6 @@ local getdisc = nuts.getdisc
local setchar = nuts.setchar
local setlink = nuts.setlink
local setprev = nuts.setprev
-local nodetail = nuts.tail
-- from now on we apply ligaturing and kerning here because it might interfere with complex
-- opentype discretionary handling where the base ligature pass expect some weird extra
@@ -46,13 +46,13 @@ local nodetail = nuts.tail
local n_ligaturing = node.ligaturing
local n_kerning = node.kerning
-local ligaturing = nuts.ligaturing
-local kerning = nuts.kerning
+local d_ligaturing = nuts.ligaturing
+local d_kerning = nuts.kerning
local basemodepass = true
-local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning = nil end
-local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning = nil end
+local function l_warning() logs.report("fonts","don't call 'node.ligaturing' directly") l_warning = nil end
+local function k_warning() logs.report("fonts","don't call 'node.kerning' directly") k_warning = nil end
function node.ligaturing(...)
if basemodepass and l_warning then
@@ -68,21 +68,38 @@ function node.kerning(...)
return n_kerning(...)
end
+function nuts.ligaturing(...)
+ if basemodepass and l_warning then
+ l_warning()
+ end
+ return d_ligaturing(...)
+end
+
+function nuts.kerning(...)
+ if basemodepass and k_warning then
+ k_warning()
+ end
+ return d_kerning(...)
+end
+
+-- direct.ligaturing = nuts.ligaturing
+-- direct.kerning = nuts.kerning
+
function nodes.handlers.setbasemodepass(v)
basemodepass = v
end
-function nodes.handlers.nodepass(head)
+local function nodepass(head,groupcode,size,packtype,direction)
local fontdata = fonts.hashes.identifiers
if fontdata then
- local nuthead = tonut(head)
local usedfonts = { }
local basefonts = { }
local prevfont = nil
local basefont = nil
local variants = nil
local redundant = nil
- for n in traverse_id(glyph_code,nuthead) do
+ local nofused = 0
+ for n in traverse_id(glyph_code,head) do
local font = getfont(n)
if font ~= prevfont then
if basefont then
@@ -98,6 +115,7 @@ function nodes.handlers.nodepass(head)
local processors = shared.processes
if processors and #processors > 0 then
usedfonts[font] = processors
+ nofused = nofused + 1
elseif basemodepass then
basefont = { n, nil }
basefonts[#basefonts+1] = basefont
@@ -118,7 +136,7 @@ function nodes.handlers.nodepass(head)
end
if variants then
local char = getchar(n)
- if char >= 0xFE00 and (char <= 0xFE0F or (char >= 0xE0100 and char <= 0xE01EF)) then
+ if (char >= 0xFE00 and char <= 0xFE0F) or (char >= 0xE0100 and char <= 0xE01EF) then
local hash = variants[char]
if hash then
local p = getprev(n)
@@ -143,8 +161,8 @@ function nodes.handlers.nodepass(head)
for i=1,#redundant do
local r = redundant[i]
local p, n = getboth(r)
- if r == nuthead then
- nuthead = n
+ if r == head then
+ head = n
setprev(n)
else
setlink(p,n)
@@ -163,7 +181,7 @@ function nodes.handlers.nodepass(head)
flush_node(r)
end
end
- for d in traverse_id(disc_code,nuthead) do
+ for d in traverse_id(disc_code,head) do
local _, _, r = getdisc(d)
if r then
for n in traverse_id(glyph_code,r) do
@@ -179,6 +197,7 @@ function nodes.handlers.nodepass(head)
local processors = shared.processes
if processors and #processors > 0 then
usedfonts[font] = processors
+ nofused = nofused + 1
end
end
end
@@ -190,7 +209,7 @@ function nodes.handlers.nodepass(head)
if next(usedfonts) then
for font, processors in next, usedfonts do
for i=1,#processors do
- head = processors[i](head,font,0) or head
+ head = processors[i](head,font,0,direction,nofused) or head
end
end
end
@@ -200,52 +219,82 @@ function nodes.handlers.nodepass(head)
local start = range[1]
local stop = range[2]
if start then
- local front = nuthead == start
- if not stop then
- stop = nodetail(start)
- end
+ local front = head == start
+ local prev, next
if stop then
- start, stop = ligaturing(start,stop)
- start, stop = kerning(start,stop)
- elseif start then -- safeguard
- start, stop = ligaturing(start,stop)
- start, stop = kerning(start,stop)
+ next = getnext(stop)
+ start, stop = d_ligaturing(start,stop)
+ start, stop = d_kerning(start,stop)
+ else
+ prev = getprev(start)
+ start = d_ligaturing(start)
+ start = d_kerning(start)
end
- if front and nuthead ~= start then
- head = tonode(start)
+ if prev then
+ setlink(prev,start)
+ end
+ if next then
+ setlink(stop,next)
+ end
+ if front and head ~= start then
+ head = start
end
end
end
end
- return head, true
- else
- return head, false
end
+ return head
end
-function nodes.handlers.basepass(head)
- if not basemodepass then
- head = n_ligaturing(head)
- head = n_kerning(head)
+local function basepass(head)
+ if basemodepass then
+ head = d_ligaturing(head)
+ head = d_kerning(head)
end
- return head, true
+ return head
end
-local nodepass = nodes.handlers.nodepass
-local basepass = nodes.handlers.basepass
+local protectpass = node.direct.protect_glyphs
local injectpass = nodes.injections.handler
-local protectpass = nodes.handlers.protectglyphs
-function nodes.simple_font_handler(head)
+-- This is the only official public interface and this one can be hooked into a callback (chain) and
+-- everything else can change!@ Functione being visibel doesn't mean that it's part of the api.
+
+function nodes.handlers.nodepass(head,...)
+ if head then
+ return tonode(nodepass(tonut(head),...))
+ end
+end
+
+function nodes.handlers.basepass(head)
+ if head then
+ return tonode(basepass(tonut(head)))
+ end
+end
+
+function nodes.handlers.injectpass(head)
+ if head then
+ return tonode(injectpass(tonut(head)))
+ end
+end
+
+function nodes.handlers.protectpass(head)
+ if head then
+ protectpass(tonut(head))
+ return head
+ end
+end
+
+function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
if head then
- head = nodepass(head)
+ head = tonut(head)
+ head = nodepass(head,groupcode,size,packtype,direction)
head = injectpass(head)
if not basemodepass then
head = basepass(head)
end
protectpass(head)
- return head, true
- else
- return head, false
+ head = tonode(head)
end
+ return head
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-lig.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-lig.lua
new file mode 100644
index 00000000000..4ce1265338e
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-lig.lua
@@ -0,0 +1,2067 @@
+-- this file is generated by context
+
+fonts.handlers.otf.addfeature {
+ ["dataset"]={
+ {
+ ["data"]={
+ ["À"]={ "A", "̀" },
+ ["Á"]={ "A", "́" },
+ ["Â"]={ "A", "̂" },
+ ["Ã"]={ "A", "̃" },
+ ["Ä"]={ "A", "̈" },
+ ["Å"]={ "A", "̊" },
+ ["Ç"]={ "C", "̧" },
+ ["È"]={ "E", "̀" },
+ ["É"]={ "E", "́" },
+ ["Ê"]={ "E", "̂" },
+ ["Ë"]={ "E", "̈" },
+ ["Ì"]={ "I", "̀" },
+ ["Í"]={ "I", "́" },
+ ["Î"]={ "I", "̂" },
+ ["Ï"]={ "I", "̈" },
+ ["Ñ"]={ "N", "̃" },
+ ["Ò"]={ "O", "̀" },
+ ["Ó"]={ "O", "́" },
+ ["Ô"]={ "O", "̂" },
+ ["Õ"]={ "O", "̃" },
+ ["Ö"]={ "O", "̈" },
+ ["Ù"]={ "U", "̀" },
+ ["Ú"]={ "U", "́" },
+ ["Û"]={ "U", "̂" },
+ ["Ü"]={ "U", "̈" },
+ ["Ý"]={ "Y", "́" },
+ ["à"]={ "a", "̀" },
+ ["á"]={ "a", "́" },
+ ["â"]={ "a", "̂" },
+ ["ã"]={ "a", "̃" },
+ ["ä"]={ "a", "̈" },
+ ["å"]={ "a", "̊" },
+ ["ç"]={ "c", "̧" },
+ ["è"]={ "e", "̀" },
+ ["é"]={ "e", "́" },
+ ["ê"]={ "e", "̂" },
+ ["ë"]={ "e", "̈" },
+ ["ì"]={ "i", "̀" },
+ ["í"]={ "i", "́" },
+ ["î"]={ "i", "̂" },
+ ["ï"]={ "i", "̈" },
+ ["ñ"]={ "n", "̃" },
+ ["ò"]={ "o", "̀" },
+ ["ó"]={ "o", "́" },
+ ["ô"]={ "o", "̂" },
+ ["õ"]={ "o", "̃" },
+ ["ö"]={ "o", "̈" },
+ ["ù"]={ "u", "̀" },
+ ["ú"]={ "u", "́" },
+ ["û"]={ "u", "̂" },
+ ["ü"]={ "u", "̈" },
+ ["ý"]={ "y", "́" },
+ ["ÿ"]={ "y", "̈" },
+ ["Ā"]={ "A", "̄" },
+ ["ā"]={ "a", "̄" },
+ ["Ă"]={ "A", "̆" },
+ ["ă"]={ "a", "̆" },
+ ["Ą"]={ "A", "̨" },
+ ["ą"]={ "a", "̨" },
+ ["Ć"]={ "C", "́" },
+ ["ć"]={ "c", "́" },
+ ["Ĉ"]={ "C", "̂" },
+ ["ĉ"]={ "c", "̂" },
+ ["Ċ"]={ "C", "̇" },
+ ["ċ"]={ "c", "̇" },
+ ["Č"]={ "C", "̌" },
+ ["č"]={ "c", "̌" },
+ ["Ď"]={ "D", "̌" },
+ ["ď"]={ "d", "̌" },
+ ["Ē"]={ "E", "̄" },
+ ["ē"]={ "e", "̄" },
+ ["Ĕ"]={ "E", "̆" },
+ ["ĕ"]={ "e", "̆" },
+ ["Ė"]={ "E", "̇" },
+ ["ė"]={ "e", "̇" },
+ ["Ę"]={ "E", "̨" },
+ ["ę"]={ "e", "̨" },
+ ["Ě"]={ "E", "̌" },
+ ["ě"]={ "e", "̌" },
+ ["Ĝ"]={ "G", "̂" },
+ ["ĝ"]={ "g", "̂" },
+ ["Ğ"]={ "G", "̆" },
+ ["ğ"]={ "g", "̆" },
+ ["Ġ"]={ "G", "̇" },
+ ["ġ"]={ "g", "̇" },
+ ["Ģ"]={ "G", "̧" },
+ ["ģ"]={ "g", "̧" },
+ ["Ĥ"]={ "H", "̂" },
+ ["ĥ"]={ "h", "̂" },
+ ["Ĩ"]={ "I", "̃" },
+ ["ĩ"]={ "i", "̃" },
+ ["Ī"]={ "I", "̄" },
+ ["ī"]={ "i", "̄" },
+ ["Ĭ"]={ "I", "̆" },
+ ["ĭ"]={ "i", "̆" },
+ ["Į"]={ "I", "̨" },
+ ["į"]={ "i", "̨" },
+ ["İ"]={ "I", "̇" },
+ ["Ĵ"]={ "J", "̂" },
+ ["ĵ"]={ "j", "̂" },
+ ["Ķ"]={ "K", "̧" },
+ ["ķ"]={ "k", "̧" },
+ ["Ĺ"]={ "L", "́" },
+ ["ĺ"]={ "l", "́" },
+ ["Ļ"]={ "L", "̧" },
+ ["ļ"]={ "l", "̧" },
+ ["Ľ"]={ "L", "̌" },
+ ["ľ"]={ "l", "̌" },
+ ["Ń"]={ "N", "́" },
+ ["ń"]={ "n", "́" },
+ ["Ņ"]={ "N", "̧" },
+ ["ņ"]={ "n", "̧" },
+ ["Ň"]={ "N", "̌" },
+ ["ň"]={ "n", "̌" },
+ ["Ō"]={ "O", "̄" },
+ ["ō"]={ "o", "̄" },
+ ["Ŏ"]={ "O", "̆" },
+ ["ŏ"]={ "o", "̆" },
+ ["Ő"]={ "O", "̋" },
+ ["ő"]={ "o", "̋" },
+ ["Ŕ"]={ "R", "́" },
+ ["ŕ"]={ "r", "́" },
+ ["Ŗ"]={ "R", "̧" },
+ ["ŗ"]={ "r", "̧" },
+ ["Ř"]={ "R", "̌" },
+ ["ř"]={ "r", "̌" },
+ ["Ś"]={ "S", "́" },
+ ["ś"]={ "s", "́" },
+ ["Ŝ"]={ "S", "̂" },
+ ["ŝ"]={ "s", "̂" },
+ ["Ş"]={ "S", "̧" },
+ ["ş"]={ "s", "̧" },
+ ["Š"]={ "S", "̌" },
+ ["š"]={ "s", "̌" },
+ ["Ţ"]={ "T", "̧" },
+ ["ţ"]={ "t", "̧" },
+ ["Ť"]={ "T", "̌" },
+ ["ť"]={ "t", "̌" },
+ ["Ũ"]={ "U", "̃" },
+ ["ũ"]={ "u", "̃" },
+ ["Ū"]={ "U", "̄" },
+ ["ū"]={ "u", "̄" },
+ ["Ŭ"]={ "U", "̆" },
+ ["ŭ"]={ "u", "̆" },
+ ["Ů"]={ "U", "̊" },
+ ["ů"]={ "u", "̊" },
+ ["Ű"]={ "U", "̋" },
+ ["ű"]={ "u", "̋" },
+ ["Ų"]={ "U", "̨" },
+ ["ų"]={ "u", "̨" },
+ ["Ŵ"]={ "W", "̂" },
+ ["ŵ"]={ "w", "̂" },
+ ["Ŷ"]={ "Y", "̂" },
+ ["ŷ"]={ "y", "̂" },
+ ["Ÿ"]={ "Y", "̈" },
+ ["Ź"]={ "Z", "́" },
+ ["ź"]={ "z", "́" },
+ ["Ż"]={ "Z", "̇" },
+ ["ż"]={ "z", "̇" },
+ ["Ž"]={ "Z", "̌" },
+ ["ž"]={ "z", "̌" },
+ ["Ơ"]={ "O", "̛" },
+ ["ơ"]={ "o", "̛" },
+ ["Ư"]={ "U", "̛" },
+ ["ư"]={ "u", "̛" },
+ ["Ǎ"]={ "A", "̌" },
+ ["ǎ"]={ "a", "̌" },
+ ["Ǐ"]={ "I", "̌" },
+ ["ǐ"]={ "i", "̌" },
+ ["Ǒ"]={ "O", "̌" },
+ ["ǒ"]={ "o", "̌" },
+ ["Ǔ"]={ "U", "̌" },
+ ["ǔ"]={ "u", "̌" },
+ ["Ǖ"]={ "Ü", "̄" },
+ ["ǖ"]={ "ü", "̄" },
+ ["Ǘ"]={ "Ü", "́" },
+ ["ǘ"]={ "ü", "́" },
+ ["Ǚ"]={ "Ü", "̌" },
+ ["ǚ"]={ "ü", "̌" },
+ ["Ǜ"]={ "Ü", "̀" },
+ ["ǜ"]={ "ü", "̀" },
+ ["Ǟ"]={ "Ä", "̄" },
+ ["ǟ"]={ "ä", "̄" },
+ ["Ǡ"]={ "Ȧ", "̄" },
+ ["ǡ"]={ "ȧ", "̄" },
+ ["Ǣ"]={ "Æ", "̄" },
+ ["ǣ"]={ "æ", "̄" },
+ ["Ǧ"]={ "G", "̌" },
+ ["ǧ"]={ "g", "̌" },
+ ["Ǩ"]={ "K", "̌" },
+ ["ǩ"]={ "k", "̌" },
+ ["Ǫ"]={ "O", "̨" },
+ ["ǫ"]={ "o", "̨" },
+ ["Ǭ"]={ "Ǫ", "̄" },
+ ["ǭ"]={ "ǫ", "̄" },
+ ["Ǯ"]={ "Ʒ", "̌" },
+ ["ǯ"]={ "ʒ", "̌" },
+ ["ǰ"]={ "j", "̌" },
+ ["Ǵ"]={ "G", "́" },
+ ["ǵ"]={ "g", "́" },
+ ["Ǹ"]={ "N", "̀" },
+ ["ǹ"]={ "n", "̀" },
+ ["Ǻ"]={ "Å", "́" },
+ ["ǻ"]={ "å", "́" },
+ ["Ǽ"]={ "Æ", "́" },
+ ["ǽ"]={ "æ", "́" },
+ ["Ǿ"]={ "Ø", "́" },
+ ["ǿ"]={ "ø", "́" },
+ ["Ȁ"]={ "A", "̏" },
+ ["ȁ"]={ "a", "̏" },
+ ["Ȃ"]={ "A", "̑" },
+ ["ȃ"]={ "a", "̑" },
+ ["Ȅ"]={ "E", "̏" },
+ ["ȅ"]={ "e", "̏" },
+ ["Ȇ"]={ "E", "̑" },
+ ["ȇ"]={ "e", "̑" },
+ ["Ȉ"]={ "I", "̏" },
+ ["ȉ"]={ "i", "̏" },
+ ["Ȋ"]={ "I", "̑" },
+ ["ȋ"]={ "i", "̑" },
+ ["Ȍ"]={ "O", "̏" },
+ ["ȍ"]={ "o", "̏" },
+ ["Ȏ"]={ "O", "̑" },
+ ["ȏ"]={ "o", "̑" },
+ ["Ȑ"]={ "R", "̏" },
+ ["ȑ"]={ "r", "̏" },
+ ["Ȓ"]={ "R", "̑" },
+ ["ȓ"]={ "r", "̑" },
+ ["Ȕ"]={ "U", "̏" },
+ ["ȕ"]={ "u", "̏" },
+ ["Ȗ"]={ "U", "̑" },
+ ["ȗ"]={ "u", "̑" },
+ ["Ș"]={ "S", "̦" },
+ ["ș"]={ "s", "̦" },
+ ["Ț"]={ "T", "̦" },
+ ["ț"]={ "t", "̦" },
+ ["Ȟ"]={ "H", "̌" },
+ ["ȟ"]={ "h", "̌" },
+ ["Ȧ"]={ "A", "̇" },
+ ["ȧ"]={ "a", "̇" },
+ ["Ȩ"]={ "E", "̧" },
+ ["ȩ"]={ "e", "̧" },
+ ["Ȫ"]={ "Ö", "̄" },
+ ["ȫ"]={ "ö", "̄" },
+ ["Ȭ"]={ "Õ", "̄" },
+ ["ȭ"]={ "õ", "̄" },
+ ["Ȯ"]={ "O", "̇" },
+ ["ȯ"]={ "o", "̇" },
+ ["Ȱ"]={ "Ȯ", "̄" },
+ ["ȱ"]={ "ȯ", "̄" },
+ ["Ȳ"]={ "Y", "̄" },
+ ["ȳ"]={ "y", "̄" },
+ ["̈́"]={ "̈", "́" },
+ ["΅"]={ "¨", "́" },
+ ["Ά"]={ "Α", "́" },
+ ["Έ"]={ "Ε", "́" },
+ ["Ή"]={ "Η", "́" },
+ ["Ί"]={ "Ι", "́" },
+ ["Ό"]={ "Ο", "́" },
+ ["Ύ"]={ "Υ", "́" },
+ ["Ώ"]={ "Ω", "́" },
+ ["ΐ"]={ "ϊ", "́" },
+ ["Ϊ"]={ "Ι", "̈" },
+ ["Ϋ"]={ "Υ", "̈" },
+ ["ά"]={ "α", "́" },
+ ["έ"]={ "ε", "́" },
+ ["ή"]={ "η", "́" },
+ ["ί"]={ "ι", "́" },
+ ["ΰ"]={ "ϋ", "́" },
+ ["ϊ"]={ "ι", "̈" },
+ ["ϋ"]={ "υ", "̈" },
+ ["ό"]={ "ο", "́" },
+ ["ύ"]={ "υ", "́" },
+ ["ώ"]={ "ω", "́" },
+ ["ϓ"]={ "ϒ", "́" },
+ ["ϔ"]={ "ϒ", "̈" },
+ ["Ѐ"]={ "Е", "̀" },
+ ["Ё"]={ "Е", "̈" },
+ ["Ѓ"]={ "Г", "́" },
+ ["Ї"]={ "І", "̈" },
+ ["Ќ"]={ "К", "́" },
+ ["Ѝ"]={ "И", "̀" },
+ ["Ў"]={ "У", "̆" },
+ ["Й"]={ "И", "̆" },
+ ["й"]={ "и", "̆" },
+ ["ѐ"]={ "е", "̀" },
+ ["ё"]={ "е", "̈" },
+ ["ѓ"]={ "г", "́" },
+ ["ї"]={ "і", "̈" },
+ ["ќ"]={ "к", "́" },
+ ["ѝ"]={ "и", "̀" },
+ ["ў"]={ "у", "̆" },
+ ["Ѷ"]={ "Ѵ", "̏" },
+ ["ѷ"]={ "ѵ", "̏" },
+ ["Ӂ"]={ "Ж", "̆" },
+ ["ӂ"]={ "ж", "̆" },
+ ["Ӑ"]={ "А", "̆" },
+ ["ӑ"]={ "а", "̆" },
+ ["Ӓ"]={ "А", "̈" },
+ ["ӓ"]={ "а", "̈" },
+ ["Ӗ"]={ "Е", "̆" },
+ ["ӗ"]={ "е", "̆" },
+ ["Ӛ"]={ "Ә", "̈" },
+ ["ӛ"]={ "ә", "̈" },
+ ["Ӝ"]={ "Ж", "̈" },
+ ["ӝ"]={ "ж", "̈" },
+ ["Ӟ"]={ "З", "̈" },
+ ["ӟ"]={ "з", "̈" },
+ ["Ӣ"]={ "И", "̄" },
+ ["ӣ"]={ "и", "̄" },
+ ["Ӥ"]={ "И", "̈" },
+ ["ӥ"]={ "и", "̈" },
+ ["Ӧ"]={ "О", "̈" },
+ ["ӧ"]={ "о", "̈" },
+ ["Ӫ"]={ "Ө", "̈" },
+ ["ӫ"]={ "ө", "̈" },
+ ["Ӭ"]={ "Э", "̈" },
+ ["ӭ"]={ "э", "̈" },
+ ["Ӯ"]={ "У", "̄" },
+ ["ӯ"]={ "у", "̄" },
+ ["Ӱ"]={ "У", "̈" },
+ ["ӱ"]={ "у", "̈" },
+ ["Ӳ"]={ "У", "̋" },
+ ["ӳ"]={ "у", "̋" },
+ ["Ӵ"]={ "Ч", "̈" },
+ ["ӵ"]={ "ч", "̈" },
+ ["Ӹ"]={ "Ы", "̈" },
+ ["ӹ"]={ "ы", "̈" },
+ ["آ"]={ "ا", "ٓ" },
+ ["أ"]={ "ا", "ٔ" },
+ ["ؤ"]={ "و", "ٔ" },
+ ["إ"]={ "ا", "ٕ" },
+ ["ئ"]={ "ي", "ٔ" },
+ ["ۀ"]={ "ە", "ٔ" },
+ ["ۂ"]={ "ہ", "ٔ" },
+ ["ۓ"]={ "ے", "ٔ" },
+ ["ऩ"]={ "न", "़" },
+ ["ऱ"]={ "र", "़" },
+ ["ऴ"]={ "ळ", "़" },
+ ["क़"]={ "क", "़" },
+ ["ख़"]={ "ख", "़" },
+ ["ग़"]={ "ग", "़" },
+ ["ज़"]={ "ज", "़" },
+ ["ड़"]={ "ड", "़" },
+ ["ढ़"]={ "ढ", "़" },
+ ["फ़"]={ "फ", "़" },
+ ["य़"]={ "य", "़" },
+ ["ো"]={ "ে", "া" },
+ ["ৌ"]={ "ে", "ৗ" },
+ ["ড়"]={ "ড", "়" },
+ ["ঢ়"]={ "ঢ", "়" },
+ ["য়"]={ "য", "়" },
+ ["ਲ਼"]={ "ਲ", "਼" },
+ ["ਸ਼"]={ "ਸ", "਼" },
+ ["ਖ਼"]={ "ਖ", "਼" },
+ ["ਗ਼"]={ "ਗ", "਼" },
+ ["ਜ਼"]={ "ਜ", "਼" },
+ ["ਫ਼"]={ "ਫ", "਼" },
+ ["ୈ"]={ "େ", "ୖ" },
+ ["ୋ"]={ "େ", "ା" },
+ ["ୌ"]={ "େ", "ୗ" },
+ ["ଡ଼"]={ "ଡ", "଼" },
+ ["ଢ଼"]={ "ଢ", "଼" },
+ ["ஔ"]={ "ஒ", "ௗ" },
+ ["ொ"]={ "ெ", "ா" },
+ ["ோ"]={ "ே", "ா" },
+ ["ௌ"]={ "ெ", "ௗ" },
+ ["ై"]={ "ె", "ౖ" },
+ ["ೀ"]={ "ಿ", "ೕ" },
+ ["ೇ"]={ "ೆ", "ೕ" },
+ ["ೈ"]={ "ೆ", "ೖ" },
+ ["ೊ"]={ "ೆ", "ೂ" },
+ ["ೋ"]={ "ೊ", "ೕ" },
+ ["ൊ"]={ "െ", "ാ" },
+ ["ോ"]={ "േ", "ാ" },
+ ["ൌ"]={ "െ", "ൗ" },
+ ["ේ"]={ "ෙ", "්" },
+ ["ො"]={ "ෙ", "ා" },
+ ["ෝ"]={ "ො", "්" },
+ ["ෞ"]={ "ෙ", "ෟ" },
+ ["གྷ"]={ "ག", "ྷ" },
+ ["ཌྷ"]={ "ཌ", "ྷ" },
+ ["དྷ"]={ "ད", "ྷ" },
+ ["བྷ"]={ "བ", "ྷ" },
+ ["ཛྷ"]={ "ཛ", "ྷ" },
+ ["ཀྵ"]={ "ཀ", "ྵ" },
+ ["ཱི"]={ "ཱ", "ི" },
+ ["ཱུ"]={ "ཱ", "ུ" },
+ ["ྲྀ"]={ "ྲ", "ྀ" },
+ ["ླྀ"]={ "ླ", "ྀ" },
+ ["ཱྀ"]={ "ཱ", "ྀ" },
+ ["ྒྷ"]={ "ྒ", "ྷ" },
+ ["ྜྷ"]={ "ྜ", "ྷ" },
+ ["ྡྷ"]={ "ྡ", "ྷ" },
+ ["ྦྷ"]={ "ྦ", "ྷ" },
+ ["ྫྷ"]={ "ྫ", "ྷ" },
+ ["ྐྵ"]={ "ྐ", "ྵ" },
+ ["ဦ"]={ "ဥ", "ီ" },
+ ["ᬆ"]={ "ᬅ", "ᬵ" },
+ ["ᬈ"]={ "ᬇ", "ᬵ" },
+ ["ᬊ"]={ "ᬉ", "ᬵ" },
+ ["ᬌ"]={ "ᬋ", "ᬵ" },
+ ["ᬎ"]={ "ᬍ", "ᬵ" },
+ ["ᬒ"]={ "ᬑ", "ᬵ" },
+ ["ᬻ"]={ "ᬺ", "ᬵ" },
+ ["ᬽ"]={ "ᬼ", "ᬵ" },
+ ["ᭀ"]={ "ᬾ", "ᬵ" },
+ ["ᭁ"]={ "ᬿ", "ᬵ" },
+ ["ᭃ"]={ "ᭂ", "ᬵ" },
+ ["Ḁ"]={ "A", "̥" },
+ ["ḁ"]={ "a", "̥" },
+ ["Ḃ"]={ "B", "̇" },
+ ["ḃ"]={ "b", "̇" },
+ ["Ḅ"]={ "B", "̣" },
+ ["ḅ"]={ "b", "̣" },
+ ["Ḇ"]={ "B", "̱" },
+ ["ḇ"]={ "b", "̱" },
+ ["Ḉ"]={ "Ç", "́" },
+ ["ḉ"]={ "ç", "́" },
+ ["Ḋ"]={ "D", "̇" },
+ ["ḋ"]={ "d", "̇" },
+ ["Ḍ"]={ "D", "̣" },
+ ["ḍ"]={ "d", "̣" },
+ ["Ḏ"]={ "D", "̱" },
+ ["ḏ"]={ "d", "̱" },
+ ["Ḑ"]={ "D", "̧" },
+ ["ḑ"]={ "d", "̧" },
+ ["Ḓ"]={ "D", "̭" },
+ ["ḓ"]={ "d", "̭" },
+ ["Ḕ"]={ "Ē", "̀" },
+ ["ḕ"]={ "ē", "̀" },
+ ["Ḗ"]={ "Ē", "́" },
+ ["ḗ"]={ "ē", "́" },
+ ["Ḙ"]={ "E", "̭" },
+ ["ḙ"]={ "e", "̭" },
+ ["Ḛ"]={ "E", "̰" },
+ ["ḛ"]={ "e", "̰" },
+ ["Ḝ"]={ "Ȩ", "̆" },
+ ["ḝ"]={ "ȩ", "̆" },
+ ["Ḟ"]={ "F", "̇" },
+ ["ḟ"]={ "f", "̇" },
+ ["Ḡ"]={ "G", "̄" },
+ ["ḡ"]={ "g", "̄" },
+ ["Ḣ"]={ "H", "̇" },
+ ["ḣ"]={ "h", "̇" },
+ ["Ḥ"]={ "H", "̣" },
+ ["ḥ"]={ "h", "̣" },
+ ["Ḧ"]={ "H", "̈" },
+ ["ḧ"]={ "h", "̈" },
+ ["Ḩ"]={ "H", "̧" },
+ ["ḩ"]={ "h", "̧" },
+ ["Ḫ"]={ "H", "̮" },
+ ["ḫ"]={ "h", "̮" },
+ ["Ḭ"]={ "I", "̰" },
+ ["ḭ"]={ "i", "̰" },
+ ["Ḯ"]={ "Ï", "́" },
+ ["ḯ"]={ "ï", "́" },
+ ["Ḱ"]={ "K", "́" },
+ ["ḱ"]={ "k", "́" },
+ ["Ḳ"]={ "K", "̣" },
+ ["ḳ"]={ "k", "̣" },
+ ["Ḵ"]={ "K", "̱" },
+ ["ḵ"]={ "k", "̱" },
+ ["Ḷ"]={ "L", "̣" },
+ ["ḷ"]={ "l", "̣" },
+ ["Ḹ"]={ "Ḷ", "̄" },
+ ["ḹ"]={ "ḷ", "̄" },
+ ["Ḻ"]={ "L", "̱" },
+ ["ḻ"]={ "l", "̱" },
+ ["Ḽ"]={ "L", "̭" },
+ ["ḽ"]={ "l", "̭" },
+ ["Ḿ"]={ "M", "́" },
+ ["ḿ"]={ "m", "́" },
+ ["Ṁ"]={ "M", "̇" },
+ ["ṁ"]={ "m", "̇" },
+ ["Ṃ"]={ "M", "̣" },
+ ["ṃ"]={ "m", "̣" },
+ ["Ṅ"]={ "N", "̇" },
+ ["ṅ"]={ "n", "̇" },
+ ["Ṇ"]={ "N", "̣" },
+ ["ṇ"]={ "n", "̣" },
+ ["Ṉ"]={ "N", "̱" },
+ ["ṉ"]={ "n", "̱" },
+ ["Ṋ"]={ "N", "̭" },
+ ["ṋ"]={ "n", "̭" },
+ ["Ṍ"]={ "Õ", "́" },
+ ["ṍ"]={ "õ", "́" },
+ ["Ṏ"]={ "Õ", "̈" },
+ ["ṏ"]={ "õ", "̈" },
+ ["Ṑ"]={ "Ō", "̀" },
+ ["ṑ"]={ "ō", "̀" },
+ ["Ṓ"]={ "Ō", "́" },
+ ["ṓ"]={ "ō", "́" },
+ ["Ṕ"]={ "P", "́" },
+ ["ṕ"]={ "p", "́" },
+ ["Ṗ"]={ "P", "̇" },
+ ["ṗ"]={ "p", "̇" },
+ ["Ṙ"]={ "R", "̇" },
+ ["ṙ"]={ "r", "̇" },
+ ["Ṛ"]={ "R", "̣" },
+ ["ṛ"]={ "r", "̣" },
+ ["Ṝ"]={ "Ṛ", "̄" },
+ ["ṝ"]={ "ṛ", "̄" },
+ ["Ṟ"]={ "R", "̱" },
+ ["ṟ"]={ "r", "̱" },
+ ["Ṡ"]={ "S", "̇" },
+ ["ṡ"]={ "s", "̇" },
+ ["Ṣ"]={ "S", "̣" },
+ ["ṣ"]={ "s", "̣" },
+ ["Ṥ"]={ "Ś", "̇" },
+ ["ṥ"]={ "ś", "̇" },
+ ["Ṧ"]={ "Š", "̇" },
+ ["ṧ"]={ "š", "̇" },
+ ["Ṩ"]={ "Ṣ", "̇" },
+ ["ṩ"]={ "ṣ", "̇" },
+ ["Ṫ"]={ "T", "̇" },
+ ["ṫ"]={ "t", "̇" },
+ ["Ṭ"]={ "T", "̣" },
+ ["ṭ"]={ "t", "̣" },
+ ["Ṯ"]={ "T", "̱" },
+ ["ṯ"]={ "t", "̱" },
+ ["Ṱ"]={ "T", "̭" },
+ ["ṱ"]={ "t", "̭" },
+ ["Ṳ"]={ "U", "̤" },
+ ["ṳ"]={ "u", "̤" },
+ ["Ṵ"]={ "U", "̰" },
+ ["ṵ"]={ "u", "̰" },
+ ["Ṷ"]={ "U", "̭" },
+ ["ṷ"]={ "u", "̭" },
+ ["Ṹ"]={ "Ũ", "́" },
+ ["ṹ"]={ "ũ", "́" },
+ ["Ṻ"]={ "Ū", "̈" },
+ ["ṻ"]={ "ū", "̈" },
+ ["Ṽ"]={ "V", "̃" },
+ ["ṽ"]={ "v", "̃" },
+ ["Ṿ"]={ "V", "̣" },
+ ["ṿ"]={ "v", "̣" },
+ ["Ẁ"]={ "W", "̀" },
+ ["ẁ"]={ "w", "̀" },
+ ["Ẃ"]={ "W", "́" },
+ ["ẃ"]={ "w", "́" },
+ ["Ẅ"]={ "W", "̈" },
+ ["ẅ"]={ "w", "̈" },
+ ["Ẇ"]={ "W", "̇" },
+ ["ẇ"]={ "w", "̇" },
+ ["Ẉ"]={ "W", "̣" },
+ ["ẉ"]={ "w", "̣" },
+ ["Ẋ"]={ "X", "̇" },
+ ["ẋ"]={ "x", "̇" },
+ ["Ẍ"]={ "X", "̈" },
+ ["ẍ"]={ "x", "̈" },
+ ["Ẏ"]={ "Y", "̇" },
+ ["ẏ"]={ "y", "̇" },
+ ["Ẑ"]={ "Z", "̂" },
+ ["ẑ"]={ "z", "̂" },
+ ["Ẓ"]={ "Z", "̣" },
+ ["ẓ"]={ "z", "̣" },
+ ["Ẕ"]={ "Z", "̱" },
+ ["ẕ"]={ "z", "̱" },
+ ["ẖ"]={ "h", "̱" },
+ ["ẗ"]={ "t", "̈" },
+ ["ẘ"]={ "w", "̊" },
+ ["ẙ"]={ "y", "̊" },
+ ["ẛ"]={ "ſ", "̇" },
+ ["Ạ"]={ "A", "̣" },
+ ["ạ"]={ "a", "̣" },
+ ["Ả"]={ "A", "̉" },
+ ["ả"]={ "a", "̉" },
+ ["Ấ"]={ "Â", "́" },
+ ["ấ"]={ "â", "́" },
+ ["Ầ"]={ "Â", "̀" },
+ ["ầ"]={ "â", "̀" },
+ ["Ẩ"]={ "Â", "̉" },
+ ["ẩ"]={ "â", "̉" },
+ ["Ẫ"]={ "Â", "̃" },
+ ["ẫ"]={ "â", "̃" },
+ ["Ậ"]={ "Ạ", "̂" },
+ ["ậ"]={ "ạ", "̂" },
+ ["Ắ"]={ "Ă", "́" },
+ ["ắ"]={ "ă", "́" },
+ ["Ằ"]={ "Ă", "̀" },
+ ["ằ"]={ "ă", "̀" },
+ ["Ẳ"]={ "Ă", "̉" },
+ ["ẳ"]={ "ă", "̉" },
+ ["Ẵ"]={ "Ă", "̃" },
+ ["ẵ"]={ "ă", "̃" },
+ ["Ặ"]={ "Ạ", "̆" },
+ ["ặ"]={ "ạ", "̆" },
+ ["Ẹ"]={ "E", "̣" },
+ ["ẹ"]={ "e", "̣" },
+ ["Ẻ"]={ "E", "̉" },
+ ["ẻ"]={ "e", "̉" },
+ ["Ẽ"]={ "E", "̃" },
+ ["ẽ"]={ "e", "̃" },
+ ["Ế"]={ "Ê", "́" },
+ ["ế"]={ "ê", "́" },
+ ["Ề"]={ "Ê", "̀" },
+ ["ề"]={ "ê", "̀" },
+ ["Ể"]={ "Ê", "̉" },
+ ["ể"]={ "ê", "̉" },
+ ["Ễ"]={ "Ê", "̃" },
+ ["ễ"]={ "ê", "̃" },
+ ["Ệ"]={ "Ẹ", "̂" },
+ ["ệ"]={ "ẹ", "̂" },
+ ["Ỉ"]={ "I", "̉" },
+ ["ỉ"]={ "i", "̉" },
+ ["Ị"]={ "I", "̣" },
+ ["ị"]={ "i", "̣" },
+ ["Ọ"]={ "O", "̣" },
+ ["ọ"]={ "o", "̣" },
+ ["Ỏ"]={ "O", "̉" },
+ ["ỏ"]={ "o", "̉" },
+ ["Ố"]={ "Ô", "́" },
+ ["ố"]={ "ô", "́" },
+ ["Ồ"]={ "Ô", "̀" },
+ ["ồ"]={ "ô", "̀" },
+ ["Ổ"]={ "Ô", "̉" },
+ ["ổ"]={ "ô", "̉" },
+ ["Ỗ"]={ "Ô", "̃" },
+ ["ỗ"]={ "ô", "̃" },
+ ["Ộ"]={ "Ọ", "̂" },
+ ["ộ"]={ "ọ", "̂" },
+ ["Ớ"]={ "Ơ", "́" },
+ ["ớ"]={ "ơ", "́" },
+ ["Ờ"]={ "Ơ", "̀" },
+ ["ờ"]={ "ơ", "̀" },
+ ["Ở"]={ "Ơ", "̉" },
+ ["ở"]={ "ơ", "̉" },
+ ["Ỡ"]={ "Ơ", "̃" },
+ ["ỡ"]={ "ơ", "̃" },
+ ["Ợ"]={ "Ơ", "̣" },
+ ["ợ"]={ "ơ", "̣" },
+ ["Ụ"]={ "U", "̣" },
+ ["ụ"]={ "u", "̣" },
+ ["Ủ"]={ "U", "̉" },
+ ["ủ"]={ "u", "̉" },
+ ["Ứ"]={ "Ư", "́" },
+ ["ứ"]={ "ư", "́" },
+ ["Ừ"]={ "Ư", "̀" },
+ ["ừ"]={ "ư", "̀" },
+ ["Ử"]={ "Ư", "̉" },
+ ["ử"]={ "ư", "̉" },
+ ["Ữ"]={ "Ư", "̃" },
+ ["ữ"]={ "ư", "̃" },
+ ["Ự"]={ "Ư", "̣" },
+ ["ự"]={ "ư", "̣" },
+ ["Ỳ"]={ "Y", "̀" },
+ ["ỳ"]={ "y", "̀" },
+ ["Ỵ"]={ "Y", "̣" },
+ ["ỵ"]={ "y", "̣" },
+ ["Ỷ"]={ "Y", "̉" },
+ ["ỷ"]={ "y", "̉" },
+ ["Ỹ"]={ "Y", "̃" },
+ ["ỹ"]={ "y", "̃" },
+ ["ἀ"]={ "α", "̓" },
+ ["ἁ"]={ "α", "̔" },
+ ["ἂ"]={ "ἀ", "̀" },
+ ["ἃ"]={ "ἁ", "̀" },
+ ["ἄ"]={ "ἀ", "́" },
+ ["ἅ"]={ "ἁ", "́" },
+ ["ἆ"]={ "ἀ", "͂" },
+ ["ἇ"]={ "ἁ", "͂" },
+ ["Ἀ"]={ "Α", "̓" },
+ ["Ἁ"]={ "Α", "̔" },
+ ["Ἂ"]={ "Ἀ", "̀" },
+ ["Ἃ"]={ "Ἁ", "̀" },
+ ["Ἄ"]={ "Ἀ", "́" },
+ ["Ἅ"]={ "Ἁ", "́" },
+ ["Ἆ"]={ "Ἀ", "͂" },
+ ["Ἇ"]={ "Ἁ", "͂" },
+ ["ἐ"]={ "ε", "̓" },
+ ["ἑ"]={ "ε", "̔" },
+ ["ἒ"]={ "ἐ", "̀" },
+ ["ἓ"]={ "ἑ", "̀" },
+ ["ἔ"]={ "ἐ", "́" },
+ ["ἕ"]={ "ἑ", "́" },
+ ["Ἐ"]={ "Ε", "̓" },
+ ["Ἑ"]={ "Ε", "̔" },
+ ["Ἒ"]={ "Ἐ", "̀" },
+ ["Ἓ"]={ "Ἑ", "̀" },
+ ["Ἔ"]={ "Ἐ", "́" },
+ ["Ἕ"]={ "Ἑ", "́" },
+ ["ἠ"]={ "η", "̓" },
+ ["ἡ"]={ "η", "̔" },
+ ["ἢ"]={ "ἠ", "̀" },
+ ["ἣ"]={ "ἡ", "̀" },
+ ["ἤ"]={ "ἠ", "́" },
+ ["ἥ"]={ "ἡ", "́" },
+ ["ἦ"]={ "ἠ", "͂" },
+ ["ἧ"]={ "ἡ", "͂" },
+ ["Ἠ"]={ "Η", "̓" },
+ ["Ἡ"]={ "Η", "̔" },
+ ["Ἢ"]={ "Ἠ", "̀" },
+ ["Ἣ"]={ "Ἡ", "̀" },
+ ["Ἤ"]={ "Ἠ", "́" },
+ ["Ἥ"]={ "Ἡ", "́" },
+ ["Ἦ"]={ "Ἠ", "͂" },
+ ["Ἧ"]={ "Ἡ", "͂" },
+ ["ἰ"]={ "ι", "̓" },
+ ["ἱ"]={ "ι", "̔" },
+ ["ἲ"]={ "ἰ", "̀" },
+ ["ἳ"]={ "ἱ", "̀" },
+ ["ἴ"]={ "ἰ", "́" },
+ ["ἵ"]={ "ἱ", "́" },
+ ["ἶ"]={ "ἰ", "͂" },
+ ["ἷ"]={ "ἱ", "͂" },
+ ["Ἰ"]={ "Ι", "̓" },
+ ["Ἱ"]={ "Ι", "̔" },
+ ["Ἲ"]={ "Ἰ", "̀" },
+ ["Ἳ"]={ "Ἱ", "̀" },
+ ["Ἴ"]={ "Ἰ", "́" },
+ ["Ἵ"]={ "Ἱ", "́" },
+ ["Ἶ"]={ "Ἰ", "͂" },
+ ["Ἷ"]={ "Ἱ", "͂" },
+ ["ὀ"]={ "ο", "̓" },
+ ["ὁ"]={ "ο", "̔" },
+ ["ὂ"]={ "ὀ", "̀" },
+ ["ὃ"]={ "ὁ", "̀" },
+ ["ὄ"]={ "ὀ", "́" },
+ ["ὅ"]={ "ὁ", "́" },
+ ["Ὀ"]={ "Ο", "̓" },
+ ["Ὁ"]={ "Ο", "̔" },
+ ["Ὂ"]={ "Ὀ", "̀" },
+ ["Ὃ"]={ "Ὁ", "̀" },
+ ["Ὄ"]={ "Ὀ", "́" },
+ ["Ὅ"]={ "Ὁ", "́" },
+ ["ὐ"]={ "υ", "̓" },
+ ["ὑ"]={ "υ", "̔" },
+ ["ὒ"]={ "ὐ", "̀" },
+ ["ὓ"]={ "ὑ", "̀" },
+ ["ὔ"]={ "ὐ", "́" },
+ ["ὕ"]={ "ὑ", "́" },
+ ["ὖ"]={ "ὐ", "͂" },
+ ["ὗ"]={ "ὑ", "͂" },
+ ["Ὑ"]={ "Υ", "̔" },
+ ["Ὓ"]={ "Ὑ", "̀" },
+ ["Ὕ"]={ "Ὑ", "́" },
+ ["Ὗ"]={ "Ὑ", "͂" },
+ ["ὠ"]={ "ω", "̓" },
+ ["ὡ"]={ "ω", "̔" },
+ ["ὢ"]={ "ὠ", "̀" },
+ ["ὣ"]={ "ὡ", "̀" },
+ ["ὤ"]={ "ὠ", "́" },
+ ["ὥ"]={ "ὡ", "́" },
+ ["ὦ"]={ "ὠ", "͂" },
+ ["ὧ"]={ "ὡ", "͂" },
+ ["Ὠ"]={ "Ω", "̓" },
+ ["Ὡ"]={ "Ω", "̔" },
+ ["Ὢ"]={ "Ὠ", "̀" },
+ ["Ὣ"]={ "Ὡ", "̀" },
+ ["Ὤ"]={ "Ὠ", "́" },
+ ["Ὥ"]={ "Ὡ", "́" },
+ ["Ὦ"]={ "Ὠ", "͂" },
+ ["Ὧ"]={ "Ὡ", "͂" },
+ ["ὰ"]={ "α", "̀" },
+ ["ὲ"]={ "ε", "̀" },
+ ["ὴ"]={ "η", "̀" },
+ ["ὶ"]={ "ι", "̀" },
+ ["ὸ"]={ "ο", "̀" },
+ ["ὺ"]={ "υ", "̀" },
+ ["ὼ"]={ "ω", "̀" },
+ ["ᾀ"]={ "ἀ", "ͅ" },
+ ["ᾁ"]={ "ἁ", "ͅ" },
+ ["ᾂ"]={ "ἂ", "ͅ" },
+ ["ᾃ"]={ "ἃ", "ͅ" },
+ ["ᾄ"]={ "ἄ", "ͅ" },
+ ["ᾅ"]={ "ἅ", "ͅ" },
+ ["ᾆ"]={ "ἆ", "ͅ" },
+ ["ᾇ"]={ "ἇ", "ͅ" },
+ ["ᾈ"]={ "Ἀ", "ͅ" },
+ ["ᾉ"]={ "Ἁ", "ͅ" },
+ ["ᾊ"]={ "Ἂ", "ͅ" },
+ ["ᾋ"]={ "Ἃ", "ͅ" },
+ ["ᾌ"]={ "Ἄ", "ͅ" },
+ ["ᾍ"]={ "Ἅ", "ͅ" },
+ ["ᾎ"]={ "Ἆ", "ͅ" },
+ ["ᾏ"]={ "Ἇ", "ͅ" },
+ ["ᾐ"]={ "ἠ", "ͅ" },
+ ["ᾑ"]={ "ἡ", "ͅ" },
+ ["ᾒ"]={ "ἢ", "ͅ" },
+ ["ᾓ"]={ "ἣ", "ͅ" },
+ ["ᾔ"]={ "ἤ", "ͅ" },
+ ["ᾕ"]={ "ἥ", "ͅ" },
+ ["ᾖ"]={ "ἦ", "ͅ" },
+ ["ᾗ"]={ "ἧ", "ͅ" },
+ ["ᾘ"]={ "Ἠ", "ͅ" },
+ ["ᾙ"]={ "Ἡ", "ͅ" },
+ ["ᾚ"]={ "Ἢ", "ͅ" },
+ ["ᾛ"]={ "Ἣ", "ͅ" },
+ ["ᾜ"]={ "Ἤ", "ͅ" },
+ ["ᾝ"]={ "Ἥ", "ͅ" },
+ ["ᾞ"]={ "Ἦ", "ͅ" },
+ ["ᾟ"]={ "Ἧ", "ͅ" },
+ ["ᾠ"]={ "ὠ", "ͅ" },
+ ["ᾡ"]={ "ὡ", "ͅ" },
+ ["ᾢ"]={ "ὢ", "ͅ" },
+ ["ᾣ"]={ "ὣ", "ͅ" },
+ ["ᾤ"]={ "ὤ", "ͅ" },
+ ["ᾥ"]={ "ὥ", "ͅ" },
+ ["ᾦ"]={ "ὦ", "ͅ" },
+ ["ᾧ"]={ "ὧ", "ͅ" },
+ ["ᾨ"]={ "Ὠ", "ͅ" },
+ ["ᾩ"]={ "Ὡ", "ͅ" },
+ ["ᾪ"]={ "Ὢ", "ͅ" },
+ ["ᾫ"]={ "Ὣ", "ͅ" },
+ ["ᾬ"]={ "Ὤ", "ͅ" },
+ ["ᾭ"]={ "Ὥ", "ͅ" },
+ ["ᾮ"]={ "Ὦ", "ͅ" },
+ ["ᾯ"]={ "Ὧ", "ͅ" },
+ ["ᾰ"]={ "α", "̆" },
+ ["ᾱ"]={ "α", "̄" },
+ ["ᾲ"]={ "ὰ", "ͅ" },
+ ["ᾳ"]={ "α", "ͅ" },
+ ["ᾴ"]={ "ά", "ͅ" },
+ ["ᾶ"]={ "α", "͂" },
+ ["ᾷ"]={ "ᾶ", "ͅ" },
+ ["Ᾰ"]={ "Α", "̆" },
+ ["Ᾱ"]={ "Α", "̄" },
+ ["Ὰ"]={ "Α", "̀" },
+ ["ᾼ"]={ "Α", "ͅ" },
+ ["῁"]={ "¨", "͂" },
+ ["ῂ"]={ "ὴ", "ͅ" },
+ ["ῃ"]={ "η", "ͅ" },
+ ["ῄ"]={ "ή", "ͅ" },
+ ["ῆ"]={ "η", "͂" },
+ ["ῇ"]={ "ῆ", "ͅ" },
+ ["Ὲ"]={ "Ε", "̀" },
+ ["Ὴ"]={ "Η", "̀" },
+ ["ῌ"]={ "Η", "ͅ" },
+ ["῍"]={ "᾿", "̀" },
+ ["῎"]={ "᾿", "́" },
+ ["῏"]={ "᾿", "͂" },
+ ["ῐ"]={ "ι", "̆" },
+ ["ῑ"]={ "ι", "̄" },
+ ["ῒ"]={ "ϊ", "̀" },
+ ["ῖ"]={ "ι", "͂" },
+ ["ῗ"]={ "ϊ", "͂" },
+ ["Ῐ"]={ "Ι", "̆" },
+ ["Ῑ"]={ "Ι", "̄" },
+ ["Ὶ"]={ "Ι", "̀" },
+ ["῝"]={ "῾", "̀" },
+ ["῞"]={ "῾", "́" },
+ ["῟"]={ "῾", "͂" },
+ ["ῠ"]={ "υ", "̆" },
+ ["ῡ"]={ "υ", "̄" },
+ ["ῢ"]={ "ϋ", "̀" },
+ ["ῤ"]={ "ρ", "̓" },
+ ["ῥ"]={ "ρ", "̔" },
+ ["ῦ"]={ "υ", "͂" },
+ ["ῧ"]={ "ϋ", "͂" },
+ ["Ῠ"]={ "Υ", "̆" },
+ ["Ῡ"]={ "Υ", "̄" },
+ ["Ὺ"]={ "Υ", "̀" },
+ ["Ῥ"]={ "Ρ", "̔" },
+ ["῭"]={ "¨", "̀" },
+ ["ῲ"]={ "ὼ", "ͅ" },
+ ["ῳ"]={ "ω", "ͅ" },
+ ["ῴ"]={ "ώ", "ͅ" },
+ ["ῶ"]={ "ω", "͂" },
+ ["ῷ"]={ "ῶ", "ͅ" },
+ ["Ὸ"]={ "Ο", "̀" },
+ ["Ὼ"]={ "Ω", "̀" },
+ ["ῼ"]={ "Ω", "ͅ" },
+ ["↚"]={ "←", "̸" },
+ ["↛"]={ "→", "̸" },
+ ["↮"]={ "↔", "̸" },
+ ["⇍"]={ "⇐", "̸" },
+ ["⇎"]={ "⇔", "̸" },
+ ["⇏"]={ "⇒", "̸" },
+ ["∄"]={ "∃", "̸" },
+ ["∉"]={ "∈", "̸" },
+ ["∌"]={ "∋", "̸" },
+ ["∤"]={ "∣", "̸" },
+ ["∦"]={ "∥", "̸" },
+ ["≁"]={ "∼", "̸" },
+ ["≄"]={ "≃", "̸" },
+ ["≇"]={ "≅", "̸" },
+ ["≉"]={ "≈", "̸" },
+ ["≠"]={ "=", "̸" },
+ ["≢"]={ "≡", "̸" },
+ ["≭"]={ "≍", "̸" },
+ ["≮"]={ "<", "̸" },
+ ["≯"]={ ">", "̸" },
+ ["≰"]={ "≤", "̸" },
+ ["≱"]={ "≥", "̸" },
+ ["≴"]={ "≲", "̸" },
+ ["≵"]={ "≳", "̸" },
+ ["≸"]={ "≶", "̸" },
+ ["≹"]={ "≷", "̸" },
+ ["⊀"]={ "≺", "̸" },
+ ["⊁"]={ "≻", "̸" },
+ ["⊄"]={ "⊂", "̸" },
+ ["⊅"]={ "⊃", "̸" },
+ ["⊈"]={ "⊆", "̸" },
+ ["⊉"]={ "⊇", "̸" },
+ ["⊬"]={ "⊢", "̸" },
+ ["⊭"]={ "⊨", "̸" },
+ ["⊮"]={ "⊩", "̸" },
+ ["⊯"]={ "⊫", "̸" },
+ ["⋠"]={ "≼", "̸" },
+ ["⋡"]={ "≽", "̸" },
+ ["⋢"]={ "⊑", "̸" },
+ ["⋣"]={ "⊒", "̸" },
+ ["⋪"]={ "⊲", "̸" },
+ ["⋫"]={ "⊳", "̸" },
+ ["⋬"]={ "⊴", "̸" },
+ ["⋭"]={ "⊵", "̸" },
+ ["⫝̸"]={ "⫝", "̸" },
+ ["が"]={ "か", "゙" },
+ ["ぎ"]={ "き", "゙" },
+ ["ぐ"]={ "く", "゙" },
+ ["げ"]={ "け", "゙" },
+ ["ご"]={ "こ", "゙" },
+ ["ざ"]={ "さ", "゙" },
+ ["じ"]={ "し", "゙" },
+ ["ず"]={ "す", "゙" },
+ ["ぜ"]={ "せ", "゙" },
+ ["ぞ"]={ "そ", "゙" },
+ ["だ"]={ "た", "゙" },
+ ["ぢ"]={ "ち", "゙" },
+ ["づ"]={ "つ", "゙" },
+ ["で"]={ "て", "゙" },
+ ["ど"]={ "と", "゙" },
+ ["ば"]={ "は", "゙" },
+ ["ぱ"]={ "は", "゚" },
+ ["び"]={ "ひ", "゙" },
+ ["ぴ"]={ "ひ", "゚" },
+ ["ぶ"]={ "ふ", "゙" },
+ ["ぷ"]={ "ふ", "゚" },
+ ["べ"]={ "へ", "゙" },
+ ["ぺ"]={ "へ", "゚" },
+ ["ぼ"]={ "ほ", "゙" },
+ ["ぽ"]={ "ほ", "゚" },
+ ["ゔ"]={ "う", "゙" },
+ ["ゞ"]={ "ゝ", "゙" },
+ ["ガ"]={ "カ", "゙" },
+ ["ギ"]={ "キ", "゙" },
+ ["グ"]={ "ク", "゙" },
+ ["ゲ"]={ "ケ", "゙" },
+ ["ゴ"]={ "コ", "゙" },
+ ["ザ"]={ "サ", "゙" },
+ ["ジ"]={ "シ", "゙" },
+ ["ズ"]={ "ス", "゙" },
+ ["ゼ"]={ "セ", "゙" },
+ ["ゾ"]={ "ソ", "゙" },
+ ["ダ"]={ "タ", "゙" },
+ ["ヂ"]={ "チ", "゙" },
+ ["ヅ"]={ "ツ", "゙" },
+ ["デ"]={ "テ", "゙" },
+ ["ド"]={ "ト", "゙" },
+ ["バ"]={ "ハ", "゙" },
+ ["パ"]={ "ハ", "゚" },
+ ["ビ"]={ "ヒ", "゙" },
+ ["ピ"]={ "ヒ", "゚" },
+ ["ブ"]={ "フ", "゙" },
+ ["プ"]={ "フ", "゚" },
+ ["ベ"]={ "ヘ", "゙" },
+ ["ペ"]={ "ヘ", "゚" },
+ ["ボ"]={ "ホ", "゙" },
+ ["ポ"]={ "ホ", "゚" },
+ ["ヴ"]={ "ウ", "゙" },
+ ["ヷ"]={ "ワ", "゙" },
+ ["ヸ"]={ "ヰ", "゙" },
+ ["ヹ"]={ "ヱ", "゙" },
+ ["ヺ"]={ "ヲ", "゙" },
+ ["ヾ"]={ "ヽ", "゙" },
+ ["יִ"]={ "י", "ִ" },
+ ["ײַ"]={ "ײ", "ַ" },
+ ["שׁ"]={ "ש", "ׁ" },
+ ["שׂ"]={ "ש", "ׂ" },
+ ["שּׁ"]={ "שּ", "ׁ" },
+ ["שּׂ"]={ "שּ", "ׂ" },
+ ["אַ"]={ "א", "ַ" },
+ ["אָ"]={ "א", "ָ" },
+ ["אּ"]={ "א", "ּ" },
+ ["בּ"]={ "ב", "ּ" },
+ ["גּ"]={ "ג", "ּ" },
+ ["דּ"]={ "ד", "ּ" },
+ ["הּ"]={ "ה", "ּ" },
+ ["וּ"]={ "ו", "ּ" },
+ ["זּ"]={ "ז", "ּ" },
+ ["טּ"]={ "ט", "ּ" },
+ ["יּ"]={ "י", "ּ" },
+ ["ךּ"]={ "ך", "ּ" },
+ ["כּ"]={ "כ", "ּ" },
+ ["לּ"]={ "ל", "ּ" },
+ ["מּ"]={ "מ", "ּ" },
+ ["נּ"]={ "נ", "ּ" },
+ ["סּ"]={ "ס", "ּ" },
+ ["ףּ"]={ "ף", "ּ" },
+ ["פּ"]={ "פ", "ּ" },
+ ["צּ"]={ "צ", "ּ" },
+ ["קּ"]={ "ק", "ּ" },
+ ["רּ"]={ "ר", "ּ" },
+ ["שּ"]={ "ש", "ּ" },
+ ["תּ"]={ "ת", "ּ" },
+ ["וֹ"]={ "ו", "ֹ" },
+ ["בֿ"]={ "ב", "ֿ" },
+ ["כֿ"]={ "כ", "ֿ" },
+ ["פֿ"]={ "פ", "ֿ" },
+ ["𑂚"]={ "𑂙", "𑂺" },
+ ["𑂜"]={ "𑂛", "𑂺" },
+ ["𑂫"]={ "𑂥", "𑂺" },
+ ["𑄮"]={ "𑄱", "𑄧" },
+ ["𑄯"]={ "𑄲", "𑄧" },
+ ["𑍋"]={ "𑍇", "𑌾" },
+ ["𑍌"]={ "𑍇", "𑍗" },
+ ["𑒻"]={ "𑒹", "𑒺" },
+ ["𑒼"]={ "𑒹", "𑒰" },
+ ["𑒾"]={ "𑒹", "𑒽" },
+ ["𑖺"]={ "𑖸", "𑖯" },
+ ["𑖻"]={ "𑖹", "𑖯" },
+ ["𝅗𝅥"]={ "𝅗", "𝅥" },
+ ["𝅘𝅥"]={ "𝅘", "𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥", "𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥", "𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥", "𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥", "𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥", "𝅲" },
+ ["𝆹𝅥"]={ "𝆹", "𝅥" },
+ ["𝆺𝅥"]={ "𝆺", "𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥", "𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥", "𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥", "𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥", "𝅯" },
+ },
+ },
+ {
+ ["data"]={
+ ["À"]={ "A", "̀" },
+ ["Á"]={ "A", "́" },
+ ["Â"]={ "A", "̂" },
+ ["Ã"]={ "A", "̃" },
+ ["Ä"]={ "A", "̈" },
+ ["Å"]={ "A", "̊" },
+ ["Ç"]={ "C", "̧" },
+ ["È"]={ "E", "̀" },
+ ["É"]={ "E", "́" },
+ ["Ê"]={ "E", "̂" },
+ ["Ë"]={ "E", "̈" },
+ ["Ì"]={ "I", "̀" },
+ ["Í"]={ "I", "́" },
+ ["Î"]={ "I", "̂" },
+ ["Ï"]={ "I", "̈" },
+ ["Ñ"]={ "N", "̃" },
+ ["Ò"]={ "O", "̀" },
+ ["Ó"]={ "O", "́" },
+ ["Ô"]={ "O", "̂" },
+ ["Õ"]={ "O", "̃" },
+ ["Ö"]={ "O", "̈" },
+ ["Ù"]={ "U", "̀" },
+ ["Ú"]={ "U", "́" },
+ ["Û"]={ "U", "̂" },
+ ["Ü"]={ "U", "̈" },
+ ["Ý"]={ "Y", "́" },
+ ["à"]={ "a", "̀" },
+ ["á"]={ "a", "́" },
+ ["â"]={ "a", "̂" },
+ ["ã"]={ "a", "̃" },
+ ["ä"]={ "a", "̈" },
+ ["å"]={ "a", "̊" },
+ ["ç"]={ "c", "̧" },
+ ["è"]={ "e", "̀" },
+ ["é"]={ "e", "́" },
+ ["ê"]={ "e", "̂" },
+ ["ë"]={ "e", "̈" },
+ ["ì"]={ "i", "̀" },
+ ["í"]={ "i", "́" },
+ ["î"]={ "i", "̂" },
+ ["ï"]={ "i", "̈" },
+ ["ñ"]={ "n", "̃" },
+ ["ò"]={ "o", "̀" },
+ ["ó"]={ "o", "́" },
+ ["ô"]={ "o", "̂" },
+ ["õ"]={ "o", "̃" },
+ ["ö"]={ "o", "̈" },
+ ["ù"]={ "u", "̀" },
+ ["ú"]={ "u", "́" },
+ ["û"]={ "u", "̂" },
+ ["ü"]={ "u", "̈" },
+ ["ý"]={ "y", "́" },
+ ["ÿ"]={ "y", "̈" },
+ ["Ā"]={ "A", "̄" },
+ ["ā"]={ "a", "̄" },
+ ["Ă"]={ "A", "̆" },
+ ["ă"]={ "a", "̆" },
+ ["Ą"]={ "A", "̨" },
+ ["ą"]={ "a", "̨" },
+ ["Ć"]={ "C", "́" },
+ ["ć"]={ "c", "́" },
+ ["Ĉ"]={ "C", "̂" },
+ ["ĉ"]={ "c", "̂" },
+ ["Ċ"]={ "C", "̇" },
+ ["ċ"]={ "c", "̇" },
+ ["Č"]={ "C", "̌" },
+ ["č"]={ "c", "̌" },
+ ["Ď"]={ "D", "̌" },
+ ["ď"]={ "d", "̌" },
+ ["Ē"]={ "E", "̄" },
+ ["ē"]={ "e", "̄" },
+ ["Ĕ"]={ "E", "̆" },
+ ["ĕ"]={ "e", "̆" },
+ ["Ė"]={ "E", "̇" },
+ ["ė"]={ "e", "̇" },
+ ["Ę"]={ "E", "̨" },
+ ["ę"]={ "e", "̨" },
+ ["Ě"]={ "E", "̌" },
+ ["ě"]={ "e", "̌" },
+ ["Ĝ"]={ "G", "̂" },
+ ["ĝ"]={ "g", "̂" },
+ ["Ğ"]={ "G", "̆" },
+ ["ğ"]={ "g", "̆" },
+ ["Ġ"]={ "G", "̇" },
+ ["ġ"]={ "g", "̇" },
+ ["Ģ"]={ "G", "̧" },
+ ["ģ"]={ "g", "̧" },
+ ["Ĥ"]={ "H", "̂" },
+ ["ĥ"]={ "h", "̂" },
+ ["Ĩ"]={ "I", "̃" },
+ ["ĩ"]={ "i", "̃" },
+ ["Ī"]={ "I", "̄" },
+ ["ī"]={ "i", "̄" },
+ ["Ĭ"]={ "I", "̆" },
+ ["ĭ"]={ "i", "̆" },
+ ["Į"]={ "I", "̨" },
+ ["į"]={ "i", "̨" },
+ ["İ"]={ "I", "̇" },
+ ["Ĵ"]={ "J", "̂" },
+ ["ĵ"]={ "j", "̂" },
+ ["Ķ"]={ "K", "̧" },
+ ["ķ"]={ "k", "̧" },
+ ["Ĺ"]={ "L", "́" },
+ ["ĺ"]={ "l", "́" },
+ ["Ļ"]={ "L", "̧" },
+ ["ļ"]={ "l", "̧" },
+ ["Ľ"]={ "L", "̌" },
+ ["ľ"]={ "l", "̌" },
+ ["Ń"]={ "N", "́" },
+ ["ń"]={ "n", "́" },
+ ["Ņ"]={ "N", "̧" },
+ ["ņ"]={ "n", "̧" },
+ ["Ň"]={ "N", "̌" },
+ ["ň"]={ "n", "̌" },
+ ["Ō"]={ "O", "̄" },
+ ["ō"]={ "o", "̄" },
+ ["Ŏ"]={ "O", "̆" },
+ ["ŏ"]={ "o", "̆" },
+ ["Ő"]={ "O", "̋" },
+ ["ő"]={ "o", "̋" },
+ ["Ŕ"]={ "R", "́" },
+ ["ŕ"]={ "r", "́" },
+ ["Ŗ"]={ "R", "̧" },
+ ["ŗ"]={ "r", "̧" },
+ ["Ř"]={ "R", "̌" },
+ ["ř"]={ "r", "̌" },
+ ["Ś"]={ "S", "́" },
+ ["ś"]={ "s", "́" },
+ ["Ŝ"]={ "S", "̂" },
+ ["ŝ"]={ "s", "̂" },
+ ["Ş"]={ "S", "̧" },
+ ["ş"]={ "s", "̧" },
+ ["Š"]={ "S", "̌" },
+ ["š"]={ "s", "̌" },
+ ["Ţ"]={ "T", "̧" },
+ ["ţ"]={ "t", "̧" },
+ ["Ť"]={ "T", "̌" },
+ ["ť"]={ "t", "̌" },
+ ["Ũ"]={ "U", "̃" },
+ ["ũ"]={ "u", "̃" },
+ ["Ū"]={ "U", "̄" },
+ ["ū"]={ "u", "̄" },
+ ["Ŭ"]={ "U", "̆" },
+ ["ŭ"]={ "u", "̆" },
+ ["Ů"]={ "U", "̊" },
+ ["ů"]={ "u", "̊" },
+ ["Ű"]={ "U", "̋" },
+ ["ű"]={ "u", "̋" },
+ ["Ų"]={ "U", "̨" },
+ ["ų"]={ "u", "̨" },
+ ["Ŵ"]={ "W", "̂" },
+ ["ŵ"]={ "w", "̂" },
+ ["Ŷ"]={ "Y", "̂" },
+ ["ŷ"]={ "y", "̂" },
+ ["Ÿ"]={ "Y", "̈" },
+ ["Ź"]={ "Z", "́" },
+ ["ź"]={ "z", "́" },
+ ["Ż"]={ "Z", "̇" },
+ ["ż"]={ "z", "̇" },
+ ["Ž"]={ "Z", "̌" },
+ ["ž"]={ "z", "̌" },
+ ["Ơ"]={ "O", "̛" },
+ ["ơ"]={ "o", "̛" },
+ ["Ư"]={ "U", "̛" },
+ ["ư"]={ "u", "̛" },
+ ["Ǎ"]={ "A", "̌" },
+ ["ǎ"]={ "a", "̌" },
+ ["Ǐ"]={ "I", "̌" },
+ ["ǐ"]={ "i", "̌" },
+ ["Ǒ"]={ "O", "̌" },
+ ["ǒ"]={ "o", "̌" },
+ ["Ǔ"]={ "U", "̌" },
+ ["ǔ"]={ "u", "̌" },
+ ["Ǖ"]={ "Ü", "̄" },
+ ["ǖ"]={ "ü", "̄" },
+ ["Ǘ"]={ "Ü", "́" },
+ ["ǘ"]={ "ü", "́" },
+ ["Ǚ"]={ "Ü", "̌" },
+ ["ǚ"]={ "ü", "̌" },
+ ["Ǜ"]={ "Ü", "̀" },
+ ["ǜ"]={ "ü", "̀" },
+ ["Ǟ"]={ "Ä", "̄" },
+ ["ǟ"]={ "ä", "̄" },
+ ["Ǡ"]={ "Ȧ", "̄" },
+ ["ǡ"]={ "ȧ", "̄" },
+ ["Ǣ"]={ "Æ", "̄" },
+ ["ǣ"]={ "æ", "̄" },
+ ["Ǧ"]={ "G", "̌" },
+ ["ǧ"]={ "g", "̌" },
+ ["Ǩ"]={ "K", "̌" },
+ ["ǩ"]={ "k", "̌" },
+ ["Ǫ"]={ "O", "̨" },
+ ["ǫ"]={ "o", "̨" },
+ ["Ǭ"]={ "Ǫ", "̄" },
+ ["ǭ"]={ "ǫ", "̄" },
+ ["Ǯ"]={ "Ʒ", "̌" },
+ ["ǯ"]={ "ʒ", "̌" },
+ ["ǰ"]={ "j", "̌" },
+ ["Ǵ"]={ "G", "́" },
+ ["ǵ"]={ "g", "́" },
+ ["Ǹ"]={ "N", "̀" },
+ ["ǹ"]={ "n", "̀" },
+ ["Ǻ"]={ "Å", "́" },
+ ["ǻ"]={ "å", "́" },
+ ["Ǽ"]={ "Æ", "́" },
+ ["ǽ"]={ "æ", "́" },
+ ["Ǿ"]={ "Ø", "́" },
+ ["ǿ"]={ "ø", "́" },
+ ["Ȁ"]={ "A", "̏" },
+ ["ȁ"]={ "a", "̏" },
+ ["Ȃ"]={ "A", "̑" },
+ ["ȃ"]={ "a", "̑" },
+ ["Ȅ"]={ "E", "̏" },
+ ["ȅ"]={ "e", "̏" },
+ ["Ȇ"]={ "E", "̑" },
+ ["ȇ"]={ "e", "̑" },
+ ["Ȉ"]={ "I", "̏" },
+ ["ȉ"]={ "i", "̏" },
+ ["Ȋ"]={ "I", "̑" },
+ ["ȋ"]={ "i", "̑" },
+ ["Ȍ"]={ "O", "̏" },
+ ["ȍ"]={ "o", "̏" },
+ ["Ȏ"]={ "O", "̑" },
+ ["ȏ"]={ "o", "̑" },
+ ["Ȑ"]={ "R", "̏" },
+ ["ȑ"]={ "r", "̏" },
+ ["Ȓ"]={ "R", "̑" },
+ ["ȓ"]={ "r", "̑" },
+ ["Ȕ"]={ "U", "̏" },
+ ["ȕ"]={ "u", "̏" },
+ ["Ȗ"]={ "U", "̑" },
+ ["ȗ"]={ "u", "̑" },
+ ["Ș"]={ "S", "̦" },
+ ["ș"]={ "s", "̦" },
+ ["Ț"]={ "T", "̦" },
+ ["ț"]={ "t", "̦" },
+ ["Ȟ"]={ "H", "̌" },
+ ["ȟ"]={ "h", "̌" },
+ ["Ȧ"]={ "A", "̇" },
+ ["ȧ"]={ "a", "̇" },
+ ["Ȩ"]={ "E", "̧" },
+ ["ȩ"]={ "e", "̧" },
+ ["Ȫ"]={ "Ö", "̄" },
+ ["ȫ"]={ "ö", "̄" },
+ ["Ȭ"]={ "Õ", "̄" },
+ ["ȭ"]={ "õ", "̄" },
+ ["Ȯ"]={ "O", "̇" },
+ ["ȯ"]={ "o", "̇" },
+ ["Ȱ"]={ "Ȯ", "̄" },
+ ["ȱ"]={ "ȯ", "̄" },
+ ["Ȳ"]={ "Y", "̄" },
+ ["ȳ"]={ "y", "̄" },
+ ["̈́"]={ "̈", "́" },
+ ["΅"]={ "¨", "́" },
+ ["Ά"]={ "Α", "́" },
+ ["Έ"]={ "Ε", "́" },
+ ["Ή"]={ "Η", "́" },
+ ["Ί"]={ "Ι", "́" },
+ ["Ό"]={ "Ο", "́" },
+ ["Ύ"]={ "Υ", "́" },
+ ["Ώ"]={ "Ω", "́" },
+ ["ΐ"]={ "ϊ", "́" },
+ ["Ϊ"]={ "Ι", "̈" },
+ ["Ϋ"]={ "Υ", "̈" },
+ ["ά"]={ "α", "́" },
+ ["έ"]={ "ε", "́" },
+ ["ή"]={ "η", "́" },
+ ["ί"]={ "ι", "́" },
+ ["ΰ"]={ "ϋ", "́" },
+ ["ϊ"]={ "ι", "̈" },
+ ["ϋ"]={ "υ", "̈" },
+ ["ό"]={ "ο", "́" },
+ ["ύ"]={ "υ", "́" },
+ ["ώ"]={ "ω", "́" },
+ ["ϓ"]={ "ϒ", "́" },
+ ["ϔ"]={ "ϒ", "̈" },
+ ["Ѐ"]={ "Е", "̀" },
+ ["Ё"]={ "Е", "̈" },
+ ["Ѓ"]={ "Г", "́" },
+ ["Ї"]={ "І", "̈" },
+ ["Ќ"]={ "К", "́" },
+ ["Ѝ"]={ "И", "̀" },
+ ["Ў"]={ "У", "̆" },
+ ["Й"]={ "И", "̆" },
+ ["й"]={ "и", "̆" },
+ ["ѐ"]={ "е", "̀" },
+ ["ё"]={ "е", "̈" },
+ ["ѓ"]={ "г", "́" },
+ ["ї"]={ "і", "̈" },
+ ["ќ"]={ "к", "́" },
+ ["ѝ"]={ "и", "̀" },
+ ["ў"]={ "у", "̆" },
+ ["Ѷ"]={ "Ѵ", "̏" },
+ ["ѷ"]={ "ѵ", "̏" },
+ ["Ӂ"]={ "Ж", "̆" },
+ ["ӂ"]={ "ж", "̆" },
+ ["Ӑ"]={ "А", "̆" },
+ ["ӑ"]={ "а", "̆" },
+ ["Ӓ"]={ "А", "̈" },
+ ["ӓ"]={ "а", "̈" },
+ ["Ӗ"]={ "Е", "̆" },
+ ["ӗ"]={ "е", "̆" },
+ ["Ӛ"]={ "Ә", "̈" },
+ ["ӛ"]={ "ә", "̈" },
+ ["Ӝ"]={ "Ж", "̈" },
+ ["ӝ"]={ "ж", "̈" },
+ ["Ӟ"]={ "З", "̈" },
+ ["ӟ"]={ "з", "̈" },
+ ["Ӣ"]={ "И", "̄" },
+ ["ӣ"]={ "и", "̄" },
+ ["Ӥ"]={ "И", "̈" },
+ ["ӥ"]={ "и", "̈" },
+ ["Ӧ"]={ "О", "̈" },
+ ["ӧ"]={ "о", "̈" },
+ ["Ӫ"]={ "Ө", "̈" },
+ ["ӫ"]={ "ө", "̈" },
+ ["Ӭ"]={ "Э", "̈" },
+ ["ӭ"]={ "э", "̈" },
+ ["Ӯ"]={ "У", "̄" },
+ ["ӯ"]={ "у", "̄" },
+ ["Ӱ"]={ "У", "̈" },
+ ["ӱ"]={ "у", "̈" },
+ ["Ӳ"]={ "У", "̋" },
+ ["ӳ"]={ "у", "̋" },
+ ["Ӵ"]={ "Ч", "̈" },
+ ["ӵ"]={ "ч", "̈" },
+ ["Ӹ"]={ "Ы", "̈" },
+ ["ӹ"]={ "ы", "̈" },
+ ["آ"]={ "ا", "ٓ" },
+ ["أ"]={ "ا", "ٔ" },
+ ["ؤ"]={ "و", "ٔ" },
+ ["إ"]={ "ا", "ٕ" },
+ ["ئ"]={ "ي", "ٔ" },
+ ["ۀ"]={ "ە", "ٔ" },
+ ["ۂ"]={ "ہ", "ٔ" },
+ ["ۓ"]={ "ے", "ٔ" },
+ ["ऩ"]={ "न", "़" },
+ ["ऱ"]={ "र", "़" },
+ ["ऴ"]={ "ळ", "़" },
+ ["क़"]={ "क", "़" },
+ ["ख़"]={ "ख", "़" },
+ ["ग़"]={ "ग", "़" },
+ ["ज़"]={ "ज", "़" },
+ ["ड़"]={ "ड", "़" },
+ ["ढ़"]={ "ढ", "़" },
+ ["फ़"]={ "फ", "़" },
+ ["य़"]={ "य", "़" },
+ ["ো"]={ "ে", "া" },
+ ["ৌ"]={ "ে", "ৗ" },
+ ["ড়"]={ "ড", "়" },
+ ["ঢ়"]={ "ঢ", "়" },
+ ["য়"]={ "য", "়" },
+ ["ਲ਼"]={ "ਲ", "਼" },
+ ["ਸ਼"]={ "ਸ", "਼" },
+ ["ਖ਼"]={ "ਖ", "਼" },
+ ["ਗ਼"]={ "ਗ", "਼" },
+ ["ਜ਼"]={ "ਜ", "਼" },
+ ["ਫ਼"]={ "ਫ", "਼" },
+ ["ୈ"]={ "େ", "ୖ" },
+ ["ୋ"]={ "େ", "ା" },
+ ["ୌ"]={ "େ", "ୗ" },
+ ["ଡ଼"]={ "ଡ", "଼" },
+ ["ଢ଼"]={ "ଢ", "଼" },
+ ["ஔ"]={ "ஒ", "ௗ" },
+ ["ொ"]={ "ெ", "ா" },
+ ["ோ"]={ "ே", "ா" },
+ ["ௌ"]={ "ெ", "ௗ" },
+ ["ై"]={ "ె", "ౖ" },
+ ["ೀ"]={ "ಿ", "ೕ" },
+ ["ೇ"]={ "ೆ", "ೕ" },
+ ["ೈ"]={ "ೆ", "ೖ" },
+ ["ೊ"]={ "ೆ", "ೂ" },
+ ["ೋ"]={ "ೊ", "ೕ" },
+ ["ൊ"]={ "െ", "ാ" },
+ ["ോ"]={ "േ", "ാ" },
+ ["ൌ"]={ "െ", "ൗ" },
+ ["ේ"]={ "ෙ", "්" },
+ ["ො"]={ "ෙ", "ා" },
+ ["ෝ"]={ "ො", "්" },
+ ["ෞ"]={ "ෙ", "ෟ" },
+ ["གྷ"]={ "ག", "ྷ" },
+ ["ཌྷ"]={ "ཌ", "ྷ" },
+ ["དྷ"]={ "ད", "ྷ" },
+ ["བྷ"]={ "བ", "ྷ" },
+ ["ཛྷ"]={ "ཛ", "ྷ" },
+ ["ཀྵ"]={ "ཀ", "ྵ" },
+ ["ཱི"]={ "ཱ", "ི" },
+ ["ཱུ"]={ "ཱ", "ུ" },
+ ["ྲྀ"]={ "ྲ", "ྀ" },
+ ["ླྀ"]={ "ླ", "ྀ" },
+ ["ཱྀ"]={ "ཱ", "ྀ" },
+ ["ྒྷ"]={ "ྒ", "ྷ" },
+ ["ྜྷ"]={ "ྜ", "ྷ" },
+ ["ྡྷ"]={ "ྡ", "ྷ" },
+ ["ྦྷ"]={ "ྦ", "ྷ" },
+ ["ྫྷ"]={ "ྫ", "ྷ" },
+ ["ྐྵ"]={ "ྐ", "ྵ" },
+ ["ဦ"]={ "ဥ", "ီ" },
+ ["ᬆ"]={ "ᬅ", "ᬵ" },
+ ["ᬈ"]={ "ᬇ", "ᬵ" },
+ ["ᬊ"]={ "ᬉ", "ᬵ" },
+ ["ᬌ"]={ "ᬋ", "ᬵ" },
+ ["ᬎ"]={ "ᬍ", "ᬵ" },
+ ["ᬒ"]={ "ᬑ", "ᬵ" },
+ ["ᬻ"]={ "ᬺ", "ᬵ" },
+ ["ᬽ"]={ "ᬼ", "ᬵ" },
+ ["ᭀ"]={ "ᬾ", "ᬵ" },
+ ["ᭁ"]={ "ᬿ", "ᬵ" },
+ ["ᭃ"]={ "ᭂ", "ᬵ" },
+ ["Ḁ"]={ "A", "̥" },
+ ["ḁ"]={ "a", "̥" },
+ ["Ḃ"]={ "B", "̇" },
+ ["ḃ"]={ "b", "̇" },
+ ["Ḅ"]={ "B", "̣" },
+ ["ḅ"]={ "b", "̣" },
+ ["Ḇ"]={ "B", "̱" },
+ ["ḇ"]={ "b", "̱" },
+ ["Ḉ"]={ "Ç", "́" },
+ ["ḉ"]={ "ç", "́" },
+ ["Ḋ"]={ "D", "̇" },
+ ["ḋ"]={ "d", "̇" },
+ ["Ḍ"]={ "D", "̣" },
+ ["ḍ"]={ "d", "̣" },
+ ["Ḏ"]={ "D", "̱" },
+ ["ḏ"]={ "d", "̱" },
+ ["Ḑ"]={ "D", "̧" },
+ ["ḑ"]={ "d", "̧" },
+ ["Ḓ"]={ "D", "̭" },
+ ["ḓ"]={ "d", "̭" },
+ ["Ḕ"]={ "Ē", "̀" },
+ ["ḕ"]={ "ē", "̀" },
+ ["Ḗ"]={ "Ē", "́" },
+ ["ḗ"]={ "ē", "́" },
+ ["Ḙ"]={ "E", "̭" },
+ ["ḙ"]={ "e", "̭" },
+ ["Ḛ"]={ "E", "̰" },
+ ["ḛ"]={ "e", "̰" },
+ ["Ḝ"]={ "Ȩ", "̆" },
+ ["ḝ"]={ "ȩ", "̆" },
+ ["Ḟ"]={ "F", "̇" },
+ ["ḟ"]={ "f", "̇" },
+ ["Ḡ"]={ "G", "̄" },
+ ["ḡ"]={ "g", "̄" },
+ ["Ḣ"]={ "H", "̇" },
+ ["ḣ"]={ "h", "̇" },
+ ["Ḥ"]={ "H", "̣" },
+ ["ḥ"]={ "h", "̣" },
+ ["Ḧ"]={ "H", "̈" },
+ ["ḧ"]={ "h", "̈" },
+ ["Ḩ"]={ "H", "̧" },
+ ["ḩ"]={ "h", "̧" },
+ ["Ḫ"]={ "H", "̮" },
+ ["ḫ"]={ "h", "̮" },
+ ["Ḭ"]={ "I", "̰" },
+ ["ḭ"]={ "i", "̰" },
+ ["Ḯ"]={ "Ï", "́" },
+ ["ḯ"]={ "ï", "́" },
+ ["Ḱ"]={ "K", "́" },
+ ["ḱ"]={ "k", "́" },
+ ["Ḳ"]={ "K", "̣" },
+ ["ḳ"]={ "k", "̣" },
+ ["Ḵ"]={ "K", "̱" },
+ ["ḵ"]={ "k", "̱" },
+ ["Ḷ"]={ "L", "̣" },
+ ["ḷ"]={ "l", "̣" },
+ ["Ḹ"]={ "Ḷ", "̄" },
+ ["ḹ"]={ "ḷ", "̄" },
+ ["Ḻ"]={ "L", "̱" },
+ ["ḻ"]={ "l", "̱" },
+ ["Ḽ"]={ "L", "̭" },
+ ["ḽ"]={ "l", "̭" },
+ ["Ḿ"]={ "M", "́" },
+ ["ḿ"]={ "m", "́" },
+ ["Ṁ"]={ "M", "̇" },
+ ["ṁ"]={ "m", "̇" },
+ ["Ṃ"]={ "M", "̣" },
+ ["ṃ"]={ "m", "̣" },
+ ["Ṅ"]={ "N", "̇" },
+ ["ṅ"]={ "n", "̇" },
+ ["Ṇ"]={ "N", "̣" },
+ ["ṇ"]={ "n", "̣" },
+ ["Ṉ"]={ "N", "̱" },
+ ["ṉ"]={ "n", "̱" },
+ ["Ṋ"]={ "N", "̭" },
+ ["ṋ"]={ "n", "̭" },
+ ["Ṍ"]={ "Õ", "́" },
+ ["ṍ"]={ "õ", "́" },
+ ["Ṏ"]={ "Õ", "̈" },
+ ["ṏ"]={ "õ", "̈" },
+ ["Ṑ"]={ "Ō", "̀" },
+ ["ṑ"]={ "ō", "̀" },
+ ["Ṓ"]={ "Ō", "́" },
+ ["ṓ"]={ "ō", "́" },
+ ["Ṕ"]={ "P", "́" },
+ ["ṕ"]={ "p", "́" },
+ ["Ṗ"]={ "P", "̇" },
+ ["ṗ"]={ "p", "̇" },
+ ["Ṙ"]={ "R", "̇" },
+ ["ṙ"]={ "r", "̇" },
+ ["Ṛ"]={ "R", "̣" },
+ ["ṛ"]={ "r", "̣" },
+ ["Ṝ"]={ "Ṛ", "̄" },
+ ["ṝ"]={ "ṛ", "̄" },
+ ["Ṟ"]={ "R", "̱" },
+ ["ṟ"]={ "r", "̱" },
+ ["Ṡ"]={ "S", "̇" },
+ ["ṡ"]={ "s", "̇" },
+ ["Ṣ"]={ "S", "̣" },
+ ["ṣ"]={ "s", "̣" },
+ ["Ṥ"]={ "Ś", "̇" },
+ ["ṥ"]={ "ś", "̇" },
+ ["Ṧ"]={ "Š", "̇" },
+ ["ṧ"]={ "š", "̇" },
+ ["Ṩ"]={ "Ṣ", "̇" },
+ ["ṩ"]={ "ṣ", "̇" },
+ ["Ṫ"]={ "T", "̇" },
+ ["ṫ"]={ "t", "̇" },
+ ["Ṭ"]={ "T", "̣" },
+ ["ṭ"]={ "t", "̣" },
+ ["Ṯ"]={ "T", "̱" },
+ ["ṯ"]={ "t", "̱" },
+ ["Ṱ"]={ "T", "̭" },
+ ["ṱ"]={ "t", "̭" },
+ ["Ṳ"]={ "U", "̤" },
+ ["ṳ"]={ "u", "̤" },
+ ["Ṵ"]={ "U", "̰" },
+ ["ṵ"]={ "u", "̰" },
+ ["Ṷ"]={ "U", "̭" },
+ ["ṷ"]={ "u", "̭" },
+ ["Ṹ"]={ "Ũ", "́" },
+ ["ṹ"]={ "ũ", "́" },
+ ["Ṻ"]={ "Ū", "̈" },
+ ["ṻ"]={ "ū", "̈" },
+ ["Ṽ"]={ "V", "̃" },
+ ["ṽ"]={ "v", "̃" },
+ ["Ṿ"]={ "V", "̣" },
+ ["ṿ"]={ "v", "̣" },
+ ["Ẁ"]={ "W", "̀" },
+ ["ẁ"]={ "w", "̀" },
+ ["Ẃ"]={ "W", "́" },
+ ["ẃ"]={ "w", "́" },
+ ["Ẅ"]={ "W", "̈" },
+ ["ẅ"]={ "w", "̈" },
+ ["Ẇ"]={ "W", "̇" },
+ ["ẇ"]={ "w", "̇" },
+ ["Ẉ"]={ "W", "̣" },
+ ["ẉ"]={ "w", "̣" },
+ ["Ẋ"]={ "X", "̇" },
+ ["ẋ"]={ "x", "̇" },
+ ["Ẍ"]={ "X", "̈" },
+ ["ẍ"]={ "x", "̈" },
+ ["Ẏ"]={ "Y", "̇" },
+ ["ẏ"]={ "y", "̇" },
+ ["Ẑ"]={ "Z", "̂" },
+ ["ẑ"]={ "z", "̂" },
+ ["Ẓ"]={ "Z", "̣" },
+ ["ẓ"]={ "z", "̣" },
+ ["Ẕ"]={ "Z", "̱" },
+ ["ẕ"]={ "z", "̱" },
+ ["ẖ"]={ "h", "̱" },
+ ["ẗ"]={ "t", "̈" },
+ ["ẘ"]={ "w", "̊" },
+ ["ẙ"]={ "y", "̊" },
+ ["ẛ"]={ "ſ", "̇" },
+ ["Ạ"]={ "A", "̣" },
+ ["ạ"]={ "a", "̣" },
+ ["Ả"]={ "A", "̉" },
+ ["ả"]={ "a", "̉" },
+ ["Ấ"]={ "Â", "́" },
+ ["ấ"]={ "â", "́" },
+ ["Ầ"]={ "Â", "̀" },
+ ["ầ"]={ "â", "̀" },
+ ["Ẩ"]={ "Â", "̉" },
+ ["ẩ"]={ "â", "̉" },
+ ["Ẫ"]={ "Â", "̃" },
+ ["ẫ"]={ "â", "̃" },
+ ["Ậ"]={ "Ạ", "̂" },
+ ["ậ"]={ "ạ", "̂" },
+ ["Ắ"]={ "Ă", "́" },
+ ["ắ"]={ "ă", "́" },
+ ["Ằ"]={ "Ă", "̀" },
+ ["ằ"]={ "ă", "̀" },
+ ["Ẳ"]={ "Ă", "̉" },
+ ["ẳ"]={ "ă", "̉" },
+ ["Ẵ"]={ "Ă", "̃" },
+ ["ẵ"]={ "ă", "̃" },
+ ["Ặ"]={ "Ạ", "̆" },
+ ["ặ"]={ "ạ", "̆" },
+ ["Ẹ"]={ "E", "̣" },
+ ["ẹ"]={ "e", "̣" },
+ ["Ẻ"]={ "E", "̉" },
+ ["ẻ"]={ "e", "̉" },
+ ["Ẽ"]={ "E", "̃" },
+ ["ẽ"]={ "e", "̃" },
+ ["Ế"]={ "Ê", "́" },
+ ["ế"]={ "ê", "́" },
+ ["Ề"]={ "Ê", "̀" },
+ ["ề"]={ "ê", "̀" },
+ ["Ể"]={ "Ê", "̉" },
+ ["ể"]={ "ê", "̉" },
+ ["Ễ"]={ "Ê", "̃" },
+ ["ễ"]={ "ê", "̃" },
+ ["Ệ"]={ "Ẹ", "̂" },
+ ["ệ"]={ "ẹ", "̂" },
+ ["Ỉ"]={ "I", "̉" },
+ ["ỉ"]={ "i", "̉" },
+ ["Ị"]={ "I", "̣" },
+ ["ị"]={ "i", "̣" },
+ ["Ọ"]={ "O", "̣" },
+ ["ọ"]={ "o", "̣" },
+ ["Ỏ"]={ "O", "̉" },
+ ["ỏ"]={ "o", "̉" },
+ ["Ố"]={ "Ô", "́" },
+ ["ố"]={ "ô", "́" },
+ ["Ồ"]={ "Ô", "̀" },
+ ["ồ"]={ "ô", "̀" },
+ ["Ổ"]={ "Ô", "̉" },
+ ["ổ"]={ "ô", "̉" },
+ ["Ỗ"]={ "Ô", "̃" },
+ ["ỗ"]={ "ô", "̃" },
+ ["Ộ"]={ "Ọ", "̂" },
+ ["ộ"]={ "ọ", "̂" },
+ ["Ớ"]={ "Ơ", "́" },
+ ["ớ"]={ "ơ", "́" },
+ ["Ờ"]={ "Ơ", "̀" },
+ ["ờ"]={ "ơ", "̀" },
+ ["Ở"]={ "Ơ", "̉" },
+ ["ở"]={ "ơ", "̉" },
+ ["Ỡ"]={ "Ơ", "̃" },
+ ["ỡ"]={ "ơ", "̃" },
+ ["Ợ"]={ "Ơ", "̣" },
+ ["ợ"]={ "ơ", "̣" },
+ ["Ụ"]={ "U", "̣" },
+ ["ụ"]={ "u", "̣" },
+ ["Ủ"]={ "U", "̉" },
+ ["ủ"]={ "u", "̉" },
+ ["Ứ"]={ "Ư", "́" },
+ ["ứ"]={ "ư", "́" },
+ ["Ừ"]={ "Ư", "̀" },
+ ["ừ"]={ "ư", "̀" },
+ ["Ử"]={ "Ư", "̉" },
+ ["ử"]={ "ư", "̉" },
+ ["Ữ"]={ "Ư", "̃" },
+ ["ữ"]={ "ư", "̃" },
+ ["Ự"]={ "Ư", "̣" },
+ ["ự"]={ "ư", "̣" },
+ ["Ỳ"]={ "Y", "̀" },
+ ["ỳ"]={ "y", "̀" },
+ ["Ỵ"]={ "Y", "̣" },
+ ["ỵ"]={ "y", "̣" },
+ ["Ỷ"]={ "Y", "̉" },
+ ["ỷ"]={ "y", "̉" },
+ ["Ỹ"]={ "Y", "̃" },
+ ["ỹ"]={ "y", "̃" },
+ ["ἀ"]={ "α", "̓" },
+ ["ἁ"]={ "α", "̔" },
+ ["ἂ"]={ "ἀ", "̀" },
+ ["ἃ"]={ "ἁ", "̀" },
+ ["ἄ"]={ "ἀ", "́" },
+ ["ἅ"]={ "ἁ", "́" },
+ ["ἆ"]={ "ἀ", "͂" },
+ ["ἇ"]={ "ἁ", "͂" },
+ ["Ἀ"]={ "Α", "̓" },
+ ["Ἁ"]={ "Α", "̔" },
+ ["Ἂ"]={ "Ἀ", "̀" },
+ ["Ἃ"]={ "Ἁ", "̀" },
+ ["Ἄ"]={ "Ἀ", "́" },
+ ["Ἅ"]={ "Ἁ", "́" },
+ ["Ἆ"]={ "Ἀ", "͂" },
+ ["Ἇ"]={ "Ἁ", "͂" },
+ ["ἐ"]={ "ε", "̓" },
+ ["ἑ"]={ "ε", "̔" },
+ ["ἒ"]={ "ἐ", "̀" },
+ ["ἓ"]={ "ἑ", "̀" },
+ ["ἔ"]={ "ἐ", "́" },
+ ["ἕ"]={ "ἑ", "́" },
+ ["Ἐ"]={ "Ε", "̓" },
+ ["Ἑ"]={ "Ε", "̔" },
+ ["Ἒ"]={ "Ἐ", "̀" },
+ ["Ἓ"]={ "Ἑ", "̀" },
+ ["Ἔ"]={ "Ἐ", "́" },
+ ["Ἕ"]={ "Ἑ", "́" },
+ ["ἠ"]={ "η", "̓" },
+ ["ἡ"]={ "η", "̔" },
+ ["ἢ"]={ "ἠ", "̀" },
+ ["ἣ"]={ "ἡ", "̀" },
+ ["ἤ"]={ "ἠ", "́" },
+ ["ἥ"]={ "ἡ", "́" },
+ ["ἦ"]={ "ἠ", "͂" },
+ ["ἧ"]={ "ἡ", "͂" },
+ ["Ἠ"]={ "Η", "̓" },
+ ["Ἡ"]={ "Η", "̔" },
+ ["Ἢ"]={ "Ἠ", "̀" },
+ ["Ἣ"]={ "Ἡ", "̀" },
+ ["Ἤ"]={ "Ἠ", "́" },
+ ["Ἥ"]={ "Ἡ", "́" },
+ ["Ἦ"]={ "Ἠ", "͂" },
+ ["Ἧ"]={ "Ἡ", "͂" },
+ ["ἰ"]={ "ι", "̓" },
+ ["ἱ"]={ "ι", "̔" },
+ ["ἲ"]={ "ἰ", "̀" },
+ ["ἳ"]={ "ἱ", "̀" },
+ ["ἴ"]={ "ἰ", "́" },
+ ["ἵ"]={ "ἱ", "́" },
+ ["ἶ"]={ "ἰ", "͂" },
+ ["ἷ"]={ "ἱ", "͂" },
+ ["Ἰ"]={ "Ι", "̓" },
+ ["Ἱ"]={ "Ι", "̔" },
+ ["Ἲ"]={ "Ἰ", "̀" },
+ ["Ἳ"]={ "Ἱ", "̀" },
+ ["Ἴ"]={ "Ἰ", "́" },
+ ["Ἵ"]={ "Ἱ", "́" },
+ ["Ἶ"]={ "Ἰ", "͂" },
+ ["Ἷ"]={ "Ἱ", "͂" },
+ ["ὀ"]={ "ο", "̓" },
+ ["ὁ"]={ "ο", "̔" },
+ ["ὂ"]={ "ὀ", "̀" },
+ ["ὃ"]={ "ὁ", "̀" },
+ ["ὄ"]={ "ὀ", "́" },
+ ["ὅ"]={ "ὁ", "́" },
+ ["Ὀ"]={ "Ο", "̓" },
+ ["Ὁ"]={ "Ο", "̔" },
+ ["Ὂ"]={ "Ὀ", "̀" },
+ ["Ὃ"]={ "Ὁ", "̀" },
+ ["Ὄ"]={ "Ὀ", "́" },
+ ["Ὅ"]={ "Ὁ", "́" },
+ ["ὐ"]={ "υ", "̓" },
+ ["ὑ"]={ "υ", "̔" },
+ ["ὒ"]={ "ὐ", "̀" },
+ ["ὓ"]={ "ὑ", "̀" },
+ ["ὔ"]={ "ὐ", "́" },
+ ["ὕ"]={ "ὑ", "́" },
+ ["ὖ"]={ "ὐ", "͂" },
+ ["ὗ"]={ "ὑ", "͂" },
+ ["Ὑ"]={ "Υ", "̔" },
+ ["Ὓ"]={ "Ὑ", "̀" },
+ ["Ὕ"]={ "Ὑ", "́" },
+ ["Ὗ"]={ "Ὑ", "͂" },
+ ["ὠ"]={ "ω", "̓" },
+ ["ὡ"]={ "ω", "̔" },
+ ["ὢ"]={ "ὠ", "̀" },
+ ["ὣ"]={ "ὡ", "̀" },
+ ["ὤ"]={ "ὠ", "́" },
+ ["ὥ"]={ "ὡ", "́" },
+ ["ὦ"]={ "ὠ", "͂" },
+ ["ὧ"]={ "ὡ", "͂" },
+ ["Ὠ"]={ "Ω", "̓" },
+ ["Ὡ"]={ "Ω", "̔" },
+ ["Ὢ"]={ "Ὠ", "̀" },
+ ["Ὣ"]={ "Ὡ", "̀" },
+ ["Ὤ"]={ "Ὠ", "́" },
+ ["Ὥ"]={ "Ὡ", "́" },
+ ["Ὦ"]={ "Ὠ", "͂" },
+ ["Ὧ"]={ "Ὡ", "͂" },
+ ["ὰ"]={ "α", "̀" },
+ ["ὲ"]={ "ε", "̀" },
+ ["ὴ"]={ "η", "̀" },
+ ["ὶ"]={ "ι", "̀" },
+ ["ὸ"]={ "ο", "̀" },
+ ["ὺ"]={ "υ", "̀" },
+ ["ὼ"]={ "ω", "̀" },
+ ["ᾀ"]={ "ἀ", "ͅ" },
+ ["ᾁ"]={ "ἁ", "ͅ" },
+ ["ᾂ"]={ "ἂ", "ͅ" },
+ ["ᾃ"]={ "ἃ", "ͅ" },
+ ["ᾄ"]={ "ἄ", "ͅ" },
+ ["ᾅ"]={ "ἅ", "ͅ" },
+ ["ᾆ"]={ "ἆ", "ͅ" },
+ ["ᾇ"]={ "ἇ", "ͅ" },
+ ["ᾈ"]={ "Ἀ", "ͅ" },
+ ["ᾉ"]={ "Ἁ", "ͅ" },
+ ["ᾊ"]={ "Ἂ", "ͅ" },
+ ["ᾋ"]={ "Ἃ", "ͅ" },
+ ["ᾌ"]={ "Ἄ", "ͅ" },
+ ["ᾍ"]={ "Ἅ", "ͅ" },
+ ["ᾎ"]={ "Ἆ", "ͅ" },
+ ["ᾏ"]={ "Ἇ", "ͅ" },
+ ["ᾐ"]={ "ἠ", "ͅ" },
+ ["ᾑ"]={ "ἡ", "ͅ" },
+ ["ᾒ"]={ "ἢ", "ͅ" },
+ ["ᾓ"]={ "ἣ", "ͅ" },
+ ["ᾔ"]={ "ἤ", "ͅ" },
+ ["ᾕ"]={ "ἥ", "ͅ" },
+ ["ᾖ"]={ "ἦ", "ͅ" },
+ ["ᾗ"]={ "ἧ", "ͅ" },
+ ["ᾘ"]={ "Ἠ", "ͅ" },
+ ["ᾙ"]={ "Ἡ", "ͅ" },
+ ["ᾚ"]={ "Ἢ", "ͅ" },
+ ["ᾛ"]={ "Ἣ", "ͅ" },
+ ["ᾜ"]={ "Ἤ", "ͅ" },
+ ["ᾝ"]={ "Ἥ", "ͅ" },
+ ["ᾞ"]={ "Ἦ", "ͅ" },
+ ["ᾟ"]={ "Ἧ", "ͅ" },
+ ["ᾠ"]={ "ὠ", "ͅ" },
+ ["ᾡ"]={ "ὡ", "ͅ" },
+ ["ᾢ"]={ "ὢ", "ͅ" },
+ ["ᾣ"]={ "ὣ", "ͅ" },
+ ["ᾤ"]={ "ὤ", "ͅ" },
+ ["ᾥ"]={ "ὥ", "ͅ" },
+ ["ᾦ"]={ "ὦ", "ͅ" },
+ ["ᾧ"]={ "ὧ", "ͅ" },
+ ["ᾨ"]={ "Ὠ", "ͅ" },
+ ["ᾩ"]={ "Ὡ", "ͅ" },
+ ["ᾪ"]={ "Ὢ", "ͅ" },
+ ["ᾫ"]={ "Ὣ", "ͅ" },
+ ["ᾬ"]={ "Ὤ", "ͅ" },
+ ["ᾭ"]={ "Ὥ", "ͅ" },
+ ["ᾮ"]={ "Ὦ", "ͅ" },
+ ["ᾯ"]={ "Ὧ", "ͅ" },
+ ["ᾰ"]={ "α", "̆" },
+ ["ᾱ"]={ "α", "̄" },
+ ["ᾲ"]={ "ὰ", "ͅ" },
+ ["ᾳ"]={ "α", "ͅ" },
+ ["ᾴ"]={ "ά", "ͅ" },
+ ["ᾶ"]={ "α", "͂" },
+ ["ᾷ"]={ "ᾶ", "ͅ" },
+ ["Ᾰ"]={ "Α", "̆" },
+ ["Ᾱ"]={ "Α", "̄" },
+ ["Ὰ"]={ "Α", "̀" },
+ ["ᾼ"]={ "Α", "ͅ" },
+ ["῁"]={ "¨", "͂" },
+ ["ῂ"]={ "ὴ", "ͅ" },
+ ["ῃ"]={ "η", "ͅ" },
+ ["ῄ"]={ "ή", "ͅ" },
+ ["ῆ"]={ "η", "͂" },
+ ["ῇ"]={ "ῆ", "ͅ" },
+ ["Ὲ"]={ "Ε", "̀" },
+ ["Ὴ"]={ "Η", "̀" },
+ ["ῌ"]={ "Η", "ͅ" },
+ ["῍"]={ "᾿", "̀" },
+ ["῎"]={ "᾿", "́" },
+ ["῏"]={ "᾿", "͂" },
+ ["ῐ"]={ "ι", "̆" },
+ ["ῑ"]={ "ι", "̄" },
+ ["ῒ"]={ "ϊ", "̀" },
+ ["ῖ"]={ "ι", "͂" },
+ ["ῗ"]={ "ϊ", "͂" },
+ ["Ῐ"]={ "Ι", "̆" },
+ ["Ῑ"]={ "Ι", "̄" },
+ ["Ὶ"]={ "Ι", "̀" },
+ ["῝"]={ "῾", "̀" },
+ ["῞"]={ "῾", "́" },
+ ["῟"]={ "῾", "͂" },
+ ["ῠ"]={ "υ", "̆" },
+ ["ῡ"]={ "υ", "̄" },
+ ["ῢ"]={ "ϋ", "̀" },
+ ["ῤ"]={ "ρ", "̓" },
+ ["ῥ"]={ "ρ", "̔" },
+ ["ῦ"]={ "υ", "͂" },
+ ["ῧ"]={ "ϋ", "͂" },
+ ["Ῠ"]={ "Υ", "̆" },
+ ["Ῡ"]={ "Υ", "̄" },
+ ["Ὺ"]={ "Υ", "̀" },
+ ["Ῥ"]={ "Ρ", "̔" },
+ ["῭"]={ "¨", "̀" },
+ ["ῲ"]={ "ὼ", "ͅ" },
+ ["ῳ"]={ "ω", "ͅ" },
+ ["ῴ"]={ "ώ", "ͅ" },
+ ["ῶ"]={ "ω", "͂" },
+ ["ῷ"]={ "ῶ", "ͅ" },
+ ["Ὸ"]={ "Ο", "̀" },
+ ["Ὼ"]={ "Ω", "̀" },
+ ["ῼ"]={ "Ω", "ͅ" },
+ ["↚"]={ "←", "̸" },
+ ["↛"]={ "→", "̸" },
+ ["↮"]={ "↔", "̸" },
+ ["⇍"]={ "⇐", "̸" },
+ ["⇎"]={ "⇔", "̸" },
+ ["⇏"]={ "⇒", "̸" },
+ ["∄"]={ "∃", "̸" },
+ ["∉"]={ "∈", "̸" },
+ ["∌"]={ "∋", "̸" },
+ ["∤"]={ "∣", "̸" },
+ ["∦"]={ "∥", "̸" },
+ ["≁"]={ "∼", "̸" },
+ ["≄"]={ "≃", "̸" },
+ ["≇"]={ "≅", "̸" },
+ ["≉"]={ "≈", "̸" },
+ ["≠"]={ "=", "̸" },
+ ["≢"]={ "≡", "̸" },
+ ["≭"]={ "≍", "̸" },
+ ["≮"]={ "<", "̸" },
+ ["≯"]={ ">", "̸" },
+ ["≰"]={ "≤", "̸" },
+ ["≱"]={ "≥", "̸" },
+ ["≴"]={ "≲", "̸" },
+ ["≵"]={ "≳", "̸" },
+ ["≸"]={ "≶", "̸" },
+ ["≹"]={ "≷", "̸" },
+ ["⊀"]={ "≺", "̸" },
+ ["⊁"]={ "≻", "̸" },
+ ["⊄"]={ "⊂", "̸" },
+ ["⊅"]={ "⊃", "̸" },
+ ["⊈"]={ "⊆", "̸" },
+ ["⊉"]={ "⊇", "̸" },
+ ["⊬"]={ "⊢", "̸" },
+ ["⊭"]={ "⊨", "̸" },
+ ["⊮"]={ "⊩", "̸" },
+ ["⊯"]={ "⊫", "̸" },
+ ["⋠"]={ "≼", "̸" },
+ ["⋡"]={ "≽", "̸" },
+ ["⋢"]={ "⊑", "̸" },
+ ["⋣"]={ "⊒", "̸" },
+ ["⋪"]={ "⊲", "̸" },
+ ["⋫"]={ "⊳", "̸" },
+ ["⋬"]={ "⊴", "̸" },
+ ["⋭"]={ "⊵", "̸" },
+ ["⫝̸"]={ "⫝", "̸" },
+ ["が"]={ "か", "゙" },
+ ["ぎ"]={ "き", "゙" },
+ ["ぐ"]={ "く", "゙" },
+ ["げ"]={ "け", "゙" },
+ ["ご"]={ "こ", "゙" },
+ ["ざ"]={ "さ", "゙" },
+ ["じ"]={ "し", "゙" },
+ ["ず"]={ "す", "゙" },
+ ["ぜ"]={ "せ", "゙" },
+ ["ぞ"]={ "そ", "゙" },
+ ["だ"]={ "た", "゙" },
+ ["ぢ"]={ "ち", "゙" },
+ ["づ"]={ "つ", "゙" },
+ ["で"]={ "て", "゙" },
+ ["ど"]={ "と", "゙" },
+ ["ば"]={ "は", "゙" },
+ ["ぱ"]={ "は", "゚" },
+ ["び"]={ "ひ", "゙" },
+ ["ぴ"]={ "ひ", "゚" },
+ ["ぶ"]={ "ふ", "゙" },
+ ["ぷ"]={ "ふ", "゚" },
+ ["べ"]={ "へ", "゙" },
+ ["ぺ"]={ "へ", "゚" },
+ ["ぼ"]={ "ほ", "゙" },
+ ["ぽ"]={ "ほ", "゚" },
+ ["ゔ"]={ "う", "゙" },
+ ["ゞ"]={ "ゝ", "゙" },
+ ["ガ"]={ "カ", "゙" },
+ ["ギ"]={ "キ", "゙" },
+ ["グ"]={ "ク", "゙" },
+ ["ゲ"]={ "ケ", "゙" },
+ ["ゴ"]={ "コ", "゙" },
+ ["ザ"]={ "サ", "゙" },
+ ["ジ"]={ "シ", "゙" },
+ ["ズ"]={ "ス", "゙" },
+ ["ゼ"]={ "セ", "゙" },
+ ["ゾ"]={ "ソ", "゙" },
+ ["ダ"]={ "タ", "゙" },
+ ["ヂ"]={ "チ", "゙" },
+ ["ヅ"]={ "ツ", "゙" },
+ ["デ"]={ "テ", "゙" },
+ ["ド"]={ "ト", "゙" },
+ ["バ"]={ "ハ", "゙" },
+ ["パ"]={ "ハ", "゚" },
+ ["ビ"]={ "ヒ", "゙" },
+ ["ピ"]={ "ヒ", "゚" },
+ ["ブ"]={ "フ", "゙" },
+ ["プ"]={ "フ", "゚" },
+ ["ベ"]={ "ヘ", "゙" },
+ ["ペ"]={ "ヘ", "゚" },
+ ["ボ"]={ "ホ", "゙" },
+ ["ポ"]={ "ホ", "゚" },
+ ["ヴ"]={ "ウ", "゙" },
+ ["ヷ"]={ "ワ", "゙" },
+ ["ヸ"]={ "ヰ", "゙" },
+ ["ヹ"]={ "ヱ", "゙" },
+ ["ヺ"]={ "ヲ", "゙" },
+ ["ヾ"]={ "ヽ", "゙" },
+ ["יִ"]={ "י", "ִ" },
+ ["ײַ"]={ "ײ", "ַ" },
+ ["שׁ"]={ "ש", "ׁ" },
+ ["שׂ"]={ "ש", "ׂ" },
+ ["שּׁ"]={ "שּ", "ׁ" },
+ ["שּׂ"]={ "שּ", "ׂ" },
+ ["אַ"]={ "א", "ַ" },
+ ["אָ"]={ "א", "ָ" },
+ ["אּ"]={ "א", "ּ" },
+ ["בּ"]={ "ב", "ּ" },
+ ["גּ"]={ "ג", "ּ" },
+ ["דּ"]={ "ד", "ּ" },
+ ["הּ"]={ "ה", "ּ" },
+ ["וּ"]={ "ו", "ּ" },
+ ["זּ"]={ "ז", "ּ" },
+ ["טּ"]={ "ט", "ּ" },
+ ["יּ"]={ "י", "ּ" },
+ ["ךּ"]={ "ך", "ּ" },
+ ["כּ"]={ "כ", "ּ" },
+ ["לּ"]={ "ל", "ּ" },
+ ["מּ"]={ "מ", "ּ" },
+ ["נּ"]={ "נ", "ּ" },
+ ["סּ"]={ "ס", "ּ" },
+ ["ףּ"]={ "ף", "ּ" },
+ ["פּ"]={ "פ", "ּ" },
+ ["צּ"]={ "צ", "ּ" },
+ ["קּ"]={ "ק", "ּ" },
+ ["רּ"]={ "ר", "ּ" },
+ ["שּ"]={ "ש", "ּ" },
+ ["תּ"]={ "ת", "ּ" },
+ ["וֹ"]={ "ו", "ֹ" },
+ ["בֿ"]={ "ב", "ֿ" },
+ ["כֿ"]={ "כ", "ֿ" },
+ ["פֿ"]={ "פ", "ֿ" },
+ ["𑂚"]={ "𑂙", "𑂺" },
+ ["𑂜"]={ "𑂛", "𑂺" },
+ ["𑂫"]={ "𑂥", "𑂺" },
+ ["𑄮"]={ "𑄱", "𑄧" },
+ ["𑄯"]={ "𑄲", "𑄧" },
+ ["𑍋"]={ "𑍇", "𑌾" },
+ ["𑍌"]={ "𑍇", "𑍗" },
+ ["𑒻"]={ "𑒹", "𑒺" },
+ ["𑒼"]={ "𑒹", "𑒰" },
+ ["𑒾"]={ "𑒹", "𑒽" },
+ ["𑖺"]={ "𑖸", "𑖯" },
+ ["𑖻"]={ "𑖹", "𑖯" },
+ ["𝅗𝅥"]={ "𝅗", "𝅥" },
+ ["𝅘𝅥"]={ "𝅘", "𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥", "𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥", "𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥", "𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥", "𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥", "𝅲" },
+ ["𝆹𝅥"]={ "𝆹", "𝅥" },
+ ["𝆺𝅥"]={ "𝆺", "𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥", "𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥", "𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥", "𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥", "𝅯" },
+ },
+ },
+ },
+ ["name"]="collapse",
+ ["prepend"]=true,
+ ["type"]="ligature",
+}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-mis.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-mis.lua
new file mode 100644
index 00000000000..d3cfd70a910
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-mis.lua
@@ -0,0 +1,31 @@
+if not modules then modules = { } end modules ['luatex-font-mis'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+if context then
+ os.exit()
+end
+
+local currentfont = font.current
+
+local hashes = fonts.hashes
+local identifiers = hashes.identifiers or { }
+local marks = hashes.marks or { }
+
+hashes.identifiers = identifiers
+hashes.marks = marks
+
+table.setmetatableindex(marks,function(t,k)
+ if k == true then
+ return marks[currentfont()]
+ else
+ local resources = identifiers[k].resources or { }
+ local marks = resources.marks or { }
+ t[k] = marks
+ return marks
+ end
+end)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-syn.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-syn.lua
index 376fd05fbf5..2ec075434ff 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-syn.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-syn.lua
@@ -7,7 +7,6 @@ if not modules then modules = { } end modules ['luatex-fonts-syn'] = {
}
if context then
- texio.write_nl("fatal error: this module is not for context")
os.exit()
end
@@ -46,12 +45,12 @@ local loaded = false
local fileformats = { "lua", "tex", "other text files" }
function fonts.names.reportmissingbase()
- texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>")
+ logs.report("fonts","missing font database, run: mtxrun --script fonts --reload --simple")
fonts.names.reportmissingbase = nil
end
function fonts.names.reportmissingname()
- texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>")
+ logs.report("fonts","unknown font in font database, run: mtxrun --script fonts --reload --simple")
fonts.names.reportmissingname = nil
end
@@ -67,7 +66,7 @@ function fonts.names.resolve(name,sub)
local foundname = resolvers.findfile(basename,format) or ""
if foundname ~= "" then
data = dofile(foundname)
- texio.write("<font database loaded: ",foundname,">")
+ logs.report("fonts","font database '%s' loaded",foundname)
break
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.lua
deleted file mode 100644
index c21389c71de..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.lua
+++ /dev/null
@@ -1,324 +0,0 @@
-if not modules then modules = { } end modules ['luatex-fonts'] = {
- version = 1.001,
- comment = "companion to luatex-fonts.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- A merged file is generated with:
---
--- mtxrun --script package --merge ./luatex-fonts.lua
---
--- A needed resource file is made by:
---
--- mtxrun --script context luatex-basics-prepare.tex
---
--- A font (generic) database is created with:
---
--- mtxrun --script font --reload --simple
-
--- The following code isolates the generic context code from already defined or to be defined
--- namespaces. This is the reference loader for plain tex. This generic code is also used in
--- luaotfload which is a low level lualatex opentype font loader but somehow has gotten a bit
--- too generic name / prefix, originally set up and maintained by Khaled Hosny. Currently that
--- set of derived files is maintained by a larger team lead by Philipp Gesang so when there are
--- issues with this code in latex, you can best contact him. It might make sense then to first
--- check if context has the same issue. We do our best to keep the interface as clean as possible.
---
--- The code base is rather stable now, especially if you stay away from the non generic code. All
--- relevant data is organized in tables within the main table of a font instance. There are a few
--- places where in context other code is plugged in, but this does not affect the core code. Users
--- can (given that their macro package provides this option) access the font data (characters,
--- descriptions, properties, parameters, etc) of this main table. The documentation is part of
--- context. There is also a manual for the helper libraries (maintained as part of the cld manuals).
---
--- Future versions will probably have some more specific context code removed, like tracing and
--- obscure hooks, so that we have a more efficient version (and less files too). So, don't depend
--- too much on low level code that is meant for context as it can change without notice. We might
--- also add more helper code here, but that depends to what extend metatex (sidetrack of context)
--- evolves into a low level layer (depends on time, as usual).
-
--- The code here is the same as in context version 2015.09.11 but the rendering in context can be
--- different from generic. This can be a side effect of additional callbacks, additional features
--- and interferences between mechanisms between macro packages. We use the rendering in context
--- and luatex-plain as reference for issues.
-
-utf = utf or unicode.utf8
-
--- We have some (global) hooks (for latex):
-
-if not non_generic_context then
- non_generic_context = { }
-end
-
-if not non_generic_context.luatex_fonts then
- non_generic_context.luatex_fonts = {
- -- load_before = nil,
- -- load_after = nil,
- -- skip_loading = nil,
- }
-end
-
-if not generic_context then
- generic_context = { }
-end
-
-if not generic_context.push_namespaces then
-
- function generic_context.push_namespaces()
- texio.write(" <push namespace>")
- local normalglobal = { }
- for k, v in next, _G do
- normalglobal[k] = v
- end
- return normalglobal
- end
-
- function generic_context.pop_namespaces(normalglobal,isolate)
- if normalglobal then
- texio.write(" <pop namespace>")
- for k, v in next, _G do
- if not normalglobal[k] then
- generic_context[k] = v
- if isolate then
- _G[k] = nil
- end
- end
- end
- for k, v in next, normalglobal do
- _G[k] = v
- end
- -- just to be sure:
- setmetatable(generic_context,_G)
- else
- texio.write(" <fatal error: invalid pop of generic_context>")
- os.exit()
- end
- end
-
-end
-
-local whatever = generic_context.push_namespaces()
-
--- We keep track of load time by storing the current time. That way we cannot be accused
--- of slowing down loading too much. Anyhow, there is no reason for this library to perform
--- slower in any other package as it does in context.
---
--- Please don't update to this version without proper testing. It might be that this version
--- lags behind stock context and the only formal release takes place around tex live code
--- freeze.
-
-local starttime = os.gettimeofday()
-
--- As we don't use the context file searching, we need to initialize the kpse library. As the
--- progname can be anything we will temporary switch to the context namespace if needed. Just
--- adding the context paths to the path specification is somewhat faster.
---
--- Now, with lua 5.2 being used we might create a special ENV for this.
-
--- kpse.set_program_name("luatex")
-
-local ctxkpse = nil
-local verbose = true
-
-local function loadmodule(name,continue)
- local foundname = kpse.find_file(name,"tex") or ""
- if not foundname then
- if not ctxkpse then
- ctxkpse = kpse.new("luatex","context")
- end
- foundname = ctxkpse:find_file(name,"tex") or ""
- end
- if foundname == "" then
- if not continue then
- texio.write_nl(string.format(" <luatex-fonts: unable to locate %s>",name))
- os.exit()
- end
- else
- if verbose then
- texio.write(string.format(" <%s>",foundname)) -- no file.basename yet
- end
- dofile(foundname)
- end
-end
-
-if non_generic_context.luatex_fonts.load_before then
- loadmodule(non_generic_context.luatex_fonts.load_before,true)
-end
-
-if non_generic_context.luatex_fonts.skip_loading ~= true then
-
- loadmodule('luatex-fonts-merged.lua',true)
-
- if fonts then
-
- if not fonts._merge_loaded_message_done_ then
- texio.write_nl("log", "!")
- texio.write_nl("log", "! I am using the merged version of 'luatex-fonts.lua' here. If")
- texio.write_nl("log", "! you run into problems or experience unexpected behaviour, and")
- texio.write_nl("log", "! if you have ConTeXt installed you can try to delete the file")
- texio.write_nl("log", "! 'luatex-font-merged.lua' as I might then use the possibly")
- texio.write_nl("log", "! updated libraries. The merged version is not supported as it")
- texio.write_nl("log", "! is a frozen instance. Problems can be reported to the ConTeXt")
- texio.write_nl("log", "! mailing list.")
- texio.write_nl("log", "!")
- end
-
- fonts._merge_loaded_message_done_ = true
-
- else
-
- -- The following helpers are a bit overkill but I don't want to mess up context code for the
- -- sake of general generality. Around version 1.0 there will be an official api defined.
- --
- -- So, I will strip these libraries and see what is really needed so that we don't have this
- -- overhead in the generic modules. The next section is only there for the packager, so stick
- -- to using luatex-fonts with luatex-fonts-merged.lua and forget about the rest. The following
- -- list might change without prior notice (for instance because we shuffled code around).
-
- loadmodule("l-lua.lua")
- loadmodule("l-lpeg.lua")
- loadmodule("l-function.lua")
- loadmodule("l-string.lua")
- loadmodule("l-table.lua")
- loadmodule("l-io.lua")
- loadmodule("l-file.lua")
- loadmodule("l-boolean.lua")
- loadmodule("l-math.lua")
- loadmodule("l-unicode.lua")
-
- -- A few slightly higher level support modules:
-
- loadmodule("util-str.lua")
- loadmodule("util-fil.lua")
-
- -- The following modules contain code that is either not used at all outside context or will
- -- fail when enabled due to lack of other modules.
-
- -- First we load a few helper modules. This is about the miminum needed to let the font modules
- -- do their work. Don't depend on their functions as we might strip them in future versions of
- -- this generic variant.
-
- loadmodule('luatex-basics-gen.lua')
- loadmodule('data-con.lua')
-
- -- We do need some basic node support. The code in there is not for general use as it might
- -- change.
-
- loadmodule('luatex-basics-nod.lua')
-
- -- We ship a resources needed for font handling (more might end up here).
-
- loadmodule('luatex-basics-chr.lua')
-
- -- Now come the font modules that deal with traditional tex fonts as well as open type fonts.
- --
- -- The font database file (if used at all) must be put someplace visible for kpse and is not
- -- shared with context. The mtx-fonts script can be used to generate this file (using the
- -- --reload --force --simple option).
-
- loadmodule('font-ini.lua')
- loadmodule('font-con.lua')
- loadmodule('luatex-fonts-enc.lua') -- will load font-age on demand
- loadmodule('font-cid.lua')
- loadmodule('font-map.lua') -- for loading lum file (will be stripped)
-
- -- We use a bit simpler database because using the context one demands loading more helper
- -- code and although it is more flexible (more wauys to resolve and so) it will never be
- -- uses in plain/latex anyway, so let's stick to a simple approach.
-
- loadmodule('luatex-fonts-syn.lua')
-
- loadmodule('font-oti.lua')
-
- -- These are the old loader and processing modules. These use the built-in font loader and
- -- will stay around (but not be extended), only fixed.
-
- -- font-otf.lua
- -- font-otb.lua
- -- font-inj.lua
- -- font-ota.lua
- -- font-otn.lua
- -- font-otp.lua
-
- -- Here come the new loader and processing modules. The loader is written in Lua and although
- -- initial loading is somewhat slower, identifying is faster, cached files can be slightly
- -- more efficient, and processing is somewhat faster (only measureable on complex fonts).
-
- loadmodule('font-otr.lua')
- loadmodule('font-cff.lua')
- loadmodule('font-ttf.lua')
- loadmodule('font-dsp.lua')
- loadmodule('font-oup.lua')
- loadmodule('font-otl.lua')
- loadmodule('font-oto.lua')
- loadmodule('font-otj.lua')
- loadmodule('font-ota.lua')
- loadmodule('font-ots.lua')
- loadmodule('font-osd.lua')
- loadmodule('font-ocl.lua') -- svg needs 0.97 (for fix in memstreams)
-
- loadmodule('font-otc.lua')
-
- -- type one code
-
- loadmodule('font-onr.lua') -- was font-afm.lua
- loadmodule('font-one.lua') -- was font-afm.lua
- loadmodule('font-afk.lua')
-
- -- traditional code
-
- loadmodule('font-tfm.lua')
-
- -- common code
-
- loadmodule('font-lua.lua')
- loadmodule('font-def.lua')
- loadmodule('font-xtx.lua') -- xetex compatible specifiers (plain/latex only)
- loadmodule('luatex-fonts-ext.lua') -- some extensions
-
- -- We need to plug into a callback and the following module implements the handlers. Actual
- -- plugging in happens later.
-
- loadmodule('font-gbn.lua')
-
- end
-
-end
-
-if non_generic_context.luatex_fonts.load_after then
- loadmodule(non_generic_context.luatex_fonts.load_after,true)
-end
-
-resolvers.loadmodule = loadmodule
-
--- In order to deal with the fonts we need to initialize some callbacks. One can overload them later
--- on if needed. First a bit of abstraction.
-
-generic_context.callback_ligaturing = false
-generic_context.callback_kerning = false
-generic_context.callback_pre_linebreak_filter = nodes.simple_font_handler
-generic_context.callback_hpack_filter = nodes.simple_font_handler
-generic_context.callback_define_font = fonts.definers.read
-
--- The next ones can be done at a different moment if needed. You can create a generic_context namespace
--- and set no_callbacks_yet to true, load this module, and enable the callbacks later. So, there is really
--- *no* need to create a alternative for luatex-fonts.lua and luatex-fonts-merged.lua: just load this one
--- and overload if needed.
-
-if not generic_context.no_callbacks_yet then
-
- callback.register('ligaturing', generic_context.callback_ligaturing)
- callback.register('kerning', generic_context.callback_kerning)
- callback.register('pre_linebreak_filter', generic_context.callback_pre_linebreak_filter)
- callback.register('hpack_filter', generic_context.callback_hpack_filter)
- callback.register('define_font' , generic_context.callback_define_font)
-
-end
-
--- We're done.
-
-texio.write(string.format(" <luatex-fonts.lua loaded in %0.3f seconds>", os.gettimeofday()-starttime))
-
-generic_context.pop_namespaces(whatever)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.tex
deleted file mode 100644
index 7b457e9b4fc..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts.tex
+++ /dev/null
@@ -1,140 +0,0 @@
-%D \module
-%D [ file=luatex-fonts,
-%D version=2009.12.01,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Generic \OPENTYPE\ Font Handler,
-%D author=Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D \subject{Welcome}
-%D
-%D This file is one of a set of basic functionality enhancements
-%D for \LUATEX\ derived from the \CONTEXT\ \MKIV\ code base. Please
-%D don't polute the \type {luatex-*} namespace with code not coming
-%D from the \CONTEXT\ development team as we may add more files.
-%D
-%D As this is an experimental setup, it might not always work out as
-%D expected. Around \LUATEX\ version 0.50 we expect the code to be
-%D more or less okay.
-%D
-%D This file implements a basic font system for a bare \LUATEX\
-%D system. By default \LUATEX\ only knows about the classic \TFM\
-%D fonts but it can read other font formats and pass them to \LUA.
-%D With some glue code one can then construct a suitable \TFM\
-%D representation that \LUATEX\ can work with. For more advanced font
-%D support a bit more code is needed that needs to be hooked
-%D into the callback mechanism.
-%D
-%D This file is currently rather simple: it just loads the \LUA\ file
-%D with the same name. An example of a \type {luatex.tex} file that is
-%D just plain \TEX:
-%D
-%D \starttyping
-%D \catcode`\{=1 % left brace is begin-group character
-%D \catcode`\}=2 % right brace is end-group character
-%D
-%D \input plain
-%D
-%D \everyjob\expandafter{\the\everyjob\input luatex-fonts\relax}
-%D
-%D \dump
-%D \stoptyping
-%D
-%D We could load the \LUA\ file in \type {\everyjob} but maybe some
-%D day we need more here.
-%D
-%D When defining a font you can use two prefixes. A \type {file:}
-%D prefix forced a file search, while a \type {name:} prefix will
-%D result in consulting the names database. Such a database can be
-%D generated with:
-%D
-%D \starttyping
-%D mtxrun --usekpse --script fonts --names
-%D \stoptyping
-%D
-%D This will generate a file \type {luatex-fonts-names.lua} that has
-%D to be placed in a location where it can be found by \KPSE. Beware:
-%D the \type {--kpseonly} flag is only used outside \CONTEXT\ and
-%D provides very limited functionality, just enough for this task.
-%D
-%D The code loaded here does not come out of thin air, but is mostly
-%D shared with \CONTEXT, however, in that macropackage we go beyond
-%D what is provided here. When you use the code packaged here you
-%D need to keep a few things in mind:
-%D
-%D \startitemize
-%D
-%D \item This subsystem will be extended, improved etc. in about the
-%D same pace as \CONTEXT\ \MKIV. However, because \CONTEXT\ provides a
-%D rather high level of integration not all features will be supported
-%D in the same quality. Use \CONTEXT\ if you want more goodies.
-%D
-%D \item There is no official \API\ yet, which means that using
-%D functions implemented here is at your own risk, in the sense that
-%D names and namespaces might change. There will be a minimal \API\
-%D defined once \LUATEX\ version 1.0 is out. Instead of patching the
-%D files it's better to overload functions if needed.
-%D
-%D \item The modules are not stripped too much, which makes it
-%D possible to benefit from improvements in the code that take place
-%D in the perspective of \CONTEXT\ development. They might be split a
-%D bit more in due time so the baseline might become smaller.
-%D
-%D \item The code is maintained and tested by the \CONTEXT\
-%D development team. As such it might be better suited for this macro
-%D package and integration in other systems might demand some
-%D additional wrapping. Problems can be reported to the team but as we
-%D use \CONTEXT\ \MKIV\ as baseline, you'd better check if the problem
-%D is a general \CONTEXT\ problem too.
-%D
-%D \item The more high level support for features that is provided in
-%D \CONTEXT\ is not part of the code loaded here as it makes no sense
-%D elsewhere. Some experimental features are not part of this code
-%D either but some might show up later.
-%D
-%D \item Math font support will be added but only in its basic form
-%D once that the Latin Modern and \TEX\ Gyre math fonts are
-%D available.
-%D
-%D \item At this moment the more nifty speed-ups are not enabled
-%D because they work in tandem with the alternative file handling
-%D that \CONTEXT\ uses. Maybe around \LUATEX\ 1.0 we will bring some
-%D speedup into this code too (if it pays off at all).
-%D
-%D \item The code defines a few global tables. If this code is used
-%D in a larger perspective then you can best make sure that no
-%D conflicts occur. The \CONTEXT\ package expects users to work in
-%D their own namespace (\type {userdata}, \type {thirddata}, \type
-%D {moduledata} or \type {document}. The team takes all freedom to
-%D use any table at the global level but will not use tables that are
-%D named after macro packages. Later the \CONTEXT\ might operate in
-%D a more controlled namespace but it has a low priority.
-%D
-%D \item There is some tracing code present but this is not enabled
-%D and not supported outside \CONTEXT\ either as it integrates quite
-%D tightly into \CONTEXT. In case of problems you can use \CONTEXT\
-%D for tracking down problems.
-%D
-%D \item Patching the code in distributions is dangerous as it might
-%D fix your problem but introduce new ones for \CONTEXT. So, best keep
-%D the original code as it is.
-%D
-%D \item Attributes are (automatically) taken from the range 127-255 so
-%D you'd best not use these yourself.
-%D
-%D \stopitemize
-%D
-%D If this all sounds a bit tricky, keep in mind that it makes no sense
-%D for us to maintain multiple code bases and we happen to use \CONTEXT.
-%D
-%D For more details about how the font subsystem works we refer to
-%D publications in \TEX\ related journals, the \CONTEXT\ documentation,
-%D and the \CONTEXT\ wiki.
-
-\directlua {
- if not fonts then
- dofile(kpse.find_file("luatex-fonts.lua","tex"))
- end
-}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua
index f2a27ad1832..46b6847d331 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua
@@ -69,31 +69,34 @@ local lpegmatch = lpeg.match
local getcurrentdir, attributes = lfs.currentdir, lfs.attributes
local checkedsplit = string.checkedsplit
--- local patterns = file.patterns or { }
--- file.patterns = patterns
-
local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc, lpeg.Ct
-- better this way:
-local tricky = S("/\\") * P(-1)
+----- tricky = S("/\\") * P(-1)
local attributes = lfs.attributes
-if sandbox then
- sandbox.redefine(lfs.isfile,"lfs.isfile")
- sandbox.redefine(lfs.isdir, "lfs.isdir")
-end
-
function lfs.isdir(name)
- if lpegmatch(tricky,name) then
- return attributes(name,"mode") == "directory"
- else
- return attributes(name.."/.","mode") == "directory"
- end
+ -- if not lpegmatch(tricky,name) then
+ -- name = name .. "/."
+ -- end
+ return attributes(name,"mode") == "directory"
end
function lfs.isfile(name)
- return attributes(name,"mode") == "file"
+ local a = attributes(name,"mode")
+ return a == "file" or a == "link" or nil
+end
+
+function lfs.isfound(name)
+ local a = attributes(name,"mode")
+ return (a == "file" or a == "link") and name or nil
+end
+
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir, "lfs.isdir")
+ sandbox.redefine(lfs.isfound, "lfs.isfound")
end
local colon = P(":")
@@ -699,3 +702,32 @@ function lfs.mkdirs(path)
lfs.mkdir(full)
end
end
+
+-- here is oen i ran into when messign around with xavante code (keppler project)
+-- where it's called in_base .. no gain in using lpeg here
+
+function file.withinbase(path) -- don't go beyond root
+ local l = 0
+ if not find(path,"^/") then
+ path = "/" .. path
+ end
+ for dir in gmatch(path,"/([^/]+)") do
+ if dir == ".." then
+ l = l - 1
+ elseif dir ~= "." then
+ l = l + 1
+ end
+ if l < 0 then
+ return false
+ end
+ end
+ return true
+end
+
+-- not used in context but was in luatex once:
+
+local symlinkattributes = lfs.symlinkattributes
+
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-io.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-io.lua
index 2039017b25d..fa3ad3c4cda 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-io.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-io.lua
@@ -10,7 +10,7 @@ local io = io
local open, flush, write, read = io.open, io.flush, io.write, io.read
local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format
local concat = table.concat
-local floor = math.floor
+----- floor = math.floor
local type = type
if string.find(os.getenv("PATH"),";",1,true) then
@@ -19,38 +19,48 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-local function readall(f)
- return f:read("*all")
-end
+-- local function readall(f)
+-- return f:read("*all")
+-- end
-- The next one is upto 50% faster on large files and less memory consumption due
-- to less intermediate large allocations. This phenomena was discussed on the
-- luatex dev list.
+local large = 0x01000000 -- 2^24 16.777.216
+local medium = 0x00100000 -- 2^20 1.048.576
+local small = 0x00020000 -- 2^17 131.072
+
+-- local function readall(f)
+-- local size = f:seek("end")
+-- if size == 0 then
+-- return ""
+-- end
+-- f:seek("set",0)
+-- if size < medium then
+-- return f:read('*all')
+-- else
+-- local step = (size > large) and large or (floor(size/(medium)) * small)
+-- local data = { }
+-- while true do
+-- local r = f:read(step)
+-- if not r then
+-- return concat(data)
+-- else
+-- data[#data+1] = r
+-- end
+-- end
+-- end
+-- end
+
local function readall(f)
+ -- return f:read("*all")
local size = f:seek("end")
- if size == 0 then
- return ""
- end
- f:seek("set",0)
- if size < 1024*1024 then
- return f:read('*all')
+ if size > 0 then
+ f:seek("set",0)
+ return f:read(size)
else
- local step
- if size > 16*1024*1024 then
- step = 16*1024*1024
- else
- step = floor(size/(1024*1024)) * 1024 * 1024 / 8
- end
- local data = { }
- while true do
- local r = f:read(step)
- if not r then
- return concat(data)
- else
- data[#data+1] = r
- end
- end
+ return ""
end
end
@@ -59,52 +69,75 @@ io.readall = readall
function io.loaddata(filename,textmode) -- return nil if empty
local f = open(filename,(textmode and 'r') or 'rb')
if f then
- local data = readall(f)
- f:close()
- if #data > 0 then
- return data
+ local size = f:seek("end")
+ local data = nil
+ if size > 0 then
+ -- data = f:read("*all")
+ f:seek("set",0)
+ data = f:read(size)
end
+ f:close()
+ return data
end
end
+-- function io.copydata(source,target,action)
+-- local f = open(source,"rb")
+-- if f then
+-- local g = open(target,"wb")
+-- if g then
+-- local size = f:seek("end")
+-- if size == 0 then
+-- -- empty
+-- else
+-- f:seek("set",0)
+-- if size < medium then
+-- local data = f:read('*all')
+-- if action then
+-- data = action(data)
+-- end
+-- if data then
+-- g:write(data)
+-- end
+-- else
+-- local step = (size > large) and large or (floor(size/(medium)) * small)
+-- while true do
+-- local data = f:read(step)
+-- if data then
+-- if action then
+-- data = action(data)
+-- end
+-- if data then
+-- g:write(data)
+-- end
+-- else
+-- break
+-- end
+-- end
+-- end
+-- end
+-- g:close()
+-- end
+-- f:close()
+-- flush()
+-- end
+-- end
+
function io.copydata(source,target,action)
local f = open(source,"rb")
if f then
local g = open(target,"wb")
if g then
local size = f:seek("end")
- if size == 0 then
- -- empty
- else
+ if size > 0 then
+ -- local data = f:read('*all')
f:seek("set",0)
- if size < 1024*1024 then
- local data = f:read('*all')
- if action then
- data = action(data)
- end
- if data then
- g:write(data)
- end
- else
- local step
- if size > 16*1024*1024 then
- step = 16*1024*1024
- else
- step = floor(size/(1024*1024)) * 1024 * 1024 / 8
- end
- while true do
- local data = f:read(step)
- if data then
- if action then
- data = action(data)
- end
- if data then
- g:write(data)
- end
- else
- break
- end
- end
+ local data = f:read(size)
+ if action then
+ data = action(data)
+ end
+ if data then
+ g:write(data)
end
end
g:close()
@@ -134,32 +167,70 @@ end
-- we can also chunk this one if needed: io.lines(filename,chunksize,"*l")
-function io.loadlines(filename,n) -- return nil if empty
- local f = open(filename,'r')
- if not f then
- -- no file
- elseif n then
- local lines = { }
- for i=1,n do
- local line = f:read("*lines")
- if line then
- lines[#lines+1] = line
- else
- break
+-- ffi.readline
+
+if fio and fio.readline then
+
+ local readline = fio.readline
+
+ function io.loadlines(filename,n) -- return nil if empty
+ local f = open(filename,'r')
+ if not f then
+ -- no file
+ elseif n then
+ local lines = { }
+ for i=1,n do
+ local line = readline(f)
+ if line then
+ lines[i] = line
+ else
+ break
+ end
+ end
+ f:close()
+ lines = concat(lines,"\n")
+ if #lines > 0 then
+ return lines
+ end
+ else
+ local line = readline(f)
+ f:close()
+ if line and #line > 0 then
+ return line
end
end
- f:close()
- lines = concat(lines,"\n")
- if #lines > 0 then
- return lines
- end
- else
- local line = f:read("*line") or ""
- f:close()
- if #line > 0 then
- return line
+ end
+
+else
+
+ function io.loadlines(filename,n) -- return nil if empty
+ local f = open(filename,'r')
+ if not f then
+ -- no file
+ elseif n then
+ local lines = { }
+ for i=1,n do
+ local line = f:read("*lines")
+ if line then
+ lines[i] = line
+ else
+ break
+ end
+ end
+ f:close()
+ lines = concat(lines,"\n")
+ if #lines > 0 then
+ return lines
+ end
+ else
+ local line = f:read("*line") or ""
+ f:close()
+ if #line > 0 then
+ return line
+ end
end
end
+
end
function io.loadchunk(filename,n)
@@ -205,6 +276,7 @@ local function noflines(f)
return 0
end
else
+ -- todo: load and lpeg
local n = 0
for _ in f:lines() do
n = n + 1
@@ -216,7 +288,7 @@ end
io.noflines = noflines
--- inlined is faster
+-- inlined is faster ... beware, better use util-fil
local nextchar = {
[ 4] = function(f)
@@ -331,7 +403,7 @@ function io.ask(question,default,options)
end
end
-local function readnumber(f,n,m)
+local function readnumber(f,n,m) -- to be replaced
if m then
f:seek("set",n)
n = m
@@ -340,38 +412,32 @@ local function readnumber(f,n,m)
return byte(f:read(1))
elseif n == 2 then
local a, b = byte(f:read(2),1,2)
- return 256 * a + b
+ return 0x100 * a + b
elseif n == 3 then
local a, b, c = byte(f:read(3),1,3)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == 4 then
local a, b, c, d = byte(f:read(4),1,4)
- return 256*256*256 * a + 256*256 * b + 256 * c + d
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
elseif n == 8 then
local a, b = readnumber(f,4), readnumber(f,4)
- return 256 * a + b
+ return 0x100 * a + b
elseif n == 12 then
local a, b, c = readnumber(f,4), readnumber(f,4), readnumber(f,4)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == -2 then
local b, a = byte(f:read(2),1,2)
- return 256*a + b
+ return 0x100 * a + b
elseif n == -3 then
local c, b, a = byte(f:read(3),1,3)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == -4 then
local d, c, b, a = byte(f:read(4),1,4)
- return 256*256*256 * a + 256*256 * b + 256*c + d
+ return 0x1000000 * a + 0x10000 * b + 0x100*c + d
elseif n == -8 then
local h, g, f, e, d, c, b, a = byte(f:read(8),1,8)
- return 256*256*256*256*256*256*256 * a +
- 256*256*256*256*256*256 * b +
- 256*256*256*256*256 * c +
- 256*256*256*256 * d +
- 256*256*256 * e +
- 256*256 * f +
- 256 * g +
- h
+ return 0x100000000000000 * a + 0x1000000000000 * b + 0x10000000000 * c + 0x100000000 * d +
+ 0x1000000 * e + 0x10000 * f + 0x100 * g + h
else
return 0
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lpeg.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lpeg.lua
index 959ca553eb8..750d5e698d7 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lpeg.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lpeg.lua
@@ -6,6 +6,10 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
license = "see context related readme files"
}
+-- we can get too many captures (e.g. on largexml files) which makes me wonder
+-- if P(foo)/"" can't be simplfied to N(foo) i.e. some direct instruction to the
+-- lpeg virtual machine to ignore it
+
-- lpeg 12 vs lpeg 10: slower compilation, similar parsing speed (i need to check
-- if i can use new features like capture / 2 and .B (at first sight the xml
-- parser is some 5% slower)
@@ -17,7 +21,13 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
-- move utf -> l-unicode
-- move string -> l-string or keep it here
-lpeg = require("lpeg")
+-- lpeg.B : backward without consumption
+-- lpeg.F = getmetatable(lpeg.P(1)).__len : forward without consumption
+
+
+lpeg = require("lpeg") -- does lpeg register itself global?
+
+local lpeg = lpeg
-- The latest lpeg doesn't have print any more, and even the new ones are not
-- available by default (only when debug mode is enabled), which is a pitty as
@@ -103,11 +113,14 @@ patterns.alwaysmatched = alwaysmatched
local sign = S('+-')
local zero = P('0')
local digit = R('09')
+local digits = digit^1
local octdigit = R("07")
+local octdigits = octdigit^1
local lowercase = R("az")
local uppercase = R("AZ")
local underscore = P("_")
local hexdigit = digit + lowercase + uppercase
+local hexdigits = hexdigit^1
local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
----- newline = crlf + S("\r\n") -- cr + lf
local newline = P("\r") * (P("\n") + P(true)) + P("\n") -- P("\r")^-1 * P("\n")^-1
@@ -187,18 +200,20 @@ local fullstripper = whitespace^0 * C((whitespace^0 * nonwhitespace^1)^0)
----- collapser = Cs(spacer^0/"" * ((spacer^1 * endofstring / "") + (spacer^1/" ") + P(1))^0)
local collapser = Cs(spacer^0/"" * nonspacer^0 * ((spacer^0/" " * nonspacer^1)^0))
+local nospacer = Cs((whitespace^1/"" + nonwhitespace^1)^0)
-local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
-local e_collapser = Cs((whitespace^1 * P(-1)/"" + nonwhitespace^1 + whitespace^1/" ")^0)
-local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
+local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
+local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
+local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
-local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
-local e_stripper = Cs((spacer^1 * P(-1)/"" + nonspacer^1 + spacer^1/" ")^0)
-local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
+local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
+local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
+local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
patterns.stripper = stripper
patterns.fullstripper = fullstripper
patterns.collapser = collapser
+patterns.nospacer = nospacer
patterns.b_collapser = b_collapser
patterns.m_collapser = m_collapser
@@ -238,43 +253,50 @@ patterns.doublequoted = dquote * patterns.nodquote * dquote
patterns.quoted = patterns.doublequoted + patterns.singlequoted
patterns.digit = digit
+patterns.digits = digits
patterns.octdigit = octdigit
+patterns.octdigits = octdigits
patterns.hexdigit = hexdigit
+patterns.hexdigits = hexdigits
patterns.sign = sign
-patterns.cardinal = digit^1
-patterns.integer = sign^-1 * digit^1
-patterns.unsigned = digit^0 * period * digit^1
+patterns.cardinal = digits
+patterns.integer = sign^-1 * digits
+patterns.unsigned = digit^0 * period * digits
patterns.float = sign^-1 * patterns.unsigned
-patterns.cunsigned = digit^0 * comma * digit^1
-patterns.cpunsigned = digit^0 * (period + comma) * digit^1
+patterns.cunsigned = digit^0 * comma * digits
+patterns.cpunsigned = digit^0 * (period + comma) * digits
patterns.cfloat = sign^-1 * patterns.cunsigned
patterns.cpfloat = sign^-1 * patterns.cpunsigned
patterns.number = patterns.float + patterns.integer
patterns.cnumber = patterns.cfloat + patterns.integer
patterns.cpnumber = patterns.cpfloat + patterns.integer
-patterns.oct = zero * octdigit^1
+patterns.oct = zero * octdigits -- hm is this ok
patterns.octal = patterns.oct
patterns.HEX = zero * P("X") * (digit+uppercase)^1
patterns.hex = zero * P("x") * (digit+lowercase)^1
-patterns.hexadecimal = zero * S("xX") * hexdigit^1
+patterns.hexadecimal = zero * S("xX") * hexdigits
patterns.hexafloat = sign^-1
* zero * S("xX")
- * (hexdigit^0 * period * hexdigit^1 + hexdigit^1 * period * hexdigit^0 + hexdigit^1)
- * (S("pP") * sign^-1 * hexdigit^1)^-1
+ * (hexdigit^0 * period * hexdigits + hexdigits * period * hexdigit^0 + hexdigits)
+ * (S("pP") * sign^-1 * hexdigits)^-1
patterns.decafloat = sign^-1
- * (digit^0 * period * digit^1 + digit^1 * period * digit^0 + digit^1)
- * S("eE") * sign^-1 * digit^1
+ * (digit^0 * period * digits + digits * period * digit^0 + digits)
+ * S("eE") * sign^-1 * digits
patterns.propername = (uppercase + lowercase + underscore) * (uppercase + lowercase + underscore + digit)^0 * endofstring
patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1
patterns.beginline = #(1-newline)
-patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^1 + whitespace^1/"" * (P(-1) + Cc(" ")))^0))
+patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^1 + whitespace^1/"" * (endofstring + Cc(" ")))^0))
-local function anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) }
+-- local function anywhere(pattern) -- slightly adapted from website
+-- return P { P(pattern) + 1 * V(1) }
+-- end
+
+function anywhere(pattern) -- faster
+ return (1-P(pattern))^0 * P(pattern)
end
lpeg.anywhere = anywhere
@@ -595,19 +617,27 @@ end
-- print(7,lpegmatch(lpeg.secondofsplit(":"),"bc"))
-- print(9,lpegmatch(lpeg.secondofsplit(":","123"),"bc"))
--- -- slower:
+-- this was slower but lpeg has been sped up in the meantime, so we no longer
+-- use this (still seems somewhat faster on long strings)
+--
+-- local nany = utf8char/""
--
-- function lpeg.counter(pattern)
--- local n, pattern = 0, (lpeg.P(pattern)/function() n = n + 1 end + lpeg.anything)^0
--- return function(str) n = 0 ; lpegmatch(pattern,str) ; return n end
+-- pattern = Cs((P(pattern)/" " + nany)^0)
+-- return function(str)
+-- return #lpegmatch(pattern,str)
+-- end
-- end
-local nany = utf8char/""
-
-function lpeg.counter(pattern)
- pattern = Cs((P(pattern)/" " + nany)^0)
- return function(str)
- return #lpegmatch(pattern,str)
+function lpeg.counter(pattern,action)
+ local n = 0
+ local pattern = (P(pattern) / function() n = n + 1 end + anything)^0
+ ----- pattern = (P(pattern) * (P(true) / function() n = n + 1 end) + anything)^0
+ ----- pattern = (P(pattern) * P(function() n = n + 1 end) + anything)^0
+ if action then
+ return function(str) n = 0 ; lpegmatch(pattern,str) ; action(n) end
+ else
+ return function(str) n = 0 ; lpegmatch(pattern,str) ; return n end
end
end
@@ -839,28 +869,42 @@ end
local p_false = P(false)
local p_true = P(true)
-local function make(t)
- local function making(t)
- local p = p_false
- local keys = sortedkeys(t)
- for i=1,#keys do
- local k = keys[i]
- if k ~= "" then
- local v = t[k]
- if v == true then
- p = p + P(k) * p_true
- elseif v == false then
- -- can't happen
- else
- p = p + P(k) * making(v)
- end
- end
- end
- if t[""] then
- p = p + p_true
- end
- return p
- end
+-- local function collapse(t,x)
+-- if type(t) ~= "table" then
+-- return t, x
+-- else
+-- local n = next(t)
+-- if n == nil then
+-- return t, x
+-- elseif next(t,n) == nil then
+-- -- one entry
+-- local k = n
+-- local v = t[k]
+-- if type(v) == "table" then
+-- return collapse(v,x..k)
+-- else
+-- return v, x .. k
+-- end
+-- else
+-- local tt = { }
+-- for k, v in next, t do
+-- local vv, kk = collapse(v,k)
+-- tt[kk] = vv
+-- end
+-- return tt, x
+-- end
+-- end
+-- end
+
+local lower = utf and utf.lower or string.lower
+local upper = utf and utf.upper or string.upper
+
+function lpeg.setutfcasers(l,u)
+ lower = l or lower
+ upper = u or upper
+end
+
+local function make1(t,rest)
local p = p_false
local keys = sortedkeys(t)
for i=1,#keys do
@@ -872,41 +916,39 @@ local function make(t)
elseif v == false then
-- can't happen
else
- p = p + P(k) * making(v)
+ p = p + P(k) * make1(v,v[""])
end
end
end
+ if rest then
+ p = p + p_true
+ end
return p
end
-local function collapse(t,x)
- if type(t) ~= "table" then
- return t, x
- else
- local n = next(t)
- if n == nil then
- return t, x
- elseif next(t,n) == nil then
- -- one entry
- local k = n
+local function make2(t,rest) -- only ascii
+ local p = p_false
+ local keys = sortedkeys(t)
+ for i=1,#keys do
+ local k = keys[i]
+ if k ~= "" then
local v = t[k]
- if type(v) == "table" then
- return collapse(v,x..k)
+ if v == true then
+ p = p + (P(lower(k))+P(upper(k))) * p_true
+ elseif v == false then
+ -- can't happen
else
- return v, x .. k
+ p = p + (P(lower(k))+P(upper(k))) * make2(v,v[""])
end
- else
- local tt = { }
- for k, v in next, t do
- local vv, kk = collapse(v,k)
- tt[kk] = vv
- end
- return tt, x
end
end
+ if rest then
+ p = p + p_true
+ end
+ return p
end
-function lpeg.utfchartabletopattern(list) -- goes to util-lpg
+local function utfchartabletopattern(list,insensitive) -- goes to util-lpg
local tree = { }
local n = #list
if n == 0 then
@@ -979,32 +1021,42 @@ function lpeg.utfchartabletopattern(list) -- goes to util-lpg
end
end
end
--- collapse(tree,"") -- needs testing, maybe optional, slightly faster because P("x")*P("X") seems slower than P"(xX") (why)
--- inspect(tree)
- return make(tree)
+ -- collapse(tree,"") -- needs testing, maybe optional, slightly faster because P("x")*P("X") seems slower than P"(xX") (why)
+ -- inspect(tree)
+ return (insensitive and make2 or make1)(tree)
+end
+
+lpeg.utfchartabletopattern = utfchartabletopattern
+
+function lpeg.utfreplacer(list,insensitive)
+ local pattern = Cs((utfchartabletopattern(list,insensitive)/list + utf8character)^0)
+ return function(str)
+ return lpegmatch(pattern,str) or str
+ end
end
+
-- local t = { "start", "stoep", "staart", "paard" }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1)
-- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1)
--- inspect(lpegmatch(p,"a"))
--- inspect(lpegmatch(p,"aa"))
--- inspect(lpegmatch(p,"aaaa"))
--- inspect(lpegmatch(p,"ac"))
--- inspect(lpegmatch(p,"bc"))
--- inspect(lpegmatch(p,"zzbczz"))
--- inspect(lpegmatch(p,"zzabezz"))
--- inspect(lpegmatch(p,"ab"))
--- inspect(lpegmatch(p,"abc"))
--- inspect(lpegmatch(p,"abe"))
--- inspect(lpegmatch(p,"xa"))
--- inspect(lpegmatch(p,"bx"))
--- inspect(lpegmatch(p,"bax"))
--- inspect(lpegmatch(p,"abxyz"))
--- inspect(lpegmatch(p,"foobarbefcrap"))
+-- inspect(lpegmatch(p,"a")=="A")
+-- inspect(lpegmatch(p,"aa")=="AA")
+-- inspect(lpegmatch(p,"aaaa")=="AAAA")
+-- inspect(lpegmatch(p,"ac")=="AC")
+-- inspect(lpegmatch(p,"bc")=="bc")
+-- inspect(lpegmatch(p,"zzbczz")=="zzbczz")
+-- inspect(lpegmatch(p,"zzabezz")=="zzABEzz")
+-- inspect(lpegmatch(p,"ab")=="Ab")
+-- inspect(lpegmatch(p,"abc")=="ABC")
+-- inspect(lpegmatch(p,"abe")=="ABE")
+-- inspect(lpegmatch(p,"xa")=="xA")
+-- inspect(lpegmatch(p,"bx")=="bx")
+-- inspect(lpegmatch(p,"bax")=="bAx")
+-- inspect(lpegmatch(p,"abxyz")=="ABXYZ")
+-- inspect(lpegmatch(p,"foobarbefcrap")=="foobArBEFcrAp")
-- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1)
@@ -1081,25 +1133,38 @@ end
-- moved here (before util-str)
------ digit = R("09")
------ period = P(".")
------ zero = P("0")
-local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-local number = digit^1 * (case_1 + case_2)
-local stripper = Cs((number + 1)^0)
+do
+
+ local trailingzeros = zero^0 * -digit -- suggested by Roberto
+ local stripper = Cs((
+ digits * (
+ period * trailingzeros / ""
+ + period * (digit - trailingzeros)^1 * (trailingzeros / "")
+ ) + 1
+ )^0)
+
+ lpeg.patterns.stripzeros = stripper -- multiple in string
-lpeg.patterns.stripzeros = stripper
+ local nonzero = digit - zero
+ local trailingzeros = zero^1 * endofstring
+ local stripper = Cs( (1-period)^0 * (
+ period * trailingzeros/""
+ + period * (nonzero^1 + (trailingzeros/"") + zero^1)^0
+ + endofstring
+ ))
--- local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
--- collectgarbage("collect")
--- str = string.rep(sample,10000)
--- local ts = os.clock()
--- lpegmatch(stripper,str)
--- print(#str, os.clock()-ts, lpegmatch(stripper,sample))
+ lpeg.patterns.stripzero = stripper -- slightly more efficient but expects a float !
--- for practical reasone we keep this here:
+ -- local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
+ -- collectgarbage("collect")
+ -- str = string.rep(sample,10000)
+ -- local ts = os.clock()
+ -- lpegmatch(stripper,str)
+ -- print(#str, os.clock()-ts, lpegmatch(stripper,sample))
+
+end
+
+-- for practical reasons we keep this here:
local byte_to_HEX = { }
local byte_to_hex = { }
@@ -1171,3 +1236,22 @@ end
-- local h = "ADFE0345"
-- local b = lpegmatch(patterns.hextobytes,h)
-- print(h,b,string.tohex(b),string.toHEX(b))
+
+local patterns = { } -- can be made weak
+
+local function containsws(what)
+ local p = patterns[what]
+ if not p then
+ local p1 = P(what) * (whitespace + endofstring) * Cc(true)
+ local p2 = whitespace * P(p1)
+ p = P(p1) + P(1-p2)^0 * p2 + Cc(false)
+ patterns[what] = p
+ end
+ return p
+end
+
+lpeg.containsws = containsws
+
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua
index 35715383635..c0a787a5c43 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua
@@ -17,28 +17,37 @@ if not modules then modules = { } end modules ['l-lua'] = {
-- utf.*
-- bit32
--- compatibility hacksand helpers
+local next, type, tonumber = next, type, tonumber
-_MAJORVERSION, _MINORVERSION = string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+-- compatibility hacks and helpers
-_MAJORVERSION = tonumber(_MAJORVERSION) or 5
-_MINORVERSION = tonumber(_MINORVERSION) or 1
-_LUAVERSION = _MAJORVERSION + _MINORVERSION/10
+LUAMAJORVERSION, LUAMINORVERSION = string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
-if _LUAVERSION < 5.2 and jit then
+LUAMAJORVERSION = tonumber(LUAMAJORVERSION) or 5
+LUAMINORVERSION = tonumber(LUAMINORVERSION) or 1
+LUAVERSION = LUAMAJORVERSION + LUAMINORVERSION/10
+
+if LUAVERSION < 5.2 and jit then
--
-- we want loadstring cum suis to behave like 5.2
--
- _MINORVERSION = 2
- _LUAVERSION = 5.2
+ MINORVERSION = 2
+ LUAVERSION = 5.2
end
+_LUAVERSION = LUAVERSION -- for old times sake, will go away
+
-- lpeg
if not lpeg then
lpeg = require("lpeg")
end
+-- if utf8 then
+-- utf8lua = utf8
+-- utf8 = nil
+-- end
+
-- basics:
if loadstring then
@@ -188,7 +197,7 @@ if lua then
lua.mask = load([[τεχ = 1]]) and "utf" or "ascii"
end
-local flush = io.flush
+local flush = io.flush
if flush then
@@ -199,3 +208,45 @@ if flush then
end
+-- new
+
+FFISUPPORTED = type(ffi) == "table" and ffi.os ~= "" and ffi.arch ~= "" and ffi.load
+
+if not FFISUPPORTED then
+
+ -- Maybe we should check for LUATEXENGINE but that's also a bti tricky as we still
+ -- can have a weird ffi library laying around. Checking for presence of 'jit' is
+ -- also not robust. So for now we hope for the best.
+
+ local okay ; okay, ffi = pcall(require,"ffi")
+
+ FFISUPPORTED = type(ffi) == "table" and ffi.os ~= "" and ffi.arch ~= "" and ffi.load
+
+end
+
+if not FFISUPPORTED then
+ ffi = nil
+elseif not ffi.number then
+ ffi.number = tonumber
+end
+
+if not bit32 then -- and utf8 then
+ -- bit32 = load ( [[ -- replacement code with 5.3 syntax so that 5.2 doesn't bark on it ]] )
+ bit32 = require("l-bit32")
+end
+
+-- We need this due a bug in luatex socket loading:
+
+-- local loaded = package.loaded
+--
+-- if not loaded["socket"] then loaded["socket"] = loaded["socket.core"] end
+-- if not loaded["mime"] then loaded["mime"] = loaded["mime.core"] end
+--
+-- if not socket.mime then socket.mime = package.loaded["mime"] end
+--
+-- if not loaded["socket.mime"] then loaded["socket.mime"] = socket.mime end
+-- if not loaded["socket.http"] then loaded["socket.http"] = socket.http end
+-- if not loaded["socket.ftp"] then loaded["socket.ftp"] = socket.ftp end
+-- if not loaded["socket.smtp"] then loaded["socket.smtp"] = socket.smtp end
+-- if not loaded["socket.tp"] then loaded["socket.tp"] = socket.tp end
+-- if not loaded["socket.url"] then loaded["socket.url"] = socket.url end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-math.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-math.lua
index ec62919b46a..e5668a5db0a 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-math.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-math.lua
@@ -6,33 +6,144 @@ if not modules then modules = { } end modules ['l-math'] = {
license = "see context related readme files"
}
-local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
-
if not math.ceiling then
+
math.ceiling = math.ceil
+
end
if not math.round then
+
+ local floor = math.floor
+
function math.round(x) return floor(x + 0.5) end
+
end
if not math.div then
+
+ local floor = math.floor
+
function math.div(n,m) return floor(n/m) end
+
end
if not math.mod then
+
function math.mod(n,m) return n % m end
-end
-local pipi = 2*math.pi/360
+end
if not math.sind then
+
+ local sin, cos, tan = math.sin, math.cos, math.tan
+
+ local pipi = 2*math.pi/360
+
function math.sind(d) return sin(d*pipi) end
function math.cosd(d) return cos(d*pipi) end
function math.tand(d) return tan(d*pipi) end
+
end
if not math.odd then
+
function math.odd (n) return n % 2 ~= 0 end
function math.even(n) return n % 2 == 0 end
+
+end
+
+if not math.cosh then
+
+ local exp = math.exp
+
+ function math.cosh(x)
+ local xx = exp(x)
+ return (xx+1/xx)/2
+ end
+ function math.sinh(x)
+ local xx = exp(x)
+ return (xx-1/xx)/2
+ end
+ function math.tanh(x)
+ local xx = exp(x)
+ return (xx-1/xx)/(xx+1/xx)
+ end
+
+end
+
+if not math.pow then
+
+ function math.pow(x,y)
+ return x^y
+ end
+
+end
+
+if not math.atan2 then
+
+ math.atan2 = math.atan
+
+end
+
+if not math.ldexp then
+
+ function math.ldexp(x,e)
+ return x * 2.0^e
+ end
+
+end
+
+-- if not math.frexp then
+--
+-- -- not a oneliner so use a math library instead
+--
+-- function math.frexp(x,e)
+-- -- returns m and e such that x = m2e, e is an integer and the absolute
+-- -- value of m is in the range [0.5, 1) (or zero when x is zero)
+-- end
+--
+-- end
+
+if not math.log10 then
+
+ local log = math.log
+
+ function math.log10(x)
+ return log(x,10)
+ end
+
+end
+
+if not math.type then
+
+ function math.type()
+ return "float"
+ end
+
+end
+
+if not math.tointeger then
+
+ math.mininteger = -0x4FFFFFFFFFFF
+ math.maxinteger = 0x4FFFFFFFFFFF
+
+ local floor = math.floor
+
+ function math.tointeger(n)
+ local f = floor(n)
+ return f == n and f or nil
+ end
+
+end
+
+if not math.ult then
+
+ local floor = math.floor
+
+ function math.tointeger(m,n)
+ -- not ok but i'm not motivated to look into it now
+ return floor(m) < floor(n) -- unsigned comparison needed
+ end
+
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-string.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-string.lua
index be8f397aee3..8ae8d8d1d76 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-string.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-string.lua
@@ -18,7 +18,7 @@ local P, S, C, Ct, Cc, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cs
--
-- function string.split(str,pattern)
-- local t = { }
--- if #str > 0 then
+-- if str ~= "" then
-- local n = 1
-- for s in gmatch(str..pattern,"(.-)"..pattern) do
-- t[n] = s
@@ -72,6 +72,7 @@ end
local stripper = patterns.stripper
local fullstripper = patterns.fullstripper
local collapser = patterns.collapser
+local nospacer = patterns.nospacer
local longtostring = patterns.longtostring
function string.strip(str)
@@ -86,6 +87,10 @@ function string.collapsespaces(str)
return str and lpegmatch(collapser,str) or ""
end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
+
function string.longtostring(str)
return str and lpegmatch(longtostring,str) or ""
end
@@ -212,3 +217,24 @@ end
string.quote = string.quoted
string.unquote = string.unquoted
+
+-- new
+
+if not string.bytetable then -- used in font-cff.lua
+
+ local limit = 5000 -- we can go to 8000 in luajit and much higher in lua if needed
+
+ function string.bytetable(str) -- from a string
+ local n = #str
+ if n > limit then
+ local t = { byte(str,1,limit) }
+ for i=limit+1,n do
+ t[i] = byte(str,i)
+ end
+ return t
+ else
+ return { byte(str,1,n) }
+ end
+ end
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua
index 39357bd25e6..69f45d9b4cd 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['l-table'] = {
license = "see context related readme files"
}
-local type, next, tostring, tonumber, ipairs, select = type, next, tostring, tonumber, ipairs, select
+local type, next, tostring, tonumber, select = type, next, tostring, tonumber, select
local table, string = table, string
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
local format, lower, dump = string.format, string.lower, string.dump
@@ -22,6 +22,10 @@ local floor = math.floor
local stripper = patterns.stripper
+function table.getn(t)
+ return t and #t -- for very old times sake
+end
+
function table.strip(tab)
local lst, l = { }, 0
for i=1,#tab do
@@ -416,7 +420,7 @@ end
-- todo : copy without metatable
-local function copy(t, tables) -- taken from lua wiki, slightly adapted
+local function copy(t,tables) -- taken from lua wiki, slightly adapted
tables = tables or { }
local tcopy = { }
if not tables[t] then
@@ -427,7 +431,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
if tables[i] then
i = tables[i]
else
- i = copy(i, tables)
+ i = copy(i,tables)
end
end
if type(v) ~= "table" then
@@ -435,7 +439,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
elseif tables[v] then
tcopy[i] = tables[v]
else
- tcopy[i] = copy(v, tables)
+ tcopy[i] = copy(v,tables)
end
end
local mt = getmetatable(t)
@@ -460,7 +464,7 @@ function table.tohash(t,value)
local h = { }
if t then
if value == nil then value = true end
- for _, v in next, t do -- no ipairs here
+ for _, v in next, t do
h[v] = value
end
end
@@ -469,7 +473,7 @@ end
function table.fromhash(t)
local hsh, h = { }, 0
- for k, v in next, t do -- no ipairs here
+ for k, v in next, t do
if v then
h = h + 1
hsh[h] = k
@@ -486,7 +490,7 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv
'NaN', 'goto',
}
--- local function simple_table(t)
+-- local function is_simple_table(t)
-- if #t > 0 then
-- local n = 0
-- for _,v in next, t do
@@ -520,29 +524,67 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv
-- return nil
-- end
-local function simple_table(t)
+-- local function is_simple_table(t)
+-- local nt = #t
+-- if nt > 0 then
+-- local n = 0
+-- for _,v in next, t do
+-- n = n + 1
+-- -- if type(v) == "table" then
+-- -- return nil
+-- -- end
+-- end
+-- if n == nt then
+-- local tt = { }
+-- for i=1,nt do
+-- local v = t[i]
+-- local tv = type(v)
+-- if tv == "number" then
+-- if hexify then
+-- tt[i] = format("0x%X",v)
+-- else
+-- tt[i] = tostring(v) -- tostring not needed
+-- end
+-- elseif tv == "string" then
+-- tt[i] = format("%q",v)
+-- elseif tv == "boolean" then
+-- tt[i] = v and "true" or "false"
+-- else
+-- return nil
+-- end
+-- end
+-- return tt
+-- end
+-- end
+-- return nil
+-- end
+
+local function is_simple_table(t,hexify) -- also used in util-tab so maybe public
local nt = #t
if nt > 0 then
local n = 0
- for _,v in next, t do
+ for _, v in next, t do
n = n + 1
- -- if type(v) == "table" then
- -- return nil
- -- end
+ if type(v) == "table" then
+ return nil
+ end
end
+ -- local haszero = t[0]
+ local haszero = rawget(t,0) -- don't trigger meta
if n == nt then
local tt = { }
for i=1,nt do
local v = t[i]
local tv = type(v)
if tv == "number" then
+ -- tt[i] = v -- not needed tostring(v)
if hexify then
tt[i] = format("0x%X",v)
else
- tt[i] = tostring(v) -- tostring not needed
+ tt[i] = v -- not needed tostring(v)
end
elseif tv == "string" then
- tt[i] = format("%q",v)
+ tt[i] = format("%q",v) -- f_string(v)
elseif tv == "boolean" then
tt[i] = v and "true" or "false"
else
@@ -550,11 +592,35 @@ local function simple_table(t)
end
end
return tt
+ elseif haszero and (n == nt + 1) then
+ local tt = { }
+ for i=0,nt do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ -- tt[i+1] = v -- not needed tostring(v)
+ if hexify then
+ tt[i+1] = format("0x%X",v)
+ else
+ tt[i+1] = v -- not needed tostring(v)
+ end
+ elseif tv == "string" then
+ tt[i+1] = format("%q",v) -- f_string(v)
+ elseif tv == "boolean" then
+ tt[i+1] = v and "true" or "false"
+ else
+ return nil
+ end
+ end
+ tt[1] = "[0] = " .. tt[1]
+ return tt
end
end
return nil
end
+table.is_simple_table = is_simple_table
+
-- Because this is a core function of mkiv I moved some function calls
-- inline.
--
@@ -637,7 +703,7 @@ local function do_serialize(root,name,depth,level,indexed)
if next(v) == nil then
handle(format("%s {},",depth))
elseif inline then -- and #t > 0
- local st = simple_table(v)
+ local st = is_simple_table(v,hexify)
if st then
handle(format("%s { %s },",depth,concat(st,", ")))
else
@@ -723,7 +789,7 @@ local function do_serialize(root,name,depth,level,indexed)
handle(format("%s [%q]={},",depth,k))
end
elseif inline then
- local st = simple_table(v)
+ local st = is_simple_table(v,hexify)
if st then
if tk == "number" then
if hexify then
@@ -1030,7 +1096,9 @@ function table.unnest(t) -- bad name
end
local function are_equal(a,b,n,m) -- indexed
- if a and b and #a == #b then
+ if a == b then
+ return true
+ elseif a and b and #a == #b then
n = n or 1
m = m or #a
for i=n,m do
@@ -1052,16 +1120,18 @@ local function are_equal(a,b,n,m) -- indexed
end
local function identical(a,b) -- assumes same structure
- for ka, va in next, a do
- local vb = b[ka]
- if va == vb then
- -- same
- elseif type(va) == "table" and type(vb) == "table" then
- if not identical(va,vb) then
+ if a ~= b then
+ for ka, va in next, a do
+ local vb = b[ka]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
return false
end
- else
- return false
end
end
return true
@@ -1155,27 +1225,35 @@ function table.reversed(t)
end
end
-function table.reverse(t)
+function table.reverse(t) -- check with 5.3 ?
if t then
local n = #t
- for i=1,floor(n/2) do
- local j = n - i + 1
+ local m = n + 1
+ for i=1,floor(n/2) do -- maybe just n//2
+ local j = m - i
t[i], t[j] = t[j], t[i]
end
return t
end
end
-function table.sequenced(t,sep,simple) -- hash only
+local function sequenced(t,sep,simple)
if not t then
return ""
+ elseif type(t) == "string" then
+ return t -- handy fallback
end
local n = #t
local s = { }
if n > 0 then
-- indexed
for i=1,n do
- s[i] = tostring(t[i])
+ local v = t[i]
+ if type(v) == "table" then
+ s[i] = "{" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[i] = tostring(t[i])
+ end
end
else
-- hashed
@@ -1187,17 +1265,27 @@ function table.sequenced(t,sep,simple) -- hash only
s[n] = k
elseif v and v~= "" then
n = n + 1
- s[n] = k .. "=" .. tostring(v)
+ if type(v) == "table" then
+ s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[n] = k .. "=" .. tostring(v)
+ end
end
else
n = n + 1
- s[n] = k .. "=" .. tostring(v)
+ if type(v) == "table" then
+ s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[n] = k .. "=" .. tostring(v)
+ end
end
end
end
return concat(s,sep or " | ")
end
+table.sequenced = sequenced
+
function table.print(t,...)
if type(t) ~= "table" then
print(tostring(t))
@@ -1326,3 +1414,26 @@ function table.filtered(t,pattern,sort,cmp)
return nothing
end
end
+
+-- lua 5.3:
+
+if not table.move then
+
+ function table.move(a1,f,e,t,a2)
+ if a2 and a1 ~= a2 then
+ for i=f,e do
+ a2[t] = a1[i]
+ t = t + 1
+ end
+ return a2
+ else
+ t = t + e - f
+ for i=e,f,-1 do
+ a1[t] = a1[i]
+ t = t - 1
+ end
+ return a1
+ end
+ end
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-unicode.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-unicode.lua
new file mode 100644
index 00000000000..b5f52d3127c
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-unicode.lua
@@ -0,0 +1,1361 @@
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- floor(b/256) => rshift(b, 8)
+-- floor(b/1024) => rshift(b,10)
+
+-- in lua 5.3:
+
+-- utf8.char(···) : concatinated
+-- utf8.charpatt : "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
+-- utf8.codes(s) : for p, c in utf8.codes(s) do body end
+-- utf8.codepoint(s [, i [, j]])
+-- utf8.len(s [, i])
+-- utf8.offset(s, n [, i])
+
+-- todo: utf.sub replacement (used in syst-aux)
+-- we put these in the utf namespace:
+
+-- used : byte char gmatch len lower sub upper
+-- not used : dump find format gfind gsub match rep reverse
+
+utf = utf or (unicode and unicode.utf8) or { }
+
+utf.characters = utf.characters or string.utfcharacters
+utf.values = utf.values or string.utfvalues
+
+-- string.utfvalues
+-- string.utfcharacters
+-- string.characters
+-- string.characterpairs
+-- string.bytes
+-- string.bytepairs
+-- string.utflength
+-- string.utfvalues
+-- string.utfcharacters
+
+local type = type
+local char, byte, format, sub, gmatch = string.char, string.byte, string.format, string.sub, string.gmatch
+local concat = table.concat
+local P, C, R, Cs, Ct, Cmt, Cc, Carg, Cp = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct, lpeg.Cmt, lpeg.Cc, lpeg.Carg, lpeg.Cp
+
+local lpegmatch = lpeg.match
+local patterns = lpeg.patterns
+local tabletopattern = lpeg.utfchartabletopattern
+
+local bytepairs = string.bytepairs
+
+local finder = lpeg.finder
+local replacer = lpeg.replacer
+
+local utfvalues = utf.values
+local utfgmatch = utf.gmatch -- not always present
+
+local p_utftype = patterns.utftype
+local p_utfstricttype = patterns.utfstricttype
+local p_utfoffset = patterns.utfoffset
+local p_utf8char = patterns.utf8character
+local p_utf8byte = patterns.utf8byte
+local p_utfbom = patterns.utfbom
+local p_newline = patterns.newline
+local p_whitespace = patterns.whitespace
+
+if not unicode then
+
+ unicode = { utf = utf } -- for a while
+
+end
+
+if not utf.char then
+
+ utf.char = string.utfcharacter or (utf8 and utf8.char)
+
+ if not utf.char then
+
+ -- no multiples
+
+ local char = string.char
+
+ if bit32 then
+
+ local rshift = bit32.rshift
+
+ function utf.char(n)
+ if n < 0x80 then
+ -- 0aaaaaaa : 0x80
+ return char(n)
+ elseif n < 0x800 then
+ -- 110bbbaa : 0xC0 : n >> 6
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ return char(
+ 0xC0 + rshift(n,6),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x10000 then
+ -- 1110bbbb : 0xE0 : n >> 12
+ -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ return char(
+ 0xE0 + rshift(n,12),
+ 0x80 + (rshift(n,6) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x200000 then
+ -- 11110ccc : 0xF0 : n >> 18
+ -- 10ccbbbb : 0x80 : (n >> 12) & 0x3F
+ -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ -- dddd : ccccc - 1
+ return char(
+ 0xF0 + rshift(n,18),
+ 0x80 + (rshift(n,12) % 0x40),
+ 0x80 + (rshift(n,6) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ else
+ return ""
+ end
+ end
+
+ else
+
+ local floor = math.floor
+
+ function utf.char(n)
+ if n < 0x80 then
+ return char(n)
+ elseif n < 0x800 then
+ return char(
+ 0xC0 + floor(n/0x40),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x10000 then
+ return char(
+ 0xE0 + floor(n/0x1000),
+ 0x80 + (floor(n/0x40) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x200000 then
+ return char(
+ 0xF0 + floor(n/0x40000),
+ 0x80 + (floor(n/0x1000) % 0x40),
+ 0x80 + (floor(n/0x40) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ else
+ return ""
+ end
+ end
+
+ end
+
+ end
+
+end
+
+if not utf.byte then
+
+ utf.byte = string.utfvalue or (utf8 and utf8.codepoint)
+
+ if not utf.byte then
+
+ local utf8byte = patterns.utf8byte
+
+ function utf.byte(c)
+ return lpegmatch(utf8byte,c)
+ end
+
+ end
+
+end
+
+local utfchar, utfbyte = utf.char, utf.byte
+
+-- As we want to get rid of the (unmaintained) utf library we implement our own
+-- variants (in due time an independent module):
+
+function utf.filetype(data)
+ return data and lpegmatch(p_utftype,data) or "unknown"
+end
+
+local toentities = Cs (
+ (
+ patterns.utf8one
+ + (
+ patterns.utf8two
+ + patterns.utf8three
+ + patterns.utf8four
+ ) / function(s) local b = utfbyte(s) if b < 127 then return s else return format("&#%X;",b) end end
+ )^0
+)
+
+patterns.toentities = toentities
+
+function utf.toentities(str)
+ return lpegmatch(toentities,str)
+end
+
+-- local utfchr = { } -- 60K -> 2.638 M extra mem but currently not called that often (on latin)
+--
+-- setmetatable(utfchr, { __index = function(t,k) local v = utfchar(k) t[k] = v return v end } )
+--
+-- collectgarbage("collect")
+-- local u = collectgarbage("count")*1024
+-- local t = os.clock()
+-- for i=1,1000 do
+-- for i=1,600 do
+-- local a = utfchr[i]
+-- end
+-- end
+-- print(os.clock()-t,collectgarbage("count")*1024-u)
+
+-- collectgarbage("collect")
+-- local t = os.clock()
+-- for i=1,1000 do
+-- for i=1,600 do
+-- local a = utfchar(i)
+-- end
+-- end
+-- print(os.clock()-t,collectgarbage("count")*1024-u)
+
+-- local byte = string.byte
+-- local utfchar = utf.char
+
+local one = P(1)
+local two = C(1) * C(1)
+local four = C(R(utfchar(0xD8),utfchar(0xFF))) * C(1) * C(1) * C(1)
+
+local pattern = P("\254\255") * Cs( (
+ four / function(a,b,c,d)
+ local ab = 0xFF * byte(a) + byte(b)
+ local cd = 0xFF * byte(c) + byte(d)
+ return utfchar((ab-0xD800)*0x400 + (cd-0xDC00) + 0x10000)
+ end
+ + two / function(a,b)
+ return utfchar(byte(a)*256 + byte(b))
+ end
+ + one
+ )^1 )
+ + P("\255\254") * Cs( (
+ four / function(b,a,d,c)
+ local ab = 0xFF * byte(a) + byte(b)
+ local cd = 0xFF * byte(c) + byte(d)
+ return utfchar((ab-0xD800)*0x400 + (cd-0xDC00) + 0x10000)
+ end
+ + two / function(b,a)
+ return utfchar(byte(a)*256 + byte(b))
+ end
+ + one
+ )^1 )
+
+function string.toutf(s) -- in string namespace
+ return lpegmatch(pattern,s) or s -- todo: utf32
+end
+
+local validatedutf = Cs (
+ (
+ patterns.utf8one
+ + patterns.utf8two
+ + patterns.utf8three
+ + patterns.utf8four
+ + P(1) / "�"
+ )^0
+)
+
+patterns.validatedutf = validatedutf
+
+function utf.is_valid(str)
+ return type(str) == "string" and lpegmatch(validatedutf,str) or false
+end
+
+if not utf.len then
+
+ utf.len = string.utflength or (utf8 and utf8.len)
+
+ if not utf.len then
+
+ -- -- alternative 1: 0.77
+ --
+ -- local utfcharcounter = utfbom^-1 * Cs((p_utf8char/'!')^0)
+ --
+ -- function utf.len(str)
+ -- return #lpegmatch(utfcharcounter,str or "")
+ -- end
+ --
+ -- -- alternative 2: 1.70
+ --
+ -- local n = 0
+ --
+ -- local utfcharcounter = utfbom^-1 * (p_utf8char/function() n = n + 1 end)^0 -- slow
+ --
+ -- function utf.length(str)
+ -- n = 0
+ -- lpegmatch(utfcharcounter,str or "")
+ -- return n
+ -- end
+ --
+ -- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047)
+
+ -- local n = 0
+ --
+ -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( ( Cp() * (
+ -- -- patterns.utf8one ^1 * Cc(1)
+ -- -- + patterns.utf8two ^1 * Cc(2)
+ -- -- + patterns.utf8three^1 * Cc(3)
+ -- -- + patterns.utf8four ^1 * Cc(4) ) * Cp() / function(f,d,t) n = n + (t - f)/d end
+ -- -- )^0 ) -- just as many captures as below
+ --
+ -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( (
+ -- -- (Cmt(patterns.utf8one ^1,function(_,_,s) n = n + #s return true end))
+ -- -- + (Cmt(patterns.utf8two ^1,function(_,_,s) n = n + #s/2 return true end))
+ -- -- + (Cmt(patterns.utf8three^1,function(_,_,s) n = n + #s/3 return true end))
+ -- -- + (Cmt(patterns.utf8four ^1,function(_,_,s) n = n + #s/4 return true end))
+ -- -- )^0 ) -- not interesting as it creates strings but sometimes faster
+ --
+ -- -- The best so far:
+ --
+ -- local utfcharcounter = utfbom^-1 * P ( (
+ -- Cp() * (patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end
+ -- + Cp() * (patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end
+ -- + Cp() * (patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end
+ -- + Cp() * (patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end
+ -- )^0 )
+
+ -- function utf.len(str)
+ -- n = 0
+ -- lpegmatch(utfcharcounter,str or "")
+ -- return n
+ -- end
+
+ local n, f = 0, 1
+
+ local utfcharcounter = patterns.utfbom^-1 * Cmt (
+ Cc(1) * patterns.utf8one ^1
+ + Cc(2) * patterns.utf8two ^1
+ + Cc(3) * patterns.utf8three^1
+ + Cc(4) * patterns.utf8four ^1,
+ function(_,t,d) -- due to Cc no string captures, so faster
+ n = n + (t - f)/d
+ f = t
+ return true
+ end
+ )^0
+
+ function utf.len(str)
+ n, f = 0, 1
+ lpegmatch(utfcharcounter,str or "")
+ return n
+ end
+
+ -- -- these are quite a bit slower:
+
+ -- utfcharcounter = utfbom^-1 * (Cmt(P(1) * R("\128\191")^0, function() n = n + 1 return true end))^0 -- 50+ times slower
+ -- utfcharcounter = utfbom^-1 * (Cmt(P(1), function() n = n + 1 return true end) * R("\128\191")^0)^0 -- 50- times slower
+
+ end
+
+end
+
+utf.length = utf.len
+
+if not utf.sub then
+
+ -- inefficient as lpeg just copies ^n
+
+ -- local function sub(str,start,stop)
+ -- local pattern = p_utf8char^-(start-1) * C(p_utf8char^-(stop-start+1))
+ -- inspect(pattern)
+ -- return lpegmatch(pattern,str) or ""
+ -- end
+
+ -- local b, e, n, first, last = 0, 0, 0, 0, 0
+ --
+ -- local function slide(s,p)
+ -- n = n + 1
+ -- if n == first then
+ -- b = p
+ -- if not last then
+ -- return nil
+ -- end
+ -- end
+ -- if n == last then
+ -- e = p
+ -- return nil
+ -- else
+ -- return p
+ -- end
+ -- end
+ --
+ -- local pattern = Cmt(p_utf8char,slide)^0
+ --
+ -- function utf.sub(str,start,stop) -- todo: from the end
+ -- if not start then
+ -- return str
+ -- end
+ -- b, e, n, first, last = 0, 0, 0, start, stop
+ -- lpegmatch(pattern,str)
+ -- if not stop then
+ -- return sub(str,b)
+ -- else
+ -- return sub(str,b,e-1)
+ -- end
+ -- end
+
+ -- print(utf.sub("Hans Hagen is my name"))
+ -- print(utf.sub("Hans Hagen is my name",5))
+ -- print(utf.sub("Hans Hagen is my name",5,10))
+
+ local utflength = utf.length
+
+ -- also negative indices, upto 10 times slower than a c variant
+
+ local b, e, n, first, last = 0, 0, 0, 0, 0
+
+ local function slide_zero(s,p)
+ n = n + 1
+ if n >= last then
+ e = p - 1
+ else
+ return p
+ end
+ end
+
+ local function slide_one(s,p)
+ n = n + 1
+ if n == first then
+ b = p
+ end
+ if n >= last then
+ e = p - 1
+ else
+ return p
+ end
+ end
+
+ local function slide_two(s,p)
+ n = n + 1
+ if n == first then
+ b = p
+ else
+ return true
+ end
+ end
+
+ local pattern_zero = Cmt(p_utf8char,slide_zero)^0
+ local pattern_one = Cmt(p_utf8char,slide_one )^0
+ local pattern_two = Cmt(p_utf8char,slide_two )^0
+
+ local pattern_first = C(patterns.utf8character)
+
+ function utf.sub(str,start,stop)
+ if not start then
+ return str
+ end
+ if start == 0 then
+ start = 1
+ end
+ if not stop then
+ if start < 0 then
+ local l = utflength(str) -- we can inline this function if needed
+ start = l + start
+ else
+ start = start - 1
+ end
+ b, n, first = 0, 0, start
+ lpegmatch(pattern_two,str)
+ if n >= first then
+ return sub(str,b)
+ else
+ return ""
+ end
+ end
+ if start < 0 or stop < 0 then
+ local l = utf.length(str)
+ if start < 0 then
+ start = l + start
+ if start <= 0 then
+ start = 1
+ else
+ start = start + 1
+ end
+ end
+ if stop < 0 then
+ stop = l + stop
+ if stop == 0 then
+ stop = 1
+ else
+ stop = stop + 1
+ end
+ end
+ end
+ if start == 1 and stop == 1 then
+ return lpegmatch(pattern_first,str) or ""
+ elseif start > stop then
+ return ""
+ elseif start > 1 then
+ b, e, n, first, last = 0, 0, 0, start - 1, stop
+ lpegmatch(pattern_one,str)
+ if n >= first and e == 0 then
+ e = #str
+ end
+ return sub(str,b,e)
+ else
+ b, e, n, last = 1, 0, 0, stop
+ lpegmatch(pattern_zero,str)
+ if e == 0 then
+ e = #str
+ end
+ return sub(str,b,e)
+ end
+ end
+
+ -- local n = 100000
+ -- local str = string.rep("123456àáâãäå",100)
+ --
+ -- for i=-15,15,1 do
+ -- for j=-15,15,1 do
+ -- if utf.xsub(str,i,j) ~= utf.sub(str,i,j) then
+ -- print("error",i,j,"l>"..utf.xsub(str,i,j),"s>"..utf.sub(str,i,j))
+ -- end
+ -- end
+ -- if utf.xsub(str,i) ~= utf.sub(str,i) then
+ -- print("error",i,"l>"..utf.xsub(str,i),"s>"..utf.sub(str,i))
+ -- end
+ -- end
+
+ -- print(" 1, 7",utf.xsub(str, 1, 7),utf.sub(str, 1, 7))
+ -- print(" 0, 7",utf.xsub(str, 0, 7),utf.sub(str, 0, 7))
+ -- print(" 0, 9",utf.xsub(str, 0, 9),utf.sub(str, 0, 9))
+ -- print(" 4 ",utf.xsub(str, 4 ),utf.sub(str, 4 ))
+ -- print(" 0 ",utf.xsub(str, 0 ),utf.sub(str, 0 ))
+ -- print(" 0, 0",utf.xsub(str, 0, 0),utf.sub(str, 0, 0))
+ -- print(" 4, 4",utf.xsub(str, 4, 4),utf.sub(str, 4, 4))
+ -- print(" 4, 0",utf.xsub(str, 4, 0),utf.sub(str, 4, 0))
+ -- print("-3, 0",utf.xsub(str,-3, 0),utf.sub(str,-3, 0))
+ -- print(" 0,-3",utf.xsub(str, 0,-3),utf.sub(str, 0,-3))
+ -- print(" 5,-3",utf.xsub(str,-5,-3),utf.sub(str,-5,-3))
+ -- print("-3 ",utf.xsub(str,-3 ),utf.sub(str,-3 ))
+
+end
+
+-- a replacement for simple gsubs:
+
+-- function utf.remapper(mapping)
+-- local pattern = Cs((p_utf8char/mapping)^0)
+-- return function(str)
+-- if not str or str == "" then
+-- return ""
+-- else
+-- return lpegmatch(pattern,str)
+-- end
+-- end, pattern
+-- end
+
+function utf.remapper(mapping,option,action) -- static also returns a pattern
+ local variant = type(mapping)
+ if variant == "table" then
+ action = action or mapping
+ if option == "dynamic" then
+ local pattern = false
+ table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern = false end)
+ return function(str)
+ if not str or str == "" then
+ return ""
+ else
+ if not pattern then
+ pattern = Cs((tabletopattern(mapping)/action + p_utf8char)^0)
+ end
+ return lpegmatch(pattern,str)
+ end
+ end
+ elseif option == "pattern" then
+ return Cs((tabletopattern(mapping)/action + p_utf8char)^0)
+ -- elseif option == "static" then
+ else
+ local pattern = Cs((tabletopattern(mapping)/action + p_utf8char)^0)
+ return function(str)
+ if not str or str == "" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+ end, pattern
+ end
+ elseif variant == "function" then
+ if option == "pattern" then
+ return Cs((p_utf8char/mapping + p_utf8char)^0)
+ else
+ local pattern = Cs((p_utf8char/mapping + p_utf8char)^0)
+ return function(str)
+ if not str or str == "" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+ end, pattern
+ end
+ else
+ -- is actually an error
+ return function(str)
+ return str or ""
+ end
+ end
+end
+
+-- local remap = utf.remapper { a = 'd', b = "c", c = "b", d = "a" }
+-- print(remap("abcd 1234 abcd"))
+
+function utf.replacer(t) -- no precheck, always string builder
+ local r = replacer(t,false,false,true)
+ return function(str)
+ return lpegmatch(r,str)
+ end
+end
+
+function utf.subtituter(t) -- with precheck and no building if no match
+ local f = finder (t)
+ local r = replacer(t,false,false,true)
+ return function(str)
+ local i = lpegmatch(f,str)
+ if not i then
+ return str
+ elseif i > #str then
+ return str
+ else
+ -- return sub(str,1,i-2) .. lpegmatch(r,str,i-1) -- slower
+ return lpegmatch(r,str)
+ end
+ end
+end
+
+-- inspect(utf.split("a b c d"))
+-- inspect(utf.split("a b c d",true))
+
+local utflinesplitter = p_utfbom^-1 * lpeg.tsplitat(p_newline)
+local utfcharsplitter_ows = p_utfbom^-1 * Ct(C(p_utf8char)^0)
+local utfcharsplitter_iws = p_utfbom^-1 * Ct((p_whitespace^1 + C(p_utf8char))^0)
+local utfcharsplitter_raw = Ct(C(p_utf8char)^0)
+
+patterns.utflinesplitter = utflinesplitter
+
+function utf.splitlines(str)
+ return lpegmatch(utflinesplitter,str or "")
+end
+
+function utf.split(str,ignorewhitespace) -- new
+ if ignorewhitespace then
+ return lpegmatch(utfcharsplitter_iws,str or "")
+ else
+ return lpegmatch(utfcharsplitter_ows,str or "")
+ end
+end
+
+function utf.totable(str) -- keeps bom
+ return lpegmatch(utfcharsplitter_raw,str)
+end
+
+-- 0 EF BB BF UTF-8
+-- 1 FF FE UTF-16-little-endian
+-- 2 FE FF UTF-16-big-endian
+-- 3 FF FE 00 00 UTF-32-little-endian
+-- 4 00 00 FE FF UTF-32-big-endian
+--
+-- \000 fails in <= 5.0 but is valid in >=5.1 where %z is depricated
+
+-- utf.name = {
+-- [0] = 'utf-8',
+-- [1] = 'utf-16-le',
+-- [2] = 'utf-16-be',
+-- [3] = 'utf-32-le',
+-- [4] = 'utf-32-be'
+-- }
+--
+-- function utf.magic(f)
+-- local str = f:read(4)
+-- if not str then
+-- f:seek('set')
+-- return 0
+-- -- elseif find(str,"^%z%z\254\255") then -- depricated
+-- -- elseif find(str,"^\000\000\254\255") then -- not permitted and bugged
+-- elseif find(str,"\000\000\254\255",1,true) then -- seems to work okay (TH)
+-- return 4
+-- -- elseif find(str,"^\255\254%z%z") then -- depricated
+-- -- elseif find(str,"^\255\254\000\000") then -- not permitted and bugged
+-- elseif find(str,"\255\254\000\000",1,true) then -- seems to work okay (TH)
+-- return 3
+-- elseif find(str,"^\254\255") then
+-- f:seek('set',2)
+-- return 2
+-- elseif find(str,"^\255\254") then
+-- f:seek('set',2)
+-- return 1
+-- elseif find(str,"^\239\187\191") then
+-- f:seek('set',3)
+-- return 0
+-- else
+-- f:seek('set')
+-- return 0
+-- end
+-- end
+
+function utf.magic(f) -- not used
+ local str = f:read(4) or ""
+ local off = lpegmatch(p_utfoffset,str)
+ if off < 4 then
+ f:seek('set',off)
+ end
+ return lpegmatch(p_utftype,str)
+end
+
+local utf16_to_utf8_be, utf16_to_utf8_le
+local utf32_to_utf8_be, utf32_to_utf8_le
+
+local utf_16_be_getbom = patterns.utfbom_16_be^-1
+local utf_16_le_getbom = patterns.utfbom_16_le^-1
+local utf_32_be_getbom = patterns.utfbom_32_be^-1
+local utf_32_le_getbom = patterns.utfbom_32_le^-1
+
+local utf_16_be_linesplitter = utf_16_be_getbom * lpeg.tsplitat(patterns.utf_16_be_nl)
+local utf_16_le_linesplitter = utf_16_le_getbom * lpeg.tsplitat(patterns.utf_16_le_nl)
+local utf_32_be_linesplitter = utf_32_be_getbom * lpeg.tsplitat(patterns.utf_32_be_nl)
+local utf_32_le_linesplitter = utf_32_le_getbom * lpeg.tsplitat(patterns.utf_32_le_nl)
+
+-- we have three possibilities: bytepairs (using tables), gmatch (using tables), gsub and
+-- lpeg. Bytepairs are the fastert but as soon as we need to remove bombs and so the gain
+-- is less due to more testing. Also, we seldom have to convert utf16 so we don't care to
+-- much about a few milliseconds more runtime. The lpeg variant is upto 20% slower but
+-- still pretty fast.
+--
+-- for historic resone we keep the bytepairs variants around .. beware they don't grab the
+-- bom like the lpegs do so they're not dropins in the functions that follow
+--
+-- utf16_to_utf8_be = function(s)
+-- if not s then
+-- return nil
+-- elseif s == "" then
+-- return ""
+-- end
+-- local result, r, more = { }, 0, 0
+-- for left, right in bytepairs(s) do
+-- if right then
+-- local now = 256*left + right
+-- if more > 0 then
+-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+-- more = 0
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- elseif now >= 0xD800 and now <= 0xDBFF then
+-- more = now
+-- else
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- end
+-- end
+-- end
+-- return concat(result)
+-- end
+--
+-- local utf16_to_utf8_be_t = function(t)
+-- if not t then
+-- return nil
+-- elseif type(t) == "string" then
+-- t = lpegmatch(utf_16_be_linesplitter,t)
+-- end
+-- local result = { } -- we reuse result
+-- for i=1,#t do
+-- local s = t[i]
+-- if s ~= "" then
+-- local r, more = 0, 0
+-- for left, right in bytepairs(s) do
+-- if right then
+-- local now = 256*left + right
+-- if more > 0 then
+-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+-- more = 0
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- elseif now >= 0xD800 and now <= 0xDBFF then
+-- more = now
+-- else
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- end
+-- end
+-- end
+-- t[i] = concat(result,"",1,r) -- we reused tmp, hence t
+-- end
+-- end
+-- return t
+-- end
+--
+-- utf16_to_utf8_le = function(s)
+-- if not s then
+-- return nil
+-- elseif s == "" then
+-- return ""
+-- end
+-- local result, r, more = { }, 0, 0
+-- for left, right in bytepairs(s) do
+-- if right then
+-- local now = 256*right + left
+-- if more > 0 then
+-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+-- more = 0
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- elseif now >= 0xD800 and now <= 0xDBFF then
+-- more = now
+-- else
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- end
+-- end
+-- end
+-- return concat(result)
+-- end
+--
+-- local utf16_to_utf8_le_t = function(t)
+-- if not t then
+-- return nil
+-- elseif type(t) == "string" then
+-- t = lpegmatch(utf_16_le_linesplitter,t)
+-- end
+-- local result = { } -- we reuse result
+-- for i=1,#t do
+-- local s = t[i]
+-- if s ~= "" then
+-- local r, more = 0, 0
+-- for left, right in bytepairs(s) do
+-- if right then
+-- local now = 256*right + left
+-- if more > 0 then
+-- now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+-- more = 0
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- elseif now >= 0xD800 and now <= 0xDBFF then
+-- more = now
+-- else
+-- r = r + 1
+-- result[r] = utfchar(now)
+-- end
+-- end
+-- end
+-- t[i] = concat(result,"",1,r) -- we reused tmp, hence t
+-- end
+-- end
+-- return t
+-- end
+--
+-- local utf32_to_utf8_be_t = function(t)
+-- if not t then
+-- return nil
+-- elseif type(t) == "string" then
+-- t = lpegmatch(utflinesplitter,t)
+-- end
+-- local result = { } -- we reuse result
+-- for i=1,#t do
+-- local r, more = 0, -1
+-- for a,b in bytepairs(t[i]) do
+-- if a and b then
+-- if more < 0 then
+-- more = 256*256*256*a + 256*256*b
+-- else
+-- r = r + 1
+-- result[t] = utfchar(more + 256*a + b)
+-- more = -1
+-- end
+-- else
+-- break
+-- end
+-- end
+-- t[i] = concat(result,"",1,r)
+-- end
+-- return t
+-- end
+--
+-- local utf32_to_utf8_le_t = function(t)
+-- if not t then
+-- return nil
+-- elseif type(t) == "string" then
+-- t = lpegmatch(utflinesplitter,t)
+-- end
+-- local result = { } -- we reuse result
+-- for i=1,#t do
+-- local r, more = 0, -1
+-- for a,b in bytepairs(t[i]) do
+-- if a and b then
+-- if more < 0 then
+-- more = 256*b + a
+-- else
+-- r = r + 1
+-- result[t] = utfchar(more + 256*256*256*b + 256*256*a)
+-- more = -1
+-- end
+-- else
+-- break
+-- end
+-- end
+-- t[i] = concat(result,"",1,r)
+-- end
+-- return t
+-- end
+
+local more = 0
+
+local p_utf16_to_utf8_be = C(1) * C(1) /function(left,right)
+ local now = 256*byte(left) + byte(right)
+ if more > 0 then
+ now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+ more = 0
+ return utfchar(now)
+ elseif now >= 0xD800 and now <= 0xDBFF then
+ more = now
+ return "" -- else the c's end up in the stream
+ else
+ return utfchar(now)
+ end
+end
+
+local p_utf16_to_utf8_le = C(1) * C(1) /function(right,left)
+ local now = 256*byte(left) + byte(right)
+ if more > 0 then
+ now = (more-0xD800)*0x400 + (now-0xDC00) + 0x10000 -- the 0x10000 smells wrong
+ more = 0
+ return utfchar(now)
+ elseif now >= 0xD800 and now <= 0xDBFF then
+ more = now
+ return "" -- else the c's end up in the stream
+ else
+ return utfchar(now)
+ end
+end
+local p_utf32_to_utf8_be = C(1) * C(1) * C(1) * C(1) /function(a,b,c,d)
+ return utfchar(256*256*256*byte(a) + 256*256*byte(b) + 256*byte(c) + byte(d))
+end
+
+local p_utf32_to_utf8_le = C(1) * C(1) * C(1) * C(1) /function(a,b,c,d)
+ return utfchar(256*256*256*byte(d) + 256*256*byte(c) + 256*byte(b) + byte(a))
+end
+
+p_utf16_to_utf8_be = P(true) / function() more = 0 end * utf_16_be_getbom * Cs(p_utf16_to_utf8_be^0)
+p_utf16_to_utf8_le = P(true) / function() more = 0 end * utf_16_le_getbom * Cs(p_utf16_to_utf8_le^0)
+p_utf32_to_utf8_be = P(true) / function() more = 0 end * utf_32_be_getbom * Cs(p_utf32_to_utf8_be^0)
+p_utf32_to_utf8_le = P(true) / function() more = 0 end * utf_32_le_getbom * Cs(p_utf32_to_utf8_le^0)
+
+patterns.utf16_to_utf8_be = p_utf16_to_utf8_be
+patterns.utf16_to_utf8_le = p_utf16_to_utf8_le
+patterns.utf32_to_utf8_be = p_utf32_to_utf8_be
+patterns.utf32_to_utf8_le = p_utf32_to_utf8_le
+
+utf16_to_utf8_be = function(s)
+ if s and s ~= "" then
+ return lpegmatch(p_utf16_to_utf8_be,s)
+ else
+ return s
+ end
+end
+
+local utf16_to_utf8_be_t = function(t)
+ if not t then
+ return nil
+ elseif type(t) == "string" then
+ t = lpegmatch(utf_16_be_linesplitter,t)
+ end
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ t[i] = lpegmatch(p_utf16_to_utf8_be,s)
+ end
+ end
+ return t
+end
+
+utf16_to_utf8_le = function(s)
+ if s and s ~= "" then
+ return lpegmatch(p_utf16_to_utf8_le,s)
+ else
+ return s
+ end
+end
+
+local utf16_to_utf8_le_t = function(t)
+ if not t then
+ return nil
+ elseif type(t) == "string" then
+ t = lpegmatch(utf_16_le_linesplitter,t)
+ end
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ t[i] = lpegmatch(p_utf16_to_utf8_le,s)
+ end
+ end
+ return t
+end
+
+utf32_to_utf8_be = function(s)
+ if s and s ~= "" then
+ return lpegmatch(p_utf32_to_utf8_be,s)
+ else
+ return s
+ end
+end
+
+local utf32_to_utf8_be_t = function(t)
+ if not t then
+ return nil
+ elseif type(t) == "string" then
+ t = lpegmatch(utf_32_be_linesplitter,t)
+ end
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ t[i] = lpegmatch(p_utf32_to_utf8_be,s)
+ end
+ end
+ return t
+end
+
+utf32_to_utf8_le = function(s)
+ if s and s ~= "" then
+ return lpegmatch(p_utf32_to_utf8_le,s)
+ else
+ return s
+ end
+end
+
+local utf32_to_utf8_le_t = function(t)
+ if not t then
+ return nil
+ elseif type(t) == "string" then
+ t = lpegmatch(utf_32_le_linesplitter,t)
+ end
+ for i=1,#t do
+ local s = t[i]
+ if s ~= "" then
+ t[i] = lpegmatch(p_utf32_to_utf8_le,s)
+ end
+ end
+ return t
+end
+
+utf.utf16_to_utf8_le_t = utf16_to_utf8_le_t
+utf.utf16_to_utf8_be_t = utf16_to_utf8_be_t
+utf.utf32_to_utf8_le_t = utf32_to_utf8_le_t
+utf.utf32_to_utf8_be_t = utf32_to_utf8_be_t
+
+utf.utf16_to_utf8_le = utf16_to_utf8_le
+utf.utf16_to_utf8_be = utf16_to_utf8_be
+utf.utf32_to_utf8_le = utf32_to_utf8_le
+utf.utf32_to_utf8_be = utf32_to_utf8_be
+
+function utf.utf8_to_utf8_t(t)
+ return type(t) == "string" and lpegmatch(utflinesplitter,t) or t
+end
+
+function utf.utf16_to_utf8_t(t,endian)
+ return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t
+end
+
+function utf.utf32_to_utf8_t(t,endian)
+ return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t
+end
+
+local function little(b)
+ if b < 0x10000 then
+ return char(b%256,rshift(b,8))
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
+ end
+end
+
+local function big(b)
+ if b < 0x10000 then
+ return char(rshift(b,8),b%256)
+ else
+ b = b - 0x10000
+ local b1 = rshift(b,10) + 0xD800
+ local b2 = b%1024 + 0xDC00
+ return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
+ end
+end
+
+local l_remap = Cs((p_utf8byte/little+P(1)/"")^0)
+local b_remap = Cs((p_utf8byte/big +P(1)/"")^0)
+
+local function utf8_to_utf16_be(str,nobom)
+ if nobom then
+ return lpegmatch(b_remap,str)
+ else
+ return char(254,255) .. lpegmatch(b_remap,str)
+ end
+end
+
+local function utf8_to_utf16_le(str,nobom)
+ if nobom then
+ return lpegmatch(l_remap,str)
+ else
+ return char(255,254) .. lpegmatch(l_remap,str)
+ end
+end
+
+utf.utf8_to_utf16_be = utf8_to_utf16_be
+utf.utf8_to_utf16_le = utf8_to_utf16_le
+
+function utf.utf8_to_utf16(str,littleendian,nobom)
+ if littleendian then
+ return utf8_to_utf16_le(str,nobom)
+ else
+ return utf8_to_utf16_be(str,nobom)
+ end
+end
+
+-- function utf.tocodes(str,separator) -- can be sped up with an lpeg
+-- local t, n = { }, 0
+-- for u in utfvalues(str) do
+-- n = n + 1
+-- t[n] = format("0x%04X",u)
+-- end
+-- return concat(t,separator or " ")
+-- end
+
+local pattern = Cs (
+ (p_utf8byte / function(unicode ) return format( "0x%04X", unicode) end) *
+ (p_utf8byte * Carg(1) / function(unicode,separator) return format("%s0x%04X",separator,unicode) end)^0
+)
+
+function utf.tocodes(str,separator)
+ return lpegmatch(pattern,str,1,separator or " ")
+end
+
+function utf.ustring(s)
+ return format("U+%05X",type(s) == "number" and s or utfbyte(s))
+end
+
+function utf.xstring(s)
+ return format("0x%05X",type(s) == "number" and s or utfbyte(s))
+end
+
+function utf.toeight(str)
+ if not str or str == "" then
+ return nil
+ end
+ local utftype = lpegmatch(p_utfstricttype,str)
+ if utftype == "utf-8" then
+ return sub(str,4) -- remove the bom
+ elseif utftype == "utf-16-be" then
+ return utf16_to_utf8_be(str) -- bom gets removed
+ elseif utftype == "utf-16-le" then
+ return utf16_to_utf8_le(str) -- bom gets removed
+ else
+ return str
+ end
+end
+
+--
+
+local p_nany = p_utf8char / ""
+
+if utfgmatch then
+
+ function utf.count(str,what)
+ if type(what) == "string" then
+ local n = 0
+ for _ in utfgmatch(str,what) do
+ n = n + 1
+ end
+ return n
+ else -- 4 times slower but still faster than / function
+ return #lpegmatch(Cs((P(what)/" " + p_nany)^0),str)
+ end
+ end
+
+else
+
+ local cache = { }
+
+ function utf.count(str,what)
+ if type(what) == "string" then
+ local p = cache[what]
+ if not p then
+ p = Cs((P(what)/" " + p_nany)^0)
+ cache[p] = p
+ end
+ return #lpegmatch(p,str)
+ else -- 4 times slower but still faster than / function
+ return #lpegmatch(Cs((P(what)/" " + p_nany)^0),str)
+ end
+ end
+
+end
+
+-- maybe also register as string.utf*
+
+
+if not utf.characters then
+
+ -- New: this gmatch hack is taken from the Lua 5.2 book. It's about two times slower
+ -- than the built-in string.utfcharacters.
+
+ function utf.characters(str)
+ return gmatch(str,".[\128-\191]*")
+ end
+
+ string.utfcharacters = utf.characters
+
+end
+
+if not utf.values then
+
+ -- So, a logical next step is to check for the values variant. It over five times
+ -- slower than the built-in string.utfvalues. I optimized it a bit for n=0,1.
+
+ ----- wrap, yield, gmatch = coroutine.wrap, coroutine.yield, string.gmatch
+ local find = string.find
+
+ local dummy = function()
+ -- we share this one
+ end
+
+ -- function utf.values(str)
+ -- local n = #str
+ -- if n == 0 then
+ -- return wrap(dummy)
+ -- elseif n == 1 then
+ -- return wrap(function() yield(utfbyte(str)) end)
+ -- else
+ -- return wrap(function() for s in gmatch(str,".[\128-\191]*") do
+ -- yield(utfbyte(s))
+ -- end end)
+ -- end
+ -- end
+ --
+ -- faster:
+
+ function utf.values(str)
+ local n = #str
+ if n == 0 then
+ return dummy
+ elseif n == 1 then
+ return function() return utfbyte(str) end
+ else
+ local p = 1
+ -- local n = #str
+ return function()
+ -- if p <= n then -- slower than the last find
+ local b, e = find(str,".[\128-\191]*",p)
+ if b then
+ p = e + 1
+ return utfbyte(sub(str,b,e))
+ end
+ -- end
+ end
+ end
+ end
+
+ -- slower:
+ --
+ -- local pattern = C(patterns.utf8character) * Cp()
+ -- ----- pattern = patterns.utf8character/utfbyte * Cp()
+ -- ----- pattern = patterns.utf8byte * Cp()
+ --
+ -- function utf.values(str) -- one of the cases where a find is faster than an lpeg
+ -- local n = #str
+ -- if n == 0 then
+ -- return dummy
+ -- elseif n == 1 then
+ -- return function() return utfbyte(str) end
+ -- else
+ -- local p = 1
+ -- return function()
+ -- local s, e = lpegmatch(pattern,str,p)
+ -- if e then
+ -- p = e
+ -- return utfbyte(s)
+ -- -- return s
+ -- end
+ -- end
+ -- end
+ -- end
+
+ string.utfvalues = utf.values
+
+end
+
+function utf.chrlen(u) -- u is number
+ return
+ (u < 0x80 and 1) or
+ (u < 0xE0 and 2) or
+ (u < 0xF0 and 3) or
+ (u < 0xF8 and 4) or
+ (u < 0xFC and 5) or
+ (u < 0xFE and 6) or 0
+end
+
+-- hashing saves a little but not that much in practice
+--
+-- local utf32 = table.setmetatableindex(function(t,k) local v = toutf32(k) t[k] = v return v end)
+
+if bit32 then
+
+ local extract = bit32.extract
+ local char = string.char
+
+ function unicode.toutf32string(n)
+ if n <= 0xFF then
+ return
+ char(n) ..
+ "\000\000\000"
+ elseif n <= 0xFFFF then
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ "\000\000"
+ elseif n <= 0xFFFFFF then
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ char(extract(n,16,8)) ..
+ "\000"
+ else
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ char(extract(n,16,8)) ..
+ char(extract(n,24,8))
+ end
+ end
+
+end
+
+-- goodie:
+
+local len = utf.len
+local rep = rep
+
+function string.utfpadd(s,n)
+ if n and n ~= 0 then
+ local l = len(s)
+ if n > 0 then
+ local d = n - l
+ if d > 0 then
+ return rep(c or " ",d) .. s
+ end
+ else
+ local d = - n - l
+ if d > 0 then
+ return s .. rep(c or " ",d)
+ end
+ end
+ end
+ return s
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.lua
deleted file mode 100644
index cecd60c1331..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.lua
+++ /dev/null
@@ -1,50 +0,0 @@
-if not modules then modules = { } end modules ['luatex-languages'] = {
- version = 1.001,
- comment = "companion to luatex-languages.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
--- We borrow from ConTeXt.
-
-languages = languages or { }
-
-local loaded = { }
-
-function languages.loadpatterns(tag)
- if not loaded[tag] then
- loaded[tag] = 0
- local filename = kpse.find_file("lang-" .. tag .. ".lua")
- if not filename or filename == "" then
- texio.write("<unknown language file for: " .. tag .. ">")
- else
- local whatever = loadfile(filename)
- if type(whatever) == "function" then
- whatever = whatever()
- if type(whatever) == "table" then
- texio.write("<language file: " .. tag .. ">")
- local characters = whatever.patterns.characters or ""
- local patterns = whatever.patterns.data or ""
- local exceptions = whatever.exceptions.data or ""
- for b in string.utfvalues(characters) do
- -- what about uppercase
--- lang.sethjcode(b,b)
- tex.setlccode(b,b)
- end
- local language = lang.new()
- lang.patterns(language, patterns)
- lang.hyphenation(language, exceptions)
- loaded[tag] = lang.id(language)
- else
- texio.write("<invalid language table: " .. tag .. ">")
- os.exit()
- end
- else
- texio.write("<invalid language file: " .. tag .. ">")
- os.exit()
- end
- end
- end
- return loaded[tag]
-end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.tex
deleted file mode 100644
index a087b30939a..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-languages.tex
+++ /dev/null
@@ -1,19 +0,0 @@
-%D \module
-%D [ file=luatex-fonts,
-%D version=2009.12.01,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Generic \OPENTYPE\ Font Handler,
-%D author=Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D Cf. discussion on \CONTEXT\ list:
-
-% \savinghyphcodes1
-
-\directlua {
- dofile(kpse.find_file("luatex-languages.lua","tex"))
-}
-
-\def\loadpatterns#1{\directlua{tex.language = languages.loadpatterns("#1")}}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.lua
deleted file mode 100644
index c316182ba32..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.lua
+++ /dev/null
@@ -1,53 +0,0 @@
-if not modules then modules = { } end modules ['luatex-math'] = {
- version = 1.001,
- comment = "companion to luatex-math.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local gaps = {
- [0x1D455] = 0x0210E,
- [0x1D49D] = 0x0212C,
- [0x1D4A0] = 0x02130,
- [0x1D4A1] = 0x02131,
- [0x1D4A3] = 0x0210B,
- [0x1D4A4] = 0x02110,
- [0x1D4A7] = 0x02112,
- [0x1D4A8] = 0x02133,
- [0x1D4AD] = 0x0211B,
- [0x1D4BA] = 0x0212F,
- [0x1D4BC] = 0x0210A,
- [0x1D4C4] = 0x02134,
- [0x1D506] = 0x0212D,
- [0x1D50B] = 0x0210C,
- [0x1D50C] = 0x02111,
- [0x1D515] = 0x0211C,
- [0x1D51D] = 0x02128,
- [0x1D53A] = 0x02102,
- [0x1D53F] = 0x0210D,
- [0x1D545] = 0x02115,
- [0x1D547] = 0x02119,
- [0x1D548] = 0x0211A,
- [0x1D549] = 0x0211D,
- [0x1D551] = 0x02124,
-}
-
-
-local function fixmath(tfmdata,key,value)
- if value then
- local characters = tfmdata.characters
- for gap, mess in pairs(gaps) do
- characters[gap] = characters[mess]
- end
- end
-end
-
-fonts.handlers.otf.features.register {
- name = "fixmath",
- description = "math font fixing",
- manipulators = {
- base = fixmath,
- node = fixmath,
- }
-}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.tex
deleted file mode 100644
index b24902100a1..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-math.tex
+++ /dev/null
@@ -1,1874 +0,0 @@
-%D \module
-%D [ file=luatex-math,
-%D version=2013.04.29,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=An exmaple of math,
-%D author=Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D This module is in no way a complete plain math implementation. I made this file
-%D because I needed it for a tutorial for (mostly) plain \TEX\ users. There are
-%D several ways to support math in \LUATEX, and this is just one of them. It was the
-%D quickest hack I could come up with and it stays somewhat close to the traditional
-%D approach (and thereby far from the \CONTEXT\ way). This file is mainly meant for
-%D Boguslaw Jackowski.
-
-% we provide a remap feature
-
-\directlua{dofile(kpse.find_file('luatex-math.lua'))}
-
-% a bunch of fonts:
-
-\let \teni = \relax
-\let \seveni = \relax
-\let \fivei = \relax
-\let \tensy = \relax
-\let \sevensy = \relax
-\let \fivesy = \relax
-\let \tenex = \relax
-\let \sevenbf = \relax
-\let \fivebf = \relax
-
-\def\latinmodern
- {\font\tenrm = file:lmroman10-regular.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\sevenrm = file:lmroman7-regular.otf:+liga;+kern;+tlig;+trep at 7pt
- \font\fiverm = file:lmroman5-regular.otf:+liga;+kern;+tlig;+trep at 5pt
- %
- \font\tentt = file:lmmono10-regular.otf at 10pt
- \font\tensl = file:lmromanslant10-regular.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenit = file:lmroman10-italic.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenbf = file:lmroman10-bold.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenbi = file:lmroman10-bolditalic.otf:+liga;+kern;+tlig;+trep at 10pt
- %
- \font\mathfonttextupright = file:latinmodern-math.otf:script=math;ssty=0;mathsize=yes at 10pt
- \font\mathfontscriptupright = file:latinmodern-math.otf:script=math;ssty=1;mathsize=yes at 7pt
- \font\mathfontscriptscriptupright = file:latinmodern-math.otf:script=math;ssty=2;mathsize=yes at 5pt
- %
- \textfont 0 = \mathfonttextupright
- \scriptfont 0 = \mathfontscriptupright
- \scriptscriptfont 0 = \mathfontscriptscriptupright
- %
- \tenrm}
-
-\def\lucidabright
- {\font\tenrm = file:lucidabrightot.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\sevenrm = file:lucidabrightot.otf:+liga;+kern;+tlig;+trep at 7pt
- \font\fiverm = file:lucidabrightot.otf:+liga;+kern;+tlig;+trep at 5pt
- %
- \font\tentt = file:lucidabrightot.otf at 10pt
- \font\tenit = file:lucidabrightot.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenit = file:lucidabrightot-italic.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenbf = file:lucidabrightot-demi.otf:+liga;+kern;+tlig;+trep at 10pt
- \font\tenbi = file:lucidabrightot-demiitalic.otf:+liga;+kern;+tlig;+trep at 10pt
- %
- \font\mathfonttextupright = file:lucidabrightmathot.otf:script=math;ssty=0;mathsize=yes at 10pt
- \font\mathfontscriptupright = file:lucidabrightmathot.otf:script=math;ssty=1;mathsize=yes at 7pt
- \font\mathfontscriptscriptupright = file:lucidabrightmathot.otf:script=math;ssty=2;mathsize=yes at 5pt
- %
- \textfont 0 = \mathfonttextupright
- \scriptfont 0 = \mathfontscriptupright
- \scriptscriptfont 0 = \mathfontscriptscriptupright
- %
- \tenrm}
-
-\directlua {
- if arguments["mtx:lucidabright"] then
- tex.print("\string\\lucidabright")
- else
- tex.print("\string\\latinmodern")
- end
-}
-
-\newtoks\everymathrm
-\newtoks\everymathmit
-\newtoks\everymathcal
-\newtoks\everymathit
-\newtoks\everymathsl
-\newtoks\everymathbf
-\newtoks\everymathbi
-\newtoks\everymathtt
-
-\def\rm{\fam0\relax\the\everymathrm\relax\tenrm\relax}
-\def\it{\fam0\relax\the\everymathit\relax\tenit\relax}
-\def\sl{\fam0\relax\the\everymathsl\relax\tensl\relax}
-\def\bf{\fam0\relax\the\everymathbf\relax\tenbf\relax}
-\def\bi{\fam0\relax\the\everymathbi\relax\tenbi\relax}
-\def\tt{\fam0\relax\the\everymathtt\relax\tentt\relax}
-
-\let\mit \relax % use names or \Uchar or define a vector
-\let\cal \relax % idem, i'm not in the mood for this now
-\let\oldstyle\relax % no longer misuse of math mode
-
-% tex is fast enough for this kind of assignments:
-
-\everymathrm {%
- \Umathcode"0041="0"0"0041%
- \Umathcode"0042="0"0"0042%
- \Umathcode"0043="0"0"0043%
- \Umathcode"0044="0"0"0044%
- \Umathcode"0045="0"0"0045%
- \Umathcode"0046="0"0"0046%
- \Umathcode"0047="0"0"0047%
- \Umathcode"0048="0"0"0048%
- \Umathcode"0049="0"0"0049%
- \Umathcode"004A="0"0"004A%
- \Umathcode"004B="0"0"004B%
- \Umathcode"004C="0"0"004C%
- \Umathcode"004D="0"0"004D%
- \Umathcode"004E="0"0"004E%
- \Umathcode"004F="0"0"004F%
- \Umathcode"0050="0"0"0050%
- \Umathcode"0051="0"0"0051%
- \Umathcode"0052="0"0"0052%
- \Umathcode"0053="0"0"0053%
- \Umathcode"0054="0"0"0054%
- \Umathcode"0055="0"0"0055%
- \Umathcode"0056="0"0"0056%
- \Umathcode"0057="0"0"0057%
- \Umathcode"0058="0"0"0058%
- \Umathcode"0059="0"0"0059%
- \Umathcode"005A="0"0"005A%
- \Umathcode"0061="0"0"0061%
- \Umathcode"0062="0"0"0062%
- \Umathcode"0063="0"0"0063%
- \Umathcode"0064="0"0"0064%
- \Umathcode"0065="0"0"0065%
- \Umathcode"0066="0"0"0066%
- \Umathcode"0067="0"0"0067%
- \Umathcode"0068="0"0"0068%
- \Umathcode"0069="0"0"0069%
- \Umathcode"006A="0"0"006A%
- \Umathcode"006B="0"0"006B%
- \Umathcode"006C="0"0"006C%
- \Umathcode"006D="0"0"006D%
- \Umathcode"006E="0"0"006E%
- \Umathcode"006F="0"0"006F%
- \Umathcode"0070="0"0"0070%
- \Umathcode"0071="0"0"0071%
- \Umathcode"0072="0"0"0072%
- \Umathcode"0073="0"0"0073%
- \Umathcode"0074="0"0"0074%
- \Umathcode"0075="0"0"0075%
- \Umathcode"0076="0"0"0076%
- \Umathcode"0077="0"0"0077%
- \Umathcode"0078="0"0"0078%
- \Umathcode"0079="0"0"0079%
- \Umathcode"007A="0"0"007A%
- \Umathcode"0391="0"0"0391%
- \Umathcode"0392="0"0"0392%
- \Umathcode"0393="0"0"0393%
- \Umathcode"0394="0"0"0394%
- \Umathcode"0395="0"0"0395%
- \Umathcode"0396="0"0"0396%
- \Umathcode"0397="0"0"0397%
- \Umathcode"0398="0"0"0398%
- \Umathcode"0399="0"0"0399%
- \Umathcode"039A="0"0"039A%
- \Umathcode"039B="0"0"039B%
- \Umathcode"039C="0"0"039C%
- \Umathcode"039D="0"0"039D%
- \Umathcode"039E="0"0"039E%
- \Umathcode"039F="0"0"039F%
- \Umathcode"03A0="0"0"03A0%
- \Umathcode"03A1="0"0"03A1%
- \Umathcode"03A3="0"0"03A3%
- \Umathcode"03A4="0"0"03A4%
- \Umathcode"03A5="0"0"03A5%
- \Umathcode"03A6="0"0"03A6%
- \Umathcode"03A7="0"0"03A7%
- \Umathcode"03A8="0"0"03A8%
- \Umathcode"03A9="0"0"03A9%
- \Umathcode"03B1="0"0"03B1%
- \Umathcode"03B2="0"0"03B2%
- \Umathcode"03B3="0"0"03B3%
- \Umathcode"03B4="0"0"03B4%
- \Umathcode"03B5="0"0"03B5%
- \Umathcode"03B6="0"0"03B6%
- \Umathcode"03B7="0"0"03B7%
- \Umathcode"03B8="0"0"03B8%
- \Umathcode"03B9="0"0"03B9%
- \Umathcode"03BA="0"0"03BA%
- \Umathcode"03BB="0"0"03BB%
- \Umathcode"03BC="0"0"03BC%
- \Umathcode"03BD="0"0"03BD%
- \Umathcode"03BE="0"0"03BE%
- \Umathcode"03BF="0"0"03BF%
- \Umathcode"03C0="0"0"03C0%
- \Umathcode"03C1="0"0"03C1%
- \Umathcode"03C2="0"0"03C2%
- \Umathcode"03C3="0"0"03C3%
- \Umathcode"03C4="0"0"03C4%
- \Umathcode"03C5="0"0"03C5%
- \Umathcode"03C6="0"0"03C6%
- \Umathcode"03C7="0"0"03C7%
- \Umathcode"03C8="0"0"03C8%
- \Umathcode"03C9="0"0"03C9%
- \Umathcode"03D1="0"0"03D1%
- \Umathcode"03D5="0"0"03D5%
- \Umathcode"03D6="0"0"03D6%
- \Umathcode"03F0="0"0"03F0%
- \Umathcode"03F1="0"0"03F1%
- \Umathcode"03F4="0"0"03F4%
- \Umathcode"03F5="0"0"03F5%
- \Umathcode"2202="0"0"2202%
- \Umathcode"2207="0"0"2207%
- \relax
-}
-
-\everymathmit {%
- % not done
-}
-
-\everymathcal {%
- % not done
-}
-
-\everymathit {%
- \Umathcode"0041="0"0"1D434%
- \Umathcode"0042="0"0"1D435%
- \Umathcode"0043="0"0"1D436%
- \Umathcode"0044="0"0"1D437%
- \Umathcode"0045="0"0"1D438%
- \Umathcode"0046="0"0"1D439%
- \Umathcode"0047="0"0"1D43A%
- \Umathcode"0048="0"0"1D43B%
- \Umathcode"0049="0"0"1D43C%
- \Umathcode"004A="0"0"1D43D%
- \Umathcode"004B="0"0"1D43E%
- \Umathcode"004C="0"0"1D43F%
- \Umathcode"004D="0"0"1D440%
- \Umathcode"004E="0"0"1D441%
- \Umathcode"004F="0"0"1D442%
- \Umathcode"0050="0"0"1D443%
- \Umathcode"0051="0"0"1D444%
- \Umathcode"0052="0"0"1D445%
- \Umathcode"0053="0"0"1D446%
- \Umathcode"0054="0"0"1D447%
- \Umathcode"0055="0"0"1D448%
- \Umathcode"0056="0"0"1D449%
- \Umathcode"0057="0"0"1D44A%
- \Umathcode"0058="0"0"1D44B%
- \Umathcode"0059="0"0"1D44C%
- \Umathcode"005A="0"0"1D44D%
- \Umathcode"0061="0"0"1D44E%
- \Umathcode"0062="0"0"1D44F%
- \Umathcode"0063="0"0"1D450%
- \Umathcode"0064="0"0"1D451%
- \Umathcode"0065="0"0"1D452%
- \Umathcode"0066="0"0"1D453%
- \Umathcode"0067="0"0"1D454%
- \Umathcode"0068="0"0"0210E%
- \Umathcode"0069="0"0"1D456%
- \Umathcode"006A="0"0"1D457%
- \Umathcode"006B="0"0"1D458%
- \Umathcode"006C="0"0"1D459%
- \Umathcode"006D="0"0"1D45A%
- \Umathcode"006E="0"0"1D45B%
- \Umathcode"006F="0"0"1D45C%
- \Umathcode"0070="0"0"1D45D%
- \Umathcode"0071="0"0"1D45E%
- \Umathcode"0072="0"0"1D45F%
- \Umathcode"0073="0"0"1D460%
- \Umathcode"0074="0"0"1D461%
- \Umathcode"0075="0"0"1D462%
- \Umathcode"0076="0"0"1D463%
- \Umathcode"0077="0"0"1D464%
- \Umathcode"0078="0"0"1D465%
- \Umathcode"0079="0"0"1D466%
- \Umathcode"007A="0"0"1D467%
- \Umathcode"0391="0"0"1D6E2%
- \Umathcode"0392="0"0"1D6E3%
- \Umathcode"0393="0"0"1D6E4%
- \Umathcode"0394="0"0"1D6E5%
- \Umathcode"0395="0"0"1D6E6%
- \Umathcode"0396="0"0"1D6E7%
- \Umathcode"0397="0"0"1D6E8%
- \Umathcode"0398="0"0"1D6E9%
- \Umathcode"0399="0"0"1D6EA%
- \Umathcode"039A="0"0"1D6EB%
- \Umathcode"039B="0"0"1D6EC%
- \Umathcode"039C="0"0"1D6ED%
- \Umathcode"039D="0"0"1D6EE%
- \Umathcode"039E="0"0"1D6EF%
- \Umathcode"039F="0"0"1D6F0%
- \Umathcode"03A0="0"0"1D6F1%
- \Umathcode"03A1="0"0"1D6F2%
- \Umathcode"03A3="0"0"1D6F4%
- \Umathcode"03A4="0"0"1D6F5%
- \Umathcode"03A5="0"0"1D6F6%
- \Umathcode"03A6="0"0"1D6F7%
- \Umathcode"03A7="0"0"1D6F8%
- \Umathcode"03A8="0"0"1D6F9%
- \Umathcode"03A9="0"0"1D6FA%
- \Umathcode"03B1="0"0"1D6FC%
- \Umathcode"03B2="0"0"1D6FD%
- \Umathcode"03B3="0"0"1D6FE%
- \Umathcode"03B4="0"0"1D6FF%
- \Umathcode"03B5="0"0"1D700%
- \Umathcode"03B6="0"0"1D701%
- \Umathcode"03B7="0"0"1D702%
- \Umathcode"03B8="0"0"1D703%
- \Umathcode"03B9="0"0"1D704%
- \Umathcode"03BA="0"0"1D705%
- \Umathcode"03BB="0"0"1D706%
- \Umathcode"03BC="0"0"1D707%
- \Umathcode"03BD="0"0"1D708%
- \Umathcode"03BE="0"0"1D709%
- \Umathcode"03BF="0"0"1D70A%
- \Umathcode"03C0="0"0"1D70B%
- \Umathcode"03C1="0"0"1D70C%
- \Umathcode"03C2="0"0"1D70D%
- \Umathcode"03C3="0"0"1D70E%
- \Umathcode"03C4="0"0"1D70F%
- \Umathcode"03C5="0"0"1D710%
- \Umathcode"03C6="0"0"1D711%
- \Umathcode"03C7="0"0"1D712%
- \Umathcode"03C8="0"0"1D713%
- \Umathcode"03C9="0"0"1D714%
- \Umathcode"03D1="0"0"1D717%
- \Umathcode"03D5="0"0"1D719%
- \Umathcode"03D6="0"0"1D71B%
- \Umathcode"03F0="0"0"1D718%
- \Umathcode"03F1="0"0"1D71A%
- \Umathcode"03F4="0"0"1D6F3%
- \Umathcode"03F5="0"0"1D716%
- \Umathcode"2202="0"0"1D715%
- \Umathcode"2207="0"0"1D6FB%
- \relax
-}
-
-\everymathsl {%
- \the\everymathit
-}
-
-\everymathbf {%
- \Umathcode"0030="0"0"1D7CE%
- \Umathcode"0031="0"0"1D7CF%
- \Umathcode"0032="0"0"1D7D0%
- \Umathcode"0033="0"0"1D7D1%
- \Umathcode"0034="0"0"1D7D2%
- \Umathcode"0035="0"0"1D7D3%
- \Umathcode"0036="0"0"1D7D4%
- \Umathcode"0037="0"0"1D7D5%
- \Umathcode"0038="0"0"1D7D6%
- \Umathcode"0039="0"0"1D7D7%
- \Umathcode"0041="0"0"1D400%
- \Umathcode"0042="0"0"1D401%
- \Umathcode"0043="0"0"1D402%
- \Umathcode"0044="0"0"1D403%
- \Umathcode"0045="0"0"1D404%
- \Umathcode"0046="0"0"1D405%
- \Umathcode"0047="0"0"1D406%
- \Umathcode"0048="0"0"1D407%
- \Umathcode"0049="0"0"1D408%
- \Umathcode"004A="0"0"1D409%
- \Umathcode"004B="0"0"1D40A%
- \Umathcode"004C="0"0"1D40B%
- \Umathcode"004D="0"0"1D40C%
- \Umathcode"004E="0"0"1D40D%
- \Umathcode"004F="0"0"1D40E%
- \Umathcode"0050="0"0"1D40F%
- \Umathcode"0051="0"0"1D410%
- \Umathcode"0052="0"0"1D411%
- \Umathcode"0053="0"0"1D412%
- \Umathcode"0054="0"0"1D413%
- \Umathcode"0055="0"0"1D414%
- \Umathcode"0056="0"0"1D415%
- \Umathcode"0057="0"0"1D416%
- \Umathcode"0058="0"0"1D417%
- \Umathcode"0059="0"0"1D418%
- \Umathcode"005A="0"0"1D419%
- \Umathcode"0061="0"0"1D41A%
- \Umathcode"0062="0"0"1D41B%
- \Umathcode"0063="0"0"1D41C%
- \Umathcode"0064="0"0"1D41D%
- \Umathcode"0065="0"0"1D41E%
- \Umathcode"0066="0"0"1D41F%
- \Umathcode"0067="0"0"1D420%
- \Umathcode"0068="0"0"1D421%
- \Umathcode"0069="0"0"1D422%
- \Umathcode"006A="0"0"1D423%
- \Umathcode"006B="0"0"1D424%
- \Umathcode"006C="0"0"1D425%
- \Umathcode"006D="0"0"1D426%
- \Umathcode"006E="0"0"1D427%
- \Umathcode"006F="0"0"1D428%
- \Umathcode"0070="0"0"1D429%
- \Umathcode"0071="0"0"1D42A%
- \Umathcode"0072="0"0"1D42B%
- \Umathcode"0073="0"0"1D42C%
- \Umathcode"0074="0"0"1D42D%
- \Umathcode"0075="0"0"1D42E%
- \Umathcode"0076="0"0"1D42F%
- \Umathcode"0077="0"0"1D430%
- \Umathcode"0078="0"0"1D431%
- \Umathcode"0079="0"0"1D432%
- \Umathcode"007A="0"0"1D433%
- \Umathcode"0391="0"0"1D6A8%
- \Umathcode"0392="0"0"1D6A9%
- \Umathcode"0393="0"0"1D6AA%
- \Umathcode"0394="0"0"1D6AB%
- \Umathcode"0395="0"0"1D6AC%
- \Umathcode"0396="0"0"1D6AD%
- \Umathcode"0397="0"0"1D6AE%
- \Umathcode"0398="0"0"1D6AF%
- \Umathcode"0399="0"0"1D6B0%
- \Umathcode"039A="0"0"1D6B1%
- \Umathcode"039B="0"0"1D6B2%
- \Umathcode"039C="0"0"1D6B3%
- \Umathcode"039D="0"0"1D6B4%
- \Umathcode"039E="0"0"1D6B5%
- \Umathcode"039F="0"0"1D6B6%
- \Umathcode"03A0="0"0"1D6B7%
- \Umathcode"03A1="0"0"1D6B8%
- \Umathcode"03A3="0"0"1D6BA%
- \Umathcode"03A4="0"0"1D6BB%
- \Umathcode"03A5="0"0"1D6BC%
- \Umathcode"03A6="0"0"1D6BD%
- \Umathcode"03A7="0"0"1D6BE%
- \Umathcode"03A8="0"0"1D6BF%
- \Umathcode"03A9="0"0"1D6C0%
- \Umathcode"03B1="0"0"1D6C2%
- \Umathcode"03B2="0"0"1D6C3%
- \Umathcode"03B3="0"0"1D6C4%
- \Umathcode"03B4="0"0"1D6C5%
- \Umathcode"03B5="0"0"1D6C6%
- \Umathcode"03B6="0"0"1D6C7%
- \Umathcode"03B7="0"0"1D6C8%
- \Umathcode"03B8="0"0"1D6C9%
- \Umathcode"03B9="0"0"1D6CA%
- \Umathcode"03BA="0"0"1D6CB%
- \Umathcode"03BB="0"0"1D6CC%
- \Umathcode"03BC="0"0"1D6CD%
- \Umathcode"03BD="0"0"1D6CE%
- \Umathcode"03BE="0"0"1D6CF%
- \Umathcode"03BF="0"0"1D6D0%
- \Umathcode"03C0="0"0"1D6D1%
- \Umathcode"03C1="0"0"1D6D2%
- \Umathcode"03C2="0"0"1D6D3%
- \Umathcode"03C3="0"0"1D6D4%
- \Umathcode"03C4="0"0"1D6D5%
- \Umathcode"03C5="0"0"1D6D6%
- \Umathcode"03C6="0"0"1D6D7%
- \Umathcode"03C7="0"0"1D6D8%
- \Umathcode"03C8="0"0"1D6D9%
- \Umathcode"03C9="0"0"1D6DA%
- \Umathcode"03D1="0"0"1D6DD%
- \Umathcode"03D5="0"0"1D6DF%
- \Umathcode"03D6="0"0"1D6E1%
- \Umathcode"03F0="0"0"1D6DE%
- \Umathcode"03F1="0"0"1D6E0%
- \Umathcode"03F4="0"0"1D6B9%
- \Umathcode"03F5="0"0"1D6DC%
- \Umathcode"2202="0"0"1D6DB%
- \Umathcode"2207="0"0"1D6C1%
- \relax
-}
-
-\everymathbi {%
- \Umathcode"0030="0"0"1D7CE%
- \Umathcode"0031="0"0"1D7CF%
- \Umathcode"0032="0"0"1D7D0%
- \Umathcode"0033="0"0"1D7D1%
- \Umathcode"0034="0"0"1D7D2%
- \Umathcode"0035="0"0"1D7D3%
- \Umathcode"0036="0"0"1D7D4%
- \Umathcode"0037="0"0"1D7D5%
- \Umathcode"0038="0"0"1D7D6%
- \Umathcode"0039="0"0"1D7D7%
- \Umathcode"0041="0"0"1D468%
- \Umathcode"0042="0"0"1D469%
- \Umathcode"0043="0"0"1D46A%
- \Umathcode"0044="0"0"1D46B%
- \Umathcode"0045="0"0"1D46C%
- \Umathcode"0046="0"0"1D46D%
- \Umathcode"0047="0"0"1D46E%
- \Umathcode"0048="0"0"1D46F%
- \Umathcode"0049="0"0"1D470%
- \Umathcode"004A="0"0"1D471%
- \Umathcode"004B="0"0"1D472%
- \Umathcode"004C="0"0"1D473%
- \Umathcode"004D="0"0"1D474%
- \Umathcode"004E="0"0"1D475%
- \Umathcode"004F="0"0"1D476%
- \Umathcode"0050="0"0"1D477%
- \Umathcode"0051="0"0"1D478%
- \Umathcode"0052="0"0"1D479%
- \Umathcode"0053="0"0"1D47A%
- \Umathcode"0054="0"0"1D47B%
- \Umathcode"0055="0"0"1D47C%
- \Umathcode"0056="0"0"1D47D%
- \Umathcode"0057="0"0"1D47E%
- \Umathcode"0058="0"0"1D47F%
- \Umathcode"0059="0"0"1D480%
- \Umathcode"005A="0"0"1D481%
- \Umathcode"0061="0"0"1D482%
- \Umathcode"0062="0"0"1D483%
- \Umathcode"0063="0"0"1D484%
- \Umathcode"0064="0"0"1D485%
- \Umathcode"0065="0"0"1D486%
- \Umathcode"0066="0"0"1D487%
- \Umathcode"0067="0"0"1D488%
- \Umathcode"0068="0"0"1D489%
- \Umathcode"0069="0"0"1D48A%
- \Umathcode"006A="0"0"1D48B%
- \Umathcode"006B="0"0"1D48C%
- \Umathcode"006C="0"0"1D48D%
- \Umathcode"006D="0"0"1D48E%
- \Umathcode"006E="0"0"1D48F%
- \Umathcode"006F="0"0"1D490%
- \Umathcode"0070="0"0"1D491%
- \Umathcode"0071="0"0"1D492%
- \Umathcode"0072="0"0"1D493%
- \Umathcode"0073="0"0"1D494%
- \Umathcode"0074="0"0"1D495%
- \Umathcode"0075="0"0"1D496%
- \Umathcode"0076="0"0"1D497%
- \Umathcode"0077="0"0"1D498%
- \Umathcode"0078="0"0"1D499%
- \Umathcode"0079="0"0"1D49A%
- \Umathcode"007A="0"0"1D49B%
- \Umathcode"0391="0"0"1D71C%
- \Umathcode"0392="0"0"1D71D%
- \Umathcode"0393="0"0"1D71E%
- \Umathcode"0394="0"0"1D71F%
- \Umathcode"0395="0"0"1D720%
- \Umathcode"0396="0"0"1D721%
- \Umathcode"0397="0"0"1D722%
- \Umathcode"0398="0"0"1D723%
- \Umathcode"0399="0"0"1D724%
- \Umathcode"039A="0"0"1D725%
- \Umathcode"039B="0"0"1D726%
- \Umathcode"039C="0"0"1D727%
- \Umathcode"039D="0"0"1D728%
- \Umathcode"039E="0"0"1D729%
- \Umathcode"039F="0"0"1D72A%
- \Umathcode"03A0="0"0"1D72B%
- \Umathcode"03A1="0"0"1D72C%
- \Umathcode"03A3="0"0"1D72E%
- \Umathcode"03A4="0"0"1D72F%
- \Umathcode"03A5="0"0"1D730%
- \Umathcode"03A6="0"0"1D731%
- \Umathcode"03A7="0"0"1D732%
- \Umathcode"03A8="0"0"1D733%
- \Umathcode"03A9="0"0"1D734%
- \Umathcode"03B1="0"0"1D736%
- \Umathcode"03B2="0"0"1D737%
- \Umathcode"03B3="0"0"1D738%
- \Umathcode"03B4="0"0"1D739%
- \Umathcode"03B5="0"0"1D73A%
- \Umathcode"03B6="0"0"1D73B%
- \Umathcode"03B7="0"0"1D73C%
- \Umathcode"03B8="0"0"1D73D%
- \Umathcode"03B9="0"0"1D73E%
- \Umathcode"03BA="0"0"1D73F%
- \Umathcode"03BB="0"0"1D740%
- \Umathcode"03BC="0"0"1D741%
- \Umathcode"03BD="0"0"1D742%
- \Umathcode"03BE="0"0"1D743%
- \Umathcode"03BF="0"0"1D744%
- \Umathcode"03C0="0"0"1D745%
- \Umathcode"03C1="0"0"1D746%
- \Umathcode"03C2="0"0"1D747%
- \Umathcode"03C3="0"0"1D748%
- \Umathcode"03C4="0"0"1D749%
- \Umathcode"03C5="0"0"1D74A%
- \Umathcode"03C6="0"0"1D74B%
- \Umathcode"03C7="0"0"1D74C%
- \Umathcode"03C8="0"0"1D74D%
- \Umathcode"03C9="0"0"1D74E%
- \Umathcode"03D1="0"0"1D751%
- \Umathcode"03D5="0"0"1D753%
- \Umathcode"03D6="0"0"1D755%
- \Umathcode"03F0="0"0"1D752%
- \Umathcode"03F1="0"0"1D754%
- \Umathcode"03F4="0"0"1D72D%
- \Umathcode"03F5="0"0"1D750%
- \Umathcode"2202="0"0"1D74F%
- \Umathcode"2207="0"0"1D735%
- \relax
-}
-
-\everymathtt {%
- % not done
-}
-
-\Udelcode "00021 = "0 "00021
-\Udelcode "00028 = "0 "00028
-\Udelcode "00028 = "0 "00028
-\Udelcode "00029 = "0 "00029
-\Udelcode "00029 = "0 "00029
-\Udelcode "0002F = "0 "0002F
-\Udelcode "0002F = "0 "0002F
-\Udelcode "0002F = "0 "02044
-\Udelcode "0003F = "0 "0003F
-\Udelcode "0005B = "0 "0005B
-\Udelcode "0005B = "0 "0005B
-\Udelcode "0005D = "0 "0005D
-\Udelcode "0005D = "0 "0005D
-\Udelcode "0007B = "0 "0007B
-\Udelcode "0007B = "0 "0007B
-\Udelcode "0007C = "0 "0007C
-\Udelcode "0007C = "0 "0007C
-\Udelcode "0007C = "0 "0007C
-\Udelcode "0007C = "0 "0007C
-\Udelcode "0007C = "0 "0007C
-\Udelcode "0007D = "0 "0007D
-\Udelcode "0007D = "0 "0007D
-\Udelcode "02016 = "0 "02016
-\Udelcode "02016 = "0 "02016
-\Udelcode "02016 = "0 "02016
-\Udelcode "02016 = "0 "02016
-\Udelcode "02016 = "0 "02016
-\Udelcode "02044 = "0 "02044
-\Udelcode "02044 = "0 "02044
-\Udelcode "02308 = "0 "02308
-\Udelcode "02308 = "0 "02308
-\Udelcode "02308 = "0 "02308
-\Udelcode "02308 = "0 "02308
-\Udelcode "02308 = "0 "02308
-\Udelcode "02309 = "0 "02309
-\Udelcode "02309 = "0 "02309
-\Udelcode "02309 = "0 "02309
-\Udelcode "02309 = "0 "02309
-\Udelcode "02309 = "0 "02309
-\Udelcode "0230A = "0 "0230A
-\Udelcode "0230A = "0 "0230A
-\Udelcode "0230B = "0 "0230B
-\Udelcode "0230B = "0 "0230B
-\Udelcode "0231C = "0 "0231C
-\Udelcode "0231C = "0 "0231C
-\Udelcode "0231D = "0 "0231D
-\Udelcode "0231D = "0 "0231D
-\Udelcode "0231E = "0 "0231E
-\Udelcode "0231E = "0 "0231E
-\Udelcode "0231F = "0 "0231F
-\Udelcode "0231F = "0 "0231F
-\Udelcode "023B0 = "0 "023B0
-\Udelcode "023B0 = "0 "023B0
-\Udelcode "023B1 = "0 "023B1
-\Udelcode "023B1 = "0 "023B1
-\Udelcode "027E6 = "0 "027E6
-\Udelcode "027E6 = "0 "027E6
-\Udelcode "027E7 = "0 "027E7
-\Udelcode "027E7 = "0 "027E7
-\Udelcode "027E8 = "0 "027E8
-\Udelcode "027E8 = "0 "027E8
-\Udelcode "027E9 = "0 "027E9
-\Udelcode "027E9 = "0 "027E9
-\Udelcode "027EA = "0 "027EA
-\Udelcode "027EA = "0 "027EA
-\Udelcode "027EB = "0 "027EB
-\Udelcode "027EB = "0 "027EB
-\Udelcode "027EE = "0 "027EE
-\Udelcode "027EE = "0 "027EE
-\Udelcode "027EF = "0 "027EF
-\Udelcode "027EF = "0 "027EF
-
-\Umathcode "00021 = "5 "0 "00021
-\Umathcode "00022 = "0 "0 "00022
-\Umathcode "00027 = "0 "0 "00027
-\Umathcode "00028 = "4 "0 "00028
-\Umathcode "00029 = "5 "0 "00029
-\Umathcode "0002A = "2 "0 "02217
-\Umathcode "0002B = "2 "0 "0002B
-\Umathcode "0002C = "6 "0 "0002C
-\Umathcode "0002D = "2 "0 "02212
-\Umathcode "0002E = "6 "0 "0002E
-\Umathcode "0002F = "4 "0 "02044
-\Umathcode "0003A = "3 "0 "0003A
-\Umathcode "0003B = "6 "0 "0003B
-\Umathcode "0003C = "3 "0 "0003C
-\Umathcode "0003D = "3 "0 "0003D
-\Umathcode "0003E = "3 "0 "0003E
-\Umathcode "0003F = "5 "0 "0003F
-\Umathcode "0005B = "4 "0 "0005B
-\Umathcode "0005C = "0 "0 "0005C
-\Umathcode "0005D = "5 "0 "0005D
-\Umathcode "0007B = "4 "0 "0007B
-\Umathcode "0007C = "0 "0 "0007C
-\Umathcode "0007D = "5 "0 "0007D
-\Umathcode "000A5 = "0 "0 "000A5
-\Umathcode "000A7 = "0 "0 "000A7
-\Umathcode "000AC = "0 "0 "000AC
-\Umathcode "000B1 = "2 "0 "000B1
-\Umathcode "000B6 = "0 "0 "000B6
-\Umathcode "000B7 = "2 "0 "000B7
-\Umathcode "000D7 = "2 "0 "000D7
-\Umathcode "000F0 = "0 "0 "000F0
-\Umathcode "000F7 = "2 "0 "000F7
-\Umathcode "00338 = "3 "0 "00338
-\Umathcode "003F0 = "0 "0 "003F0
-\Umathcode "02016 = "0 "0 "02016
-\Umathcode "02020 = "2 "0 "02020
-\Umathcode "02021 = "2 "0 "02021
-\Umathcode "02022 = "2 "0 "02022
-\Umathcode "02026 = "0 "0 "02026
-\Umathcode "02032 = "0 "0 "02032
-\Umathcode "02033 = "0 "0 "02033
-\Umathcode "02034 = "0 "0 "02034
-\Umathcode "02044 = "0 "0 "02044
-\Umathcode "0207A = "2 "0 "0207A
-\Umathcode "0207B = "2 "0 "0207B
-\Umathcode "020DD = "0 "0 "020DD
-\Umathcode "020DE = "0 "0 "020DE
-\Umathcode "020DF = "0 "0 "020DF
-\Umathcode "02111 = "0 "0 "02111
-\Umathcode "02113 = "0 "0 "02113
-\Umathcode "02118 = "0 "0 "02118
-\Umathcode "0211C = "0 "0 "0211C
-\Umathcode "02132 = "0 "0 "02132
-\Umathcode "02135 = "0 "0 "02135
-\Umathcode "02136 = "0 "0 "02136
-\Umathcode "02137 = "0 "0 "02137
-\Umathcode "02138 = "0 "0 "02138
-\Umathcode "02141 = "0 "0 "02141
-\Umathcode "02142 = "0 "0 "02142
-\Umathcode "02143 = "0 "0 "02143
-\Umathcode "02144 = "0 "0 "02144
-\Umathcode "02145 = "0 "0 "02145
-\Umathcode "02146 = "0 "0 "02146
-\Umathcode "02147 = "0 "0 "02147
-\Umathcode "02148 = "0 "0 "02148
-\Umathcode "02149 = "0 "0 "02149
-\Umathcode "0214A = "0 "0 "0214A
-\Umathcode "0214B = "2 "0 "0214B
-\Umathcode "02190 = "3 "0 "02190
-\Umathcode "02191 = "3 "0 "02191
-\Umathcode "02192 = "3 "0 "02192
-\Umathcode "02193 = "3 "0 "02193
-\Umathcode "02194 = "3 "0 "02194
-\Umathcode "02195 = "3 "0 "02195
-\Umathcode "02196 = "3 "0 "02196
-\Umathcode "02197 = "3 "0 "02197
-\Umathcode "02198 = "3 "0 "02198
-\Umathcode "02199 = "3 "0 "02199
-\Umathcode "0219A = "3 "0 "0219A
-\Umathcode "0219B = "3 "0 "0219B
-\Umathcode "0219C = "3 "0 "0219C
-\Umathcode "0219D = "3 "0 "0219D
-\Umathcode "0219E = "3 "0 "0219E
-\Umathcode "0219F = "3 "0 "0219F
-\Umathcode "021A0 = "3 "0 "021A0
-\Umathcode "021A1 = "3 "0 "021A1
-\Umathcode "021A2 = "3 "0 "021A2
-\Umathcode "021A3 = "3 "0 "021A3
-\Umathcode "021A4 = "3 "0 "021A4
-\Umathcode "021A5 = "3 "0 "021A5
-\Umathcode "021A6 = "3 "0 "021A6
-\Umathcode "021A7 = "3 "0 "021A7
-\Umathcode "021A8 = "0 "0 "021A8
-\Umathcode "021A9 = "3 "0 "021A9
-\Umathcode "021AA = "3 "0 "021AA
-\Umathcode "021AB = "3 "0 "021AB
-\Umathcode "021AC = "3 "0 "021AC
-\Umathcode "021AD = "3 "0 "021AD
-\Umathcode "021AE = "3 "0 "021AE
-\Umathcode "021AF = "3 "0 "021AF
-\Umathcode "021B0 = "3 "0 "021B0
-\Umathcode "021B1 = "3 "0 "021B1
-\Umathcode "021B2 = "3 "0 "021B2
-\Umathcode "021B3 = "3 "0 "021B3
-\Umathcode "021B4 = "0 "0 "021B4
-\Umathcode "021B5 = "0 "0 "021B5
-\Umathcode "021B6 = "3 "0 "021B6
-\Umathcode "021B7 = "3 "0 "021B7
-\Umathcode "021B8 = "3 "0 "021B8
-\Umathcode "021B9 = "3 "0 "021B9
-\Umathcode "021BA = "3 "0 "021BA
-\Umathcode "021BB = "3 "0 "021BB
-\Umathcode "021BC = "3 "0 "021BC
-\Umathcode "021BD = "3 "0 "021BD
-\Umathcode "021BE = "3 "0 "021BE
-\Umathcode "021BF = "3 "0 "021BF
-\Umathcode "021C0 = "3 "0 "021C0
-\Umathcode "021C1 = "3 "0 "021C1
-\Umathcode "021C2 = "3 "0 "021C2
-\Umathcode "021C3 = "3 "0 "021C3
-\Umathcode "021C4 = "3 "0 "021C4
-\Umathcode "021C5 = "3 "0 "021C5
-\Umathcode "021C6 = "3 "0 "021C6
-\Umathcode "021C7 = "3 "0 "021C7
-\Umathcode "021C8 = "3 "0 "021C8
-\Umathcode "021C9 = "3 "0 "021C9
-\Umathcode "021CA = "3 "0 "021CA
-\Umathcode "021CB = "3 "0 "021CB
-\Umathcode "021CC = "3 "0 "021CC
-\Umathcode "021CD = "3 "0 "021CD
-\Umathcode "021CE = "3 "0 "021CE
-\Umathcode "021CF = "3 "0 "021CF
-\Umathcode "021D0 = "3 "0 "021D0
-\Umathcode "021D1 = "3 "0 "021D1
-\Umathcode "021D2 = "3 "0 "021D2
-\Umathcode "021D3 = "3 "0 "021D3
-\Umathcode "021D4 = "3 "0 "021D4
-\Umathcode "021D5 = "3 "0 "021D5
-\Umathcode "021D6 = "3 "0 "021D6
-\Umathcode "021D7 = "3 "0 "021D7
-\Umathcode "021D8 = "3 "0 "021D8
-\Umathcode "021D9 = "3 "0 "021D9
-\Umathcode "021DA = "3 "0 "021DA
-\Umathcode "021DB = "3 "0 "021DB
-\Umathcode "021DC = "3 "0 "021DC
-\Umathcode "021DD = "3 "0 "021DD
-\Umathcode "021DE = "3 "0 "021DE
-\Umathcode "021DF = "3 "0 "021DF
-\Umathcode "021E0 = "3 "0 "021E0
-\Umathcode "021E1 = "3 "0 "021E1
-\Umathcode "021E2 = "3 "0 "021E2
-\Umathcode "021E3 = "3 "0 "021E3
-\Umathcode "021E4 = "3 "0 "021E4
-\Umathcode "021E5 = "3 "0 "021E5
-\Umathcode "021E6 = "0 "0 "021E6
-\Umathcode "021E7 = "0 "0 "021E7
-\Umathcode "021E8 = "0 "0 "021E8
-\Umathcode "021E9 = "0 "0 "021E9
-\Umathcode "021EB = "0 "0 "021EB
-\Umathcode "021F4 = "3 "0 "021F4
-\Umathcode "021F5 = "3 "0 "021F5
-\Umathcode "021F6 = "3 "0 "021F6
-\Umathcode "021F7 = "3 "0 "021F7
-\Umathcode "021F8 = "3 "0 "021F8
-\Umathcode "021F9 = "3 "0 "021F9
-\Umathcode "021FA = "3 "0 "021FA
-\Umathcode "021FB = "3 "0 "021FB
-\Umathcode "021FC = "3 "0 "021FC
-\Umathcode "021FD = "3 "0 "021FD
-\Umathcode "021FE = "3 "0 "021FE
-\Umathcode "021FF = "3 "0 "021FF
-\Umathcode "02200 = "0 "0 "02200
-\Umathcode "02201 = "0 "0 "02201
-\Umathcode "02202 = "0 "0 "02202
-\Umathcode "02203 = "0 "0 "02203
-\Umathcode "02204 = "0 "0 "02204
-\Umathcode "02205 = "0 "0 "02205
-\Umathcode "02208 = "3 "0 "02208
-\Umathcode "02209 = "3 "0 "02209
-\Umathcode "0220B = "3 "0 "0220B
-\Umathcode "0220C = "3 "0 "0220C
-\Umathcode "0220F = "1 "0 "0220F
-\Umathcode "02210 = "1 "0 "02210
-\Umathcode "02211 = "1 "0 "02211
-\Umathcode "02212 = "2 "0 "02212
-\Umathcode "02213 = "2 "0 "02213
-\Umathcode "02214 = "2 "0 "02214
-\Umathcode "02216 = "2 "0 "02216
-\Umathcode "02217 = "2 "0 "02217
-\Umathcode "02218 = "2 "0 "02218
-\Umathcode "02219 = "2 "0 "02219
-\Umathcode "0221D = "3 "0 "0221D
-\Umathcode "0221E = "0 "0 "0221E
-\Umathcode "0221F = "0 "0 "0221F
-\Umathcode "02220 = "0 "0 "02220
-\Umathcode "02221 = "0 "0 "02221
-\Umathcode "02222 = "0 "0 "02222
-\Umathcode "02223 = "2 "0 "02223
-\Umathcode "02224 = "2 "0 "02224
-\Umathcode "02225 = "3 "0 "02225
-\Umathcode "02226 = "3 "0 "02226
-\Umathcode "02227 = "2 "0 "02227
-\Umathcode "02228 = "2 "0 "02228
-\Umathcode "02229 = "2 "0 "02229
-\Umathcode "0222A = "2 "0 "0222A
-\Umathcode "0222B = "1 "0 "0222B
-\Umathcode "0222C = "1 "0 "0222C
-\Umathcode "0222D = "1 "0 "0222D
-\Umathcode "0222E = "1 "0 "0222E
-\Umathcode "0222F = "1 "0 "0222F
-\Umathcode "02230 = "1 "0 "02230
-\Umathcode "02231 = "1 "0 "02231
-\Umathcode "02232 = "1 "0 "02232
-\Umathcode "02233 = "1 "0 "02233
-\Umathcode "02234 = "3 "0 "02234
-\Umathcode "02235 = "3 "0 "02235
-\Umathcode "02236 = "6 "0 "02236
-\Umathcode "02237 = "3 "0 "02237
-\Umathcode "02238 = "2 "0 "02238
-\Umathcode "02239 = "3 "0 "02239
-\Umathcode "0223C = "3 "0 "0223C
-\Umathcode "0223D = "3 "0 "0223D
-\Umathcode "02240 = "2 "0 "02240
-\Umathcode "02241 = "3 "0 "02241
-\Umathcode "02242 = "3 "0 "02242
-\Umathcode "02243 = "3 "0 "02243
-\Umathcode "02244 = "3 "0 "02244
-\Umathcode "02245 = "3 "0 "02245
-\Umathcode "02246 = "3 "0 "02246
-\Umathcode "02247 = "3 "0 "02247
-\Umathcode "02248 = "3 "0 "02248
-\Umathcode "02249 = "3 "0 "02249
-\Umathcode "0224A = "3 "0 "0224A
-\Umathcode "0224C = "3 "0 "0224C
-\Umathcode "0224D = "3 "0 "0224D
-\Umathcode "0224E = "3 "0 "0224E
-\Umathcode "02250 = "3 "0 "02250
-\Umathcode "02251 = "3 "0 "02251
-\Umathcode "02252 = "3 "0 "02252
-\Umathcode "02253 = "3 "0 "02253
-\Umathcode "02254 = "3 "0 "02254
-\Umathcode "02255 = "3 "0 "02255
-\Umathcode "02256 = "3 "0 "02256
-\Umathcode "02257 = "3 "0 "02257
-\Umathcode "02259 = "3 "0 "02259
-\Umathcode "0225A = "3 "0 "0225A
-\Umathcode "0225B = "3 "0 "0225B
-\Umathcode "0225C = "3 "0 "0225C
-\Umathcode "0225D = "3 "0 "0225D
-\Umathcode "0225E = "3 "0 "0225E
-\Umathcode "0225F = "3 "0 "0225F
-\Umathcode "02260 = "3 "0 "02260
-\Umathcode "02261 = "3 "0 "02261
-\Umathcode "02262 = "3 "0 "02262
-\Umathcode "02263 = "3 "0 "02263
-\Umathcode "02264 = "3 "0 "02264
-\Umathcode "02265 = "3 "0 "02265
-\Umathcode "02266 = "3 "0 "02266
-\Umathcode "02267 = "3 "0 "02267
-\Umathcode "02268 = "3 "0 "02268
-\Umathcode "02269 = "3 "0 "02269
-\Umathcode "0226A = "3 "0 "0226A
-\Umathcode "0226B = "3 "0 "0226B
-\Umathcode "0226C = "3 "0 "0226C
-\Umathcode "0226D = "3 "0 "0226D
-\Umathcode "0226E = "3 "0 "0226E
-\Umathcode "0226F = "3 "0 "0226F
-\Umathcode "02270 = "3 "0 "02270
-\Umathcode "02271 = "3 "0 "02271
-\Umathcode "02272 = "3 "0 "02272
-\Umathcode "02273 = "3 "0 "02273
-\Umathcode "02274 = "3 "0 "02274
-\Umathcode "02275 = "3 "0 "02275
-\Umathcode "02276 = "3 "0 "02276
-\Umathcode "02277 = "3 "0 "02277
-\Umathcode "02278 = "3 "0 "02278
-\Umathcode "02279 = "3 "0 "02279
-\Umathcode "0227A = "3 "0 "0227A
-\Umathcode "0227B = "3 "0 "0227B
-\Umathcode "0227C = "3 "0 "0227C
-\Umathcode "0227D = "3 "0 "0227D
-\Umathcode "0227E = "3 "0 "0227E
-\Umathcode "0227F = "3 "0 "0227F
-\Umathcode "02280 = "3 "0 "02280
-\Umathcode "02281 = "3 "0 "02281
-\Umathcode "02282 = "3 "0 "02282
-\Umathcode "02283 = "3 "0 "02283
-\Umathcode "02284 = "3 "0 "02284
-\Umathcode "02285 = "3 "0 "02285
-\Umathcode "02286 = "3 "0 "02286
-\Umathcode "02287 = "3 "0 "02287
-\Umathcode "02288 = "3 "0 "02288
-\Umathcode "02289 = "3 "0 "02289
-\Umathcode "0228A = "3 "0 "0228A
-\Umathcode "0228B = "3 "0 "0228B
-\Umathcode "0228E = "2 "0 "0228E
-\Umathcode "0228F = "3 "0 "0228F
-\Umathcode "02290 = "3 "0 "02290
-\Umathcode "02291 = "2 "0 "02291
-\Umathcode "02292 = "2 "0 "02292
-\Umathcode "02293 = "2 "0 "02293
-\Umathcode "02294 = "2 "0 "02294
-\Umathcode "02295 = "2 "0 "02295
-\Umathcode "02296 = "2 "0 "02296
-\Umathcode "02297 = "2 "0 "02297
-\Umathcode "02298 = "2 "0 "02298
-\Umathcode "02299 = "2 "0 "02299
-\Umathcode "0229A = "2 "0 "0229A
-\Umathcode "0229B = "2 "0 "0229B
-\Umathcode "0229C = "2 "0 "0229C
-\Umathcode "0229D = "2 "0 "0229D
-\Umathcode "0229E = "2 "0 "0229E
-\Umathcode "0229F = "2 "0 "0229F
-\Umathcode "022A0 = "2 "0 "022A0
-\Umathcode "022A1 = "2 "0 "022A1
-\Umathcode "022A2 = "3 "0 "022A2
-\Umathcode "022A3 = "3 "0 "022A3
-\Umathcode "022A4 = "0 "0 "022A4
-\Umathcode "022A5 = "0 "0 "022A5
-\Umathcode "022A7 = "3 "0 "022A7
-\Umathcode "022A8 = "3 "0 "022A8
-\Umathcode "022A9 = "3 "0 "022A9
-\Umathcode "022AA = "3 "0 "022AA
-\Umathcode "022AB = "3 "0 "022AB
-\Umathcode "022AC = "3 "0 "022AC
-\Umathcode "022AD = "3 "0 "022AD
-\Umathcode "022AE = "3 "0 "022AE
-\Umathcode "022AF = "3 "0 "022AF
-\Umathcode "022B2 = "2 "0 "022B2
-\Umathcode "022B3 = "2 "0 "022B3
-\Umathcode "022B8 = "3 "0 "022B8
-\Umathcode "022BA = "2 "0 "022BA
-\Umathcode "022BB = "2 "0 "022BB
-\Umathcode "022BC = "2 "0 "022BC
-\Umathcode "022C0 = "1 "0 "022C0
-\Umathcode "022C1 = "1 "0 "022C1
-\Umathcode "022C2 = "1 "0 "022C2
-\Umathcode "022C3 = "1 "0 "022C3
-\Umathcode "022C4 = "2 "0 "022C4
-\Umathcode "022C5 = "2 "0 "022C5
-\Umathcode "022C6 = "2 "0 "022C6
-\Umathcode "022C7 = "2 "0 "022C7
-\Umathcode "022C8 = "3 "0 "022C8
-\Umathcode "022C9 = "2 "0 "022C9
-\Umathcode "022CA = "2 "0 "022CA
-\Umathcode "022CB = "2 "0 "022CB
-\Umathcode "022CC = "2 "0 "022CC
-\Umathcode "022CE = "2 "0 "022CE
-\Umathcode "022CF = "2 "0 "022CF
-\Umathcode "022D0 = "3 "0 "022D0
-\Umathcode "022D1 = "3 "0 "022D1
-\Umathcode "022D2 = "2 "0 "022D2
-\Umathcode "022D3 = "2 "0 "022D3
-\Umathcode "022D4 = "3 "0 "022D4
-\Umathcode "022D6 = "2 "0 "022D6
-\Umathcode "022D7 = "2 "0 "022D7
-\Umathcode "022D8 = "3 "0 "022D8
-\Umathcode "022D9 = "3 "0 "022D9
-\Umathcode "022DA = "3 "0 "022DA
-\Umathcode "022DB = "3 "0 "022DB
-\Umathcode "022DC = "3 "0 "022DC
-\Umathcode "022DD = "3 "0 "022DD
-\Umathcode "022DE = "3 "0 "022DE
-\Umathcode "022DF = "3 "0 "022DF
-\Umathcode "022E0 = "3 "0 "022E0
-\Umathcode "022E1 = "3 "0 "022E1
-\Umathcode "022E2 = "3 "0 "022E2
-\Umathcode "022E3 = "3 "0 "022E3
-\Umathcode "022E4 = "3 "0 "022E4
-\Umathcode "022E5 = "3 "0 "022E5
-\Umathcode "022E6 = "3 "0 "022E6
-\Umathcode "022E7 = "3 "0 "022E7
-\Umathcode "022E8 = "3 "0 "022E8
-\Umathcode "022E9 = "3 "0 "022E9
-\Umathcode "022EA = "3 "0 "022EA
-\Umathcode "022EB = "3 "0 "022EB
-\Umathcode "022EC = "3 "0 "022EC
-\Umathcode "022ED = "3 "0 "022ED
-\Umathcode "022EE = "0 "0 "022EE
-\Umathcode "022EF = "0 "0 "022EF
-\Umathcode "022F0 = "0 "0 "022F0
-\Umathcode "022F1 = "0 "0 "022F1
-\Umathcode "02300 = "0 "0 "02300
-\Umathcode "02308 = "4 "0 "02308
-\Umathcode "02309 = "5 "0 "02309
-\Umathcode "0230A = "4 "0 "0230A
-\Umathcode "0230B = "5 "0 "0230B
-\Umathcode "0231C = "4 "0 "0231C
-\Umathcode "0231D = "5 "0 "0231D
-\Umathcode "0231E = "4 "0 "0231E
-\Umathcode "0231F = "5 "0 "0231F
-\Umathcode "02322 = "3 "0 "02322
-\Umathcode "02323 = "3 "0 "02323
-\Umathcode "023B0 = "4 "0 "023B0
-\Umathcode "023B1 = "5 "0 "023B1
-\Umathcode "024C7 = "0 "0 "024C7
-\Umathcode "024C8 = "0 "0 "024C8
-\Umathcode "025A0 = "0 "0 "025A0
-\Umathcode "025A1 = "0 "0 "025A1
-\Umathcode "025A2 = "0 "0 "025A2
-\Umathcode "025B2 = "2 "0 "025B2
-\Umathcode "025B3 = "0 "0 "025B3
-\Umathcode "025B6 = "2 "0 "025B6
-\Umathcode "025B7 = "2 "0 "025B7
-\Umathcode "025BC = "2 "0 "025BC
-\Umathcode "025BD = "2 "0 "025BD
-\Umathcode "025C0 = "2 "0 "025C0
-\Umathcode "025C1 = "2 "0 "025C1
-\Umathcode "025CA = "0 "0 "025CA
-\Umathcode "025EF = "2 "0 "025EF
-\Umathcode "02605 = "0 "0 "02605
-\Umathcode "02660 = "0 "0 "02660
-\Umathcode "02661 = "0 "0 "02661
-\Umathcode "02662 = "0 "0 "02662
-\Umathcode "02663 = "0 "0 "02663
-\Umathcode "02666 = "0 "0 "02666
-\Umathcode "0266D = "0 "0 "0266D
-\Umathcode "0266E = "0 "0 "0266E
-\Umathcode "0266F = "0 "0 "0266F
-\Umathcode "02713 = "0 "0 "02713
-\Umathcode "02720 = "0 "0 "02720
-\Umathcode "027E6 = "4 "0 "027E6
-\Umathcode "027E7 = "5 "0 "027E7
-\Umathcode "027E8 = "4 "0 "027E8
-\Umathcode "027E9 = "5 "0 "027E9
-\Umathcode "027EA = "4 "0 "027EA
-\Umathcode "027EB = "5 "0 "027EB
-\Umathcode "027EE = "4 "0 "027EE
-\Umathcode "027EF = "5 "0 "027EF
-\Umathcode "027F5 = "3 "0 "027F5
-\Umathcode "027F6 = "3 "0 "027F6
-\Umathcode "027F7 = "3 "0 "027F7
-\Umathcode "027F8 = "3 "0 "027F8
-\Umathcode "027F9 = "3 "0 "027F9
-\Umathcode "027FA = "3 "0 "027FA
-\Umathcode "027FB = "3 "0 "027FB
-\Umathcode "027FC = "3 "0 "027FC
-\Umathcode "027FD = "3 "0 "027FD
-\Umathcode "027FE = "3 "0 "027FE
-\Umathcode "027FF = "3 "0 "027FF
-\Umathcode "02906 = "3 "0 "02906
-\Umathcode "02907 = "3 "0 "02907
-\Umathcode "0290A = "3 "0 "0290A
-\Umathcode "0290B = "3 "0 "0290B
-\Umathcode "0290C = "3 "0 "0290C
-\Umathcode "0290D = "3 "0 "0290D
-\Umathcode "02911 = "3 "0 "02911
-\Umathcode "02916 = "3 "0 "02916
-\Umathcode "02917 = "3 "0 "02917
-\Umathcode "02921 = "3 "0 "02921
-\Umathcode "02922 = "3 "0 "02922
-\Umathcode "02923 = "3 "0 "02923
-\Umathcode "02924 = "3 "0 "02924
-\Umathcode "02925 = "3 "0 "02925
-\Umathcode "02926 = "3 "0 "02926
-\Umathcode "02A00 = "1 "0 "02A00
-\Umathcode "02A01 = "1 "0 "02A01
-\Umathcode "02A02 = "1 "0 "02A02
-\Umathcode "02A03 = "1 "0 "02A03
-\Umathcode "02A04 = "1 "0 "02A04
-\Umathcode "02A05 = "1 "0 "02A05
-\Umathcode "02A06 = "1 "0 "02A06
-\Umathcode "02A09 = "1 "0 "02A09
-\Umathcode "02A3F = "2 "0 "02A3F
-\Umathcode "02A7D = "3 "0 "02A7D
-\Umathcode "02A7E = "3 "0 "02A7E
-\Umathcode "02A85 = "3 "0 "02A85
-\Umathcode "02A86 = "3 "0 "02A86
-\Umathcode "02A87 = "3 "0 "02A87
-\Umathcode "02A88 = "3 "0 "02A88
-\Umathcode "02A89 = "3 "0 "02A89
-\Umathcode "02A8A = "3 "0 "02A8A
-\Umathcode "02A8B = "3 "0 "02A8B
-\Umathcode "02A8C = "3 "0 "02A8C
-\Umathcode "02A95 = "3 "0 "02A95
-\Umathcode "02A96 = "3 "0 "02A96
-\Umathcode "02AAF = "3 "0 "02AAF
-\Umathcode "02AB0 = "3 "0 "02AB0
-\Umathcode "02AB1 = "3 "0 "02AB1
-\Umathcode "02AB2 = "3 "0 "02AB2
-\Umathcode "02AB3 = "3 "0 "02AB3
-\Umathcode "02AB4 = "3 "0 "02AB4
-\Umathcode "02AB5 = "3 "0 "02AB5
-\Umathcode "02AB6 = "3 "0 "02AB6
-\Umathcode "02AB7 = "3 "0 "02AB7
-\Umathcode "02AB8 = "3 "0 "02AB8
-\Umathcode "02AB9 = "3 "0 "02AB9
-\Umathcode "02ABA = "3 "0 "02ABA
-\Umathcode "02AC5 = "3 "0 "02AC5
-\Umathcode "02AC6 = "3 "0 "02AC6
-\Umathcode "02ACB = "3 "0 "02ACB
-\Umathcode "02ACC = "3 "0 "02ACC
-\Umathcode "12035 = "0 "0 "12035
-\Umathcode "1D6A4 = "0 "0 "1D6A4
-\Umathcode "1D6A5 = "0 "0 "1D6A5
-\Umathcode "1D6FB = "0 "0 "1D6FB
-\Umathcode "1D717 = "0 "0 "1D717
-\Umathcode "1D718 = "0 "0 "1D718
-
-% gaps .. done in lua (as example)
-
-% \Umathcode "1D455 = "0 "0 "0210E
-% \Umathcode "1D49D = "0 "0 "0212C
-% \Umathcode "1D4A0 = "0 "0 "02130
-% \Umathcode "1D4A1 = "0 "0 "02131
-% \Umathcode "1D4A3 = "0 "0 "0210B
-% \Umathcode "1D4A4 = "0 "0 "02110
-% \Umathcode "1D4A7 = "0 "0 "02112
-% \Umathcode "1D4A8 = "0 "0 "02133
-% \Umathcode "1D4AD = "0 "0 "0211B
-% \Umathcode "1D4BA = "0 "0 "0212F
-% \Umathcode "1D4BC = "0 "0 "0210A
-% \Umathcode "1D4C4 = "0 "0 "02134
-% \Umathcode "1D506 = "0 "0 "0212D
-% \Umathcode "1D50B = "0 "0 "0210C
-% \Umathcode "1D50C = "0 "0 "02111
-% \Umathcode "1D515 = "0 "0 "0211C
-% \Umathcode "1D51D = "0 "0 "02128
-% \Umathcode "1D53A = "0 "0 "02102
-% \Umathcode "1D53F = "0 "0 "0210D
-% \Umathcode "1D545 = "0 "0 "02115
-% \Umathcode "1D547 = "0 "0 "02119
-% \Umathcode "1D548 = "0 "0 "0211A
-% \Umathcode "1D549 = "0 "0 "0211D
-% \Umathcode "1D551 = "0 "0 "02124
-
-% initialization
-
-\the\everymathit
-
-% a couple of definitions (we could also use \mathchardef):
-
-\def\acute {\Umathaccent"0"0"0000B4 }
-\def\acwopencirclearrow {\Umathchar "3"0"0021BA }
-\def\aleph {\Umathchar "0"0"002135 }
-\def\Alpha {\Umathchar "0"0"000391 }
-\def\alpha {\Umathchar "0"0"0003B1 }
-\def\amalg {\Umathchar "2"0"002A3F }
-\def\angle {\Umathchar "0"0"002220 }
-\def\Angstrom {\Umathchar "0"0"00212B }
-\def\approx {\Umathchar "3"0"002248 }
-\def\approxEq {\Umathchar "3"0"002245 }
-\def\approxeq {\Umathchar "3"0"00224A }
-\def\approxnEq {\Umathchar "3"0"002247 }
-\def\arrowvert {\Umathchar "0"0"00007C }
-\def\Arrowvert {\Umathchar "0"0"002016 }
-\def\ast {\Umathchar "2"0"002217 }
-\def\ast {\Umathchar "2"0"002217 }
-\def\asymp {\Umathchar "3"0"00224D }
-\def\backepsilon {\Umathchar "0"0"0003F6 }
-\def\backprime {\Umathchar "0"0"012035 }
-\def\backsim {\Umathchar "3"0"00223D }
-\def\backslash {\Umathchar "0"0"00005C }
-\def\bar {\Umathaccent"0"0"0000AF }
-\def\barleftarrow {\Umathchar "3"0"0021E4 }
-\def\barleftarrowrightarrowbar {\Umathchar "3"0"0021B9 }
-\def\barovernorthwestarrow {\Umathchar "3"0"0021B8 }
-\def\barwedge {\Umathchar "2"0"0022BC }
-\def\because {\Umathchar "3"0"002235 }
-\def\Beta {\Umathchar "0"0"000392 }
-\def\beta {\Umathchar "0"0"0003B2 }
-\def\beth {\Umathchar "0"0"002136 }
-\def\between {\Umathchar "3"0"00226C }
-\def\bigcap {\Umathchar "1"0"0022C2 }
-\def\bigcirc {\Umathchar "2"0"0025EF }
-\def\bigcircle {\Umathchar "2"0"0020DD }
-\def\bigcircle {\Umathchar "2"0"0020DD }
-\def\bigcup {\Umathchar "1"0"0022C3 }
-\def\bigdiamond {\Umathchar "0"0"0020DF }
-\def\bigodot {\Umathchar "1"0"002A00 }
-\def\bigoplus {\Umathchar "1"0"002A01 }
-\def\bigotimes {\Umathchar "1"0"002A02 }
-\def\bigsqcap {\Umathchar "1"0"002A05 }
-\def\bigsqcup {\Umathchar "1"0"002A06 }
-\def\bigsquare {\Umathchar "0"0"0020DE }
-\def\bigstar {\Umathchar "0"0"002605 }
-\def\bigtimes {\Umathchar "1"0"002A09 }
-\def\bigtriangledown {\Umathchar "2"0"0025BD }
-\def\bigtriangleup {\Umathchar "2"0"0025B3 }
-\def\bigudot {\Umathchar "1"0"002A03 }
-\def\biguplus {\Umathchar "1"0"002A04 }
-\def\bigvee {\Umathchar "1"0"0022C1 }
-\def\bigwedge {\Umathchar "1"0"0022C0 }
-\def\blacklozenge {\Umathchar "0"0"002666 }
-\def\blacksquare {\Umathchar "0"0"0025A0 }
-\def\blacktriangle {\Umathchar "2"0"0025B2 }
-\def\blacktriangledown {\Umathchar "2"0"0025BC }
-\def\blacktriangleleft {\Umathchar "2"0"0025C0 }
-\def\blacktriangleright {\Umathchar "2"0"0025B6 }
-\def\bot {\Umathchar "0"0"0022A5 }
-\def\bowtie {\Umathchar "3"0"0022C8 }
-\def\Box {\Umathchar "0"0"0025A1 }
-\def\boxdot {\Umathchar "2"0"0022A1 }
-\def\boxminus {\Umathchar "2"0"00229F }
-\def\boxplus {\Umathchar "2"0"00229E }
-\def\boxtimes {\Umathchar "2"0"0022A0 }
-%def\braceld {\Umathchar "0"0"000000 }
-%def\bracerd {\Umathchar "0"0"000000 }
-%def\bracelu {\Umathchar "0"0"000000 }
-%def\braceru {\Umathchar "0"0"000000 }
-\def\breve {\Umathaccent"0"0"0002D8 }
-\def\bullet {\Umathchar "2"0"002022 }
-\def\bullet {\Umathchar "2"0"002022 }
-\def\Bumpeq {\Umathchar "3"0"00224E }
-\def\cap {\Umathchar "2"0"002229 }
-\def\Cap {\Umathchar "2"0"0022D2 }
-\def\carriagereturn {\Umathchar "0"0"0021B5 }
-\def\cdot {\Umathchar "2"0"0022C5 }
-\def\cdotp {\Umathchar "6"0"0022C5 }
-\def\cdots {\Umathchar "0"0"0022EF }
-\def\centerdot {\Umathchar "2"0"0000B7 }
-\def\check {\Umathaccent"0"0"0002C7 }
-\def\checkmark {\Umathchar "0"0"002713 }
-\def\Chi {\Umathchar "0"0"0003A7 }
-\def\chi {\Umathchar "0"0"0003C7 }
-\def\circ {\Umathchar "2"0"002218 }
-\def\circeq {\Umathchar "3"0"002257 }
-\def\circlearrowleft {\Umathchar "3"0"0021BB }
-\def\circlearrowright {\Umathchar "3"0"0021BA }
-\def\circledast {\Umathchar "2"0"00229B }
-\def\circledcirc {\Umathchar "2"0"00229A }
-\def\circleddash {\Umathchar "2"0"00229D }
-\def\circledequals {\Umathchar "2"0"00229C }
-\def\circledR {\Umathchar "0"0"0024C7 }
-\def\circledS {\Umathchar "0"0"0024C8 }
-\def\circleonrightarrow {\Umathchar "3"0"0021F4 }
-\def\clubsuit {\Umathchar "0"0"002663 }
-\def\colon {\Umathchar "6"0"002236 }
-\def\colonequals {\Umathchar "3"0"002254 }
-\def\complement {\Umathchar "0"0"002201 }
-\def\complexes {\Umathchar "0"0"002102 }
-\def\cong {\Umathchar "3"0"002245 }
-\def\coprod {\Umathchar "1"0"002210 }
-\def\cup {\Umathchar "2"0"00222A }
-\def\Cup {\Umathchar "2"0"0022D3 }
-\def\curlyeqprec {\Umathchar "3"0"0022DE }
-\def\curlyeqsucc {\Umathchar "3"0"0022DF }
-\def\curlyvee {\Umathchar "2"0"0022CE }
-\def\curlywedge {\Umathchar "2"0"0022CF }
-\def\curvearrowleft {\Umathchar "3"0"0021B6 }
-\def\curvearrowright {\Umathchar "3"0"0021B7 }
-\def\cwopencirclearrow {\Umathchar "3"0"0021BB }
-\def\dag {\Umathchar "0"0"002020 }
-\def\dagger {\Umathchar "2"0"002020 }
-\def\daleth {\Umathchar "0"0"002138 }
-\def\dasharrow {\Umathchar "3"0"0021E2 }
-\def\dashedleftarrow {\Umathchar "3"0"00290C }
-\def\dashedrightarrow {\Umathchar "3"0"00290D }
-\def\dashv {\Umathchar "3"0"0022A3 }
-\def\ddag {\Umathchar "0"0"002021 }
-\def\ddagger {\Umathchar "2"0"002021 }
-\def\dddot {\Umathaccent"0"0"0020DB }
-\def\ddot {\Umathaccent"0"0"0000A8 }
-\def\ddots {\Umathchar "0"0"0022F1 }
-\def\Ddownarrow {\Umathchar "3"0"00290B }
-\def\definedeq {\Umathchar "3"0"00225D }
-\def\Delta {\Umathchar "0"0"000394 }
-\def\delta {\Umathchar "0"0"0003B4 }
-\def\diamond {\Umathchar "2"0"0022C4 }
-\def\diamondsuit {\Umathchar "0"0"002662 }
-\def\differentialD {\Umathchar "0"0"002145 }
-\def\differentiald {\Umathchar "0"0"002146 }
-\def\digamma {\Umathchar "0"0"0003DC }
-\def\div {\Umathchar "2"0"0000F7 }
-\def\divideontimes {\Umathchar "2"0"0022C7 }
-\def\divides {\Umathchar "2"0"002223 }
-\def\dot {\Umathaccent"0"0"0002D9 }
-\def\doteq {\Umathchar "3"0"002250 }
-\def\Doteq {\Umathchar "3"0"002251 }
-\def\doteqdot {\Umathchar "3"0"002251 }
-\def\dotminus {\Umathchar "2"0"002238 }
-\def\dotplus {\Umathchar "2"0"002214 }
-\def\dots {\Umathchar "0"0"002026 }
-\def\dottedrightarrow {\Umathchar "3"0"002911 }
-\def\doublecap {\Umathchar "2"0"0022D2 }
-\def\doublecup {\Umathchar "2"0"0022D3 }
-\def\doubleprime {\Umathchar "0"0"002033 }
-\def\downarrow {\Umathchar "3"0"002193 }
-\def\Downarrow {\Umathchar "3"0"0021D3 }
-\def\downdasharrow {\Umathchar "3"0"0021E3 }
-\def\downdownarrows {\Umathchar "3"0"0021CA }
-\def\downharpoonleft {\Umathchar "3"0"0021C3 }
-\def\downharpoonright {\Umathchar "3"0"0021C2 }
-\def\downuparrows {\Umathchar "3"0"0021F5 }
-\def\downwhitearrow {\Umathchar "0"0"0021E9 }
-\def\downzigzagarrow {\Umathchar "3"0"0021AF }
-\def\ell {\Umathchar "0"0"002113 }
-\def\emptyset {\Umathchar "0"0"002205 }
-\def\Epsilon {\Umathchar "0"0"000395 }
-\def\epsilon {\Umathchar "0"0"0003F5 }
-\def\eq {\Umathchar "3"0"00003D }
-\def\eqcirc {\Umathchar "3"0"002256 }
-\def\eqgtr {\Umathchar "3"0"0022DD }
-\def\eqless {\Umathchar "3"0"0022DC }
-\def\eqsim {\Umathchar "3"0"002242 }
-\def\eqslantgtr {\Umathchar "3"0"002A96 }
-\def\eqslantless {\Umathchar "3"0"002A95 }
-\def\equalscolon {\Umathchar "3"0"002255 }
-\def\equiv {\Umathchar "3"0"002261 }
-\def\Eta {\Umathchar "0"0"000397 }
-\def\eta {\Umathchar "0"0"0003B7 }
-\def\eth {\Umathchar "0"0"0000F0 }
-\def\Eulerconst {\Umathchar "0"0"002107 }
-\def\exists {\Umathchar "0"0"002203 }
-\def\exponentiale {\Umathchar "0"0"002147 }
-\def\fallingdotseq {\Umathchar "3"0"002252 }
-\def\Finv {\Umathchar "0"0"002132 }
-\def\flat {\Umathchar "0"0"00266D }
-\def\forall {\Umathchar "0"0"002200 }
-\def\frown {\Umathchar "3"0"002322 }
-\def\Game {\Umathchar "0"0"002141 }
-\def\Gamma {\Umathchar "0"0"000393 }
-\def\gamma {\Umathchar "0"0"0003B3 }
-\def\ge {\Umathchar "3"0"002265 }
-\def\geq {\Umathchar "3"0"002265 }
-\def\geqq {\Umathchar "3"0"002267 }
-\def\geqslant {\Umathchar "3"0"002A7E }
-\def\gets {\Umathchar "3"0"002190 }
-\def\gg {\Umathchar "3"0"00226B }
-\def\ggg {\Umathchar "3"0"0022D9 }
-\def\gggtr {\Umathchar "3"0"0022D9 }
-\def\gimel {\Umathchar "0"0"002137 }
-\def\gnapprox {\Umathchar "3"0"002A8A }
-\def\gneqq {\Umathchar "3"0"002269 }
-\def\gnsim {\Umathchar "3"0"0022E7 }
-\def\grave {\Umathaccent"0"0"000060 }
-\def\gt {\Umathchar "3"0"00003E }
-\def\gtrapprox {\Umathchar "3"0"002A86 }
-\def\gtrdot {\Umathchar "2"0"0022D7 }
-\def\gtreqless {\Umathchar "3"0"0022DB }
-\def\gtreqqless {\Umathchar "3"0"002A8C }
-\def\gtrless {\Umathchar "3"0"002277 }
-\def\gtrsim {\Umathchar "3"0"002273 }
-\def\hat {\Umathaccent"0"0"0002C6 }
-\def\hbar {\Umathchar "0"0"00210F }
-\def\heartsuit {\Umathchar "0"0"002661 }
-\def\hookleftarrow {\Umathchar "3"0"0021A9 }
-\def\hookrightarrow {\Umathchar "3"0"0021AA }
-\def\hslash {\Umathchar "0"0"00210F }
-\def\iiint {\Umathchar "1"0"00222D }
-\def\iiintop {\Umathchar "0"0"00222D }
-\def\iint {\Umathchar "1"0"00222C }
-\def\iintop {\Umathchar "0"0"00222C }
-\def\Im {\Umathchar "0"0"002111 }
-\def\imaginaryi {\Umathchar "0"0"002148 }
-\def\imaginaryj {\Umathchar "0"0"002149 }
-\def\imath {\Umathchar "0"0"01D6A4 }
-\def\imply {\Umathchar "3"0"0021D2 }
-\def\in {\Umathchar "0"0"002208 }
-\def\infty {\Umathchar "0"0"00221E }
-\def\int {\Umathchar "1"0"00222B }
-\def\intclockwise {\Umathchar "1"0"002231 }
-\def\integers {\Umathchar "0"0"002124 }
-\def\intercal {\Umathchar "2"0"0022BA }
-\def\intop {\Umathchar "0"0"00222B }
-\def\Iota {\Umathchar "0"0"000399 }
-\def\iota {\Umathchar "0"0"0003B9 }
-\def\jmath {\Umathchar "0"0"01D6A5 }
-\def\Join {\Umathchar "3"0"0022C8 }
-\def\Kappa {\Umathchar "0"0"00039A }
-\def\kappa {\Umathchar "0"0"0003BA }
-\def\Lambda {\Umathchar "0"0"00039B }
-\def\lambda {\Umathchar "0"0"0003BB }
-\def\land {\Umathchar "2"0"002227 }
-\def\langle {\Udelimiter "4"0"0027E8 }
-\def\lbrace {\Udelimiter "4"0"00007B }
-\def\lbrack {\Udelimiter "4"0"00005B }
-\def\lceil {\Udelimiter "4"0"002308 }
-\def\lceiling {\Udelimiter "4"0"002308 }
-\def\ldotp {\Umathchar "6"0"00002E }
-\def\ldots {\Umathchar "0"0"002026 }
-\def\Ldsh {\Umathchar "3"0"0021B2 }
-\def\le {\Umathchar "3"0"002264 }
-\def\leadsto {\Umathchar "3"0"0021DD }
-\def\leftarrow {\Umathchar "3"0"002190 }
-\def\Leftarrow {\Umathchar "3"0"0021D0 }
-\def\leftarrowtail {\Umathchar "3"0"0021A2 }
-\def\leftarrowtriangle {\Umathchar "3"0"0021FD }
-\def\leftdasharrow {\Umathchar "3"0"0021E0 }
-\def\leftharpoondown {\Umathchar "3"0"0021BD }
-\def\leftharpoonup {\Umathchar "3"0"0021BC }
-\def\leftleftarrows {\Umathchar "3"0"0021C7 }
-\def\leftrightarrow {\Umathchar "3"0"002194 }
-\def\Leftrightarrow {\Umathchar "3"0"0021D4 }
-\def\leftrightarrows {\Umathchar "3"0"0021C6 }
-\def\leftrightarrowtriangle {\Umathchar "3"0"0021FF }
-\def\leftrightharpoons {\Umathchar "3"0"0021CB }
-\def\leftrightsquigarrow {\Umathchar "3"0"0021AD }
-\def\leftsquigarrow {\Umathchar "3"0"0021DC }
-\def\leftthreetimes {\Umathchar "2"0"0022CB }
-\def\leftwavearrow {\Umathchar "3"0"00219C }
-\def\leftwhitearrow {\Umathchar "0"0"0021E6 }
-\def\leq {\Umathchar "3"0"002264 }
-\def\leqq {\Umathchar "3"0"002266 }
-\def\leqslant {\Umathchar "3"0"002A7D }
-\def\lessapprox {\Umathchar "3"0"002A85 }
-\def\lessdot {\Umathchar "2"0"0022D6 }
-\def\lesseqgtr {\Umathchar "3"0"0022DA }
-\def\lesseqqgtr {\Umathchar "3"0"002A8B }
-\def\lessgtr {\Umathchar "3"0"002276 }
-\def\lesssim {\Umathchar "3"0"002272 }
-\def\lfloor {\Udelimiter "4"0"00230A }
-\def\lgroup {\Udelimiter "4"0"0027EE }
-\def\lhook {\Umathchar "3"0"0FE322 }
-\def\lhooknwarrow {\Umathchar "3"0"002923 }
-\def\lhooksearrow {\Umathchar "3"0"002925 }
-\def\linefeed {\Umathchar "0"0"0021B4 }
-\def\ll {\Umathchar "3"0"00226A }
-\def\llangle {\Udelimiter "4"0"0027EA }
-\def\llbracket {\Udelimiter "4"0"0027E6 }
-\def\llcorner {\Udelimiter "4"0"00231E }
-\def\Lleftarrow {\Umathchar "3"0"0021DA }
-\def\lll {\Umathchar "3"0"0022D8 }
-\def\llless {\Umathchar "3"0"0022D8 }
-\def\lmoustache {\Udelimiter "4"0"0023B0 }
-\def\lnapprox {\Umathchar "3"0"002A89 }
-\def\lneq {\Umathchar "3"0"002A87 }
-\def\lneqq {\Umathchar "3"0"002268 }
-\def\lnot {\Umathchar "0"0"0000AC }
-\def\lnsim {\Umathchar "3"0"0022E6 }
-\def\longleftarrow {\Umathchar "3"0"0027F5 }
-\def\Longleftarrow {\Umathchar "3"0"0027F8 }
-\def\longleftrightarrow {\Umathchar "3"0"0027F7 }
-\def\Longleftrightarrow {\Umathchar "3"0"0027FA }
-\def\longmapsfrom {\Umathchar "3"0"0027FB }
-\def\Longmapsfrom {\Umathchar "3"0"0027FD }
-\def\longmapsto {\Umathchar "3"0"0027FC }
-\def\Longmapsto {\Umathchar "3"0"0027FE }
-\def\longrightarrow {\Umathchar "3"0"0027F6 }
-\def\Longrightarrow {\Umathchar "3"0"0027F9 }
-\def\longrightsquigarrow {\Umathchar "3"0"0027FF }
-\def\looparrowleft {\Umathchar "3"0"0021AB }
-\def\looparrowright {\Umathchar "3"0"0021AC }
-\def\lor {\Umathchar "2"0"002228 }
-\def\lozenge {\Umathchar "0"0"0025CA }
-\def\lparent {\Udelimiter "4"0"000028 }
-\def\lrcorner {\Udelimiter "5"0"00231F }
-\def\Lsh {\Umathchar "3"0"0021B0 }
-\def\lt {\Umathchar "3"0"00003C }
-\def\ltimes {\Umathchar "2"0"0022C9 }
-\def\lvert {\Udelimiter "4"0"00007C }
-\def\lVert {\Udelimiter "4"0"002016 }
-\def\maltese {\Umathchar "0"0"002720 }
-\def\mapsdown {\Umathchar "3"0"0021A7 }
-\def\mapsfrom {\Umathchar "3"0"0021A4 }
-\def\Mapsfrom {\Umathchar "3"0"002906 }
-\def\mapsfromchar {\Umathchar "3"0"0FE324 }
-\def\mapsto {\Umathchar "3"0"0021A6 }
-\def\Mapsto {\Umathchar "3"0"002907 }
-\def\mapstochar {\Umathchar "3"0"0FE321 }
-\def\mapsup {\Umathchar "3"0"0021A5 }
-\def\mathring {\Umathaccent"0"0"0002DA }
-\def\measuredangle {\Umathchar "0"0"002221 }
-\def\measuredeq {\Umathchar "3"0"00225E }
-\def\mho {\Umathchar "0"0"002127 }
-\def\mid {\Umathchar "3"0"00007C }
-\def\minus {\Umathchar "2"0"002212 }
-\def\minuscolon {\Umathchar "2"0"002239 }
-\def\models {\Umathchar "3"0"0022A7 }
-\def\mp {\Umathchar "2"0"002213 }
-\def\Mu {\Umathchar "0"0"00039C }
-\def\mu {\Umathchar "0"0"0003BC }
-\def\multimap {\Umathchar "3"0"0022B8 }
-\def\napprox {\Umathchar "3"0"002249 }
-\def\napproxEq {\Umathchar "3"0"002246 }
-\def\nasymp {\Umathchar "3"0"00226D }
-\def\natural {\Umathchar "0"0"00266E }
-\def\naturalnumbers {\Umathchar "0"0"002115 }
-\def\ncong {\Umathchar "3"0"002246 }
-\def\ndivides {\Umathchar "2"0"002224 }
-\def\ne {\Umathchar "3"0"002260 }
-\def\nearrow {\Umathchar "3"0"002197 }
-\def\Nearrow {\Umathchar "3"0"0021D7 }
-\def\neg {\Umathchar "0"0"0000AC }
-\def\negativesign {\Umathchar "2"0"00207B }
-\def\neq {\Umathchar "3"0"002260 }
-\def\nequiv {\Umathchar "3"0"002262 }
-\def\neswarrow {\Umathchar "3"0"002922 }
-\def\nexists {\Umathchar "0"0"002204 }
-\def\ngeq {\Umathchar "3"0"002271 }
-\def\ngtr {\Umathchar "3"0"00226F }
-\def\ngtrless {\Umathchar "3"0"002279 }
-\def\ngtrsim {\Umathchar "3"0"002275 }
-\def\nHdownarrow {\Umathchar "3"0"0021DF }
-\def\nHuparrow {\Umathchar "3"0"0021DE }
-\def\ni {\Umathchar "3"0"00220B }
-\def\nin {\Umathchar "3"0"002209 }
-\def\nleftarrow {\Umathchar "3"0"00219A }
-\def\nLeftarrow {\Umathchar "3"0"0021CD }
-\def\nleftrightarrow {\Umathchar "3"0"0021AE }
-\def\nLeftrightarrow {\Umathchar "3"0"0021CE }
-\def\nleq {\Umathchar "3"0"002270 }
-\def\nless {\Umathchar "3"0"00226E }
-\def\nlessgtr {\Umathchar "3"0"002278 }
-\def\nlesssim {\Umathchar "3"0"002274 }
-\def\nmid {\Umathchar "3"0"002224 }
-\def\nni {\Umathchar "3"0"00220C }
-\def\not {\Umathchar "3"0"000338 }
-\def\notin {\Umathchar "3"0"002209 }
-\def\nowns {\Umathchar "3"0"00220C }
-\def\nparallel {\Umathchar "3"0"002226 }
-\def\nprec {\Umathchar "3"0"002280 }
-\def\npreccurlyeq {\Umathchar "3"0"0022E0 }
-\def\nrightarrow {\Umathchar "3"0"00219B }
-\def\nRightarrow {\Umathchar "3"0"0021CF }
-\def\nsim {\Umathchar "3"0"002241 }
-\def\nsimeq {\Umathchar "3"0"002244 }
-\def\nsqsubseteq {\Umathchar "3"0"0022E2 }
-\def\nsqsupseteq {\Umathchar "3"0"0022E3 }
-\def\nsubset {\Umathchar "3"0"002284 }
-\def\nsubseteq {\Umathchar "3"0"002288 }
-\def\nsucc {\Umathchar "3"0"002281 }
-\def\nsucccurlyeq {\Umathchar "3"0"0022E1 }
-\def\nsupset {\Umathchar "3"0"002285 }
-\def\nsupseteq {\Umathchar "3"0"002289 }
-\def\ntriangleleft {\Umathchar "3"0"0022EB }
-\def\ntrianglelefteq {\Umathchar "3"0"0022EC }
-\def\ntriangleright {\Umathchar "3"0"0022EA }
-\def\ntrianglerighteq {\Umathchar "3"0"0022ED }
-\def\Nu {\Umathchar "0"0"00039D }
-\def\nu {\Umathchar "0"0"0003BD }
-\def\nvdash {\Umathchar "3"0"0022AC }
-\def\nvDash {\Umathchar "3"0"0022AD }
-\def\nVdash {\Umathchar "3"0"0022AE }
-\def\nVDash {\Umathchar "3"0"0022AF }
-\def\nvleftarrow {\Umathchar "3"0"0021F7 }
-\def\nVleftarrow {\Umathchar "3"0"0021FA }
-\def\nvleftrightarrow {\Umathchar "3"0"0021F9 }
-\def\nVleftrightarrow {\Umathchar "3"0"0021FC }
-\def\nvrightarrow {\Umathchar "3"0"0021F8 }
-\def\nVrightarrow {\Umathchar "3"0"0021FB }
-\def\nwarrow {\Umathchar "3"0"002196 }
-\def\Nwarrow {\Umathchar "3"0"0021D6 }
-\def\nwsearrow {\Umathchar "3"0"002921 }
-\def\odot {\Umathchar "2"0"002299 }
-\def\ohm {\Umathchar "0"0"002126 }
-\def\oiiint {\Umathchar "1"0"002230 }
-\def\oiint {\Umathchar "1"0"00222F }
-\def\oint {\Umathchar "1"0"00222E }
-\def\ointclockwise {\Umathchar "1"0"002232 }
-\def\ointctrclockwise {\Umathchar "1"0"002233 }
-\def\Omega {\Umathchar "0"0"0003A9 }
-\def\omega {\Umathchar "0"0"0003C9 }
-\def\Omicron {\Umathchar "0"0"00039F }
-\def\omicron {\Umathchar "0"0"0003BF }
-\def\ominus {\Umathchar "2"0"002296 }
-\def\oplus {\Umathchar "2"0"002295 }
-\def\oslash {\Umathchar "2"0"002298 }
-\def\otimes {\Umathchar "2"0"002297 }
-\def\overbar {\Umathaccent"0"0"00203E }
-\def\overbrace {\Umathaccent"0"0"0023DE }
-\def\overbracket {\Umathaccent"0"0"0023B4 }
-\def\overparent {\Umathaccent"0"0"0023DC }
-\def\owns {\Umathchar "3"0"00220B }
-\def\P {\Umathchar "0"0"0000B6 }
-\def\parallel {\Umathchar "3"0"002225 }
-\def\partial {\Umathchar "0"0"002202 }
-\def\perp {\Umathchar "3"0"0022A5 }
-\def\Phi {\Umathchar "0"0"0003A6 }
-\def\phi {\Umathchar "0"0"0003D5 }
-\def\Pi {\Umathchar "0"0"0003A0 }
-\def\pi {\Umathchar "0"0"0003C0 }
-\def\pitchfork {\Umathchar "3"0"0022D4 }
-\def\Plankconst {\Umathchar "0"0"00210E }
-\def\pm {\Umathchar "2"0"0000B1 }
-\def\positivesign {\Umathchar "2"0"00207A }
-\def\prec {\Umathchar "3"0"00227A }
-\def\precapprox {\Umathchar "3"0"002AB7 }
-\def\preccurlyeq {\Umathchar "3"0"00227C }
-\def\preceq {\Umathchar "3"0"002AAF }
-\def\preceqq {\Umathchar "3"0"002AB3 }
-\def\precnapprox {\Umathchar "3"0"002AB9 }
-\def\precneq {\Umathchar "3"0"002AB1 }
-\def\precneqq {\Umathchar "3"0"002AB5 }
-\def\precnsim {\Umathchar "3"0"0022E8 }
-\def\precsim {\Umathchar "3"0"00227E }
-\def\prime {\Umathchar "0"0"002032 }
-\def\primes {\Umathchar "0"0"002119 }
-\def\prod {\Umathchar "1"0"00220F }
-\def\PropertyLine {\Umathchar "0"0"00214A }
-\def\propto {\Umathchar "3"0"00221D }
-\def\Psi {\Umathchar "0"0"0003A8 }
-\def\psi {\Umathchar "0"0"0003C8 }
-\def\questionedeq {\Umathchar "3"0"00225F }
-\def\rangle {\Udelimiter "5"0"0027E9 }
-\def\rationals {\Umathchar "0"0"00211A }
-\def\rbrace {\Udelimiter "5"0"00007D }
-\def\rbrack {\Udelimiter "5"0"00005D }
-\def\rceil {\Udelimiter "5"0"002309 }
-\def\rceiling {\Udelimiter "5"0"002309 }
-\def\Rdsh {\Umathchar "3"0"0021B3 }
-\def\Re {\Umathchar "0"0"00211C }
-\def\reals {\Umathchar "0"0"00211D }
-\def\Relbar {\Umathchar "3"0"00003D }
-\def\relbar {\Umathchar "3"0"002212 }
-\def\restriction {\Umathchar "3"0"0021BE }
-\def\rfloor {\Udelimiter "5"0"00230B }
-\def\rgroup {\Udelimiter "5"0"0027EF }
-\def\Rho {\Umathchar "0"0"0003A1 }
-\def\rho {\Umathchar "0"0"0003C1 }
-\def\rhook {\Umathchar "3"0"0FE323 }
-\def\rhooknearrow {\Umathchar "3"0"002924 }
-\def\rhookswarrow {\Umathchar "3"0"002926 }
-\def\rightangle {\Umathchar "0"0"00221F }
-\def\rightarrow {\Umathchar "3"0"002192 }
-\def\Rightarrow {\Umathchar "3"0"0021D2 }
-\def\rightarrowbar {\Umathchar "3"0"0021E5 }
-\def\rightarrowtail {\Umathchar "3"0"0021A3 }
-\def\rightarrowtriangle {\Umathchar "3"0"0021FE }
-\def\rightdasharrow {\Umathchar "3"0"0021E2 }
-\def\rightharpoondown {\Umathchar "3"0"0021C1 }
-\def\rightharpoonup {\Umathchar "3"0"0021C0 }
-\def\rightleftarrows {\Umathchar "3"0"0021C4 }
-\def\rightleftharpoons {\Umathchar "3"0"0021CC }
-\def\rightrightarrows {\Umathchar "3"0"0021C9 }
-\def\rightsquigarrow {\Umathchar "3"0"0021DD }
-\def\rightthreearrows {\Umathchar "3"0"0021F6 }
-\def\rightthreetimes {\Umathchar "2"0"0022CC }
-\def\rightwavearrow {\Umathchar "3"0"00219D }
-\def\rightwhitearrow {\Umathchar "0"0"0021E8 }
-\def\risingdotseq {\Umathchar "3"0"002253 }
-\def\rmoustache {\Udelimiter "5"0"0023B1 }
-\def\rneq {\Umathchar "3"0"002A88 }
-\def\rparent {\Udelimiter "5"0"000029 }
-\def\rrangle {\Udelimiter "5"0"0027EB }
-\def\rrbracket {\Udelimiter "5"0"0027E7 }
-\def\Rrightarrow {\Umathchar "3"0"0021DB }
-\def\Rsh {\Umathchar "3"0"0021B1 }
-\def\rtimes {\Umathchar "2"0"0022CA }
-\def\rvert {\Udelimiter "5"0"00007C }
-\def\rVert {\Udelimiter "5"0"002016 }
-\def\S {\Umathchar "0"0"0000A7 }
-\def\searrow {\Umathchar "3"0"002198 }
-\def\Searrow {\Umathchar "3"0"0021D8 }
-\def\setminus {\Umathchar "2"0"002216 }
-\def\sharp {\Umathchar "0"0"00266F }
-\def\Sigma {\Umathchar "0"0"0003A3 }
-\def\sigma {\Umathchar "0"0"0003C3 }
-\def\sim {\Umathchar "3"0"00223C }
-\def\simeq {\Umathchar "3"0"002243 }
-\def\slash {\Umathchar "0"0"002044 }
-\def\smile {\Umathchar "3"0"002323 }
-\def\solidus {\Udelimiter "5"0"002044 }
-\def\spadesuit {\Umathchar "0"0"002660 }
-\def\sphericalangle {\Umathchar "0"0"002222 }
-\def\sqcap {\Umathchar "2"0"002293 }
-\def\sqcup {\Umathchar "2"0"002294 }
-\def\sqsubset {\Umathchar "3"0"00228F }
-\def\sqsubseteq {\Umathchar "2"0"002291 }
-\def\sqsubsetneq {\Umathchar "3"0"0022E4 }
-\def\sqsupset {\Umathchar "3"0"002290 }
-\def\sqsupseteq {\Umathchar "2"0"002292 }
-\def\sqsupsetneq {\Umathchar "3"0"0022E5 }
-\def\square {\Umathchar "0"0"0025A1 }
-\def\squaredots {\Umathchar "3"0"002237 }
-\def\star {\Umathchar "2"0"0022C6 }
-\def\stareq {\Umathchar "3"0"00225B }
-\def\subset {\Umathchar "3"0"002282 }
-\def\Subset {\Umathchar "3"0"0022D0 }
-\def\subseteq {\Umathchar "3"0"002286 }
-\def\subseteqq {\Umathchar "3"0"002AC5 }
-\def\subsetneq {\Umathchar "3"0"00228A }
-\def\subsetneqq {\Umathchar "3"0"002ACB }
-\def\succ {\Umathchar "3"0"00227B }
-\def\succapprox {\Umathchar "3"0"002AB8 }
-\def\succcurlyeq {\Umathchar "3"0"00227D }
-\def\succeq {\Umathchar "3"0"002AB0 }
-\def\succeqq {\Umathchar "3"0"002AB4 }
-\def\succnapprox {\Umathchar "3"0"002ABA }
-\def\succneq {\Umathchar "3"0"002AB2 }
-\def\succneqq {\Umathchar "3"0"002AB6 }
-\def\succnsim {\Umathchar "3"0"0022E9 }
-\def\succsim {\Umathchar "3"0"00227F }
-\def\sum {\Umathchar "1"0"002211 }
-\def\supset {\Umathchar "3"0"002283 }
-\def\Supset {\Umathchar "3"0"0022D1 }
-\def\supseteq {\Umathchar "3"0"002287 }
-\def\supseteqq {\Umathchar "3"0"002AC6 }
-\def\supsetneq {\Umathchar "3"0"00228B }
-\def\supsetneqq {\Umathchar "3"0"002ACC }
-\def\surd {\Umathchar "2"0"00221A }
-\def\swarrow {\Umathchar "3"0"002199 }
-\def\Swarrow {\Umathchar "3"0"0021D9 }
-\def\Tau {\Umathchar "0"0"0003A4 }
-\def\tau {\Umathchar "0"0"0003C4 }
-\def\therefore {\Umathchar "3"0"002234 }
-\def\Theta {\Umathchar "0"0"000398 }
-\def\theta {\Umathchar "0"0"0003B8 }
-\def\tilde {\Umathaccent"0"0"0002DC }
-\def\times {\Umathchar "2"0"0000D7 }
-\def\to {\Umathchar "3"0"002192 }
-\def\top {\Umathchar "0"0"0022A4 }
-\def\triangle {\Umathchar "0"0"0025B3 }
-\def\triangledown {\Umathchar "2"0"0025BD }
-\def\triangleleft {\Umathchar "2"0"0025C1 }
-\def\triangleq {\Umathchar "3"0"00225C }
-\def\triangleright {\Umathchar "2"0"0025B7 }
-\def\tripleprime {\Umathchar "0"0"002034 }
-\def\turnediota {\Umathchar "0"0"002129 }
-\def\twoheaddownarrow {\Umathchar "3"0"0021A1 }
-\def\twoheadleftarrow {\Umathchar "3"0"00219E }
-\def\twoheadrightarrow {\Umathchar "3"0"0021A0 }
-\def\twoheadrightarrowtail {\Umathchar "3"0"002916 }
-\def\twoheaduparrow {\Umathchar "3"0"00219F }
-\def\udots {\Umathchar "0"0"0022F0 }
-\def\ulcorner {\Udelimiter "4"0"00231C }
-\def\underbar {\Umathaccent bottom "0"0"00203E }
-\def\underbrace {\Umathaccent bottom "0"0"0023DF }
-\def\underbracket {\Umathaccent bottom "0"0"0023B5 }
-\def\underparent {\Umathaccent bottom "0"0"0023DD }
-\def\upand {\Umathchar "2"0"00214B }
-\def\uparrow {\Umathchar "3"0"002191 }
-\def\Uparrow {\Umathchar "3"0"0021D1 }
-\def\updasharrow {\Umathchar "3"0"0021E1 }
-\def\updownarrow {\Umathchar "3"0"002195 }
-\def\Updownarrow {\Umathchar "3"0"0021D5 }
-\def\updownarrowbar {\Umathchar "0"0"0021A8 }
-\def\updownarrows {\Umathchar "3"0"0021C5 }
-\def\upharpoonleft {\Umathchar "3"0"0021BF }
-\def\upharpoonright {\Umathchar "3"0"0021BE }
-\def\uplus {\Umathchar "2"0"00228E }
-\def\Upsilon {\Umathchar "0"0"0003A5 }
-\def\upsilon {\Umathchar "0"0"0003C5 }
-\def\upuparrows {\Umathchar "3"0"0021C8 }
-\def\upwhitearrow {\Umathchar "0"0"0021E7 }
-\def\urcorner {\Udelimiter "5"0"00231D }
-\def\Uuparrow {\Umathchar "3"0"00290A }
-\def\varepsilon {\Umathchar "0"0"0003B5 }
-\def\varkappa {\Umathchar "0"0"0003F0 }
-\def\varkappa {\Umathchar "0"0"0003F0 }
-\def\varnothing {\Umathchar "0"0"002300 }
-\def\varphi {\Umathchar "0"0"0003C6 }
-\def\varpi {\Umathchar "0"0"0003D6 }
-\def\varrho {\Umathchar "0"0"01D71A }
-\def\varsigma {\Umathchar "0"0"0003C2 }
-\def\vartheta {\Umathchar "0"0"01D717 }
-\def\varTheta {\Umathchar "0"0"0003D1 }
-\def\vdash {\Umathchar "3"0"0022A2 }
-\def\vDash {\Umathchar "3"0"0022A8 }
-\def\Vdash {\Umathchar "3"0"0022A9 }
-\def\VDash {\Umathchar "3"0"0022AB }
-\def\vdots {\Umathchar "0"0"0022EE }
-\def\vec {\Umathaccent"0"0"0020D7 }
-\def\vee {\Umathchar "2"0"002228 }
-\def\veebar {\Umathchar "2"0"0022BB }
-\def\veeeq {\Umathchar "3"0"00225A }
-\def\vert {\Udelimiter "0"0"00007C }
-\def\Vert {\Udelimiter "0"0"002016 }
-\def\Vvdash {\Umathchar "3"0"0022AA }
-\def\wedge {\Umathchar "2"0"002227 }
-\def\wedgeeq {\Umathchar "3"0"002259 }
-\def\whitearrowupfrombar {\Umathchar "0"0"0021EB }
-\def\widehat {\Umathaccent"0"0"000302 }
-\def\widetilde {\Umathaccent"0"0"000303 }
-\def\wp {\Umathchar "0"0"002118 }
-\def\wr {\Umathchar "2"0"002240 }
-\def\Xi {\Umathchar "0"0"00039E }
-\def\xi {\Umathchar "0"0"0003BE }
-\def\yen {\Umathchar "0"0"0000A5 }
-\def\Zeta {\Umathchar "0"0"000396 }
-\def\zeta {\Umathchar "0"0"0003B6 }
-
-% a few definitions:
-
-\def\sqrt {\Uroot "0 "221A{}}
-\def\root#1\of{\Uroot "0 "221A{#1}}
-
-% \skewchar\teni='177 \skewchar\seveni='177 \skewchar\fivei='177
-% \skewchar\tensy='60 \skewchar\sevensy='60 \skewchar\fivesy='60
-
-\chardef\% = "25
-\chardef\& = "26
-\chardef\# = "23
-\chardef\$ = "24
-\chardef\_ = "5F
-
-\let\ss ß
-\let\ae æ
-\let\oe œ
-\let\o ø
-\let\AE Æ
-\let\OE Œ
-\let\O Ø
-\let\i ı
-\let\aa å
-\let\l ł
-\let\L Ł
-\let\AA Å
-\let\copyright ©
-
-% just use utf
-
-\def\`#1{\string\`\string{#1\string}}
-\def\'#1{\string\'\string{#1\string}}
-\def\v#1{\string\v\string{#1\string}}
-\def\u#1{\string\u\string{#1\string}}
-\def\=#1{\string\=\string{#1\string}}
-\def\^#1{\string\^\string{#1\string}}
-\def\.#1{\string\.\string{#1\string}}
-\def\H#1{\string\H\string{#1\string}}
-\def\~#1{\string\~\string{#1\string}}
-\def\"#1{\string\"\string{#1\string}}
-\def\d#1{\string\d\string{#1\string}}
-\def\b#1{\string\b\string{#1\string}}
-\def\c#1{\string\c\string{#1\string}}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.lua
deleted file mode 100644
index 976bb59f91b..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.lua
+++ /dev/null
@@ -1,591 +0,0 @@
-if not modules then modules = { } end modules ['luatex-mplib'] = {
- version = 1.001,
- comment = "companion to luatex-mplib.tex",
- author = "Hans Hagen & Taco Hoekwater",
- copyright = "ConTeXt Development Team",
- license = "public domain",
-}
-
---[[ldx--
-<p>This module is a stripped down version of libraries that are used
-by <l n='context'/>. It can be used in other macro packages and/or
-serve as an example. Embedding in a macro package is upto others and
-normally boils down to inputting <t>supp-mpl.tex</t>.</p>
---ldx]]--
-
-if metapost and metapost.version then
-
- --[[ldx--
- <p>Let's silently quit and make sure that no one loads it
- manually in <l n='context'/>.</p>
- --ldx]]--
-
-else
-
- local format, match, gsub = string.format, string.match, string.gsub
- local concat = table.concat
- local abs = math.abs
-
- local mplib = require ('mplib')
- local kpse = require ('kpse')
-
- --[[ldx--
- <p>We create a namespace and some variables to it. If a namespace is
- already defined it wil not be initialized. This permits hooking
- in code beforehand.</p>
-
- <p>We don't make a format automatically. After all, distributions
- might have their own preferences and normally a format (mem) file will
- have some special place in the <l n='tex'/> tree. Also, there can already
- be format files, different memort settings and other nasty pitfalls that
- we don't want to interfere with. If you want, you can define a function
- <t>metapost.make(name,mem_name) that does the job.</t></p>
- --ldx]]--
-
- metapost = metapost or { }
- metapost.version = 1.00
- metapost.showlog = metapost.showlog or false
- metapost.lastlog = ""
-
- --[[ldx--
- <p>A few helpers, taken from <t>l-file.lua</t>.</p>
- --ldx]]--
-
- local file = file or { }
-
- function file.replacesuffix(filename, suffix)
- return (string.gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
- end
-
- function file.stripsuffix(filename)
- return (string.gsub(filename,"%.[%a%d]+$",""))
- end
-
- --[[ldx--
- <p>We use the <l n='kpse'/> library unless a finder is already
- defined.</p>
- --ldx]]--
-
- local mpkpse = kpse.new("luatex","mpost")
-
- metapost.finder = metapost.finder or function(name, mode, ftype)
- if mode == "w" then
- return name
- else
- return mpkpse:find_file(name,ftype)
- end
- end
-
- --[[ldx--
- <p>You can use your own reported if needed, as long as it handles multiple
- arguments and formatted strings.</p>
- --ldx]]--
-
- metapost.report = metapost.report or function(...)
- texio.write(format("<mplib: %s>",format(...)))
- end
-
- --[[ldx--
- <p>The rest of this module is not documented. More info can be found in the
- <l n='luatex'/> manual, articles in user group journals and the files that
- ship with <l n='context'/>.</p>
- --ldx]]--
-
- function metapost.resetlastlog()
- metapost.lastlog = ""
- end
-
- local mplibone = tonumber(mplib.version()) <= 1.50
-
- if mplibone then
-
- metapost.make = metapost.make or function(name,mem_name,dump)
- local t = os.clock()
- local mpx = mplib.new {
- ini_version = true,
- find_file = metapost.finder,
- job_name = file.stripsuffix(name)
- }
- mpx:execute(string.format("input %s ;",name))
- if dump then
- mpx:execute("dump ;")
- metapost.report("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t)
- else
- metapost.report("%s read in %0.3f seconds",name,os.clock()-t)
- end
- return mpx
- end
-
- function metapost.load(name)
- local mem_name = file.replacesuffix(name,"mem")
- local mpx = mplib.new {
- ini_version = false,
- mem_name = mem_name,
- find_file = metapost.finder
- }
- if not mpx and type(metapost.make) == "function" then
- -- when i have time i'll locate the format and dump
- mpx = metapost.make(name,mem_name)
- end
- if mpx then
- metapost.report("using format %s",mem_name,false)
- return mpx, nil
- else
- return nil, { status = 99, error = "out of memory or invalid format" }
- end
- end
-
- else
-
- local preamble = [[
- boolean mplib ; mplib := true ;
- let dump = endinput ;
- input %s ;
- ]]
-
- metapost.make = metapost.make or function()
- end
-
- local template = [[
- \pdfoutput=1
- \pdfpkresolution600
- \pdfcompresslevel=9
- %s\relax
- \hsize=100in
- \vsize=\hsize
- \hoffset=-1in
- \voffset=\hoffset
- \topskip=0pt
- \setbox0=\hbox{%s}\relax
- \pageheight=\ht0
- \pagewidth=\wd0
- \box0
- \bye
- ]]
-
- metapost.texrunner = "mtxrun --script plain"
-
- local texruns = 0 -- per document
- local texhash = { } -- per document
-
- function metapost.maketext(mpd,str,what)
- -- inefficient but one can always use metafun .. it's more a test
- -- feature
- local verbatimtex = mpd.verbatimtex
- if not verbatimtex then
- verbatimtex = { }
- mpd.verbatimtex = verbatimtex
- end
- if what == 1 then
- table.insert(verbatimtex,str)
- else
- local texcode = format(template,concat(verbatimtex,"\n"),str)
- local texdone = texhash[texcode]
- local jobname = tex.jobname
- if not texdone then
- texruns = texruns + 1
- texdone = texruns
- texhash[texcode] = texdone
- local texname = format("%s-mplib-%s.tmp",jobname,texdone)
- local logname = format("%s-mplib-%s.log",jobname,texdone)
- local pdfname = format("%s-mplib-%s.pdf",jobname,texdone)
- io.savedata(texname,texcode)
- os.execute(format("%s %s",metapost.texrunner,texname))
- os.remove(texname)
- os.remove(logname)
- end
- return format('"image::%s-mplib-%s.pdf" infont defaultfont',jobname,texdone)
- end
- end
-
- local function mpprint(buffer,...)
- for i=1,select("#",...) do
- local value = select(i,...)
- if value ~= nil then
- local t = type(value)
- if t == "number" then
- buffer[#buffer+1] = format("%.16f",value)
- elseif t == "string" then
- buffer[#buffer+1] = value
- elseif t == "table" then
- buffer[#buffer+1] = "(" .. concat(value,",") .. ")"
- else -- boolean or whatever
- buffer[#buffer+1] = tostring(value)
- end
- end
- end
- end
-
- function metapost.runscript(mpd,code)
- local code = loadstring(code)
- if type(code) == "function" then
- local buffer = { }
- function metapost.print(...)
- mpprint(buffer,...)
- end
- code()
- -- mpd.buffer = buffer -- for tracing
- return concat(buffer,"")
- end
- return ""
- end
-
- function metapost.load(name)
- local mpd = {
- buffer = { },
- verbatim = { }
- }
- local mpx = mplib.new {
- ini_version = true,
- find_file = metapost.finder,
- make_text = function(...) return metapost.maketext (mpd,...) end,
- run_script = function(...) return metapost.runscript(mpd,...) end,
- extensions = 1,
- }
- local result
- if not mpx then
- result = { status = 99, error = "out of memory"}
- else
- result = mpx:execute(format(preamble, file.replacesuffix(name,"mp")))
- end
- metapost.reporterror(result)
- return mpx, result
- end
-
- end
-
- function metapost.unload(mpx)
- if mpx then
- mpx:finish()
- end
- end
-
- function metapost.reporterror(result)
- if not result then
- metapost.report("mp error: no result object returned")
- elseif result.status > 0 then
- local t, e, l = result.term, result.error, result.log
- if t then
- metapost.report("mp terminal: %s",t)
- end
- if e then
- metapost.report("mp error: %s", e)
- end
- if not t and not e and l then
- metapost.lastlog = metapost.lastlog .. "\n " .. l
- metapost.report("mp log: %s",l)
- else
- metapost.report("mp error: unknown, no error, terminal or log messages")
- end
- else
- return false
- end
- return true
- end
-
- function metapost.process(mpx, data)
- local converted, result = false, {}
- mpx = metapost.load(mpx)
- if mpx and data then
- local result = mpx:execute(data)
- if not result then
- metapost.report("mp error: no result object returned")
- elseif result.status > 0 then
- metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
- elseif metapost.showlog then
- metapost.lastlog = metapost.lastlog .. "\n" .. result.term
- metapost.report("mp info: %s",result.term or "no-term")
- elseif result.fig then
- converted = metapost.convert(result)
- else
- metapost.report("mp error: unknown error, maybe no beginfig/endfig")
- end
- else
- metapost.report("mp error: mem file not found")
- end
- return converted, result
- end
-
- local function getobjects(result,figure,f)
- return figure:objects()
- end
-
- function metapost.convert(result,flusher)
- metapost.flush(result,flusher)
- return true -- done
- end
-
- --[[ldx--
- <p>We removed some message and tracing code. We might even remove the flusher</p>
- --ldx]]--
-
- local function pdf_startfigure(n,llx,lly,urx,ury)
- tex.sprint(format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
- end
-
- local function pdf_stopfigure()
- tex.sprint("\\stopMPLIBtoPDF")
- end
-
- function pdf_literalcode(fmt,...) -- table
- tex.sprint(format("\\MPLIBtoPDF{%s}",format(fmt,...)))
- end
-
- function pdf_textfigure(font,size,text,width,height,depth)
- local how, what = match(text,"^(.-)::(.+)$")
- if how == "image" then
- tex.sprint(format("\\MPLIBpdftext{%s}{%s}",what,depth))
- else
- text = gsub(text,".","\\hbox{%1}") -- kerning happens in metapost
- tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}",font,size,text,depth))
- end
- end
-
- local bend_tolerance = 131/65536
-
- local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
-
- local function pen_characteristics(object)
- local t = mplib.pen_info(object)
- rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
- divider = sx*sy - rx*ry
- return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
- end
-
- local function concatinated(px, py) -- no tx, ty here
- return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
- end
-
- local function curved(ith,pth)
- local d = pth.left_x - ith.right_x
- if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
- d = pth.left_y - ith.right_y
- if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
- return false
- end
- end
- return true
- end
-
- local function flushnormalpath(path,open)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord)
- elseif curved(ith,pth) then
- pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
- else
- pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord)
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
- else
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
- elseif #path == 1 then
- -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
- return t
- end
-
- local function flushconcatpath(path,open)
- pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",concatinated(pth.x_coord,pth.y_coord))
- elseif curved(ith,pth) then
- local a, b = concatinated(ith.right_x,ith.right_y)
- local c, d = concatinated(pth.left_x,pth.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(pth.x_coord, pth.y_coord))
- else
- pdf_literalcode("%f %f l",concatinated(pth.x_coord, pth.y_coord))
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- local a, b = concatinated(pth.right_x,pth.right_y)
- local c, d = concatinated(one.left_x,one.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(one.x_coord, one.y_coord))
- else
- pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord))
- end
- elseif #path == 1 then
- -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord))
- end
- return t
- end
-
- --[[ldx--
- <p>Support for specials has been removed.</p>
- --ldx]]--
-
- function metapost.flush(result,flusher)
- if result then
- local figures = result.fig
- if figures then
- for f=1, #figures do
- metapost.report("flushing figure %s",f)
- local figure = figures[f]
- local objects = getobjects(result,figure,f)
- local fignum = tonumber(match(figure:filename(),"([%d]+)$") or figure:charcode() or 0)
- local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- local bbox = figure:boundingbox()
- local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack
- if urx < llx then
- -- invalid
- pdf_startfigure(fignum,0,0,0,0)
- pdf_stopfigure()
- else
- pdf_startfigure(fignum,llx,lly,urx,ury)
- pdf_literalcode("q")
- if objects then
- for o=1,#objects do
- local object = objects[o]
- local objecttype = object.type
- if objecttype == "start_bounds" or objecttype == "stop_bounds" then
- -- skip
- elseif objecttype == "start_clip" then
- pdf_literalcode("q")
- flushnormalpath(object.path,t,false)
- pdf_literalcode("W n")
- elseif objecttype == "stop_clip" then
- pdf_literalcode("Q")
- miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
- elseif objecttype == "special" then
- -- not supported
- elseif objecttype == "text" then
- local ot = object.transform -- 3,4,5,6,1,2
- pdf_literalcode("q %f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2])
- pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
- pdf_literalcode("Q")
- else
- local cs = object.color
- local cr = false
- if cs and #cs > 0 then
- cs, cr = metapost.colorconverter(cs)
- pdf_literalcode(cs)
- end
- local ml = object.miterlimit
- if ml and ml ~= miterlimit then
- miterlimit = ml
- pdf_literalcode("%f M",ml)
- end
- local lj = object.linejoin
- if lj and lj ~= linejoin then
- linejoin = lj
- pdf_literalcode("%i j",lj)
- end
- local lc = object.linecap
- if lc and lc ~= linecap then
- linecap = lc
- pdf_literalcode("%i J",lc)
- end
- local dl = object.dash
- if dl then
- local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
- if d ~= dashed then
- dashed = d
- pdf_literalcode(dashed)
- end
- elseif dashed then
- pdf_literalcode("[] 0 d")
- dashed = false
- end
- local path = object.path
- local transformed, penwidth = false, 1
- local open = path and path[1].left_type and path[#path].right_type
- local pen = object.pen
- if pen then
- if pen.type == 'elliptical' then
- transformed, penwidth = pen_characteristics(object) -- boolean, value
- pdf_literalcode("%f w",penwidth)
- if objecttype == 'fill' then
- objecttype = 'both'
- end
- else -- calculated by mplib itself
- objecttype = 'fill'
- end
- end
- if transformed then
- pdf_literalcode("q")
- end
- if path then
- if transformed then
- flushconcatpath(path,open)
- else
- flushnormalpath(path,open)
- end
- if objecttype == "fill" then
- pdf_literalcode("h f")
- elseif objecttype == "outline" then
- pdf_literalcode((open and "S") or "h S")
- elseif objecttype == "both" then
- pdf_literalcode("h B")
- end
- end
- if transformed then
- pdf_literalcode("Q")
- end
- local path = object.htap
- if path then
- if transformed then
- pdf_literalcode("q")
- end
- if transformed then
- flushconcatpath(path,open)
- else
- flushnormalpath(path,open)
- end
- if objecttype == "fill" then
- pdf_literalcode("h f")
- elseif objecttype == "outline" then
- pdf_literalcode((open and "S") or "h S")
- elseif objecttype == "both" then
- pdf_literalcode("h B")
- end
- if transformed then
- pdf_literalcode("Q")
- end
- end
- if cr then
- pdf_literalcode(cr)
- end
- end
- end
- end
- pdf_literalcode("Q")
- pdf_stopfigure()
- end
- end
- end
- end
- end
-
- function metapost.colorconverter(cr)
- local n = #cr
- if n == 4 then
- local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
- return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G"
- elseif n == 3 then
- local r, g, b = cr[1], cr[2], cr[3]
- return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G"
- else
- local s = cr[1]
- return format("%.3f g %.3f G",s,s), "0 g 0 G"
- end
- end
-
-end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.tex
deleted file mode 100644
index f9de4b223f4..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-mplib.tex
+++ /dev/null
@@ -1,140 +0,0 @@
-%D \module
-%D [ file=luatex-mplib,
-%D version=2009.12.01,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=\METAPOST\ to \PDF\ conversion,
-%D author=Taco Hoekwater \& Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D This is the companion to the \LUA\ module \type {supp-mpl.lua}. Further
-%D embedding is up to others. A simple example of usage in plain \TEX\ is:
-%D
-%D \starttyping
-%D \pdfoutput=1
-%D
-%D \input luatex-mplib.tex
-%D
-%D \setmplibformat{plain}
-%D
-%D \mplibcode
-%D beginfig(1);
-%D draw fullcircle
-%D scaled 10cm
-%D withcolor red
-%D withpen pencircle xscaled 4mm yscaled 2mm rotated 30 ;
-%D endfig;
-%D \endmplibcode
-%D
-%D \end
-%D \stoptyping
-
-\def\setmplibformat#1{\def\mplibformat{#1}}
-
-\def\setupmplibcatcodes
- {\catcode`\{=12 % could be optional .. not really needed
- \catcode`\}=12 % could be optional .. not really needed
- \catcode`\#=12
- \catcode`\^=12
- \catcode`\~=12
- \catcode`\_=12
- \catcode`\%=12
- \catcode`\&=12
- \catcode`\$=12 }
-
-\def\mplibcode
- {\bgroup
- \setupmplibcatcodes
- \domplibcode}
-
-\long\def\domplibcode#1\endmplibcode
- {\egroup
- \directlua{metapost.process('\mplibformat',[[#1]])}}
-
-%D We default to \type {plain} \METAPOST:
-
-\def\mplibformat{plain}
-
-%D We use a dedicated scratchbox:
-
-\ifx\mplibscratchbox\undefined \newbox\mplibscratchbox \fi
-
-%D Now load the needed \LUA\ code.
-
-\directlua{dofile(kpse.find_file('luatex-mplib.lua'))}
-% \directlua{dofile(resolvers.findfile('luatex-mplib.lua'))}
-
-%D The following code takes care of encapsulating the literals:
-
-\def\startMPLIBtoPDF#1#2#3#4%
- {\hbox\bgroup
- \xdef\MPllx{#1}\xdef\MPlly{#2}%
- \xdef\MPurx{#3}\xdef\MPury{#4}%
- \xdef\MPwidth{\the\dimexpr#3bp-#1bp\relax}%
- \xdef\MPheight{\the\dimexpr#4bp-#2bp\relax}%
- \parskip0pt%
- \leftskip0pt%
- \parindent0pt%
- \everypar{}%
- \setbox\mplibscratchbox\vbox\bgroup
- \noindent}
-
-\def\stopMPLIBtoPDF
- {\egroup
- \setbox\mplibscratchbox\hbox
- {\hskip-\MPllx bp%
- \raise-\MPlly bp%
- \box\mplibscratchbox}%
- \setbox\mplibscratchbox\vbox to \MPheight
- {\vfill
- \hsize\MPwidth
- \wd\mplibscratchbox0pt%
- \ht\mplibscratchbox0pt%
- \dp\mplibscratchbox0pt%
- \box\mplibscratchbox}%
- \wd\mplibscratchbox\MPwidth
- \ht\mplibscratchbox\MPheight
- \box\mplibscratchbox
- \egroup}
-
-%D The body of picture, except for text items, is taken care of by:
-
-\ifnum\pdfoutput>0
- \let\MPLIBtoPDF\pdfliteral
-\else
- \def\MPLIBtoPDF#1{\special{pdf:literal direct #1}} % not ok yet
-\fi
-
-%D Text items have a special handler:
-
-\def\MPLIBtextext#1#2#3#4%
- {\begingroup
- \setbox\mplibscratchbox\hbox
- {\font\temp=#1 at #2bp%
- \temp
- #3}%
- \setbox\mplibscratchbox\hbox
- {\raise#4sp%
- \box\mplibscratchbox}%
- \wd\mplibscratchbox0pt%
- \ht\mplibscratchbox0pt%
- \dp\mplibscratchbox0pt%
- \box\mplibscratchbox
- \endgroup}
-
-\def\MPLIBpdftext#1#2%
- {\ifcsname mplib::#1\endcsname
- % already done, forgotten outside convert group
- \message{<reusing mplib: #1>}%
- \else
- \message{<embedding mplib: #1>}%
- \immediate\pdfximage{#1}% we cannot remove the file as it is included last
- \expandafter\edef\csname mplib::#1\endcsname{\the\pdflastximage}%
- \fi
- \setbox\mplibscratchbox\hbox
- {\raise#2sp\hbox{\pdfrefximage\csname mplib::#1\endcsname}}%
- \wd\mplibscratchbox0pt%
- \ht\mplibscratchbox0pt%
- \dp\mplibscratchbox0pt%
- \box\mplibscratchbox}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-plain.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-plain.tex
deleted file mode 100644
index 0a806c76ff1..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-plain.tex
+++ /dev/null
@@ -1,55 +0,0 @@
-%D \module
-%D [ file=luatex-plain,
-%D version=2009.12.01,
-%D title=\LUATEX\ Macros,
-%D subtitle=Plain Format,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-\input plain
-
-\directlua {tex.enableprimitives('', tex.extraprimitives())}
-
-% We assume that pdf is used.
-
-\ifdefined\pdfextension
- \input luatex-pdf \relax
-\fi
-
-\outputmode 1
-
-% \outputmode 0 \magnification\magstep5
-
-% We set the page dimensions because otherwise the backend does weird things
-% when we have for instance this on a line of its own:
-%
-% \hbox to 100cm {\hss wide indeed\hss}
-%
-% The page dimension calculation is a fuzzy one as there are some compensations
-% for the \hoffset and \voffset and such. I remember long discussions and much
-% trial and error in figuring this out during pdftex development times. Where
-% a dvi driver will project on a papersize (and thereby clip) the pdf backend
-% has to deal with the lack of a page concept on tex by some guessing. Normally
-% a macro package will set the dimensions to something reasonable anyway.
-
-\pagewidth 8.5truein
-\pageheight 11.0truein
-
-% We load some code at runtime:
-
-\everyjob \expandafter {%
- \the\everyjob
- \input {luatex-basics}%
- \input {luatex-fonts}%
- \input {luatex-math}%
- \input {luatex-languages}%
- \input {luatex-mplib}%
- \input {luatex-gadgets}%
-}
-
-% We also patch the version number:
-
-\edef\fmtversion{\fmtversion+luatex}
-
-\dump
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor-test.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor-test.tex
deleted file mode 100644
index 857b28f831b..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor-test.tex
+++ /dev/null
@@ -1,30 +0,0 @@
-\ifdefined\inputpreprocessed
-
- \def\TestOne[#1]%
- {test one: [#1]\par}
-
- \def\TestTwo#some%
- {test two: #some\par}
-
- \def\TestThree[#whatever][#more]%
- {test three: [#more] and [#whatever]\par}
-
- \def\TestFour[#one]#two%
- {\def\TestFive[#alpha][#one]%
- {test four and five: [#one], [#two] and [#alpha]}\par}
-
- \def\TestSix[#{one}]#{two}%
- {test six: [#{one}] and #{two}\par}
-
- \TestOne [one]
- \TestTwo {one}
- \TestThree[one][two]
- \TestFour [one]{two}
- \TestFive [one][two]
- \TestSix [one]{two}
-
-\else
- \input{luatex-preprocessor.tex}
- \inputpreprocessed{luatex-preprocessor-test.tex}
- \expandafter \end
-\fi
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.lua
deleted file mode 100644
index 8faa0b47e69..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.lua
+++ /dev/null
@@ -1,163 +0,0 @@
-if not modules then modules = { } end modules ['luatex-preprocessor'] = {
- version = 1.001,
- comment = "companion to luatex-preprocessor.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx
-<p>This is a stripped down version of the preprocessor. In
-<l n='context'/> we have a bit more, use a different logger, and
-use a few optimizations. A few examples are shown at the end.</p>
---ldx]]
-
-local rep, sub, gmatch = string.rep, string.sub, string.gmatch
-local insert, remove = table.insert, table.remove
-local setmetatable = setmetatable
-
-local stack, top, n, hashes = { }, nil, 0, { }
-
-local function set(s)
- if top then
- n = n + 1
- if n > 9 then
- texio.write_nl("number of arguments > 9, ignoring: " .. s)
- else
- local ns = #stack
- local h = hashes[ns]
- if not h then
- h = rep("#",ns)
- hashes[ns] = h
- end
- m = h .. n
- top[s] = m
- return m
- end
- end
-end
-
-local function get(s)
- local m = top and top[s] or s
- return m
-end
-
-local function push()
- top = { }
- n = 0
- local s = stack[#stack]
- if s then
- setmetatable(top,{ __index = s })
- end
- insert(stack,top)
-end
-
-local function pop()
- top = remove(stack)
-end
-
-local leftbrace = lpeg.P("{")
-local rightbrace = lpeg.P("}")
-local escape = lpeg.P("\\")
-
-local space = lpeg.P(" ")
-local spaces = space^1
-local newline = lpeg.S("\r\n")
-local nobrace = 1 - leftbrace - rightbrace
-
-local name = lpeg.R("AZ","az")^1
-local longname = (leftbrace/"") * (nobrace^1) * (rightbrace/"")
-local variable = lpeg.P("#") * lpeg.Cs(name + longname)
-local escapedname = escape * name
-local definer = escape * (lpeg.P("def") + lpeg.P("egdx") * lpeg.P("def"))
-local anything = lpeg.P(1)
-local always = lpeg.P(true)
-
-local pushlocal = always / push
-local poplocal = always / pop
-local declaration = variable / set
-local identifier = variable / get
-
-local function matcherror(str,pos)
- texio.write_nl("runaway definition at: " .. sub(str,pos-30,pos))
-end
-
-local parser = lpeg.Cs { "converter",
- definition = pushlocal
- * definer
- * escapedname
- * (declaration + (1-leftbrace))^0
- * lpeg.V("braced")
- * poplocal,
- braced = leftbrace
- * ( lpeg.V("definition")
- + identifier
- + lpeg.V("braced")
- + nobrace
- )^0
- * (rightbrace + lpeg.Cmt(always,matcherror)),
- converter = (lpeg.V("definition") + anything)^1,
-}
-
---[[ldx
-<p>We provide a few commands.</p>
---ldx]]
-
--- local texkpse
-
-local function find_file(...)
- -- texkpse = texkpse or kpse.new("luatex","tex")
- -- return texkpse:find_file(...) or ""
- return kpse.find_file(...) or ""
-end
-
-commands = commands or { }
-
-function commands.preprocessed(str)
- return lpeg.match(parser,str)
-end
-
-function commands.inputpreprocessed(name)
- local name = find_file(name) or ""
- if name ~= "" then
- -- we could use io.loaddata as it's loaded in luatex-plain
- local f = io.open(name,'rb')
- if f then
- texio.write("("..name)
- local d = commands.preprocessed(f:read("*a"))
- if d and d ~= "" then
- texio.write("processed: " .. name)
- for s in gmatch(d,"[^\n\r]+") do
- tex.print(s) -- we do a dumb feedback
- end
- end
- f:close()
- texio.write(")")
- else
- tex.error("preprocessor error, invalid file: " .. name)
- end
- else
- tex.error("preprocessor error, unknown file: " .. name)
- end
-end
-
-function commands.preprocessfile(oldfile,newfile) -- no checking
- if oldfile and oldfile ~= newfile then
- local f = io.open(oldfile,'rb')
- if f then
- local g = io.open(newfile,'wb')
- if g then
- g:write(lpeg.match(parser,f:read("*a") or ""))
- g:close()
- end
- f:close()
- end
- end
-end
-
---~ print(preprocessed([[\def\test#oeps{test:#oeps}]]))
---~ print(preprocessed([[\def\test#oeps{test:#{oeps}}]]))
---~ print(preprocessed([[\def\test#{oeps:1}{test:#{oeps:1}}]]))
---~ print(preprocessed([[\def\test#{oeps}{test:#oeps}]]))
---~ preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]])
---~ print(preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}}]]))
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.tex
deleted file mode 100644
index 03b483f4185..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-preprocessor.tex
+++ /dev/null
@@ -1,14 +0,0 @@
-%D \module
-%D [ file=luatex-preprocessor,
-%D version=2010.12.02,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Generic Preprocessor,
-%D author=Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-\directlua{dofile(kpse.find_file('luatex-preprocessor.lua'))}
-
-\def\inputpreprocessed#1%
- {\directlua{commands.inputpreprocessed("#1")}}
-
-\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua
index 3a4a70c6261..8ee2fcb32de 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 01/27/17 14:39:39
+-- merge date : 09/24/18 14:11:29
do -- begin closure to overcome local limits and interference
@@ -11,14 +11,16 @@ if not modules then modules={} end modules ['l-lua']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-_MAJORVERSION,_MINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
-_MAJORVERSION=tonumber(_MAJORVERSION) or 5
-_MINORVERSION=tonumber(_MINORVERSION) or 1
-_LUAVERSION=_MAJORVERSION+_MINORVERSION/10
-if _LUAVERSION<5.2 and jit then
- _MINORVERSION=2
- _LUAVERSION=5.2
-end
+local next,type,tonumber=next,type,tonumber
+LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5
+LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1
+LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10
+if LUAVERSION<5.2 and jit then
+ MINORVERSION=2
+ LUAVERSION=5.2
+end
+_LUAVERSION=LUAVERSION
if not lpeg then
lpeg=require("lpeg")
end
@@ -108,6 +110,19 @@ if flush then
local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end
local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end
end
+FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+if not FFISUPPORTED then
+ local okay;okay,ffi=pcall(require,"ffi")
+ FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
+end
+if not FFISUPPORTED then
+ ffi=nil
+elseif not ffi.number then
+ ffi.number=tonumber
+end
+if not bit32 then
+ bit32=require("l-bit32")
+end
end -- closure
@@ -120,7 +135,8 @@ if not modules then modules={} end modules ['l-lpeg']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-lpeg=require("lpeg")
+lpeg=require("lpeg")
+local lpeg=lpeg
if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
local type,next,tostring=type,next,tostring
local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
@@ -142,11 +158,14 @@ patterns.alwaysmatched=alwaysmatched
local sign=S('+-')
local zero=P('0')
local digit=R('09')
+local digits=digit^1
local octdigit=R("07")
+local octdigits=octdigit^1
local lowercase=R("az")
local uppercase=R("AZ")
local underscore=P("_")
local hexdigit=digit+lowercase+uppercase
+local hexdigits=hexdigit^1
local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
local newline=P("\r")*(P("\n")+P(true))+P("\n")
local escaped=P("\\")*anything
@@ -203,15 +222,17 @@ patterns.nonwhitespace=nonwhitespace
local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)
local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
+local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
-local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
-local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
patterns.stripper=stripper
patterns.fullstripper=fullstripper
patterns.collapser=collapser
+patterns.nospacer=nospacer
patterns.b_collapser=b_collapser
patterns.m_collapser=m_collapser
patterns.e_collapser=e_collapser
@@ -246,33 +267,36 @@ patterns.singlequoted=squote*patterns.nosquote*squote
patterns.doublequoted=dquote*patterns.nodquote*dquote
patterns.quoted=patterns.doublequoted+patterns.singlequoted
patterns.digit=digit
+patterns.digits=digits
patterns.octdigit=octdigit
+patterns.octdigits=octdigits
patterns.hexdigit=hexdigit
+patterns.hexdigits=hexdigits
patterns.sign=sign
-patterns.cardinal=digit^1
-patterns.integer=sign^-1*digit^1
-patterns.unsigned=digit^0*period*digit^1
+patterns.cardinal=digits
+patterns.integer=sign^-1*digits
+patterns.unsigned=digit^0*period*digits
patterns.float=sign^-1*patterns.unsigned
-patterns.cunsigned=digit^0*comma*digit^1
-patterns.cpunsigned=digit^0*(period+comma)*digit^1
+patterns.cunsigned=digit^0*comma*digits
+patterns.cpunsigned=digit^0*(period+comma)*digits
patterns.cfloat=sign^-1*patterns.cunsigned
patterns.cpfloat=sign^-1*patterns.cpunsigned
patterns.number=patterns.float+patterns.integer
patterns.cnumber=patterns.cfloat+patterns.integer
patterns.cpnumber=patterns.cpfloat+patterns.integer
-patterns.oct=zero*octdigit^1
+patterns.oct=zero*octdigits
patterns.octal=patterns.oct
patterns.HEX=zero*P("X")*(digit+uppercase)^1
patterns.hex=zero*P("x")*(digit+lowercase)^1
-patterns.hexadecimal=zero*S("xX")*hexdigit^1
-patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1
-patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1
+patterns.hexadecimal=zero*S("xX")*hexdigits
+patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
+patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
patterns.somecontent=(anything-newline-space)^1
patterns.beginline=#(1-newline)
-patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0))
-local function anywhere(pattern)
- return P { P(pattern)+1*V(1) }
+patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0))
+function anywhere(pattern)
+ return (1-P(pattern))^0*P(pattern)
end
lpeg.anywhere=anywhere
function lpeg.instringchecker(p)
@@ -513,11 +537,13 @@ function lpeg.balancer(left,right)
left,right=P(left),P(right)
return P { left*((1-left-right)+V(1))^0*right }
end
-local nany=utf8char/""
-function lpeg.counter(pattern)
- pattern=Cs((P(pattern)/" "+nany)^0)
- return function(str)
- return #lpegmatch(pattern,str)
+function lpeg.counter(pattern,action)
+ local n=0
+ local pattern=(P(pattern)/function() n=n+1 end+anything)^0
+ if action then
+ return function(str) n=0;lpegmatch(pattern,str);action(n) end
+ else
+ return function(str) n=0;lpegmatch(pattern,str);return n end
end
end
utf=utf or (unicode and unicode.utf8) or {}
@@ -678,27 +704,13 @@ function lpeg.append(list,pp,delayed,checked)
end
local p_false=P(false)
local p_true=P(true)
-local function make(t)
- local function making(t)
- local p=p_false
- local keys=sortedkeys(t)
- for i=1,#keys do
- local k=keys[i]
- if k~="" then
- local v=t[k]
- if v==true then
- p=p+P(k)*p_true
- elseif v==false then
- else
- p=p+P(k)*making(v)
- end
- end
- end
- if t[""] then
- p=p+p_true
- end
- return p
- end
+local lower=utf and utf.lower or string.lower
+local upper=utf and utf.upper or string.upper
+function lpeg.setutfcasers(l,u)
+ lower=l or lower
+ upper=u or upper
+end
+local function make1(t,rest)
local p=p_false
local keys=sortedkeys(t)
for i=1,#keys do
@@ -709,38 +721,36 @@ local function make(t)
p=p+P(k)*p_true
elseif v==false then
else
- p=p+P(k)*making(v)
+ p=p+P(k)*make1(v,v[""])
end
end
end
+ if rest then
+ p=p+p_true
+ end
return p
end
-local function collapse(t,x)
- if type(t)~="table" then
- return t,x
- else
- local n=next(t)
- if n==nil then
- return t,x
- elseif next(t,n)==nil then
- local k=n
+local function make2(t,rest)
+ local p=p_false
+ local keys=sortedkeys(t)
+ for i=1,#keys do
+ local k=keys[i]
+ if k~="" then
local v=t[k]
- if type(v)=="table" then
- return collapse(v,x..k)
+ if v==true then
+ p=p+(P(lower(k))+P(upper(k)))*p_true
+ elseif v==false then
else
- return v,x..k
+ p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""])
end
- else
- local tt={}
- for k,v in next,t do
- local vv,kk=collapse(v,k)
- tt[kk]=vv
- end
- return tt,x
end
end
+ if rest then
+ p=p+p_true
+ end
+ return p
end
-function lpeg.utfchartabletopattern(list)
+local function utfchartabletopattern(list,insensitive)
local tree={}
local n=#list
if n==0 then
@@ -811,7 +821,14 @@ function lpeg.utfchartabletopattern(list)
end
end
end
- return make(tree)
+ return (insensitive and make2 or make1)(tree)
+end
+lpeg.utfchartabletopattern=utfchartabletopattern
+function lpeg.utfreplacer(list,insensitive)
+ local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
+ return function(str)
+ return lpegmatch(pattern,str) or str
+ end
end
patterns.containseol=lpeg.finder(eol)
local function nextstep(n,step,result)
@@ -842,12 +859,21 @@ end
function lpeg.times(pattern,n)
return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
end
-local trailingzeros=zero^0*-digit
-local case_1=period*trailingzeros/""
-local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"")
-local number=digit^1*(case_1+case_2)
-local stripper=Cs((number+1)^0)
-lpeg.patterns.stripzeros=stripper
+do
+ local trailingzeros=zero^0*-digit
+ local stripper=Cs((
+ digits*(
+ period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
+ )+1
+ )^0)
+ lpeg.patterns.stripzeros=stripper
+ local nonzero=digit-zero
+ local trailingzeros=zero^1*endofstring
+ local stripper=Cs((1-period)^0*(
+ period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
+ ))
+ lpeg.patterns.stripzero=stripper
+end
local byte_to_HEX={}
local byte_to_hex={}
local byte_to_dec={}
@@ -907,6 +933,21 @@ function string.tobytes(s)
return lpegmatch(hextobytes,s)
end
end
+local patterns={}
+local function containsws(what)
+ local p=patterns[what]
+ if not p then
+ local p1=P(what)*(whitespace+endofstring)*Cc(true)
+ local p2=whitespace*P(p1)
+ p=P(p1)+P(1-p2)^0*p2+Cc(false)
+ patterns[what]=p
+ end
+ return p
+end
+lpeg.containsws=containsws
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
end -- closure
@@ -962,6 +1003,7 @@ end
local stripper=patterns.stripper
local fullstripper=patterns.fullstripper
local collapser=patterns.collapser
+local nospacer=patterns.nospacer
local longtostring=patterns.longtostring
function string.strip(str)
return str and lpegmatch(stripper,str) or ""
@@ -972,6 +1014,9 @@ end
function string.collapsespaces(str)
return str and lpegmatch(collapser,str) or ""
end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
function string.longtostring(str)
return str and lpegmatch(longtostring,str) or ""
end
@@ -1022,6 +1067,21 @@ function string.tformat(fmt,...)
end
string.quote=string.quoted
string.unquote=string.unquoted
+if not string.bytetable then
+ local limit=5000
+ function string.bytetable(str)
+ local n=#str
+ if n>limit then
+ local t={ byte(str,1,limit) }
+ for i=limit+1,n do
+ t[i]=byte(str,i)
+ end
+ return t
+ else
+ return { byte(str,1,n) }
+ end
+ end
+end
end -- closure
@@ -1034,7 +1094,7 @@ if not modules then modules={} end modules ['l-table']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local type,next,tostring,tonumber,ipairs,select=type,next,tostring,tonumber,ipairs,select
+local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select
local table,string=table,string
local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove
local format,lower,dump=string.format,string.lower,string.dump
@@ -1043,6 +1103,9 @@ local getinfo=debug.getinfo
local lpegmatch,patterns=lpeg.match,lpeg.patterns
local floor=math.floor
local stripper=patterns.stripper
+function table.getn(t)
+ return t and #t
+end
function table.strip(tab)
local lst,l={},0
for i=1,#tab do
@@ -1336,7 +1399,7 @@ function table.tohash(t,value)
local h={}
if t then
if value==nil then value=true end
- for _,v in next,t do
+ for _,v in next,t do
h[v]=value
end
end
@@ -1344,7 +1407,7 @@ function table.tohash(t,value)
end
function table.fromhash(t)
local hsh,h={},0
- for k,v in next,t do
+ for k,v in next,t do
if v then
h=h+1
hsh[h]=k
@@ -1358,13 +1421,17 @@ local reserved=table.tohash {
'in','local','nil','not','or','repeat','return','then','true','until','while',
'NaN','goto',
}
-local function simple_table(t)
+local function is_simple_table(t,hexify)
local nt=#t
if nt>0 then
local n=0
for _,v in next,t do
n=n+1
+ if type(v)=="table" then
+ return nil
+ end
end
+ local haszero=rawget(t,0)
if n==nt then
local tt={}
for i=1,nt do
@@ -1374,10 +1441,10 @@ local function simple_table(t)
if hexify then
tt[i]=format("0x%X",v)
else
- tt[i]=tostring(v)
+ tt[i]=v
end
elseif tv=="string" then
- tt[i]=format("%q",v)
+ tt[i]=format("%q",v)
elseif tv=="boolean" then
tt[i]=v and "true" or "false"
else
@@ -1385,10 +1452,32 @@ local function simple_table(t)
end
end
return tt
+ elseif haszero and (n==nt+1) then
+ local tt={}
+ for i=0,nt do
+ local v=t[i]
+ local tv=type(v)
+ if tv=="number" then
+ if hexify then
+ tt[i+1]=format("0x%X",v)
+ else
+ tt[i+1]=v
+ end
+ elseif tv=="string" then
+ tt[i+1]=format("%q",v)
+ elseif tv=="boolean" then
+ tt[i+1]=v and "true" or "false"
+ else
+ return nil
+ end
+ end
+ tt[1]="[0] = "..tt[1]
+ return tt
end
end
return nil
end
+table.is_simple_table=is_simple_table
local propername=patterns.propername
local function dummy() end
local function do_serialize(root,name,depth,level,indexed)
@@ -1450,7 +1539,7 @@ local function do_serialize(root,name,depth,level,indexed)
if next(v)==nil then
handle(format("%s {},",depth))
elseif inline then
- local st=simple_table(v)
+ local st=is_simple_table(v,hexify)
if st then
handle(format("%s { %s },",depth,concat(st,", ")))
else
@@ -1533,7 +1622,7 @@ local function do_serialize(root,name,depth,level,indexed)
handle(format("%s [%q]={},",depth,k))
end
elseif inline then
- local st=simple_table(v)
+ local st=is_simple_table(v,hexify)
if st then
if tk=="number" then
if hexify then
@@ -1793,7 +1882,9 @@ function table.unnest(t)
return unnest(t)
end
local function are_equal(a,b,n,m)
- if a and b and #a==#b then
+ if a==b then
+ return true
+ elseif a and b and #a==#b then
n=n or 1
m=m or #a
for i=n,m do
@@ -1813,15 +1904,17 @@ local function are_equal(a,b,n,m)
end
end
local function identical(a,b)
- for ka,va in next,a do
- local vb=b[ka]
- if va==vb then
- elseif type(va)=="table" and type(vb)=="table" then
- if not identical(va,vb) then
+ if a~=b then
+ for ka,va in next,a do
+ local vb=b[ka]
+ if va==vb then
+ elseif type(va)=="table" and type(vb)=="table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
return false
end
- else
- return false
end
end
return true
@@ -1904,25 +1997,33 @@ function table.reversed(t)
return tt
end
end
-function table.reverse(t)
+function table.reverse(t)
if t then
local n=#t
- for i=1,floor(n/2) do
- local j=n-i+1
+ local m=n+1
+ for i=1,floor(n/2) do
+ local j=m-i
t[i],t[j]=t[j],t[i]
end
return t
end
end
-function table.sequenced(t,sep,simple)
+local function sequenced(t,sep,simple)
if not t then
return ""
+ elseif type(t)=="string" then
+ return t
end
local n=#t
local s={}
if n>0 then
for i=1,n do
- s[i]=tostring(t[i])
+ local v=t[i]
+ if type(v)=="table" then
+ s[i]="{"..sequenced(v,sep,simple).."}"
+ else
+ s[i]=tostring(t[i])
+ end
end
else
n=0
@@ -1933,16 +2034,25 @@ function table.sequenced(t,sep,simple)
s[n]=k
elseif v and v~="" then
n=n+1
- s[n]=k.."="..tostring(v)
+ if type(v)=="table" then
+ s[n]=k.."={"..sequenced(v,sep,simple).."}"
+ else
+ s[n]=k.."="..tostring(v)
+ end
end
else
n=n+1
- s[n]=k.."="..tostring(v)
+ if type(v)=="table" then
+ s[n]=k.."={"..sequenced(v,sep,simple).."}"
+ else
+ s[n]=k.."="..tostring(v)
+ end
end
end
end
return concat(s,sep or " | ")
end
+table.sequenced=sequenced
function table.print(t,...)
if type(t)~="table" then
print(tostring(t))
@@ -2043,6 +2153,24 @@ function table.filtered(t,pattern,sort,cmp)
return nothing
end
end
+if not table.move then
+ function table.move(a1,f,e,t,a2)
+ if a2 and a1~=a2 then
+ for i=f,e do
+ a2[t]=a1[i]
+ t=t+1
+ end
+ return a2
+ else
+ t=t+e-f
+ for i=e,f,-1 do
+ a1[t]=a1[i]
+ t=t-1
+ end
+ return a1
+ end
+ end
+end
end -- closure
@@ -2059,51 +2187,36 @@ local io=io
local open,flush,write,read=io.open,io.flush,io.write,io.read
local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
local concat=table.concat
-local floor=math.floor
local type=type
if string.find(os.getenv("PATH"),";",1,true) then
io.fileseparator,io.pathseparator="\\",";"
else
io.fileseparator,io.pathseparator="/",":"
end
-local function readall(f)
- return f:read("*all")
-end
+local large=0x01000000
+local medium=0x00100000
+local small=0x00020000
local function readall(f)
local size=f:seek("end")
- if size==0 then
- return ""
- end
- f:seek("set",0)
- if size<1024*1024 then
- return f:read('*all')
+ if size>0 then
+ f:seek("set",0)
+ return f:read(size)
else
- local step
- if size>16*1024*1024 then
- step=16*1024*1024
- else
- step=floor(size/(1024*1024))*1024*1024/8
- end
- local data={}
- while true do
- local r=f:read(step)
- if not r then
- return concat(data)
- else
- data[#data+1]=r
- end
- end
+ return ""
end
end
io.readall=readall
function io.loaddata(filename,textmode)
local f=open(filename,(textmode and 'r') or 'rb')
if f then
- local data=readall(f)
- f:close()
- if #data>0 then
- return data
+ local size=f:seek("end")
+ local data=nil
+ if size>0 then
+ f:seek("set",0)
+ data=f:read(size)
end
+ f:close()
+ return data
end
end
function io.copydata(source,target,action)
@@ -2112,37 +2225,14 @@ function io.copydata(source,target,action)
local g=open(target,"wb")
if g then
local size=f:seek("end")
- if size==0 then
- else
+ if size>0 then
f:seek("set",0)
- if size<1024*1024 then
- local data=f:read('*all')
- if action then
- data=action(data)
- end
- if data then
- g:write(data)
- end
- else
- local step
- if size>16*1024*1024 then
- step=16*1024*1024
- else
- step=floor(size/(1024*1024))*1024*1024/8
- end
- while true do
- local data=f:read(step)
- if data then
- if action then
- data=action(data)
- end
- if data then
- g:write(data)
- end
- else
- break
- end
- end
+ local data=f:read(size)
+ if action then
+ data=action(data)
+ end
+ if data then
+ g:write(data)
end
end
g:close()
@@ -2168,29 +2258,59 @@ function io.savedata(filename,data,joiner)
return false
end
end
-function io.loadlines(filename,n)
- local f=open(filename,'r')
- if not f then
- elseif n then
- local lines={}
- for i=1,n do
- local line=f:read("*lines")
- if line then
- lines[#lines+1]=line
- else
- break
+if fio and fio.readline then
+ local readline=fio.readline
+ function io.loadlines(filename,n)
+ local f=open(filename,'r')
+ if not f then
+ elseif n then
+ local lines={}
+ for i=1,n do
+ local line=readline(f)
+ if line then
+ lines[i]=line
+ else
+ break
+ end
+ end
+ f:close()
+ lines=concat(lines,"\n")
+ if #lines>0 then
+ return lines
+ end
+ else
+ local line=readline(f)
+ f:close()
+ if line and #line>0 then
+ return line
end
end
- f:close()
- lines=concat(lines,"\n")
- if #lines>0 then
- return lines
- end
- else
- local line=f:read("*line") or ""
- f:close()
- if #line>0 then
- return line
+ end
+else
+ function io.loadlines(filename,n)
+ local f=open(filename,'r')
+ if not f then
+ elseif n then
+ local lines={}
+ for i=1,n do
+ local line=f:read("*lines")
+ if line then
+ lines[i]=line
+ else
+ break
+ end
+ end
+ f:close()
+ lines=concat(lines,"\n")
+ if #lines>0 then
+ return lines
+ end
+ else
+ local line=f:read("*line") or ""
+ f:close()
+ if #line>0 then
+ return line
+ end
end
end
end
@@ -2351,7 +2471,7 @@ function io.ask(question,default,options)
end
end
end
-local function readnumber(f,n,m)
+local function readnumber(f,n,m)
if m then
f:seek("set",n)
n=m
@@ -2360,31 +2480,31 @@ local function readnumber(f,n,m)
return byte(f:read(1))
elseif n==2 then
local a,b=byte(f:read(2),1,2)
- return 256*a+b
+ return 0x100*a+b
elseif n==3 then
local a,b,c=byte(f:read(3),1,3)
- return 256*256*a+256*b+c
+ return 0x10000*a+0x100*b+c
elseif n==4 then
local a,b,c,d=byte(f:read(4),1,4)
- return 256*256*256*a+256*256*b+256*c+d
+ return 0x1000000*a+0x10000*b+0x100*c+d
elseif n==8 then
local a,b=readnumber(f,4),readnumber(f,4)
- return 256*a+b
+ return 0x100*a+b
elseif n==12 then
local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
- return 256*256*a+256*b+c
+ return 0x10000*a+0x100*b+c
elseif n==-2 then
local b,a=byte(f:read(2),1,2)
- return 256*a+b
+ return 0x100*a+b
elseif n==-3 then
local c,b,a=byte(f:read(3),1,3)
- return 256*256*a+256*b+c
+ return 0x10000*a+0x100*b+c
elseif n==-4 then
local d,c,b,a=byte(f:read(4),1,4)
- return 256*256*256*a+256*256*b+256*c+d
+ return 0x1000000*a+0x10000*b+0x100*c+d
elseif n==-8 then
local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
- return 256*256*256*256*256*256*256*a+256*256*256*256*256*256*b+256*256*256*256*256*c+256*256*256*256*d+256*256*256*e+256*256*f+256*g+h
+ return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
else
return 0
end
@@ -2421,21 +2541,22 @@ local lpegmatch=lpeg.match
local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
local checkedsplit=string.checkedsplit
local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct
-local tricky=S("/\\")*P(-1)
local attributes=lfs.attributes
-if sandbox then
- sandbox.redefine(lfs.isfile,"lfs.isfile")
- sandbox.redefine(lfs.isdir,"lfs.isdir")
-end
function lfs.isdir(name)
- if lpegmatch(tricky,name) then
- return attributes(name,"mode")=="directory"
- else
- return attributes(name.."/.","mode")=="directory"
- end
+ return attributes(name,"mode")=="directory"
end
function lfs.isfile(name)
- return attributes(name,"mode")=="file"
+ local a=attributes(name,"mode")
+ return a=="file" or a=="link" or nil
+end
+function lfs.isfound(name)
+ local a=attributes(name,"mode")
+ return (a=="file" or a=="link") and name or nil
+end
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir,"lfs.isdir")
+ sandbox.redefine(lfs.isfound,"lfs.isfound")
end
local colon=P(":")
local period=P(".")
@@ -2775,6 +2896,27 @@ function lfs.mkdirs(path)
lfs.mkdir(full)
end
end
+function file.withinbase(path)
+ local l=0
+ if not find(path,"^/") then
+ path="/"..path
+ end
+ for dir in gmatch(path,"/([^/]+)") do
+ if dir==".." then
+ l=l-1
+ elseif dir~="." then
+ l=l+1
+ end
+ if l<0 then
+ return false
+ end
+ end
+ return true
+end
+local symlinkattributes=lfs.symlinkattributes
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
end -- closure
@@ -2854,21 +2996,23 @@ if not modules then modules={} end modules ['l-math']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local floor,sin,cos,tan=math.floor,math.sin,math.cos,math.tan
if not math.ceiling then
math.ceiling=math.ceil
end
if not math.round then
+ local floor=math.floor
function math.round(x) return floor(x+0.5) end
end
if not math.div then
+ local floor=math.floor
function math.div(n,m) return floor(n/m) end
end
if not math.mod then
function math.mod(n,m) return n%m end
end
-local pipi=2*math.pi/360
if not math.sind then
+ local sin,cos,tan=math.sin,math.cos,math.tan
+ local pipi=2*math.pi/360
function math.sind(d) return sin(d*pipi) end
function math.cosd(d) return cos(d*pipi) end
function math.tand(d) return tan(d*pipi) end
@@ -2877,6 +3021,60 @@ if not math.odd then
function math.odd (n) return n%2~=0 end
function math.even(n) return n%2==0 end
end
+if not math.cosh then
+ local exp=math.exp
+ function math.cosh(x)
+ local xx=exp(x)
+ return (xx+1/xx)/2
+ end
+ function math.sinh(x)
+ local xx=exp(x)
+ return (xx-1/xx)/2
+ end
+ function math.tanh(x)
+ local xx=exp(x)
+ return (xx-1/xx)/(xx+1/xx)
+ end
+end
+if not math.pow then
+ function math.pow(x,y)
+ return x^y
+ end
+end
+if not math.atan2 then
+ math.atan2=math.atan
+end
+if not math.ldexp then
+ function math.ldexp(x,e)
+ return x*2.0^e
+ end
+end
+if not math.log10 then
+ local log=math.log
+ function math.log10(x)
+ return log(x,10)
+ end
+end
+if not math.type then
+ function math.type()
+ return "float"
+ end
+end
+if not math.tointeger then
+ math.mininteger=-0x4FFFFFFFFFFF
+ math.maxinteger=0x4FFFFFFFFFFF
+ local floor=math.floor
+ function math.tointeger(n)
+ local f=floor(n)
+ return f==n and f or nil
+ end
+end
+if not math.ult then
+ local floor=math.floor
+ function math.tointeger(m,n)
+ return floor(m)<floor(n)
+ end
+end
end -- closure
@@ -2916,37 +3114,73 @@ if not unicode then
unicode={ utf=utf }
end
if not utf.char then
- local floor,char=math.floor,string.char
- function utf.char(n)
- if n<0x80 then
- return char(n)
- elseif n<0x800 then
- return char(
- 0xC0+floor(n/0x40),
- 0x80+(n%0x40)
- )
- elseif n<0x10000 then
- return char(
- 0xE0+floor(n/0x1000),
- 0x80+(floor(n/0x40)%0x40),
- 0x80+(n%0x40)
- )
- elseif n<0x200000 then
- return char(
- 0xF0+floor(n/0x40000),
- 0x80+(floor(n/0x1000)%0x40),
- 0x80+(floor(n/0x40)%0x40),
- 0x80+(n%0x40)
- )
+ utf.char=string.utfcharacter or (utf8 and utf8.char)
+ if not utf.char then
+ local char=string.char
+ if bit32 then
+ local rshift=bit32.rshift
+ function utf.char(n)
+ if n<0x80 then
+ return char(n)
+ elseif n<0x800 then
+ return char(
+ 0xC0+rshift(n,6),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x10000 then
+ return char(
+ 0xE0+rshift(n,12),
+ 0x80+(rshift(n,6)%0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x200000 then
+ return char(
+ 0xF0+rshift(n,18),
+ 0x80+(rshift(n,12)%0x40),
+ 0x80+(rshift(n,6)%0x40),
+ 0x80+(n%0x40)
+ )
+ else
+ return ""
+ end
+ end
else
- return ""
+ local floor=math.floor
+ function utf.char(n)
+ if n<0x80 then
+ return char(n)
+ elseif n<0x800 then
+ return char(
+ 0xC0+floor(n/0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x10000 then
+ return char(
+ 0xE0+floor(n/0x1000),
+ 0x80+(floor(n/0x40)%0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x200000 then
+ return char(
+ 0xF0+floor(n/0x40000),
+ 0x80+(floor(n/0x1000)%0x40),
+ 0x80+(floor(n/0x40)%0x40),
+ 0x80+(n%0x40)
+ )
+ else
+ return ""
+ end
+ end
end
end
end
if not utf.byte then
- local utf8byte=patterns.utf8byte
- function utf.byte(c)
- return lpegmatch(utf8byte,c)
+ utf.byte=string.utfvalue or (utf8 and utf8.codepoint)
+ if not utf.byte then
+ local utf8byte=patterns.utf8byte
+ function utf.byte(c)
+ return lpegmatch(utf8byte,c)
+ end
end
end
local utfchar,utfbyte=utf.char,utf.byte
@@ -2997,19 +3231,22 @@ function utf.is_valid(str)
return type(str)=="string" and lpegmatch(validatedutf,str) or false
end
if not utf.len then
- local n,f=0,1
- local utfcharcounter=patterns.utfbom^-1*Cmt (
- Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1,
- function(_,t,d)
- n=n+(t-f)/d
- f=t
- return true
+ utf.len=string.utflength or (utf8 and utf8.len)
+ if not utf.len then
+ local n,f=0,1
+ local utfcharcounter=patterns.utfbom^-1*Cmt (
+ Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1,
+ function(_,t,d)
+ n=n+(t-f)/d
+ f=t
+ return true
+ end
+ )^0
+ function utf.len(str)
+ n,f=0,1
+ lpegmatch(utfcharcounter,str or "")
+ return n
end
- )^0
- function utf.len(str)
- n,f=0,1
- lpegmatch(utfcharcounter,str or "")
- return n
end
end
utf.length=utf.len
@@ -3357,20 +3594,22 @@ function utf.utf32_to_utf8_t(t,endian)
end
local function little(b)
if b<0x10000 then
- return char(b%256,b/256)
+ return char(b%256,rshift(b,8))
else
b=b-0x10000
- local b1,b2=b/1024+0xD800,b%1024+0xDC00
- return char(b1%256,b1/256,b2%256,b2/256)
+ local b1=rshift(b,10)+0xD800
+ local b2=b%1024+0xDC00
+ return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8))
end
end
local function big(b)
if b<0x10000 then
- return char(b/256,b%256)
+ return char(rshift(b,8),b%256)
else
b=b-0x10000
- local b1,b2=b/1024+0xD800,b%1024+0xDC00
- return char(b1/256,b1%256,b2/256,b2%256)
+ local b1=rshift(b,10)+0xD800
+ local b2=b%1024+0xDC00
+ return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256)
end
end
local l_remap=Cs((p_utf8byte/little+P(1)/"")^0)
@@ -3491,6 +3730,44 @@ function utf.chrlen(u)
(u<0xFC and 5) or
(u<0xFE and 6) or 0
end
+if bit32 then
+ local extract=bit32.extract
+ local char=string.char
+ function unicode.toutf32string(n)
+ if n<=0xFF then
+ return
+ char(n).."\000\000\000"
+ elseif n<=0xFFFF then
+ return
+ char(extract(n,0,8))..char(extract(n,8,8)).."\000\000"
+ elseif n<=0xFFFFFF then
+ return
+ char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000"
+ else
+ return
+ char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8))
+ end
+ end
+end
+local len=utf.len
+local rep=rep
+function string.utfpadd(s,n)
+ if n and n~=0 then
+ local l=len(s)
+ if n>0 then
+ local d=n-l
+ if d>0 then
+ return rep(c or " ",d)..s
+ end
+ else
+ local d=- n-l
+ if d>0 then
+ return s..rep(c or " ",d)
+ end
+ end
+ end
+ return s
+end
end -- closure
@@ -3508,13 +3785,15 @@ utilities.strings=utilities.strings or {}
local strings=utilities.strings
local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
local load,dump=load,string.dump
-local tonumber,type,tostring=tonumber,type,tostring
+local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
+local unpack,concat=table.unpack,table.concat
local unpack,concat=table.unpack,table.concat
local 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
local patterns,lpegmatch=lpeg.patterns,lpeg.match
-local utfchar,utfbyte=utf.char,utf.byte
+local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
local loadstripped=nil
-if _LUAVERSION<5.2 then
+local oldfashioned=LUAVERSION<5.2
+if oldfashioned then
loadstripped=function(str,shortcuts)
return load(str)
end
@@ -3528,25 +3807,52 @@ else
end
end
if not number then number={} end
-local stripper=patterns.stripzeros
+local stripzero=patterns.stripzero
+local stripzeros=patterns.stripzeros
local newline=patterns.newline
local endofstring=patterns.endofstring
+local anything=patterns.anything
local whitespace=patterns.whitespace
+local space=patterns.space
local spacer=patterns.spacer
local spaceortab=patterns.spaceortab
+local digit=patterns.digit
+local sign=patterns.sign
+local period=patterns.period
+local ptf=1/65536
+local bpf=(7200/7227)/65536
local function points(n)
+ if n==0 then
+ return "0pt"
+ end
n=tonumber(n)
- return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
+ if not n or n==0 then
+ return "0pt"
+ end
+ n=n*ptf
+ if n%1==0 then
+ return format("%ipt",n)
+ end
+ return lpegmatch(stripzeros,format("%.5fpt",n))
end
local function basepoints(n)
+ if n==0 then
+ return "0pt"
+ end
n=tonumber(n)
- return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536))
+ if not n or n==0 then
+ return "0pt"
+ end
+ n=n*bpf
+ if n%1==0 then
+ return format("%ibp",n)
+ end
+ return lpegmatch(stripzeros,format("%.5fbp",n))
end
number.points=points
number.basepoints=basepoints
local rubish=spaceortab^0*newline
local anyrubish=spaceortab+newline
-local anything=patterns.anything
local stripped=(spaceortab^1/"")*newline
local leading=rubish^0/""
local trailing=(anyrubish^1*endofstring)/""
@@ -3597,24 +3903,39 @@ local pattern=Carg(1)/function(t)
end
end+newline*Cp()/function(position)
extra,start=0,position
- end+patterns.anything
+ end+anything
)^1)
function strings.tabtospace(str,tab)
return lpegmatch(pattern,str,1,tab or 7)
end
-local space=spacer^0
-local nospace=space/""
+function string.utfpadding(s,n)
+ if not n or n==0 then
+ return ""
+ end
+ local l=utflen(s)
+ if n>0 then
+ return nspaces[n-l]
+ else
+ return nspaces[-n-l]
+ end
+end
+local optionalspace=spacer^0
+local nospace=optionalspace/""
local endofline=nospace*newline
local stripend=(whitespace^1*endofstring)/""
-local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace)
+local normalline=(nospace*((1-optionalspace*(newline+endofstring))^1)*nospace)
local stripempty=endofline^1/""
local normalempty=endofline^1
local singleempty=endofline*(endofline^0/"")
local doubleempty=endofline*endofline^-1*(endofline^0/"")
local stripstart=stripempty^0
+local intospace=whitespace^1/" "
+local noleading=whitespace^1/""
+local notrailing=noleading*endofstring
local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 )
local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 )
local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 )
+local p_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^0 )
local p_retain_normal=Cs ((normalline+normalempty )^0 )
local p_retain_collapse=Cs ((normalline+doubleempty )^0 )
local p_retain_noempty=Cs ((normalline+singleempty )^0 )
@@ -3622,6 +3943,7 @@ local striplinepatterns={
["prune"]=p_prune_normal,
["prune and collapse"]=p_prune_collapse,
["prune and no empty"]=p_prune_noempty,
+ ["prune and to space"]=p_prune_intospace,
["retain"]=p_retain_normal,
["retain and collapse"]=p_retain_collapse,
["retain and no empty"]=p_retain_noempty,
@@ -3632,6 +3954,9 @@ strings.striplinepatterns=striplinepatterns
function strings.striplines(str,how)
return str and lpegmatch(striplinepatterns[how],str) or str
end
+function strings.collapse(str)
+ return str and lpegmatch(p_prune_intospace,str) or str
+end
strings.striplong=strings.striplines
function strings.nice(str)
str=gsub(str,"[:%-+_]+"," ")
@@ -3689,34 +4014,60 @@ function number.signed(i)
return "-",-i
end
end
-local digit=patterns.digit
-local period=patterns.period
-local three=digit*digit*digit
+local two=digit*digit
+local three=two*digit
+local prefix=(Carg(1)*three)^1
local splitter=Cs (
- (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
+ (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2)
+)
+local splitter3=Cs (
+ three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit
)
patterns.formattednumber=splitter
function number.formatted(n,sep1,sep2)
- local s=type(s)=="string" and n or format("%0.2f",n)
- if sep1==true then
- return lpegmatch(splitter,s,1,".",",")
- elseif sep1=="." then
- return lpegmatch(splitter,s,1,sep1,sep2 or ",")
- elseif sep1=="," then
- return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+ if sep1==false then
+ if type(n)=="number" then
+ n=tostring(n)
+ end
+ return lpegmatch(splitter3,n,1,sep2 or ".")
else
- return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+ if type(n)=="number" then
+ n=format("%0.2f",n)
+ end
+ if sep1==true then
+ return lpegmatch(splitter,n,1,".",",")
+ elseif sep1=="." then
+ return lpegmatch(splitter,n,1,sep1,sep2 or ",")
+ elseif sep1=="," then
+ return lpegmatch(splitter,n,1,sep1,sep2 or ".")
+ else
+ return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".")
+ end
end
end
+local p=Cs(
+ P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0
+ )
+function number.compactfloat(n,fmt)
+ if n==0 then
+ return "0"
+ elseif n==1 then
+ return "1"
+ end
+ n=lpegmatch(p,format(fmt or "%0.3f",n))
+ if n=="." or n=="" or n=="-" then
+ return "0"
+ end
+ return n
+end
local zero=P("0")^1/""
local plus=P("+")/""
local minus=P("-")
-local separator=S(".")
-local digit=R("09")
+local separator=period
local trailing=zero^1*#S("eE")
-local exponent=(S("eE")*(plus+Cs((minus*zero^0*P(-1))/"")+minus)*zero^0*(P(-1)*Cc("0")+P(1)^1))
+local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1))
local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
-local pattern_b=Cs((exponent+P(1))^0)
+local pattern_b=Cs((exponent+anything)^0)
function number.sparseexponent(f,n)
if not n then
n=f
@@ -3733,13 +4084,34 @@ function number.sparseexponent(f,n)
end
return tostring(n)
end
+local hf={}
+local hs={}
+setmetatable(hf,{ __index=function(t,k)
+ local v="%."..k.."f"
+ t[k]=v
+ return v
+end } )
+setmetatable(hs,{ __index=function(t,k)
+ local v="%"..k.."s"
+ t[k]=v
+ return v
+end } )
+function number.formattedfloat(n,b,a)
+ local s=format(hf[a],n)
+ local l=(b or 0)+(a or 0)+1
+ if #s<l then
+ return format(hs[l],s)
+ else
+ return s
+ end
+end
local template=[[
%s
%s
return function(%s) return %s end
]]
local preamble,environment="",{}
-if _LUAVERSION<5.2 then
+if oldfashioned then
preamble=[[
local lpeg=lpeg
local type=type
@@ -3754,12 +4126,16 @@ local utfchar=utf.char
local utfbyte=utf.byte
local lpegmatch=lpeg.match
local nspaces=string.nspaces
+local utfpadding=string.utfpadding
local tracedchar=string.tracedchar
local autosingle=string.autosingle
local autodouble=string.autodouble
local sequenced=table.sequenced
local formattednumber=number.formatted
local sparseexponent=number.sparseexponent
+local formattedfloat=number.formattedfloat
+local stripzero=lpeg.patterns.stripzero
+local stripzeros=lpeg.patterns.stripzeros
]]
else
environment={
@@ -3777,12 +4153,16 @@ else
utfbyte=utf.byte,
lpegmatch=lpeg.match,
nspaces=string.nspaces,
+ utfpadding=string.utfpadding,
tracedchar=string.tracedchar,
autosingle=string.autosingle,
autodouble=string.autodouble,
sequenced=table.sequenced,
formattednumber=number.formatted,
sparseexponent=number.sparseexponent,
+ formattedfloat=number.formattedfloat,
+ stripzero=lpeg.patterns.stripzero,
+ stripzeros=lpeg.patterns.stripzeros,
}
end
local arguments={ "a1" }
@@ -3792,7 +4172,8 @@ setmetatable(arguments,{ __index=function(t,k)
return v
end
})
-local prefix_any=C((S("+- .")+R("09"))^0)
+local prefix_any=C((sign+space+period+digit)^0)
+local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(0))
local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0)
local format_s=function(f)
n=n+1
@@ -3810,9 +4191,32 @@ local format_S=function(f)
return format("tostring(a%s)",n)
end
end
+local format_right=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+ return format("(a%s or '')",n)
+ elseif f>0 then
+ return format("utfpadding(a%s,%i)..a%s",n,f,n)
+ else
+ return format("a%s..utfpadding(a%s,%i)",n,n,f)
+ end
+end
+local format_left=function(f)
+ n=n+1
+ f=tonumber(f)
+ if not f or f==0 then
+ return format("(a%s or '')",n)
+ end
+ if f<0 then
+ return format("utfpadding(a%s,%i)..a%s",n,-f,n)
+ else
+ return format("a%s..utfpadding(a%s,%i)",n,n,-f)
+ end
+end
local format_q=function()
n=n+1
- return format("(a%s and format('%%q',a%s) or '')",n,n)
+ return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
end
local format_Q=function()
n=n+1
@@ -3843,6 +4247,10 @@ local format_F=function(f)
return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
end
end
+local format_k=function(b,a)
+ n=n+1
+ return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0)
+end
local format_g=function(f)
n=n+1
return format("format('%%%sg',a%s)",f,n)
@@ -3959,9 +4367,16 @@ local format_L=function()
n=n+1
return format("(a%s and 'TRUE' or 'FALSE')",n)
end
-local format_N=function()
+local format_n=function()
n=n+1
- return format("tostring(tonumber(a%s) or a%s)",n,n)
+ return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
+end
+local format_N=function(f)
+ n=n+1
+ if not f or f=="" then
+ f=".9"
+ end
+ return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
end
local format_a=function(f)
n=n+1
@@ -3996,14 +4411,22 @@ local format_m=function(f)
if not f or f=="" then
f=","
end
- return format([[formattednumber(a%s,%q,".")]],n,f)
+ if f=="0" then
+ return format([[formattednumber(a%s,false)]],n)
+ else
+ return format([[formattednumber(a%s,%q,".")]],n,f)
+ end
end
local format_M=function(f)
n=n+1
if not f or f=="" then
f="."
end
- return format([[formattednumber(a%s,%q,",")]],n,f)
+ if f=="0" then
+ return format([[formattednumber(a%s,false)]],n)
+ else
+ return format([[formattednumber(a%s,%q,",")]],n,f)
+ end
end
local format_z=function(f)
n=n+(tonumber(f) or 1)
@@ -4051,7 +4474,9 @@ local builder=Cs { "start",
+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")
+V("c")+V("C")+V("S")
+V("Q")
-+V("N")
++V("n")
++V("N")
++V("k")
+V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w")
+V("W")
+V("a")
@@ -4059,8 +4484,10 @@ local builder=Cs { "start",
+V("j")+V("J")
+V("m")+V("M")
+V("z")
++V(">")
++V("<")
)+V("*")
- )*(P(-1)+Carg(1))
+ )*(endofstring+Carg(1))
)^0,
["s"]=(prefix_any*P("s"))/format_s,
["q"]=(prefix_any*P("q"))/format_q,
@@ -4076,8 +4503,10 @@ local builder=Cs { "start",
["X"]=(prefix_any*P("X"))/format_X,
["o"]=(prefix_any*P("o"))/format_o,
["S"]=(prefix_any*P("S"))/format_S,
- ["Q"]=(prefix_any*P("Q"))/format_S,
+ ["Q"]=(prefix_any*P("Q"))/format_Q,
+ ["n"]=(prefix_any*P("n"))/format_n,
["N"]=(prefix_any*P("N"))/format_N,
+ ["k"]=(prefix_sub*P("k"))/format_k,
["c"]=(prefix_any*P("c"))/format_c,
["C"]=(prefix_any*P("C"))/format_C,
["r"]=(prefix_any*P("r"))/format_r,
@@ -4096,21 +4525,29 @@ local builder=Cs { "start",
["W"]=(prefix_any*P("W"))/format_W,
["j"]=(prefix_any*P("j"))/format_j,
["J"]=(prefix_any*P("J"))/format_J,
- ["m"]=(prefix_tab*P("m"))/format_m,
- ["M"]=(prefix_tab*P("M"))/format_M,
+ ["m"]=(prefix_any*P("m"))/format_m,
+ ["M"]=(prefix_any*P("M"))/format_M,
["z"]=(prefix_any*P("z"))/format_z,
["a"]=(prefix_any*P("a"))/format_a,
["A"]=(prefix_any*P("A"))/format_A,
+ ["<"]=(prefix_any*P("<"))/format_left,
+ [">"]=(prefix_any*P(">"))/format_right,
["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest,
["?"]=Cs(((1-P("%"))^1 )^1)/format_rest,
["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
}
-local direct=Cs (
- P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]]
-)
+local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end })
+local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end })
+local preset={
+ ["%02x"]=function(n) return xx[n] end,
+ ["%02X"]=function(n) return XX[n] end,
+}
+local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]]
local function make(t,str)
- local f
- local p
+ local f=preset[str]
+ if f then
+ return f
+ end
local p=lpegmatch(direct,str)
if p then
f=loadstripped(p)()
@@ -4131,7 +4568,7 @@ local function use(t,fmt,...)
return t[fmt](...)
end
strings.formatters={}
-if _LUAVERSION<5.2 then
+if oldfashioned then
function strings.formatters.new(noconcat)
local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} }
setmetatable(t,{ __index=make,__call=use })
@@ -4164,11 +4601,11 @@ local function add(t,name,template,preamble)
end
end
strings.formatters.add=add
-patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+P(1))^0)
-patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0)
+patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+anything)^0)
+patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^0)
patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0)
patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"'))
-if _LUAVERSION<5.2 then
+if oldfashioned then
add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape")
add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape")
add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape")
@@ -4179,7 +4616,6 @@ else
end
local dquote=patterns.dquote
local equote=patterns.escaped+dquote/'\\"'+1
-local space=patterns.space
local cquote=Cc('"')
local pattern=Cs(dquote*(equote-P(-2))^0*dquote)
+Cs(cquote*(equote-space)^0*space*equote^0*cquote)
@@ -4190,6 +4626,21 @@ local pattern=Cs((newline/(os.newline or "\r")+1)^0)
function string.replacenewlines(str)
return lpegmatch(pattern,str)
end
+function strings.newcollector()
+ local result,r={},0
+ return
+ function(fmt,str,...)
+ r=r+1
+ result[r]=str==nil and fmt or formatters[fmt](str,...)
+ end,
+ function(connector)
+ if result then
+ local str=concat(result,connector)
+ result,r={},0
+ return str
+ end
+ end
+end
end -- closure
@@ -4204,8 +4655,6 @@ if not modules then modules={} end modules ['util-fil']={
}
local byte=string.byte
local char=string.char
-local extract=bit32 and bit32.extract
-local floor=math.floor
utilities=utilities or {}
local files={}
utilities.files=files
@@ -4222,7 +4671,10 @@ function files.close(f)
f:close()
end
function files.size(f)
- return f:seek("end")
+ local current=f:seek()
+ local size=f:seek("end")
+ f:seek("set",current)
+ return size
end
files.getsize=files.size
function files.setposition(f,n)
@@ -4262,6 +4714,10 @@ end
function files.readbytes(f,n)
return byte(f:read(n),1,n)
end
+function files.readbytetable(f,n)
+ local s=f:read(n or 1)
+ return { byte(s,1,#s) }
+end
function files.readchar(f)
return f:read(1)
end
@@ -4279,6 +4735,7 @@ end
files.readcardinal1=files.readbyte
files.readcardinal=files.readcardinal1
files.readinteger=files.readinteger1
+files.readsignedbyte=files.readinteger1
function files.readcardinal2(f)
local a,b=byte(f:read(2),1,2)
return 0x100*a+b
@@ -4289,20 +4746,18 @@ function files.readcardinal2le(f)
end
function files.readinteger2(f)
local a,b=byte(f:read(2),1,2)
- local n=0x100*a+b
- if n>=0x8000 then
- return n-0x10000
+ if a>=0x80 then
+ return 0x100*a+b-0x10000
else
- return n
+ return 0x100*a+b
end
end
function files.readinteger2le(f)
local b,a=byte(f:read(2),1,2)
- local n=0x100*a+b
- if n>=0x8000 then
- return n-0x10000
+ if a>=0x80 then
+ return 0x100*a+b-0x10000
else
- return n
+ return 0x100*a+b
end
end
function files.readcardinal3(f)
@@ -4315,20 +4770,18 @@ function files.readcardinal3le(f)
end
function files.readinteger3(f)
local a,b,c=byte(f:read(3),1,3)
- local n=0x10000*a+0x100*b+c
- if n>=0x80000 then
- return n-0x1000000
+ if a>=0x80 then
+ return 0x10000*a+0x100*b+c-0x1000000
else
- return n
+ return 0x10000*a+0x100*b+c
end
end
function files.readinteger3le(f)
local c,b,a=byte(f:read(3),1,3)
- local n=0x10000*a+0x100*b+c
- if n>=0x80000 then
- return n-0x1000000
+ if a>=0x80 then
+ return 0x10000*a+0x100*b+c-0x1000000
else
- return n
+ return 0x10000*a+0x100*b+c
end
end
function files.readcardinal4(f)
@@ -4341,42 +4794,47 @@ function files.readcardinal4le(f)
end
function files.readinteger4(f)
local a,b,c,d=byte(f:read(4),1,4)
- local n=0x1000000*a+0x10000*b+0x100*c+d
- if n>=0x8000000 then
- return n-0x100000000
+ if a>=0x80 then
+ return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
else
- return n
+ return 0x1000000*a+0x10000*b+0x100*c+d
end
end
function files.readinteger4le(f)
local d,c,b,a=byte(f:read(4),1,4)
- local n=0x1000000*a+0x10000*b+0x100*c+d
- if n>=0x8000000 then
- return n-0x100000000
+ if a>=0x80 then
+ return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
else
- return n
+ return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function files.readfixed2(f)
+ local a,b=byte(f:read(2),1,2)
+ if a>=0x80 then
+ return (a-0x100)+b/0x100
+ else
+ return (a )+b/0x100
end
end
function files.readfixed4(f)
local a,b,c,d=byte(f:read(4),1,4)
- local n=0x100*a+b
- if n>=0x8000 then
- return n-0x10000+(0x100*c+d)/0xFFFF
+ if a>=0x80 then
+ return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000
else
- return n+(0x100*c+d)/0xFFFF
+ return (0x100*a+b )+(0x100*c+d)/0x10000
end
end
-if extract then
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
function files.read2dot14(f)
local a,b=byte(f:read(2),1,2)
- local n=0x100*a+b
- local m=extract(n,0,30)
- if n>0x7FFF then
- n=extract(n,30,2)
- return m/0x4000-4
+ if a>=0x80 then
+ local n=-(0x100*a+b)
+ return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
else
- n=extract(n,30,2)
- return n+m/0x4000
+ local n=0x100*a+b
+ return (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
end
end
end
@@ -4386,19 +4844,30 @@ end
function files.skiplong(f,n)
f:read(4*(n or 1))
end
-function files.writecardinal2(f,n)
- local a=char(n%256)
- n=floor(n/256)
- local b=char(n%256)
- f:write(b,a)
+if bit32 then
+ local rshift=bit32.rshift
+ function files.writecardinal2(f,n)
+ local a=char(n%256)
+ n=rshift(n,8)
+ local b=char(n%256)
+ f:write(b,a)
+ end
+else
+ local floor=math.floor
+ function files.writecardinal2(f,n)
+ local a=char(n%256)
+ n=floor(n/256)
+ local b=char(n%256)
+ f:write(b,a)
+ end
end
function files.writecardinal4(f,n)
local a=char(n%256)
- n=floor(n/256)
+ n=rshift(n,8)
local b=char(n%256)
- n=floor(n/256)
+ n=rshift(n,8)
local c=char(n%256)
- n=floor(n/256)
+ n=rshift(n,8)
local d=char(n%256)
f:write(d,c,b,a)
end
@@ -4408,6 +4877,64 @@ end
function files.writebyte(f,b)
f:write(char(b))
end
+if fio and fio.readcardinal1 then
+ files.readcardinal1=fio.readcardinal1
+ files.readcardinal2=fio.readcardinal2
+ files.readcardinal3=fio.readcardinal3
+ files.readcardinal4=fio.readcardinal4
+ files.readinteger1=fio.readinteger1
+ files.readinteger2=fio.readinteger2
+ files.readinteger3=fio.readinteger3
+ files.readinteger4=fio.readinteger4
+ files.readfixed2=fio.readfixed2
+ files.readfixed4=fio.readfixed4
+ files.read2dot14=fio.read2dot14
+ files.setposition=fio.setposition
+ files.getposition=fio.getposition
+ files.readbyte=files.readcardinal1
+ files.readsignedbyte=files.readinteger1
+ files.readcardinal=files.readcardinal1
+ files.readinteger=files.readinteger1
+ local skipposition=fio.skipposition
+ files.skipposition=skipposition
+ files.readbytes=fio.readbytes
+ files.readbytetable=fio.readbytetable
+ function files.skipshort(f,n)
+ skipposition(f,2*(n or 1))
+ end
+ function files.skiplong(f,n)
+ skipposition(f,4*(n or 1))
+ end
+end
+if fio and fio.readcardinaltable then
+ files.readcardinaltable=fio.readcardinaltable
+ files.readintegertable=fio.readintegertable
+else
+ local readcardinal1=files.readcardinal1
+ local readcardinal2=files.readcardinal2
+ local readcardinal3=files.readcardinal3
+ local readcardinal4=files.readcardinal4
+ function files.readcardinaltable(f,n,b)
+ local t={}
+ if b==1 then for i=1,n do t[i]=readcardinal1(f) end
+ elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end
+ elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end
+ elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end
+ return t
+ end
+ local readinteger1=files.readinteger1
+ local readinteger2=files.readinteger2
+ local readinteger3=files.readinteger3
+ local readinteger4=files.readinteger4
+ function files.readintegertable(f,n,b)
+ local t={}
+ if b==1 then for i=1,n do t[i]=readinteger1(f) end
+ elseif b==2 then for i=1,n do t[i]=readinteger2(f) end
+ elseif b==3 then for i=1,n do t[i]=readinteger3(f) end
+ elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end
+ return t
+ end
+end
end -- closure
@@ -4421,21 +4948,33 @@ if not modules then modules={} end modules ['luat-basics-gen']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
+local match,gmatch,gsub,lower=string.match,string.gmatch,string.gsub,string.lower
+local formatters,split,format,dump=string.formatters,string.split,string.format,string.dump
+local loadfile,type=loadfile,type
+local setmetatable,getmetatable,collectgarbage=setmetatable,getmetatable,collectgarbage
local dummyfunction=function()
end
local dummyreporter=function(c)
return function(f,...)
local r=texio.reporter or texio.write_nl
if f then
- r(c.." : "..string.formatters(f,...))
+ r(c.." : "..(formatters or format)(f,...))
else
r("")
end
end
end
+local dummyreport=function(c,f,...)
+ local r=texio.reporter or texio.write_nl
+ if f then
+ r(c.." : "..(formatters or format)(f,...))
+ else
+ r("")
+ end
+end
statistics={
register=dummyfunction,
starttiming=dummyfunction,
@@ -4465,14 +5004,15 @@ logs={
new=dummyreporter,
reporter=dummyreporter,
messenger=dummyreporter,
- report=dummyfunction,
+ report=dummyreport,
}
callbacks={
register=function(n,f)
return callback.register(n,f)
end,
}
-utilities=utilities or {} utilities.storage={
+utilities=utilities or {}
+utilities.storage=utilities.storage or {
allocate=function(t)
return t or {}
end,
@@ -4480,6 +5020,25 @@ utilities=utilities or {} utilities.storage={
return t or {}
end,
}
+utilities.parsers=utilities.parsers or {
+ settings_to_array=function(s)
+ return split(s,",")
+ end,
+ settings_to_hash=function(s)
+ local t={}
+ for k,v in gmatch(s,"([^%s,=]+)=([^%s,]+)") do
+ t[k]=v
+ end
+ return t
+ end,
+ settings_to_hash_colon_too=function(s)
+ local t={}
+ for k,v in gmatch(s,"([^%s,=:]+)[=:]([^%s,]+)") do
+ t[k]=v
+ end
+ return t
+ end,
+}
characters=characters or {
data={}
}
@@ -4494,16 +5053,17 @@ local remapper={
pfb="type1 fonts",
afm="afm",
enc="enc files",
+ lua="tex",
}
function resolvers.findfile(name,fileformat)
- name=string.gsub(name,"\\","/")
+ name=gsub(name,"\\","/")
if not fileformat or fileformat=="" then
fileformat=file.suffix(name)
if fileformat=="" then
fileformat="tex"
end
end
- fileformat=string.lower(fileformat)
+ fileformat=lower(fileformat)
fileformat=remapper[fileformat] or fileformat
local found=kpse.find_file(name,fileformat)
if not found or found=="" then
@@ -4549,13 +5109,13 @@ do
if cachepaths=="" then
cachepaths="."
end
- cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":")
+ cachepaths=split(cachepaths,os.type=="windows" and ";" or ":")
for i=1,#cachepaths do
local cachepath=cachepaths[i]
if not lfs.isdir(cachepath) then
lfs.mkdirs(cachepath)
if lfs.isdir(cachepath) then
- texio.write(string.format("(created cache path: %s)",cachepath))
+ logs.report("system","creating cache path '%s'",cachepath)
end
end
if file.is_writable(cachepath) then
@@ -4572,16 +5132,16 @@ do
end
end
if not writable then
- texio.write_nl("quiting: fix your writable cache path")
+ logs.report("system","no writeable cache path, quiting")
os.exit()
elseif #readables==0 then
- texio.write_nl("quiting: fix your readable cache path")
+ logs.report("system","no readable cache path, quiting")
os.exit()
elseif #readables==1 and readables[1]==writable then
- texio.write(string.format("(using cache: %s)",writable))
+ logs.report("system","using cache '%s'",writable)
else
- texio.write(string.format("(using write cache: %s)",writable))
- texio.write(string.format("(using read cache: %s)",table.concat(readables," ")))
+ logs.report("system","using write cache '%s'",writable)
+ logs.report("system","using read cache '%s'",table.concat(readables," "))
end
end
function caches.getwritablepath(category,subcategory)
@@ -4613,27 +5173,27 @@ function caches.loaddata(readables,name,writable)
local loader=false
local luaname,lucname=makefullname(path,name)
if lfs.isfile(lucname) then
- texio.write(string.format("(load luc: %s)",lucname))
+ logs.report("system","loading luc file '%s'",lucname)
loader=loadfile(lucname)
end
if not loader and lfs.isfile(luaname) then
local luacrap,lucname=makefullname(writable,name)
- texio.write(string.format("(compiling luc: %s)",lucname))
+ logs.report("system","compiling luc file '%s'",lucname)
if lfs.isfile(lucname) then
loader=loadfile(lucname)
end
caches.compile(data,luaname,lucname)
if lfs.isfile(lucname) then
- texio.write(string.format("(load luc: %s)",lucname))
+ logs.report("system","loading luc file '%s'",lucname)
loader=loadfile(lucname)
else
- texio.write(string.format("(loading failed: %s)",lucname))
+ logs.report("system","error in loading luc file '%s'",lucname)
end
if not loader then
- texio.write(string.format("(load lua: %s)",luaname))
+ logs.report("system","loading lua file '%s'",luaname)
loader=loadfile(luaname)
else
- texio.write(string.format("(loading failed: %s)",luaname))
+ logs.report("system","error in loading lua file '%s'",luaname)
end
end
if loader then
@@ -4647,11 +5207,11 @@ end
function caches.savedata(path,name,data)
local luaname,lucname=makefullname(path,name)
if luaname then
- texio.write(string.format("(save: %s)",luaname))
+ logs.report("system","saving lua file '%s'",luaname)
table.tofile(luaname,data,true)
if lucname and type(caches.compile)=="function" then
os.remove(lucname)
- texio.write(string.format("(save: %s)",lucname))
+ logs.report("system","saving luc file '%s'",lucname)
caches.compile(data,luaname,lucname)
end
end
@@ -4666,7 +5226,7 @@ function caches.compile(data,luaname,lucname)
if f then
local s=loadstring(d)
if s then
- f:write(string.dump(s,true))
+ f:write(dump(s,true))
end
f:close()
end
@@ -4687,10 +5247,19 @@ function table.setmetatableindex(t,f)
end
return t
end
+function table.makeweak(t)
+ local m=getmetatable(t)
+ if m then
+ m.__mode="v"
+ else
+ setmetatable(t,{ __mode="v" })
+ end
+ return t
+end
arguments={}
if arg then
for i=1,#arg do
- local k,v=string.match(arg[i],"^%-%-([^=]+)=?(.-)$")
+ local k,v=match(arg[i],"^%-%-([^=]+)=?(.-)$")
if k and v then
arguments[k]=v
end
@@ -4823,8 +5392,8 @@ if not modules then modules={} end modules ['luatex-fonts-nod']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
if tex.attribute[0]~=0 then
texio.write_nl("log","!")
@@ -4849,7 +5418,6 @@ attributes.private=attributes.private or function(name)
return number
end
nodes={}
-nodes.pool={}
nodes.handlers={}
local nodecodes={}
local glyphcodes=node.subtypes("glyph")
@@ -4859,21 +5427,20 @@ for k,v in next,node.types() do
nodecodes[k]=v
nodecodes[v]=k
end
-for i=0,#glyphcodes do
- glyphcodes[glyphcodes[i]]=i
+for k,v in next,glyphcodes do
+ glyphcodes[v]=k
end
-for i=0,#disccodes do
- disccodes[disccodes[i]]=i
+for k,v in next,glyphcodes do
+ disccodes[v]=k
end
nodes.nodecodes=nodecodes
nodes.glyphcodes=glyphcodes
nodes.disccodes=disccodes
local flush_node=node.flush_node
local remove_node=node.remove
-local new_node=node.new
local traverse_id=node.traverse_id
-nodes.handlers.protectglyphs=node.protect_glyphs
-nodes.handlers.unprotectglyphs=node.unprotect_glyphs
+nodes.handlers.protectglyphs=node.protect_glyphs
+nodes.handlers.unprotectglyphs=node.unprotect_glyphs
local math_code=nodecodes.math
local end_of_math=node.end_of_math
function node.end_of_math(n)
@@ -4899,11 +5466,6 @@ end
function nodes.delete(head,current)
return nodes.remove(head,current,true)
end
-function nodes.pool.kern(k)
- local n=new_node("kern",1)
- n.kern=k
- return n
-end
local getfield=node.getfield
local setfield=node.setfield
nodes.getfield=getfield
@@ -4969,16 +5531,38 @@ nuts.setattr=setfield
nuts.getfont=direct.getfont
nuts.setfont=direct.setfont
nuts.getsubtype=direct.getsubtype
-nuts.setsubtype=direct.setsubtype or function(n,s) setfield(n,"subtype",s) end
+nuts.setsubtype=direct.setsubtype
nuts.getchar=direct.getchar
nuts.setchar=direct.setchar
nuts.getdisc=direct.getdisc
nuts.setdisc=direct.setdisc
nuts.setlink=direct.setlink
+nuts.setsplit=direct.setsplit
nuts.getlist=direct.getlist
-nuts.setlist=direct.setlist or function(n,l) setfield(n,"list",l) end
-nuts.getleader=direct.getleader
-nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.setlist=direct.setlist
+nuts.getoffsets=direct.getoffsets or
+ function(n)
+ return getfield(n,"xoffset"),getfield(n,"yoffset")
+ end
+nuts.setoffsets=direct.setoffsets or
+ function(n,x,y)
+ if x then setfield(n,"xoffset",x) end
+ if y then setfield(n,"xoffset",y) end
+ end
+nuts.getleader=direct.getleader or function(n) return getfield(n,"leader") end
+nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end
+nuts.getcomponents=direct.getcomponents or function(n) return getfield(n,"components") end
+nuts.setcomponents=direct.setcomponents or function(n,c) setfield(n,"components",c) end
+nuts.getkern=direct.getkern or function(n) return getfield(n,"kern") end
+nuts.setkern=direct.setkern or function(n,k) setfield(n,"kern",k) end
+nuts.getdir=direct.getdir or function(n) return getfield(n,"dir") end
+nuts.setdir=direct.setdir or function(n,d) setfield(n,"dir",d) end
+nuts.getwidth=direct.getwidth or function(n) return getfield(n,"width") end
+nuts.setwidth=direct.setwidth or function(n,w) return setfield(n,"width",w) end
+nuts.getheight=direct.getheight or function(n) return getfield(n,"height") end
+nuts.setheight=direct.setheight or function(n,h) return setfield(n,"height",h) end
+nuts.getdepth=direct.getdepth or function(n) return getfield(n,"depth") end
+nuts.setdepth=direct.setdepth or function(n,d) return setfield(n,"depth",d) end
if not direct.is_glyph then
local getchar=direct.getchar
local getid=direct.getid
@@ -5032,18 +5616,12 @@ nuts.end_of_math=direct.end_of_math
nuts.traverse=direct.traverse
nuts.traverse_id=direct.traverse_id
nuts.traverse_char=direct.traverse_char
+nuts.traverse_glyph=direct.traverse_glyph
nuts.ligaturing=direct.ligaturing
nuts.kerning=direct.kerning
+nuts.new=direct.new
nuts.getprop=nuts.getattr
nuts.setprop=nuts.setattr
-local new_nut=direct.new
-nuts.new=new_nut
-nuts.pool={}
-function nuts.pool.kern(k)
- local n=new_nut("kern",1)
- setfield(n,"kern",k)
- return n
-end
local propertydata=direct.get_properties_table()
nodes.properties={ data=propertydata }
direct.set_properties_mode(true,true)
@@ -5066,6 +5644,157 @@ nuts.setprop=function(n,k,v)
end
nodes.setprop=nodes.setproperty
nodes.getprop=nodes.getproperty
+local setprev=nuts.setprev
+local setnext=nuts.setnext
+local getnext=nuts.getnext
+local setlink=nuts.setlink
+local getfield=nuts.getfield
+local setfield=nuts.setfield
+local getcomponents=nuts.getcomponents
+local setcomponents=nuts.setcomponents
+local find_tail=nuts.tail
+local flush_list=nuts.flush_list
+local flush_node=nuts.flush_node
+local traverse_id=nuts.traverse_id
+local copy_node=nuts.copy_node
+local glyph_code=nodes.nodecodes.glyph
+function nuts.set_components(target,start,stop)
+ local head=getcomponents(target)
+ if head then
+ flush_list(head)
+ head=nil
+ end
+ if start then
+ setprev(start)
+ else
+ return nil
+ end
+ if stop then
+ setnext(stop)
+ end
+ local tail=nil
+ while start do
+ local c=getcomponents(start)
+ local n=getnext(start)
+ if c then
+ if head then
+ setlink(tail,c)
+ else
+ head=c
+ end
+ tail=find_tail(c)
+ setcomponents(start)
+ flush_node(start)
+ else
+ if head then
+ setlink(tail,start)
+ else
+ head=start
+ end
+ tail=start
+ end
+ start=n
+ end
+ setcomponents(target,head)
+ return head
+end
+nuts.get_components=nuts.getcomponents
+function nuts.take_components(target)
+ local c=getcomponents(target)
+ setcomponents(target)
+ return c
+end
+function nuts.count_components(n,marks)
+ local components=getcomponents(n)
+ if components then
+ if marks then
+ local i=0
+ for g in traverse_id(glyph_code,components) do
+ if not marks[getchar(g)] then
+ i=i+1
+ end
+ end
+ return i
+ else
+ return count(glyph_code,components)
+ end
+ else
+ return 0
+ end
+end
+function nuts.copy_no_components(g,copyinjection)
+ local components=getcomponents(g)
+ if components then
+ setcomponents(g)
+ local n=copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ setcomponents(g,components)
+ return n
+ else
+ local n=copy_node(g)
+ if copyinjection then
+ copyinjection(n,g)
+ end
+ return n
+ end
+end
+function nuts.copy_only_glyphs(current)
+ local head=nil
+ local previous=nil
+ for n in traverse_id(glyph_code,current) do
+ n=copy_node(n)
+ if head then
+ setlink(previous,n)
+ else
+ head=n
+ end
+ previous=n
+ end
+ return head
+end
+nuts.uses_font=direct.uses_font
+if not nuts.uses_font then
+ local getdisc=nuts.getdisc
+ local getfont=nuts.getfont
+ function nuts.uses_font(n,font)
+ local pre,post,replace=getdisc(n)
+ if pre then
+ for n in traverse_id(glyph_code,pre) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ if post then
+ for n in traverse_id(glyph_code,post) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ if replace then
+ for n in traverse_id(glyph_code,replace) do
+ if getfont(n)==font then
+ return true
+ end
+ end
+ end
+ return false
+ end
+end
+do
+ local dummy=tonut(node.new("glyph"))
+ nuts.traversers={
+ glyph=nuts.traverse_id(nodecodes.glyph,dummy),
+ glue=nuts.traverse_id(nodecodes.glue,dummy),
+ disc=nuts.traverse_id(nodecodes.disc,dummy),
+ boundary=nuts.traverse_id(nodecodes.boundary,dummy),
+ char=nuts.traverse_char(dummy),
+ node=nuts.traverse(dummy),
+ }
+end
end -- closure
@@ -5075,6 +5804,174 @@ do -- begin closure to overcome local limits and interference
characters=characters or {}
characters.blockrange={}
characters.classifiers={
+ [768]=5,
+ [769]=5,
+ [770]=5,
+ [771]=5,
+ [772]=5,
+ [773]=5,
+ [774]=5,
+ [775]=5,
+ [776]=5,
+ [777]=5,
+ [778]=5,
+ [779]=5,
+ [780]=5,
+ [781]=5,
+ [782]=5,
+ [783]=5,
+ [784]=5,
+ [785]=5,
+ [786]=5,
+ [787]=5,
+ [788]=5,
+ [789]=5,
+ [790]=5,
+ [791]=5,
+ [792]=5,
+ [793]=5,
+ [794]=5,
+ [795]=5,
+ [796]=5,
+ [797]=5,
+ [798]=5,
+ [799]=5,
+ [800]=5,
+ [801]=5,
+ [802]=5,
+ [803]=5,
+ [804]=5,
+ [805]=5,
+ [806]=5,
+ [807]=5,
+ [808]=5,
+ [809]=5,
+ [810]=5,
+ [811]=5,
+ [812]=5,
+ [813]=5,
+ [814]=5,
+ [815]=5,
+ [816]=5,
+ [817]=5,
+ [818]=5,
+ [819]=5,
+ [820]=5,
+ [821]=5,
+ [822]=5,
+ [823]=5,
+ [824]=5,
+ [825]=5,
+ [826]=5,
+ [827]=5,
+ [828]=5,
+ [829]=5,
+ [830]=5,
+ [831]=5,
+ [832]=5,
+ [833]=5,
+ [834]=5,
+ [835]=5,
+ [836]=5,
+ [837]=5,
+ [838]=5,
+ [839]=5,
+ [840]=5,
+ [841]=5,
+ [842]=5,
+ [843]=5,
+ [844]=5,
+ [845]=5,
+ [846]=5,
+ [847]=5,
+ [848]=5,
+ [849]=5,
+ [850]=5,
+ [851]=5,
+ [852]=5,
+ [853]=5,
+ [854]=5,
+ [855]=5,
+ [856]=5,
+ [857]=5,
+ [858]=5,
+ [859]=5,
+ [860]=5,
+ [861]=5,
+ [862]=5,
+ [863]=5,
+ [864]=5,
+ [865]=5,
+ [866]=5,
+ [867]=5,
+ [868]=5,
+ [869]=5,
+ [870]=5,
+ [871]=5,
+ [872]=5,
+ [873]=5,
+ [874]=5,
+ [875]=5,
+ [876]=5,
+ [877]=5,
+ [878]=5,
+ [879]=5,
+ [1155]=5,
+ [1156]=5,
+ [1157]=5,
+ [1158]=5,
+ [1159]=5,
+ [1425]=5,
+ [1426]=5,
+ [1427]=5,
+ [1428]=5,
+ [1429]=5,
+ [1430]=5,
+ [1431]=5,
+ [1432]=5,
+ [1433]=5,
+ [1434]=5,
+ [1435]=5,
+ [1436]=5,
+ [1437]=5,
+ [1438]=5,
+ [1439]=5,
+ [1440]=5,
+ [1441]=5,
+ [1442]=5,
+ [1443]=5,
+ [1444]=5,
+ [1445]=5,
+ [1446]=5,
+ [1447]=5,
+ [1448]=5,
+ [1449]=5,
+ [1450]=5,
+ [1451]=5,
+ [1452]=5,
+ [1453]=5,
+ [1454]=5,
+ [1455]=5,
+ [1456]=5,
+ [1457]=5,
+ [1458]=5,
+ [1459]=5,
+ [1460]=5,
+ [1461]=5,
+ [1462]=5,
+ [1463]=5,
+ [1464]=5,
+ [1465]=5,
+ [1466]=5,
+ [1467]=5,
+ [1468]=5,
+ [1469]=5,
+ [1471]=5,
+ [1473]=5,
+ [1474]=5,
+ [1476]=5,
+ [1477]=5,
+ [1479]=5,
[1536]=4,
[1537]=4,
[1538]=4,
@@ -5455,6 +6352,17 @@ characters.classifiers={
[1917]=2,
[1918]=2,
[1919]=2,
+ [1958]=5,
+ [1959]=5,
+ [1960]=5,
+ [1961]=5,
+ [1962]=5,
+ [1963]=5,
+ [1964]=5,
+ [1965]=5,
+ [1966]=5,
+ [1967]=5,
+ [1968]=5,
[1984]=6,
[1985]=6,
[1986]=6,
@@ -5514,6 +6422,27 @@ characters.classifiers={
[2040]=6,
[2041]=6,
[2042]=2,
+ [2070]=5,
+ [2071]=5,
+ [2072]=5,
+ [2073]=5,
+ [2075]=5,
+ [2076]=5,
+ [2077]=5,
+ [2078]=5,
+ [2079]=5,
+ [2080]=5,
+ [2081]=5,
+ [2082]=5,
+ [2083]=5,
+ [2085]=5,
+ [2086]=5,
+ [2087]=5,
+ [2089]=5,
+ [2090]=5,
+ [2091]=5,
+ [2092]=5,
+ [2093]=5,
[2112]=3,
[2113]=2,
[2114]=2,
@@ -5539,6 +6468,20 @@ characters.classifiers={
[2134]=4,
[2135]=4,
[2136]=4,
+ [2137]=5,
+ [2138]=5,
+ [2139]=5,
+ [2144]=2,
+ [2145]=4,
+ [2146]=2,
+ [2147]=2,
+ [2148]=2,
+ [2149]=2,
+ [2150]=4,
+ [2151]=3,
+ [2152]=2,
+ [2153]=3,
+ [2154]=3,
[2208]=2,
[2209]=2,
[2210]=2,
@@ -5560,9 +6503,348 @@ characters.classifiers={
[2226]=3,
[2227]=2,
[2228]=2,
+ [2230]=2,
+ [2231]=2,
+ [2232]=2,
+ [2233]=3,
+ [2234]=2,
+ [2235]=2,
+ [2236]=2,
+ [2237]=2,
+ [2260]=5,
+ [2261]=5,
+ [2262]=5,
+ [2263]=5,
+ [2264]=5,
+ [2265]=5,
+ [2266]=5,
+ [2267]=5,
+ [2268]=5,
+ [2269]=5,
+ [2270]=5,
+ [2271]=5,
+ [2272]=5,
+ [2273]=5,
+ [2274]=4,
+ [2275]=5,
+ [2276]=5,
+ [2277]=5,
+ [2278]=5,
+ [2279]=5,
+ [2280]=5,
+ [2281]=5,
+ [2282]=5,
+ [2283]=5,
+ [2284]=5,
+ [2285]=5,
+ [2286]=5,
+ [2287]=5,
+ [2288]=5,
+ [2289]=5,
+ [2290]=5,
+ [2291]=5,
+ [2292]=5,
+ [2293]=5,
+ [2294]=5,
+ [2295]=5,
+ [2296]=5,
+ [2297]=5,
+ [2298]=5,
+ [2299]=5,
+ [2300]=5,
+ [2301]=5,
+ [2302]=5,
+ [2303]=5,
+ [2304]=5,
+ [2305]=5,
+ [2306]=5,
+ [2362]=5,
+ [2364]=5,
+ [2369]=5,
+ [2370]=5,
+ [2371]=5,
+ [2372]=5,
+ [2373]=5,
+ [2374]=5,
+ [2375]=5,
+ [2376]=5,
+ [2381]=5,
+ [2385]=5,
+ [2386]=5,
+ [2387]=5,
+ [2388]=5,
+ [2389]=5,
+ [2390]=5,
+ [2391]=5,
+ [2402]=5,
+ [2403]=5,
+ [2433]=5,
+ [2492]=5,
+ [2497]=5,
+ [2498]=5,
+ [2499]=5,
+ [2500]=5,
+ [2509]=5,
+ [2530]=5,
+ [2531]=5,
+ [2561]=5,
+ [2562]=5,
+ [2620]=5,
+ [2625]=5,
+ [2626]=5,
+ [2631]=5,
+ [2632]=5,
+ [2635]=5,
+ [2636]=5,
+ [2637]=5,
+ [2641]=5,
+ [2672]=5,
+ [2673]=5,
+ [2677]=5,
+ [2689]=5,
+ [2690]=5,
+ [2748]=5,
+ [2753]=5,
+ [2754]=5,
+ [2755]=5,
+ [2756]=5,
+ [2757]=5,
+ [2759]=5,
+ [2760]=5,
+ [2765]=5,
+ [2786]=5,
+ [2787]=5,
+ [2810]=5,
+ [2811]=5,
+ [2812]=5,
+ [2813]=5,
+ [2814]=5,
+ [2815]=5,
+ [2817]=5,
+ [2876]=5,
+ [2879]=5,
+ [2881]=5,
+ [2882]=5,
+ [2883]=5,
+ [2884]=5,
+ [2893]=5,
+ [2902]=5,
+ [2914]=5,
+ [2915]=5,
+ [2946]=5,
+ [3008]=5,
+ [3021]=5,
+ [3072]=5,
+ [3134]=5,
+ [3135]=5,
+ [3136]=5,
+ [3142]=5,
+ [3143]=5,
+ [3144]=5,
+ [3146]=5,
+ [3147]=5,
+ [3148]=5,
+ [3149]=5,
+ [3157]=5,
+ [3158]=5,
+ [3170]=5,
+ [3171]=5,
+ [3201]=5,
+ [3260]=5,
+ [3263]=5,
+ [3270]=5,
+ [3276]=5,
+ [3277]=5,
+ [3298]=5,
+ [3299]=5,
+ [3328]=5,
+ [3329]=5,
+ [3387]=5,
+ [3388]=5,
+ [3393]=5,
+ [3394]=5,
+ [3395]=5,
+ [3396]=5,
+ [3405]=5,
+ [3426]=5,
+ [3427]=5,
+ [3530]=5,
+ [3538]=5,
+ [3539]=5,
+ [3540]=5,
+ [3542]=5,
+ [3633]=5,
+ [3636]=5,
+ [3637]=5,
+ [3638]=5,
+ [3639]=5,
+ [3640]=5,
+ [3641]=5,
+ [3642]=5,
+ [3655]=5,
+ [3656]=5,
+ [3657]=5,
+ [3658]=5,
+ [3659]=5,
+ [3660]=5,
+ [3661]=5,
+ [3662]=5,
+ [3761]=5,
+ [3764]=5,
+ [3765]=5,
+ [3766]=5,
+ [3767]=5,
+ [3768]=5,
+ [3769]=5,
+ [3771]=5,
+ [3772]=5,
+ [3784]=5,
+ [3785]=5,
+ [3786]=5,
+ [3787]=5,
+ [3788]=5,
+ [3789]=5,
+ [3864]=5,
+ [3865]=5,
+ [3893]=5,
+ [3895]=5,
+ [3897]=5,
+ [3953]=5,
+ [3954]=5,
+ [3955]=5,
+ [3956]=5,
+ [3957]=5,
+ [3958]=5,
+ [3959]=5,
+ [3960]=5,
+ [3961]=5,
+ [3962]=5,
+ [3963]=5,
+ [3964]=5,
+ [3965]=5,
+ [3966]=5,
+ [3968]=5,
+ [3969]=5,
+ [3970]=5,
+ [3971]=5,
+ [3972]=5,
+ [3974]=5,
+ [3975]=5,
+ [3981]=5,
+ [3982]=5,
+ [3983]=5,
+ [3984]=5,
+ [3985]=5,
+ [3986]=5,
+ [3987]=5,
+ [3988]=5,
+ [3989]=5,
+ [3990]=5,
+ [3991]=5,
+ [3993]=5,
+ [3994]=5,
+ [3995]=5,
+ [3996]=5,
+ [3997]=5,
+ [3998]=5,
+ [3999]=5,
+ [4000]=5,
+ [4001]=5,
+ [4002]=5,
+ [4003]=5,
+ [4004]=5,
+ [4005]=5,
+ [4006]=5,
+ [4007]=5,
+ [4008]=5,
+ [4009]=5,
+ [4010]=5,
+ [4011]=5,
+ [4012]=5,
+ [4013]=5,
+ [4014]=5,
+ [4015]=5,
+ [4016]=5,
+ [4017]=5,
+ [4018]=5,
+ [4019]=5,
+ [4020]=5,
+ [4021]=5,
+ [4022]=5,
+ [4023]=5,
+ [4024]=5,
+ [4025]=5,
+ [4026]=5,
+ [4027]=5,
+ [4028]=5,
+ [4038]=5,
+ [4141]=5,
+ [4142]=5,
+ [4143]=5,
+ [4144]=5,
+ [4146]=5,
+ [4147]=5,
+ [4148]=5,
+ [4149]=5,
+ [4150]=5,
+ [4151]=5,
+ [4153]=5,
+ [4154]=5,
+ [4157]=5,
+ [4158]=5,
+ [4184]=5,
+ [4185]=5,
+ [4190]=5,
+ [4191]=5,
+ [4192]=5,
+ [4209]=5,
+ [4210]=5,
+ [4211]=5,
+ [4212]=5,
+ [4226]=5,
+ [4229]=5,
+ [4230]=5,
+ [4237]=5,
+ [4253]=5,
+ [4957]=5,
+ [4958]=5,
+ [4959]=5,
+ [5906]=5,
+ [5907]=5,
+ [5908]=5,
+ [5938]=5,
+ [5939]=5,
+ [5940]=5,
+ [5970]=5,
+ [5971]=5,
+ [6002]=5,
+ [6003]=5,
+ [6071]=5,
+ [6072]=5,
+ [6073]=5,
+ [6074]=5,
+ [6075]=5,
+ [6076]=5,
+ [6077]=5,
+ [6086]=5,
+ [6089]=5,
+ [6090]=5,
+ [6091]=5,
+ [6092]=5,
+ [6093]=5,
+ [6094]=5,
+ [6095]=5,
+ [6096]=5,
+ [6097]=5,
+ [6098]=5,
+ [6099]=5,
+ [6109]=5,
[6150]=4,
[6151]=2,
[6154]=2,
+ [6155]=5,
+ [6156]=5,
+ [6157]=5,
[6158]=4,
[6176]=2,
[6177]=2,
@@ -5657,8 +6939,6 @@ characters.classifiers={
[6274]=4,
[6275]=4,
[6276]=4,
- [6277]=4,
- [6278]=4,
[6279]=2,
[6280]=2,
[6281]=2,
@@ -5693,13 +6973,295 @@ characters.classifiers={
[6310]=2,
[6311]=2,
[6312]=2,
+ [6313]=5,
[6314]=2,
+ [6432]=5,
+ [6433]=5,
+ [6434]=5,
+ [6439]=5,
+ [6440]=5,
+ [6450]=5,
+ [6457]=5,
+ [6458]=5,
+ [6459]=5,
+ [6679]=5,
+ [6680]=5,
+ [6742]=5,
+ [6744]=5,
+ [6745]=5,
+ [6746]=5,
+ [6747]=5,
+ [6748]=5,
+ [6749]=5,
+ [6750]=5,
+ [6752]=5,
+ [6754]=5,
+ [6757]=5,
+ [6758]=5,
+ [6759]=5,
+ [6760]=5,
+ [6761]=5,
+ [6762]=5,
+ [6763]=5,
+ [6764]=5,
+ [6771]=5,
+ [6772]=5,
+ [6773]=5,
+ [6774]=5,
+ [6775]=5,
+ [6776]=5,
+ [6777]=5,
+ [6778]=5,
+ [6779]=5,
+ [6780]=5,
+ [6783]=5,
+ [6832]=5,
+ [6833]=5,
+ [6834]=5,
+ [6835]=5,
+ [6836]=5,
+ [6837]=5,
+ [6838]=5,
+ [6839]=5,
+ [6840]=5,
+ [6841]=5,
+ [6842]=5,
+ [6843]=5,
+ [6844]=5,
+ [6845]=5,
+ [6912]=5,
+ [6913]=5,
+ [6914]=5,
+ [6915]=5,
+ [6964]=5,
+ [6966]=5,
+ [6967]=5,
+ [6968]=5,
+ [6969]=5,
+ [6970]=5,
+ [6972]=5,
+ [6978]=5,
+ [7019]=5,
+ [7020]=5,
+ [7021]=5,
+ [7022]=5,
+ [7023]=5,
+ [7024]=5,
+ [7025]=5,
+ [7026]=5,
+ [7027]=5,
+ [7040]=5,
+ [7041]=5,
+ [7074]=5,
+ [7075]=5,
+ [7076]=5,
+ [7077]=5,
+ [7080]=5,
+ [7081]=5,
+ [7083]=5,
+ [7142]=5,
+ [7144]=5,
+ [7145]=5,
+ [7149]=5,
+ [7151]=5,
+ [7152]=5,
+ [7153]=5,
+ [7212]=5,
+ [7213]=5,
+ [7214]=5,
+ [7215]=5,
+ [7216]=5,
+ [7217]=5,
+ [7218]=5,
+ [7219]=5,
+ [7222]=5,
+ [7223]=5,
+ [7376]=5,
+ [7377]=5,
+ [7378]=5,
+ [7380]=5,
+ [7381]=5,
+ [7382]=5,
+ [7383]=5,
+ [7384]=5,
+ [7385]=5,
+ [7386]=5,
+ [7387]=5,
+ [7388]=5,
+ [7389]=5,
+ [7390]=5,
+ [7391]=5,
+ [7392]=5,
+ [7394]=5,
+ [7395]=5,
+ [7396]=5,
+ [7397]=5,
+ [7398]=5,
+ [7399]=5,
+ [7400]=5,
+ [7405]=5,
+ [7412]=5,
+ [7416]=5,
+ [7417]=5,
+ [7616]=5,
+ [7617]=5,
+ [7618]=5,
+ [7619]=5,
+ [7620]=5,
+ [7621]=5,
+ [7622]=5,
+ [7623]=5,
+ [7624]=5,
+ [7625]=5,
+ [7626]=5,
+ [7627]=5,
+ [7628]=5,
+ [7629]=5,
+ [7630]=5,
+ [7631]=5,
+ [7632]=5,
+ [7633]=5,
+ [7634]=5,
+ [7635]=5,
+ [7636]=5,
+ [7637]=5,
+ [7638]=5,
+ [7639]=5,
+ [7640]=5,
+ [7641]=5,
+ [7642]=5,
+ [7643]=5,
+ [7644]=5,
+ [7645]=5,
+ [7646]=5,
+ [7647]=5,
+ [7648]=5,
+ [7649]=5,
+ [7650]=5,
+ [7651]=5,
+ [7652]=5,
+ [7653]=5,
+ [7654]=5,
+ [7655]=5,
+ [7656]=5,
+ [7657]=5,
+ [7658]=5,
+ [7659]=5,
+ [7660]=5,
+ [7661]=5,
+ [7662]=5,
+ [7663]=5,
+ [7664]=5,
+ [7665]=5,
+ [7666]=5,
+ [7667]=5,
+ [7668]=5,
+ [7669]=5,
+ [7670]=5,
+ [7671]=5,
+ [7672]=5,
+ [7673]=5,
+ [7675]=5,
+ [7676]=5,
+ [7677]=5,
+ [7678]=5,
+ [7679]=5,
[8204]=4,
[8205]=2,
+ [8239]=4,
[8294]=4,
[8295]=4,
[8296]=4,
[8297]=4,
+ [8400]=5,
+ [8401]=5,
+ [8402]=5,
+ [8403]=5,
+ [8404]=5,
+ [8405]=5,
+ [8406]=5,
+ [8407]=5,
+ [8408]=5,
+ [8409]=5,
+ [8410]=5,
+ [8411]=5,
+ [8412]=5,
+ [8417]=5,
+ [8421]=5,
+ [8422]=5,
+ [8423]=5,
+ [8424]=5,
+ [8425]=5,
+ [8426]=5,
+ [8427]=5,
+ [8428]=5,
+ [8429]=5,
+ [8430]=5,
+ [8431]=5,
+ [8432]=5,
+ [11503]=5,
+ [11504]=5,
+ [11505]=5,
+ [11647]=5,
+ [11744]=5,
+ [11745]=5,
+ [11746]=5,
+ [11747]=5,
+ [11748]=5,
+ [11749]=5,
+ [11750]=5,
+ [11751]=5,
+ [11752]=5,
+ [11753]=5,
+ [11754]=5,
+ [11755]=5,
+ [11756]=5,
+ [11757]=5,
+ [11758]=5,
+ [11759]=5,
+ [11760]=5,
+ [11761]=5,
+ [11762]=5,
+ [11763]=5,
+ [11764]=5,
+ [11765]=5,
+ [11766]=5,
+ [11767]=5,
+ [11768]=5,
+ [11769]=5,
+ [11770]=5,
+ [11771]=5,
+ [11772]=5,
+ [11773]=5,
+ [11774]=5,
+ [11775]=5,
+ [12330]=5,
+ [12331]=5,
+ [12332]=5,
+ [12333]=5,
+ [12334]=5,
+ [12335]=5,
+ [12441]=5,
+ [12442]=5,
+ [42607]=5,
+ [42612]=5,
+ [42613]=5,
+ [42614]=5,
+ [42615]=5,
+ [42616]=5,
+ [42617]=5,
+ [42618]=5,
+ [42619]=5,
+ [42620]=5,
+ [42621]=5,
+ [42654]=5,
+ [42655]=5,
+ [42736]=5,
+ [42737]=5,
+ [43014]=5,
+ [43019]=5,
+ [43045]=5,
+ [43046]=5,
[43072]=2,
[43073]=2,
[43074]=2,
@@ -5752,6 +7314,120 @@ characters.classifiers={
[43121]=2,
[43122]=1,
[43123]=4,
+ [43204]=5,
+ [43205]=5,
+ [43232]=5,
+ [43233]=5,
+ [43234]=5,
+ [43235]=5,
+ [43236]=5,
+ [43237]=5,
+ [43238]=5,
+ [43239]=5,
+ [43240]=5,
+ [43241]=5,
+ [43242]=5,
+ [43243]=5,
+ [43244]=5,
+ [43245]=5,
+ [43246]=5,
+ [43247]=5,
+ [43248]=5,
+ [43249]=5,
+ [43302]=5,
+ [43303]=5,
+ [43304]=5,
+ [43305]=5,
+ [43306]=5,
+ [43307]=5,
+ [43308]=5,
+ [43309]=5,
+ [43335]=5,
+ [43336]=5,
+ [43337]=5,
+ [43338]=5,
+ [43339]=5,
+ [43340]=5,
+ [43341]=5,
+ [43342]=5,
+ [43343]=5,
+ [43344]=5,
+ [43345]=5,
+ [43392]=5,
+ [43393]=5,
+ [43394]=5,
+ [43443]=5,
+ [43446]=5,
+ [43447]=5,
+ [43448]=5,
+ [43449]=5,
+ [43452]=5,
+ [43493]=5,
+ [43561]=5,
+ [43562]=5,
+ [43563]=5,
+ [43564]=5,
+ [43565]=5,
+ [43566]=5,
+ [43569]=5,
+ [43570]=5,
+ [43573]=5,
+ [43574]=5,
+ [43587]=5,
+ [43596]=5,
+ [43644]=5,
+ [43696]=5,
+ [43698]=5,
+ [43699]=5,
+ [43700]=5,
+ [43703]=5,
+ [43704]=5,
+ [43710]=5,
+ [43711]=5,
+ [43713]=5,
+ [43756]=5,
+ [43757]=5,
+ [43766]=5,
+ [44005]=5,
+ [44008]=5,
+ [44013]=5,
+ [64286]=5,
+ [65056]=5,
+ [65057]=5,
+ [65058]=5,
+ [65059]=5,
+ [65060]=5,
+ [65061]=5,
+ [65062]=5,
+ [65063]=5,
+ [65064]=5,
+ [65065]=5,
+ [65066]=5,
+ [65067]=5,
+ [65068]=5,
+ [65069]=5,
+ [65070]=5,
+ [65071]=5,
+ [66045]=5,
+ [66272]=5,
+ [66422]=5,
+ [66423]=5,
+ [66424]=5,
+ [66425]=5,
+ [66426]=5,
+ [68097]=5,
+ [68098]=5,
+ [68099]=5,
+ [68101]=5,
+ [68102]=5,
+ [68108]=5,
+ [68109]=5,
+ [68110]=5,
+ [68111]=5,
+ [68152]=5,
+ [68153]=5,
+ [68154]=5,
+ [68159]=5,
[68288]=2,
[68289]=2,
[68290]=2,
@@ -5789,6 +7465,8 @@ characters.classifiers={
[68322]=4,
[68323]=4,
[68324]=3,
+ [68325]=5,
+ [68326]=5,
[68331]=2,
[68332]=2,
[68333]=2,
@@ -5819,6 +7497,1544 @@ characters.classifiers={
[68525]=2,
[68526]=2,
[68527]=4,
+ [69633]=5,
+ [69688]=5,
+ [69689]=5,
+ [69690]=5,
+ [69691]=5,
+ [69692]=5,
+ [69693]=5,
+ [69694]=5,
+ [69695]=5,
+ [69696]=5,
+ [69697]=5,
+ [69698]=5,
+ [69699]=5,
+ [69700]=5,
+ [69701]=5,
+ [69702]=5,
+ [69759]=5,
+ [69760]=5,
+ [69761]=5,
+ [69811]=5,
+ [69812]=5,
+ [69813]=5,
+ [69814]=5,
+ [69817]=5,
+ [69818]=5,
+ [69888]=5,
+ [69889]=5,
+ [69890]=5,
+ [69927]=5,
+ [69928]=5,
+ [69929]=5,
+ [69930]=5,
+ [69931]=5,
+ [69933]=5,
+ [69934]=5,
+ [69935]=5,
+ [69936]=5,
+ [69937]=5,
+ [69938]=5,
+ [69939]=5,
+ [69940]=5,
+ [70003]=5,
+ [70016]=5,
+ [70017]=5,
+ [70070]=5,
+ [70071]=5,
+ [70072]=5,
+ [70073]=5,
+ [70074]=5,
+ [70075]=5,
+ [70076]=5,
+ [70077]=5,
+ [70078]=5,
+ [70090]=5,
+ [70091]=5,
+ [70092]=5,
+ [70191]=5,
+ [70192]=5,
+ [70193]=5,
+ [70196]=5,
+ [70198]=5,
+ [70199]=5,
+ [70206]=5,
+ [70367]=5,
+ [70371]=5,
+ [70372]=5,
+ [70373]=5,
+ [70374]=5,
+ [70375]=5,
+ [70376]=5,
+ [70377]=5,
+ [70378]=5,
+ [70400]=5,
+ [70401]=5,
+ [70460]=5,
+ [70464]=5,
+ [70502]=5,
+ [70503]=5,
+ [70504]=5,
+ [70505]=5,
+ [70506]=5,
+ [70507]=5,
+ [70508]=5,
+ [70512]=5,
+ [70513]=5,
+ [70514]=5,
+ [70515]=5,
+ [70516]=5,
+ [70712]=5,
+ [70713]=5,
+ [70714]=5,
+ [70715]=5,
+ [70716]=5,
+ [70717]=5,
+ [70718]=5,
+ [70719]=5,
+ [70722]=5,
+ [70723]=5,
+ [70724]=5,
+ [70726]=5,
+ [70835]=5,
+ [70836]=5,
+ [70837]=5,
+ [70838]=5,
+ [70839]=5,
+ [70840]=5,
+ [70842]=5,
+ [70847]=5,
+ [70848]=5,
+ [70850]=5,
+ [70851]=5,
+ [71090]=5,
+ [71091]=5,
+ [71092]=5,
+ [71093]=5,
+ [71100]=5,
+ [71101]=5,
+ [71103]=5,
+ [71104]=5,
+ [71132]=5,
+ [71133]=5,
+ [71219]=5,
+ [71220]=5,
+ [71221]=5,
+ [71222]=5,
+ [71223]=5,
+ [71224]=5,
+ [71225]=5,
+ [71226]=5,
+ [71229]=5,
+ [71231]=5,
+ [71232]=5,
+ [71339]=5,
+ [71341]=5,
+ [71344]=5,
+ [71345]=5,
+ [71346]=5,
+ [71347]=5,
+ [71348]=5,
+ [71349]=5,
+ [71351]=5,
+ [71453]=5,
+ [71454]=5,
+ [71455]=5,
+ [71458]=5,
+ [71459]=5,
+ [71460]=5,
+ [71461]=5,
+ [71463]=5,
+ [71464]=5,
+ [71465]=5,
+ [71466]=5,
+ [71467]=5,
+ [72193]=5,
+ [72194]=5,
+ [72195]=5,
+ [72196]=5,
+ [72197]=5,
+ [72198]=5,
+ [72201]=5,
+ [72202]=5,
+ [72243]=5,
+ [72244]=5,
+ [72245]=5,
+ [72246]=5,
+ [72247]=5,
+ [72248]=5,
+ [72251]=5,
+ [72252]=5,
+ [72253]=5,
+ [72254]=5,
+ [72263]=5,
+ [72273]=5,
+ [72274]=5,
+ [72275]=5,
+ [72276]=5,
+ [72277]=5,
+ [72278]=5,
+ [72281]=5,
+ [72282]=5,
+ [72283]=5,
+ [72330]=5,
+ [72331]=5,
+ [72332]=5,
+ [72333]=5,
+ [72334]=5,
+ [72335]=5,
+ [72336]=5,
+ [72337]=5,
+ [72338]=5,
+ [72339]=5,
+ [72340]=5,
+ [72341]=5,
+ [72342]=5,
+ [72344]=5,
+ [72345]=5,
+ [72752]=5,
+ [72753]=5,
+ [72754]=5,
+ [72755]=5,
+ [72756]=5,
+ [72757]=5,
+ [72758]=5,
+ [72760]=5,
+ [72761]=5,
+ [72762]=5,
+ [72763]=5,
+ [72764]=5,
+ [72765]=5,
+ [72767]=5,
+ [72850]=5,
+ [72851]=5,
+ [72852]=5,
+ [72853]=5,
+ [72854]=5,
+ [72855]=5,
+ [72856]=5,
+ [72857]=5,
+ [72858]=5,
+ [72859]=5,
+ [72860]=5,
+ [72861]=5,
+ [72862]=5,
+ [72863]=5,
+ [72864]=5,
+ [72865]=5,
+ [72866]=5,
+ [72867]=5,
+ [72868]=5,
+ [72869]=5,
+ [72870]=5,
+ [72871]=5,
+ [72874]=5,
+ [72875]=5,
+ [72876]=5,
+ [72877]=5,
+ [72878]=5,
+ [72879]=5,
+ [72880]=5,
+ [72882]=5,
+ [72883]=5,
+ [72885]=5,
+ [72886]=5,
+ [73009]=5,
+ [73010]=5,
+ [73011]=5,
+ [73012]=5,
+ [73013]=5,
+ [73014]=5,
+ [73018]=5,
+ [73020]=5,
+ [73021]=5,
+ [73023]=5,
+ [73024]=5,
+ [73025]=5,
+ [73026]=5,
+ [73027]=5,
+ [73028]=5,
+ [73029]=5,
+ [73031]=5,
+ [92912]=5,
+ [92913]=5,
+ [92914]=5,
+ [92915]=5,
+ [92916]=5,
+ [92976]=5,
+ [92977]=5,
+ [92978]=5,
+ [92979]=5,
+ [92980]=5,
+ [92981]=5,
+ [92982]=5,
+ [94095]=5,
+ [94096]=5,
+ [94097]=5,
+ [94098]=5,
+ [113821]=5,
+ [113822]=5,
+ [119143]=5,
+ [119144]=5,
+ [119145]=5,
+ [119163]=5,
+ [119164]=5,
+ [119165]=5,
+ [119166]=5,
+ [119167]=5,
+ [119168]=5,
+ [119169]=5,
+ [119170]=5,
+ [119173]=5,
+ [119174]=5,
+ [119175]=5,
+ [119176]=5,
+ [119177]=5,
+ [119178]=5,
+ [119179]=5,
+ [119210]=5,
+ [119211]=5,
+ [119212]=5,
+ [119213]=5,
+ [119362]=5,
+ [119363]=5,
+ [119364]=5,
+ [121344]=5,
+ [121345]=5,
+ [121346]=5,
+ [121347]=5,
+ [121348]=5,
+ [121349]=5,
+ [121350]=5,
+ [121351]=5,
+ [121352]=5,
+ [121353]=5,
+ [121354]=5,
+ [121355]=5,
+ [121356]=5,
+ [121357]=5,
+ [121358]=5,
+ [121359]=5,
+ [121360]=5,
+ [121361]=5,
+ [121362]=5,
+ [121363]=5,
+ [121364]=5,
+ [121365]=5,
+ [121366]=5,
+ [121367]=5,
+ [121368]=5,
+ [121369]=5,
+ [121370]=5,
+ [121371]=5,
+ [121372]=5,
+ [121373]=5,
+ [121374]=5,
+ [121375]=5,
+ [121376]=5,
+ [121377]=5,
+ [121378]=5,
+ [121379]=5,
+ [121380]=5,
+ [121381]=5,
+ [121382]=5,
+ [121383]=5,
+ [121384]=5,
+ [121385]=5,
+ [121386]=5,
+ [121387]=5,
+ [121388]=5,
+ [121389]=5,
+ [121390]=5,
+ [121391]=5,
+ [121392]=5,
+ [121393]=5,
+ [121394]=5,
+ [121395]=5,
+ [121396]=5,
+ [121397]=5,
+ [121398]=5,
+ [121403]=5,
+ [121404]=5,
+ [121405]=5,
+ [121406]=5,
+ [121407]=5,
+ [121408]=5,
+ [121409]=5,
+ [121410]=5,
+ [121411]=5,
+ [121412]=5,
+ [121413]=5,
+ [121414]=5,
+ [121415]=5,
+ [121416]=5,
+ [121417]=5,
+ [121418]=5,
+ [121419]=5,
+ [121420]=5,
+ [121421]=5,
+ [121422]=5,
+ [121423]=5,
+ [121424]=5,
+ [121425]=5,
+ [121426]=5,
+ [121427]=5,
+ [121428]=5,
+ [121429]=5,
+ [121430]=5,
+ [121431]=5,
+ [121432]=5,
+ [121433]=5,
+ [121434]=5,
+ [121435]=5,
+ [121436]=5,
+ [121437]=5,
+ [121438]=5,
+ [121439]=5,
+ [121440]=5,
+ [121441]=5,
+ [121442]=5,
+ [121443]=5,
+ [121444]=5,
+ [121445]=5,
+ [121446]=5,
+ [121447]=5,
+ [121448]=5,
+ [121449]=5,
+ [121450]=5,
+ [121451]=5,
+ [121452]=5,
+ [121461]=5,
+ [121476]=5,
+ [121499]=5,
+ [121500]=5,
+ [121501]=5,
+ [121502]=5,
+ [121503]=5,
+ [121505]=5,
+ [121506]=5,
+ [121507]=5,
+ [121508]=5,
+ [121509]=5,
+ [121510]=5,
+ [121511]=5,
+ [121512]=5,
+ [121513]=5,
+ [121514]=5,
+ [121515]=5,
+ [121516]=5,
+ [121517]=5,
+ [121518]=5,
+ [121519]=5,
+ [122880]=5,
+ [122881]=5,
+ [122882]=5,
+ [122883]=5,
+ [122884]=5,
+ [122885]=5,
+ [122886]=5,
+ [122888]=5,
+ [122889]=5,
+ [122890]=5,
+ [122891]=5,
+ [122892]=5,
+ [122893]=5,
+ [122894]=5,
+ [122895]=5,
+ [122896]=5,
+ [122897]=5,
+ [122898]=5,
+ [122899]=5,
+ [122900]=5,
+ [122901]=5,
+ [122902]=5,
+ [122903]=5,
+ [122904]=5,
+ [122907]=5,
+ [122908]=5,
+ [122909]=5,
+ [122910]=5,
+ [122911]=5,
+ [122912]=5,
+ [122913]=5,
+ [122915]=5,
+ [122916]=5,
+ [122918]=5,
+ [122919]=5,
+ [122920]=5,
+ [122921]=5,
+ [122922]=5,
+ [125136]=5,
+ [125137]=5,
+ [125138]=5,
+ [125139]=5,
+ [125140]=5,
+ [125141]=5,
+ [125142]=5,
+ [125184]=2,
+ [125185]=2,
+ [125186]=2,
+ [125187]=2,
+ [125188]=2,
+ [125189]=2,
+ [125190]=2,
+ [125191]=2,
+ [125192]=2,
+ [125193]=2,
+ [125194]=2,
+ [125195]=2,
+ [125196]=2,
+ [125197]=2,
+ [125198]=2,
+ [125199]=2,
+ [125200]=2,
+ [125201]=2,
+ [125202]=2,
+ [125203]=2,
+ [125204]=2,
+ [125205]=2,
+ [125206]=2,
+ [125207]=2,
+ [125208]=2,
+ [125209]=2,
+ [125210]=2,
+ [125211]=2,
+ [125212]=2,
+ [125213]=2,
+ [125214]=2,
+ [125215]=2,
+ [125216]=2,
+ [125217]=2,
+ [125218]=2,
+ [125219]=2,
+ [125220]=2,
+ [125221]=2,
+ [125222]=2,
+ [125223]=2,
+ [125224]=2,
+ [125225]=2,
+ [125226]=2,
+ [125227]=2,
+ [125228]=2,
+ [125229]=2,
+ [125230]=2,
+ [125231]=2,
+ [125232]=2,
+ [125233]=2,
+ [125234]=2,
+ [125235]=2,
+ [125236]=2,
+ [125237]=2,
+ [125238]=2,
+ [125239]=2,
+ [125240]=2,
+ [125241]=2,
+ [125242]=2,
+ [125243]=2,
+ [125244]=2,
+ [125245]=2,
+ [125246]=2,
+ [125247]=2,
+ [125248]=2,
+ [125249]=2,
+ [125250]=2,
+ [125251]=2,
+ [125252]=5,
+ [125253]=5,
+ [125254]=5,
+ [125255]=5,
+ [125256]=5,
+ [125257]=5,
+ [125258]=5,
+ [1042752]=5,
+}
+characters.indicgroups={
+ ["above_mark"]={
+ [2304]=true,
+ [2305]=true,
+ [2306]=true,
+ [2362]=true,
+ [2373]=true,
+ [2374]=true,
+ [2375]=true,
+ [2376]=true,
+ [2385]=true,
+ [2387]=true,
+ [2388]=true,
+ [2389]=true,
+ [2631]=true,
+ [2632]=true,
+ [2635]=true,
+ [2636]=true,
+ [2757]=true,
+ [2759]=true,
+ [2760]=true,
+ [2879]=true,
+ [3008]=true,
+ [3021]=true,
+ [3134]=true,
+ [3135]=true,
+ [3136]=true,
+ [3142]=true,
+ [3143]=true,
+ [3144]=true,
+ [3146]=true,
+ [3147]=true,
+ [3148]=true,
+ [3149]=true,
+ [3263]=true,
+ [3270]=true,
+ [3406]=true,
+ [43232]=true,
+ [43233]=true,
+ [43234]=true,
+ [43235]=true,
+ [43236]=true,
+ [43237]=true,
+ [43238]=true,
+ [43239]=true,
+ [43240]=true,
+ [43241]=true,
+ [43242]=true,
+ [43243]=true,
+ [43244]=true,
+ [43245]=true,
+ [43246]=true,
+ [43247]=true,
+ [43248]=true,
+ [43249]=true,
+ },
+ ["after_half"]={},
+ ["after_main"]={
+ [2864]=true,
+ [2879]=true,
+ [2902]=true,
+ [3376]=true,
+ },
+ ["after_postscript"]={
+ [2433]=true,
+ [2494]=true,
+ [2496]=true,
+ [2519]=true,
+ [2561]=true,
+ [2562]=true,
+ [2622]=true,
+ [2624]=true,
+ [2625]=true,
+ [2626]=true,
+ [2672]=true,
+ [2673]=true,
+ [2750]=true,
+ [2752]=true,
+ [2753]=true,
+ [2754]=true,
+ [2755]=true,
+ [2756]=true,
+ [2761]=true,
+ [2763]=true,
+ [2764]=true,
+ [2786]=true,
+ [2787]=true,
+ [2878]=true,
+ [2880]=true,
+ [2903]=true,
+ [2992]=true,
+ [3006]=true,
+ [3007]=true,
+ [3009]=true,
+ [3010]=true,
+ [3031]=true,
+ [3120]=true,
+ [3248]=true,
+ [3390]=true,
+ [3391]=true,
+ [3392]=true,
+ [3393]=true,
+ [3394]=true,
+ [3395]=true,
+ [3415]=true,
+ },
+ ["after_subscript"]={
+ [2366]=true,
+ [2368]=true,
+ [2369]=true,
+ [2370]=true,
+ [2371]=true,
+ [2372]=true,
+ [2373]=true,
+ [2374]=true,
+ [2375]=true,
+ [2376]=true,
+ [2377]=true,
+ [2378]=true,
+ [2379]=true,
+ [2380]=true,
+ [2402]=true,
+ [2403]=true,
+ [2480]=true,
+ [2497]=true,
+ [2498]=true,
+ [2499]=true,
+ [2500]=true,
+ [2530]=true,
+ [2531]=true,
+ [2544]=true,
+ [2631]=true,
+ [2632]=true,
+ [2635]=true,
+ [2636]=true,
+ [2757]=true,
+ [2759]=true,
+ [2760]=true,
+ [2881]=true,
+ [2882]=true,
+ [2883]=true,
+ [3008]=true,
+ [3139]=true,
+ [3140]=true,
+ [3267]=true,
+ [3268]=true,
+ [3285]=true,
+ [3286]=true,
+ },
+ ["anudatta"]={
+ [2386]=true,
+ },
+ ["before_half"]={
+ [2367]=true,
+ [2382]=true,
+ [2495]=true,
+ [2503]=true,
+ [2504]=true,
+ [2623]=true,
+ [2751]=true,
+ [2887]=true,
+ },
+ ["before_main"]={
+ [3014]=true,
+ [3015]=true,
+ [3016]=true,
+ [3398]=true,
+ [3399]=true,
+ [3400]=true,
+ },
+ ["before_postscript"]={
+ [2352]=true,
+ [2736]=true,
+ },
+ ["before_subscript"]={
+ [2608]=true,
+ [2817]=true,
+ [3134]=true,
+ [3135]=true,
+ [3136]=true,
+ [3137]=true,
+ [3138]=true,
+ [3142]=true,
+ [3143]=true,
+ [3146]=true,
+ [3147]=true,
+ [3148]=true,
+ [3157]=true,
+ [3158]=true,
+ [3262]=true,
+ [3263]=true,
+ [3265]=true,
+ [3266]=true,
+ [3270]=true,
+ [3276]=true,
+ [3298]=true,
+ [3299]=true,
+ },
+ ["below_mark"]={
+ [2364]=true,
+ [2369]=true,
+ [2370]=true,
+ [2371]=true,
+ [2372]=true,
+ [2381]=true,
+ [2386]=true,
+ [2390]=true,
+ [2391]=true,
+ [2402]=true,
+ [2403]=true,
+ [2492]=true,
+ [2497]=true,
+ [2498]=true,
+ [2499]=true,
+ [2500]=true,
+ [2509]=true,
+ [2620]=true,
+ [2625]=true,
+ [2626]=true,
+ [2637]=true,
+ [2748]=true,
+ [2753]=true,
+ [2754]=true,
+ [2755]=true,
+ [2756]=true,
+ [2765]=true,
+ [2876]=true,
+ [2881]=true,
+ [2882]=true,
+ [2883]=true,
+ [2884]=true,
+ [2893]=true,
+ [2914]=true,
+ [2915]=true,
+ [3009]=true,
+ [3010]=true,
+ [3170]=true,
+ [3171]=true,
+ [3260]=true,
+ [3298]=true,
+ [3299]=true,
+ [3426]=true,
+ [3427]=true,
+ },
+ ["consonant"]={
+ [2325]=true,
+ [2326]=true,
+ [2327]=true,
+ [2328]=true,
+ [2329]=true,
+ [2330]=true,
+ [2331]=true,
+ [2332]=true,
+ [2333]=true,
+ [2334]=true,
+ [2335]=true,
+ [2336]=true,
+ [2337]=true,
+ [2338]=true,
+ [2339]=true,
+ [2340]=true,
+ [2341]=true,
+ [2342]=true,
+ [2343]=true,
+ [2344]=true,
+ [2345]=true,
+ [2346]=true,
+ [2347]=true,
+ [2348]=true,
+ [2349]=true,
+ [2350]=true,
+ [2351]=true,
+ [2352]=true,
+ [2353]=true,
+ [2354]=true,
+ [2355]=true,
+ [2356]=true,
+ [2357]=true,
+ [2358]=true,
+ [2359]=true,
+ [2360]=true,
+ [2361]=true,
+ [2392]=true,
+ [2393]=true,
+ [2394]=true,
+ [2395]=true,
+ [2396]=true,
+ [2397]=true,
+ [2398]=true,
+ [2399]=true,
+ [2424]=true,
+ [2425]=true,
+ [2426]=true,
+ [2453]=true,
+ [2454]=true,
+ [2455]=true,
+ [2456]=true,
+ [2457]=true,
+ [2458]=true,
+ [2459]=true,
+ [2460]=true,
+ [2461]=true,
+ [2462]=true,
+ [2463]=true,
+ [2464]=true,
+ [2465]=true,
+ [2466]=true,
+ [2467]=true,
+ [2468]=true,
+ [2469]=true,
+ [2470]=true,
+ [2471]=true,
+ [2472]=true,
+ [2474]=true,
+ [2475]=true,
+ [2476]=true,
+ [2477]=true,
+ [2478]=true,
+ [2479]=true,
+ [2480]=true,
+ [2482]=true,
+ [2486]=true,
+ [2487]=true,
+ [2488]=true,
+ [2489]=true,
+ [2510]=true,
+ [2524]=true,
+ [2525]=true,
+ [2527]=true,
+ [2581]=true,
+ [2582]=true,
+ [2583]=true,
+ [2584]=true,
+ [2585]=true,
+ [2586]=true,
+ [2587]=true,
+ [2588]=true,
+ [2589]=true,
+ [2590]=true,
+ [2591]=true,
+ [2592]=true,
+ [2593]=true,
+ [2594]=true,
+ [2595]=true,
+ [2596]=true,
+ [2597]=true,
+ [2598]=true,
+ [2599]=true,
+ [2600]=true,
+ [2602]=true,
+ [2603]=true,
+ [2604]=true,
+ [2605]=true,
+ [2606]=true,
+ [2607]=true,
+ [2608]=true,
+ [2610]=true,
+ [2611]=true,
+ [2613]=true,
+ [2614]=true,
+ [2616]=true,
+ [2617]=true,
+ [2649]=true,
+ [2650]=true,
+ [2651]=true,
+ [2652]=true,
+ [2654]=true,
+ [2709]=true,
+ [2710]=true,
+ [2711]=true,
+ [2712]=true,
+ [2713]=true,
+ [2714]=true,
+ [2715]=true,
+ [2716]=true,
+ [2717]=true,
+ [2718]=true,
+ [2719]=true,
+ [2720]=true,
+ [2721]=true,
+ [2722]=true,
+ [2723]=true,
+ [2724]=true,
+ [2725]=true,
+ [2726]=true,
+ [2727]=true,
+ [2728]=true,
+ [2730]=true,
+ [2731]=true,
+ [2732]=true,
+ [2733]=true,
+ [2734]=true,
+ [2735]=true,
+ [2736]=true,
+ [2738]=true,
+ [2739]=true,
+ [2741]=true,
+ [2742]=true,
+ [2743]=true,
+ [2744]=true,
+ [2745]=true,
+ [2837]=true,
+ [2838]=true,
+ [2839]=true,
+ [2840]=true,
+ [2841]=true,
+ [2842]=true,
+ [2843]=true,
+ [2844]=true,
+ [2845]=true,
+ [2846]=true,
+ [2847]=true,
+ [2848]=true,
+ [2849]=true,
+ [2850]=true,
+ [2851]=true,
+ [2852]=true,
+ [2853]=true,
+ [2854]=true,
+ [2855]=true,
+ [2856]=true,
+ [2858]=true,
+ [2859]=true,
+ [2860]=true,
+ [2861]=true,
+ [2862]=true,
+ [2863]=true,
+ [2864]=true,
+ [2866]=true,
+ [2867]=true,
+ [2869]=true,
+ [2870]=true,
+ [2871]=true,
+ [2872]=true,
+ [2873]=true,
+ [2908]=true,
+ [2909]=true,
+ [2929]=true,
+ [2965]=true,
+ [2969]=true,
+ [2970]=true,
+ [2972]=true,
+ [2974]=true,
+ [2975]=true,
+ [2979]=true,
+ [2980]=true,
+ [2984]=true,
+ [2985]=true,
+ [2986]=true,
+ [2990]=true,
+ [2991]=true,
+ [2992]=true,
+ [2993]=true,
+ [2994]=true,
+ [2995]=true,
+ [2996]=true,
+ [2997]=true,
+ [2998]=true,
+ [2999]=true,
+ [3000]=true,
+ [3001]=true,
+ [3093]=true,
+ [3094]=true,
+ [3095]=true,
+ [3096]=true,
+ [3097]=true,
+ [3098]=true,
+ [3099]=true,
+ [3100]=true,
+ [3101]=true,
+ [3102]=true,
+ [3103]=true,
+ [3104]=true,
+ [3105]=true,
+ [3106]=true,
+ [3107]=true,
+ [3108]=true,
+ [3109]=true,
+ [3110]=true,
+ [3111]=true,
+ [3112]=true,
+ [3114]=true,
+ [3115]=true,
+ [3116]=true,
+ [3117]=true,
+ [3118]=true,
+ [3119]=true,
+ [3120]=true,
+ [3121]=true,
+ [3122]=true,
+ [3123]=true,
+ [3124]=true,
+ [3125]=true,
+ [3126]=true,
+ [3127]=true,
+ [3128]=true,
+ [3129]=true,
+ [3133]=true,
+ [3221]=true,
+ [3222]=true,
+ [3223]=true,
+ [3224]=true,
+ [3225]=true,
+ [3226]=true,
+ [3227]=true,
+ [3228]=true,
+ [3229]=true,
+ [3230]=true,
+ [3231]=true,
+ [3232]=true,
+ [3233]=true,
+ [3234]=true,
+ [3235]=true,
+ [3236]=true,
+ [3237]=true,
+ [3238]=true,
+ [3239]=true,
+ [3240]=true,
+ [3242]=true,
+ [3243]=true,
+ [3244]=true,
+ [3245]=true,
+ [3246]=true,
+ [3247]=true,
+ [3248]=true,
+ [3249]=true,
+ [3250]=true,
+ [3251]=true,
+ [3253]=true,
+ [3254]=true,
+ [3255]=true,
+ [3256]=true,
+ [3257]=true,
+ [3294]=true,
+ [3349]=true,
+ [3350]=true,
+ [3351]=true,
+ [3352]=true,
+ [3353]=true,
+ [3354]=true,
+ [3355]=true,
+ [3356]=true,
+ [3357]=true,
+ [3358]=true,
+ [3359]=true,
+ [3360]=true,
+ [3361]=true,
+ [3362]=true,
+ [3363]=true,
+ [3364]=true,
+ [3365]=true,
+ [3366]=true,
+ [3367]=true,
+ [3368]=true,
+ [3369]=true,
+ [3370]=true,
+ [3371]=true,
+ [3372]=true,
+ [3373]=true,
+ [3374]=true,
+ [3375]=true,
+ [3376]=true,
+ [3377]=true,
+ [3378]=true,
+ [3379]=true,
+ [3380]=true,
+ [3381]=true,
+ [3382]=true,
+ [3383]=true,
+ [3384]=true,
+ [3385]=true,
+ [3386]=true,
+ },
+ ["dependent_vowel"]={
+ [2362]=true,
+ [2363]=true,
+ [2366]=true,
+ [2367]=true,
+ [2368]=true,
+ [2369]=true,
+ [2370]=true,
+ [2371]=true,
+ [2372]=true,
+ [2373]=true,
+ [2374]=true,
+ [2375]=true,
+ [2376]=true,
+ [2377]=true,
+ [2378]=true,
+ [2379]=true,
+ [2380]=true,
+ [2382]=true,
+ [2383]=true,
+ [2389]=true,
+ [2390]=true,
+ [2391]=true,
+ [2402]=true,
+ [2403]=true,
+ [2494]=true,
+ [2495]=true,
+ [2496]=true,
+ [2497]=true,
+ [2498]=true,
+ [2499]=true,
+ [2500]=true,
+ [2503]=true,
+ [2504]=true,
+ [2622]=true,
+ [2623]=true,
+ [2624]=true,
+ [2625]=true,
+ [2626]=true,
+ [2631]=true,
+ [2632]=true,
+ [2635]=true,
+ [2636]=true,
+ [2750]=true,
+ [2751]=true,
+ [2752]=true,
+ [2753]=true,
+ [2754]=true,
+ [2755]=true,
+ [2756]=true,
+ [2757]=true,
+ [2759]=true,
+ [2760]=true,
+ [2761]=true,
+ [2763]=true,
+ [2764]=true,
+ [2878]=true,
+ [2879]=true,
+ [2880]=true,
+ [2881]=true,
+ [2882]=true,
+ [2883]=true,
+ [2884]=true,
+ [2887]=true,
+ [2888]=true,
+ [2891]=true,
+ [2892]=true,
+ [2914]=true,
+ [2915]=true,
+ [3006]=true,
+ [3007]=true,
+ [3008]=true,
+ [3009]=true,
+ [3010]=true,
+ [3014]=true,
+ [3015]=true,
+ [3016]=true,
+ [3018]=true,
+ [3019]=true,
+ [3020]=true,
+ [3134]=true,
+ [3135]=true,
+ [3136]=true,
+ [3137]=true,
+ [3138]=true,
+ [3139]=true,
+ [3140]=true,
+ [3142]=true,
+ [3143]=true,
+ [3144]=true,
+ [3146]=true,
+ [3147]=true,
+ [3148]=true,
+ [3170]=true,
+ [3171]=true,
+ [3262]=true,
+ [3263]=true,
+ [3264]=true,
+ [3265]=true,
+ [3266]=true,
+ [3267]=true,
+ [3268]=true,
+ [3270]=true,
+ [3271]=true,
+ [3272]=true,
+ [3274]=true,
+ [3275]=true,
+ [3276]=true,
+ [3298]=true,
+ [3299]=true,
+ [3390]=true,
+ [3391]=true,
+ [3392]=true,
+ [3393]=true,
+ [3394]=true,
+ [3395]=true,
+ [3396]=true,
+ [3398]=true,
+ [3399]=true,
+ [3400]=true,
+ [3402]=true,
+ [3403]=true,
+ [3404]=true,
+ [3415]=true,
+ [3426]=true,
+ [3427]=true,
+ },
+ ["halant"]={
+ [2381]=true,
+ [2509]=true,
+ [2637]=true,
+ [2765]=true,
+ [2893]=true,
+ [3021]=true,
+ [3149]=true,
+ [3277]=true,
+ [3405]=true,
+ },
+ ["independent_vowel"]={
+ [2308]=true,
+ [2309]=true,
+ [2310]=true,
+ [2311]=true,
+ [2312]=true,
+ [2313]=true,
+ [2314]=true,
+ [2315]=true,
+ [2316]=true,
+ [2317]=true,
+ [2318]=true,
+ [2319]=true,
+ [2320]=true,
+ [2321]=true,
+ [2322]=true,
+ [2323]=true,
+ [2324]=true,
+ [2400]=true,
+ [2401]=true,
+ [2418]=true,
+ [2419]=true,
+ [2420]=true,
+ [2421]=true,
+ [2422]=true,
+ [2423]=true,
+ [2437]=true,
+ [2438]=true,
+ [2439]=true,
+ [2440]=true,
+ [2441]=true,
+ [2442]=true,
+ [2443]=true,
+ [2444]=true,
+ [2447]=true,
+ [2448]=true,
+ [2451]=true,
+ [2452]=true,
+ [2528]=true,
+ [2529]=true,
+ [2530]=true,
+ [2531]=true,
+ [2565]=true,
+ [2566]=true,
+ [2567]=true,
+ [2568]=true,
+ [2569]=true,
+ [2570]=true,
+ [2575]=true,
+ [2576]=true,
+ [2579]=true,
+ [2580]=true,
+ [2693]=true,
+ [2694]=true,
+ [2695]=true,
+ [2696]=true,
+ [2697]=true,
+ [2698]=true,
+ [2699]=true,
+ [2700]=true,
+ [2701]=true,
+ [2703]=true,
+ [2704]=true,
+ [2705]=true,
+ [2707]=true,
+ [2708]=true,
+ [2784]=true,
+ [2785]=true,
+ [2786]=true,
+ [2787]=true,
+ [2821]=true,
+ [2822]=true,
+ [2823]=true,
+ [2824]=true,
+ [2825]=true,
+ [2826]=true,
+ [2827]=true,
+ [2828]=true,
+ [2831]=true,
+ [2832]=true,
+ [2835]=true,
+ [2836]=true,
+ [2912]=true,
+ [2913]=true,
+ [2949]=true,
+ [2950]=true,
+ [2951]=true,
+ [2952]=true,
+ [2953]=true,
+ [2954]=true,
+ [2958]=true,
+ [2959]=true,
+ [2960]=true,
+ [2962]=true,
+ [2963]=true,
+ [2964]=true,
+ [3077]=true,
+ [3078]=true,
+ [3079]=true,
+ [3080]=true,
+ [3081]=true,
+ [3082]=true,
+ [3083]=true,
+ [3084]=true,
+ [3086]=true,
+ [3087]=true,
+ [3088]=true,
+ [3090]=true,
+ [3091]=true,
+ [3092]=true,
+ [3168]=true,
+ [3169]=true,
+ [3205]=true,
+ [3206]=true,
+ [3207]=true,
+ [3208]=true,
+ [3209]=true,
+ [3210]=true,
+ [3211]=true,
+ [3212]=true,
+ [3214]=true,
+ [3215]=true,
+ [3216]=true,
+ [3218]=true,
+ [3219]=true,
+ [3220]=true,
+ [3296]=true,
+ [3297]=true,
+ [3333]=true,
+ [3334]=true,
+ [3335]=true,
+ [3336]=true,
+ [3337]=true,
+ [3338]=true,
+ [3339]=true,
+ [3340]=true,
+ [3342]=true,
+ [3343]=true,
+ [3344]=true,
+ [3346]=true,
+ [3347]=true,
+ [3348]=true,
+ [3423]=true,
+ [3424]=true,
+ [3425]=true,
+ },
+ ["nukta"]={
+ [2364]=true,
+ [2492]=true,
+ [2620]=true,
+ [2748]=true,
+ [2876]=true,
+ [3260]=true,
+ },
+ ["post_mark"]={
+ [2307]=true,
+ [2363]=true,
+ [2366]=true,
+ [2368]=true,
+ [2377]=true,
+ [2378]=true,
+ [2379]=true,
+ [2380]=true,
+ [2383]=true,
+ [2494]=true,
+ [2496]=true,
+ [2503]=true,
+ [2504]=true,
+ [2622]=true,
+ [2624]=true,
+ [2750]=true,
+ [2752]=true,
+ [2761]=true,
+ [2763]=true,
+ [2764]=true,
+ [2878]=true,
+ [2880]=true,
+ [3006]=true,
+ [3007]=true,
+ [3137]=true,
+ [3138]=true,
+ [3139]=true,
+ [3140]=true,
+ [3262]=true,
+ [3264]=true,
+ [3265]=true,
+ [3266]=true,
+ [3267]=true,
+ [3268]=true,
+ [3271]=true,
+ [3272]=true,
+ [3274]=true,
+ [3275]=true,
+ [3276]=true,
+ [3390]=true,
+ [3391]=true,
+ [3392]=true,
+ [3393]=true,
+ [3394]=true,
+ [3395]=true,
+ [3396]=true,
+ [3415]=true,
+ },
+ ["pre_mark"]={
+ [2367]=true,
+ [2382]=true,
+ [2495]=true,
+ [2623]=true,
+ [2751]=true,
+ [2887]=true,
+ [2888]=true,
+ [3014]=true,
+ [3015]=true,
+ [3016]=true,
+ [3398]=true,
+ [3399]=true,
+ [3400]=true,
+ },
+ ["ra"]={
+ [2352]=true,
+ [2480]=true,
+ [2608]=true,
+ [2736]=true,
+ [2864]=true,
+ [2992]=true,
+ [3120]=true,
+ [3248]=true,
+ [3376]=true,
+ },
+ ["stress_tone_mark"]={
+ [2385]=true,
+ [2386]=true,
+ [2387]=true,
+ [2388]=true,
+ [2507]=true,
+ [2508]=true,
+ [3277]=true,
+ [3405]=true,
+ },
+ ["twopart_mark"]={
+ [2891]={ 2887,2878 },
+ [2892]={ 2887,2903 },
+ [3018]={ 3014,3006 },
+ [3019]={ 3015,3006 },
+ [3020]={ 3014,3031 },
+ [3402]={ 3398,3390 },
+ [3403]={ 3399,3390 },
+ [3404]={ 3398,3415 },
+ },
+ ["vowel_modifier"]={
+ [2304]=true,
+ [2305]=true,
+ [2306]=true,
+ [2307]=true,
+ [3330]=true,
+ [3331]=true,
+ [43232]=true,
+ [43233]=true,
+ [43234]=true,
+ [43235]=true,
+ [43236]=true,
+ [43237]=true,
+ [43238]=true,
+ [43239]=true,
+ [43240]=true,
+ [43241]=true,
+ [43242]=true,
+ [43243]=true,
+ [43244]=true,
+ [43245]=true,
+ [43246]=true,
+ [43247]=true,
+ [43248]=true,
+ [43249]=true,
+ },
}
end -- closure
@@ -5835,7 +9051,7 @@ if not modules then modules={} end modules ['font-ini']={
local allocate=utilities.storage.allocate
fonts=fonts or {}
local fonts=fonts
-fonts.hashes={ identifiers=allocate() }
+fonts.hashes=fonts.hashes or { identifiers=allocate() }
fonts.tables=fonts.tables or {}
fonts.helpers=fonts.helpers or {}
fonts.tracers=fonts.tracers or {}
@@ -5844,7 +9060,42 @@ fonts.analyzers={}
fonts.readers={}
fonts.definers={ methods={} }
fonts.loggers={ register=function() end }
-fontloader.totable=fontloader.to_table
+if context then
+--removed
+
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['luatex-font-mis']={
+ version=1.001,
+ comment="companion to luatex-*.tex",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+if context then
+--removed
+
+end
+local currentfont=font.current
+local hashes=fonts.hashes
+local identifiers=hashes.identifiers or {}
+local marks=hashes.marks or {}
+hashes.identifiers=identifiers
+hashes.marks=marks
+table.setmetatableindex(marks,function(t,k)
+ if k==true then
+ return marks[currentfont()]
+ else
+ local resources=identifiers[k].resources or {}
+ local marks=resources.marks or {}
+ t[k]=marks
+ return marks
+ end
+end)
end -- closure
@@ -5857,11 +9108,14 @@ if not modules then modules={} end modules ['font-con']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local next,tostring,rawget=next,tostring,rawget
+local next,tostring,tonumber,rawget=next,tostring,tonumber,rawget
local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find
-local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
+local sort,insert,concat=table.sort,table.insert,table.concat
+local sortedkeys,sortedhash,serialize,fastcopy=table.sortedkeys,table.sortedhash,table.serialize,table.fastcopy
local derivetable=table.derive
local ioflush=io.flush
+local round=math.round
+local setmetatable,getmetatable,rawget,rawset=setmetatable,getmetatable,rawget,rawset
local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end)
local report_defining=logs.reporter("fonts","defining")
@@ -5907,6 +9161,28 @@ function constructors.scaled(scaledpoints,designsize)
return scaledpoints
end
end
+function constructors.getprivate(tfmdata)
+ local properties=tfmdata.properties
+ local private=properties.private
+ properties.private=private+1
+ return private
+end
+function constructors.setmathparameter(tfmdata,name,value)
+ local m=tfmdata.mathparameters
+ local c=tfmdata.MathConstants
+ if m then
+ m[name]=value
+ end
+ if c and c~=m then
+ c[name]=value
+ end
+end
+function constructors.getmathparameter(tfmdata,name)
+ local p=tfmdata.mathparameters or tfmdata.MathConstants
+ if p then
+ return p[name]
+ end
+end
function constructors.cleanuptable(tfmdata)
if constructors.autocleanup and tfmdata.properties.virtualized then
for k,v in next,tfmdata.characters do
@@ -5983,27 +9259,62 @@ function constructors.trytosharefont(target,tfmdata)
end
end
end
+local synonyms={
+ exheight="x_height",
+ xheight="x_height",
+ ex="x_height",
+ emwidth="quad",
+ em="quad",
+ spacestretch="space_stretch",
+ stretch="space_stretch",
+ spaceshrink="space_shrink",
+ shrink="space_shrink",
+ extraspace="extra_space",
+ xspace="extra_space",
+ slantperpoint="slant",
+}
function constructors.enhanceparameters(parameters)
- local xheight=parameters.x_height
- local quad=parameters.quad
- local space=parameters.space
- local stretch=parameters.space_stretch
- local shrink=parameters.space_shrink
- local extra=parameters.extra_space
- local slant=parameters.slant
- parameters.xheight=xheight
- parameters.spacestretch=stretch
- parameters.spaceshrink=shrink
- parameters.extraspace=extra
- parameters.em=quad
- parameters.ex=xheight
- parameters.slantperpoint=slant
- parameters.spacing={
- width=space,
- stretch=stretch,
- shrink=shrink,
- extra=extra,
- }
+ local mt=getmetatable(parameters)
+ local getter=function(t,k)
+ if not k then
+ return nil
+ end
+ local s=synonyms[k]
+ if s then
+ return rawget(t,s) or (mt and mt[s]) or nil
+ end
+ if k=="spacing" then
+ return {
+ width=t.space,
+ stretch=t.space_stretch,
+ shrink=t.space_shrink,
+ extra=t.extra_space,
+ }
+ end
+ return mt and mt[k] or nil
+ end
+ local setter=function(t,k,v)
+ if not k then
+ return 0
+ end
+ local s=synonyms[k]
+ if s then
+ rawset(t,s,v)
+ elseif k=="spacing" then
+ if type(v)=="table" then
+ rawset(t,"space",v.width or 0)
+ rawset(t,"space_stretch",v.stretch or 0)
+ rawset(t,"space_shrink",v.shrink or 0)
+ rawset(t,"extra_space",v.extra or 0)
+ end
+ else
+ rawset(t,k,v)
+ end
+ end
+ setmetatable(parameters,{
+ __index=getter,
+ __newindex=setter,
+ })
end
local function mathkerns(v,vdelta)
local k={}
@@ -6022,7 +9333,7 @@ local psfake=0
local function fixedpsname(psname,fallback)
local usedname=psname
if psname and psname~="" then
- if find(psname," ") then
+ if find(psname," ",1,true) then
usedname=gsub(psname,"[%s]+","-")
else
end
@@ -6067,7 +9378,7 @@ function constructors.scale(tfmdata,specification)
target.unscaled=tfmdata
local mathsize=tonumber(specification.mathsize) or 0
local textsize=tonumber(specification.textsize) or scaledpoints
- local forcedsize=tonumber(parameters.mathsize ) or 0
+ local forcedsize=tonumber(parameters.mathsize ) or 0
local extrafactor=tonumber(specification.factor ) or 1
if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then
scaledpoints=parameters.scriptpercentage*textsize/100
@@ -6075,6 +9386,7 @@ function constructors.scale(tfmdata,specification)
scaledpoints=parameters.scriptscriptpercentage*textsize/100
elseif forcedsize>1000 then
scaledpoints=forcedsize
+ else
end
targetparameters.mathsize=mathsize
targetparameters.textsize=textsize
@@ -6085,9 +9397,6 @@ function constructors.scale(tfmdata,specification)
local defaultheight=resources.defaultheight or 0
local defaultdepth=resources.defaultdepth or 0
local units=parameters.units or 1000
- if target.fonts then
- target.fonts=fastcopy(target.fonts)
- end
targetproperties.language=properties.language or "dflt"
targetproperties.script=properties.script or "dflt"
targetproperties.mode=properties.mode or "base"
@@ -6129,24 +9438,34 @@ function constructors.scale(tfmdata,specification)
target.stretch=expansion.stretch
target.shrink=expansion.shrink
target.step=expansion.step
- target.auto_expand=expansion.auto
end
- local protrusion=parameters.protrusion
- if protrusion then
- target.auto_protrude=protrusion.auto
+ local slantfactor=parameters.slantfactor or 0
+ if slantfactor~=0 then
+ target.slant=slantfactor*1000
+ else
+ target.slant=0
end
local extendfactor=parameters.extendfactor or 0
if extendfactor~=0 and extendfactor~=1 then
hdelta=hdelta*extendfactor
- target.extend=extendfactor*1000
+ target.extend=extendfactor*1000
else
target.extend=1000
end
- local slantfactor=parameters.slantfactor or 0
- if slantfactor~=0 then
- target.slant=slantfactor*1000
+ local squeezefactor=parameters.squeezefactor or 0
+ if squeezefactor~=0 and squeezefactor~=1 then
+ vdelta=vdelta*squeezefactor
+ target.squeeze=squeezefactor*1000
else
- target.slant=0
+ target.squeeze=1000
+ end
+ local mode=parameters.mode or 0
+ if mode~=0 then
+ target.mode=mode
+ end
+ local width=parameters.width or 0
+ if width~=0 then
+ target.width=width*delta*1000/655360
end
targetparameters.factor=delta
targetparameters.hfactor=hdelta
@@ -6154,8 +9473,10 @@ function constructors.scale(tfmdata,specification)
targetparameters.size=scaledpoints
targetparameters.units=units
targetparameters.scaledpoints=askedscaledpoints
+ targetparameters.mode=mode
+ targetparameters.width=width
local isvirtual=properties.virtualized or tfmdata.type=="virtual"
- local hasquality=target.auto_expand or target.auto_protrude
+ local hasquality=parameters.expansion or parameters.protrusion
local hasitalics=properties.hasitalics
local autoitalicamount=properties.autoitalicamount
local stackmath=not properties.nostackmath
@@ -6165,6 +9486,12 @@ function constructors.scale(tfmdata,specification)
local realdimensions=properties.realdimensions
local writingmode=properties.writingmode or "horizontal"
local identity=properties.identity or "horizontal"
+ local vfonts=target.fonts
+ if vfonts and #vfonts>0 then
+ target.fonts=fastcopy(vfonts)
+ elseif isvirtual then
+ target.fonts={ { id=0 } }
+ end
if changed and not next(changed) then
changed=false
end
@@ -6240,10 +9567,15 @@ function constructors.scale(tfmdata,specification)
local chr,description,index
if changed then
local c=changed[unicode]
- if c then
- description=descriptions[c] or descriptions[unicode] or character
- character=characters[c] or character
- index=description.index or c
+ if c and c~=unicode then
+ if c then
+ description=descriptions[c] or descriptions[unicode] or character
+ character=characters[c] or character
+ index=description.index or c
+ else
+ description=descriptions[unicode] or character
+ index=description.index or unicode
+ end
else
description=descriptions[unicode] or character
index=description.index or unicode
@@ -6340,10 +9672,13 @@ function constructors.scale(tfmdata,specification)
local t={}
for i=1,#vv do
local vvi=vv[i]
- t[i]={
- ["start"]=(vvi["start"] or 0)*vdelta,
- ["end"]=(vvi["end"] or 0)*vdelta,
- ["advance"]=(vvi["advance"] or 0)*vdelta,
+ local s=vvi["start"] or 0
+ local e=vvi["end"] or 0
+ local a=vvi["advance"] or 0
+ t[i]={
+ ["start"]=s==0 and 0 or s*vdelta,
+ ["end"]=e==0 and 0 or e*vdelta,
+ ["advance"]=a==0 and 0 or a*vdelta,
["extender"]=vvi["extender"],
["glyph"]=vvi["glyph"],
}
@@ -6355,10 +9690,13 @@ function constructors.scale(tfmdata,specification)
local t={}
for i=1,#hv do
local hvi=hv[i]
- t[i]={
- ["start"]=(hvi["start"] or 0)*hdelta,
- ["end"]=(hvi["end"] or 0)*hdelta,
- ["advance"]=(hvi["advance"] or 0)*hdelta,
+ local s=hvi["start"] or 0
+ local e=hvi["end"] or 0
+ local a=hvi["advance"] or 0
+ t[i]={
+ ["start"]=s==0 and 0 or s*hdelta,
+ ["end"]=e==0 and 0 or e*hdelta,
+ ["advance"]=a==0 and 0 or a*hdelta,
["extender"]=hvi["extender"],
["glyph"]=hvi["glyph"],
}
@@ -6445,7 +9783,7 @@ function constructors.scale(tfmdata,specification)
local ok=false
for i=1,#vc do
local key=vc[i][1]
- if key=="right" or key=="down" then
+ if key=="right" or key=="down" or key=="rule" then
ok=true
break
end
@@ -6469,7 +9807,6 @@ function constructors.scale(tfmdata,specification)
else
chr.commands=vc
end
- chr.index=nil
end
end
targetcharacters[unicode]=chr
@@ -6477,6 +9814,20 @@ function constructors.scale(tfmdata,specification)
properties.setitalics=hasitalics
constructors.aftercopyingcharacters(target,tfmdata)
constructors.trytosharefont(target,tfmdata)
+ local vfonts=target.fonts
+if isvirtual or target.type=="virtual" or properties.virtualized then
+ properties.virtualized=true
+target.type="virtual"
+ if not vfonts or #vfonts==0 then
+ target.fonts={ { id=0 } }
+ end
+ elseif vfonts then
+ properties.virtualized=true
+ target.type="virtual"
+ if #vfonts==0 then
+ target.fonts={ { id=0 } }
+ end
+ end
return target
end
function constructors.finalize(tfmdata)
@@ -6495,26 +9846,29 @@ function constructors.finalize(tfmdata)
end
if not parameters.expansion then
parameters.expansion={
- stretch=tfmdata.stretch or 0,
- shrink=tfmdata.shrink or 0,
- step=tfmdata.step or 0,
- auto=tfmdata.auto_expand or false,
- }
- end
- if not parameters.protrusion then
- parameters.protrusion={
- auto=auto_protrude
+ stretch=tfmdata.stretch or 0,
+ shrink=tfmdata.shrink or 0,
+ step=tfmdata.step or 0,
}
end
if not parameters.size then
parameters.size=tfmdata.size
end
- if not parameters.extendfactor then
- parameters.extendfactor=tfmdata.extend or 0
+ if not parameters.mode then
+ parameters.mode=0
+ end
+ if not parameters.width then
+ parameters.width=0
end
if not parameters.slantfactor then
parameters.slantfactor=tfmdata.slant or 0
end
+ if not parameters.extendfactor then
+ parameters.extendfactor=tfmdata.extend or 0
+ end
+ if not parameters.squeezefactor then
+ parameters.squeezefactor=tfmdata.squeeze or 0
+ end
local designsize=parameters.designsize
if designsize then
parameters.minsize=tfmdata.minsize or designsize
@@ -6589,10 +9943,11 @@ function constructors.finalize(tfmdata)
tfmdata.stretch=nil
tfmdata.shrink=nil
tfmdata.step=nil
- tfmdata.auto_expand=nil
- tfmdata.auto_protrude=nil
- tfmdata.extend=nil
tfmdata.slant=nil
+ tfmdata.extend=nil
+ tfmdata.squeeze=nil
+ tfmdata.mode=nil
+ tfmdata.width=nil
tfmdata.units=nil
tfmdata.units_per_em=nil
tfmdata.cache=nil
@@ -6604,20 +9959,20 @@ constructors.hashmethods=hashmethods
function constructors.hashfeatures(specification)
local features=specification.features
if features then
- local t,tn={},0
- for category,list in next,features do
+ local t,n={},0
+ for category,list in sortedhash(features) do
if next(list) then
local hasher=hashmethods[category]
if hasher then
local hash=hasher(list)
if hash then
- tn=tn+1
- t[tn]=category..":"..hash
+ n=n+1
+ t[n]=category..":"..hash
end
end
end
end
- if tn>0 then
+ if n>0 then
return concat(t," & ")
end
end
@@ -6631,7 +9986,17 @@ hashmethods.normal=function(list)
elseif k=="number" or k=="features" then
else
n=n+1
- s[n]=k..'='..tostring(v)
+ if type(v)=="table" then
+ local t={}
+ local m=0
+ for k,v in next,v do
+ m=m+1
+ t[m]=k..'='..tostring(v)
+ end
+ s[n]=k..'={'..concat(t,",").."}"
+ else
+ s[n]=k..'='..tostring(v)
+ end
end
end
if n>0 then
@@ -6646,13 +10011,15 @@ function constructors.hashinstance(specification,force)
specification.hash=hash
end
if size<1000 and designsizes[hash] then
- size=math.round(constructors.scaled(size,designsizes[hash]))
- specification.size=size
+ size=round(constructors.scaled(size,designsizes[hash]))
+ else
+ size=round(size)
end
+ specification.size=size
if fallbacks then
- return hash..' @ '..tostring(size)..' @ '..fallbacks
+ return hash..' @ '..size..' @ '..fallbacks
else
- return hash..' @ '..tostring(size)
+ return hash..' @ '..size
end
end
function constructors.setname(tfmdata,specification)
@@ -6833,10 +10200,12 @@ do
local handler=handlers[format]
local enhancers=handler.enhancers
if not enhancers then
- local actions=allocate()
+ local actions=allocate()
local before=allocate()
local after=allocate()
local order=allocate()
+ local known={}
+ local nofsteps=0
local patches={ before=before,after=after }
local trace=false
local report=logs.reporter("fonts",format.." enhancing")
@@ -6858,7 +10227,7 @@ do
report("%s enhancing file %a","start",filename)
end
ioflush()
- for e=1,#order do
+ for e=1,nofsteps do
local enhancer=order[e]
local b=before[enhancer]
if b then
@@ -6868,7 +10237,7 @@ do
end
end
end
- enhance(enhancer,data,filename,raw)
+ enhance(enhancer,data,filename,raw)
local a=after[enhancer]
if a then
for pattern,action in next,a do
@@ -6888,7 +10257,9 @@ do
if action then
if actions[what] then
else
- order[#order+1]=what
+ nofsteps=nofsteps+1
+ order[nofsteps]=what
+ known[what]=nofsteps
end
actions[what]=action
else
@@ -6902,7 +10273,12 @@ do
if ww then
ww[pattern]=action
else
- pw[where]={ [pattern]=action}
+ pw[where]={ [pattern]=action }
+ if not known[where] then
+ nofsteps=nofsteps+1
+ order[nofsteps]=where
+ known[where]=nofsteps
+ end
end
end
end
@@ -6910,7 +10286,11 @@ do
register=register,
apply=apply,
patch=patch,
- patches={ register=patch },
+ report=report,
+ patches={
+ register=patch,
+ report=report,
+ },
}
handler.enhancers=enhancers
end
@@ -7070,8 +10450,8 @@ if not modules then modules={} end modules ['luatex-font-enc']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
local fonts=fonts
local encodings={}
@@ -7080,7 +10460,7 @@ encodings.agl={}
encodings.known={}
setmetatable(encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
- texio.write(" <loading (extended) adobe glyph list>")
+ logs.report("fonts","loading (extended) adobe glyph list")
local unicodes=dofile(resolvers.findfile("font-age.lua"))
encodings.agl={ unicodes=unicodes }
return unicodes
@@ -7136,7 +10516,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-cid']={
version=1.001,
- comment="companion to font-otf.lua (cidmaps)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
@@ -7297,12 +10677,12 @@ if not modules then modules={} end modules ['font-map']={
local tonumber,next,type=tonumber,next,type
local match,format,find,concat,gsub,lower=string.match,string.format,string.find,table.concat,string.gsub,string.lower
local P,R,S,C,Ct,Cc,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.match
-local floor=math.floor
local formatters=string.formatters
local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
+local rshift=bit32.rshift
local trace_loading=false trackers.register("fonts.loading",function(v) trace_loading=v end)
local trace_mapping=false trackers.register("fonts.mapping",function(v) trace_mapping=v end)
-local report_fonts=logs.reporter("fonts","loading")
+local report_fonts=logs.reporter("fonts","loading")
local force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end)
local fonts=fonts or {}
local mappings=fonts.mappings or {}
@@ -7337,7 +10717,7 @@ local function tounicode16(unicode)
return f_single(unicode)
else
unicode=unicode-0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
+ return f_double(rshift(unicode,10)+0xD800,unicode%1024+0xDC00)
end
end
local function tounicode16sequence(unicodes)
@@ -7348,32 +10728,40 @@ local function tounicode16sequence(unicodes)
t[l]=f_single(u)
else
u=u-0x10000
- t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
+ t[l]=f_double(rshift(u,10)+0xD800,u%1024+0xDC00)
end
end
return concat(t)
end
-local function tounicode(unicode,name)
- if type(unicode)=="table" then
- local t={}
- for l=1,#unicode do
- local u=unicode[l]
- if u<0xD7FF or (u>0xDFFF and u<=0xFFFF) then
- t[l]=f_single(u)
- else
- u=u-0x10000
- t[l]=f_double(floor(u/1024)+0xD800,u%1024+0xDC00)
- end
- end
- return concat(t)
+local unknown=f_single(0xFFFD)
+local hash={}
+local conc={}
+table.setmetatableindex(hash,function(t,k)
+ if type(k)=="table" then
+ local n=#k
+ for l=1,n do
+ conc[l]=hash[k[l]]
+ end
+ return concat(conc,"",1,n)
+ end
+ local v
+ if k>=0x00E000 and k<=0x00F8FF then
+ v=unknown
+ elseif k>=0x0F0000 and k<=0x0FFFFF then
+ v=unknown
+ elseif k>=0x100000 and k<=0x10FFFF then
+ v=unknown
+ elseif k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then
+ v=f_single(k)
else
- if unicode<0xD7FF or (unicode>0xDFFF and unicode<=0xFFFF) then
- return f_single(unicode)
- else
- unicode=unicode-0x10000
- return f_double(floor(unicode/1024)+0xD800,unicode%1024+0xDC00)
- end
+ k=k-0x10000
+ v=f_double(rshift(k,10)+0xD800,k%1024+0xDC00)
end
+ t[k]=v
+ return v
+end)
+local function tounicode(unicode)
+ return hash[unicode]
end
local function fromunicode16(str)
if #str==4 then
@@ -7392,7 +10780,7 @@ local ligseparator=P("_")
local varseparator=P(".")
local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0)
do
- local overloads=allocate {
+ local overloads={
IJ={ name="I_J",unicode={ 0x49,0x4A },mess=0x0132 },
ij={ name="i_j",unicode={ 0x69,0x6A },mess=0x0133 },
ff={ name="f_f",unicode={ 0x66,0x66 },mess=0xFB00 },
@@ -7403,7 +10791,7 @@ do
fj={ name="f_j",unicode={ 0x66,0x6A } },
fk={ name="f_k",unicode={ 0x66,0x6B } },
}
- local o={}
+ local o=allocate {}
for k,v in next,overloads do
local name=v.name
local mess=v.mess
@@ -7417,7 +10805,7 @@ do
end
mappings.overloads=o
end
-function mappings.addtounicode(data,filename,checklookups)
+function mappings.addtounicode(data,filename,checklookups,forceligatures)
local resources=data.resources
local unicodes=resources.unicodes
if not unicodes then
@@ -7586,34 +10974,46 @@ function mappings.addtounicode(data,filename,checklookups)
if type(checklookups)=="function" then
checklookups(data,missing,nofmissing)
end
- local collected=false
local unicoded=0
- for i=1,#dlist do
- local du=dlist[i]
- local glyph=descriptions[du]
- if glyph.class=="ligature" and (force_ligatures or not glyph.unicode) then
- if not collected then
- collected=fonts.handlers.otf.readers.getcomponents(data)
- if not collected then
- break
- end
+ local collected=fonts.handlers.otf.readers.getcomponents(data)
+ local function resolve(glyph,u)
+ local n=#u
+ for i=1,n do
+ if u[i]>private then
+ n=0
+ break
end
- local u=collected[du]
- if u then
- local n=#u
- for i=1,n do
- if u[i]>private then
- n=0
- break
- end
+ end
+ if n>0 then
+ if n>1 then
+ glyph.unicode=u
+ else
+ glyph.unicode=u[1]
+ end
+ unicoded=unicoded+1
+ end
+ end
+ if not collected then
+ elseif forceligatures or force_ligatures then
+ for i=1,#dlist do
+ local du=dlist[i]
+ if du>=private or (du>=0xE000 and du<=0xF8FF) then
+ local u=collected[du]
+ if u then
+ resolve(descriptions[du],u)
end
- if n>0 then
- if n>1 then
- glyph.unicode=u
- else
- glyph.unicode=u[1]
+ end
+ end
+ else
+ for i=1,#dlist do
+ local du=dlist[i]
+ if du>=private or (du>=0xE000 and du<=0xF8FF) then
+ local glyph=descriptions[du]
+ if glyph.class=="ligature" and not glyph.unicode then
+ local u=collected[du]
+ if u then
+ resolve(glyph,u)
end
- unicoded=unicoded+1
end
end
end
@@ -7660,8 +11060,8 @@ if not modules then modules={} end modules ['luatex-fonts-syn']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
local fonts=fonts
fonts.names=fonts.names or {}
@@ -7672,11 +11072,11 @@ local data=nil
local loaded=false
local fileformats={ "lua","tex","other text files" }
function fonts.names.reportmissingbase()
- texio.write("<missing font database, run: mtxrun --script fonts --reload --simple>")
+ logs.report("fonts","missing font database, run: mtxrun --script fonts --reload --simple")
fonts.names.reportmissingbase=nil
end
function fonts.names.reportmissingname()
- texio.write("<unknown font in database, run: mtxrun --script fonts --reload --simple>")
+ logs.report("fonts","unknown font in font database, run: mtxrun --script fonts --reload --simple")
fonts.names.reportmissingname=nil
end
function fonts.names.resolve(name,sub)
@@ -7691,7 +11091,7 @@ function fonts.names.resolve(name,sub)
local foundname=resolvers.findfile(basename,format) or ""
if foundname~="" then
data=dofile(foundname)
- texio.write("<font database loaded: ",foundname,">")
+ logs.report("fonts","font database '%s' loaded",foundname)
break
end
end
@@ -7729,146 +11129,79 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-oti']={
+if not modules then modules={} end modules ['font-vfc']={
version=1.001,
- comment="companion to font-ini.mkiv",
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local lower=string.lower
+local select=select
+local insert=table.insert
local fonts=fonts
-local constructors=fonts.constructors
-local otf=constructors.handlers.otf
-local otffeatures=constructors.features.otf
-local registerotffeature=otffeatures.register
-local otftables=otf.tables or {}
-otf.tables=otftables
-local allocate=utilities.storage.allocate
-registerotffeature {
- name="features",
- description="initialization of feature handler",
- default=true,
-}
-local function setmode(tfmdata,value)
- if value then
- tfmdata.properties.mode=lower(value)
- end
-end
-otf.modeinitializer=setmode
-local function setlanguage(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local languages=otftables and otftables.languages
- local properties=tfmdata.properties
- if not languages then
- properties.language=cleanvalue
- elseif languages[value] then
- properties.language=cleanvalue
- else
- properties.language="dflt"
+local helpers=fonts.helpers
+local setmetatableindex=table.setmetatableindex
+local makeweak=table.makeweak
+local push={ "push" }
+local pop={ "pop" }
+local dummy={ "comment" }
+function helpers.prependcommands(commands,...)
+ insert(commands,1,push)
+ for i=select("#",...),1,-1 do
+ local s=select(i,...)
+ if s then
+ insert(commands,1,s)
end
end
+ insert(commands,pop)
+ return commands
end
-local function setscript(tfmdata,value)
- if value then
- local cleanvalue=lower(value)
- local scripts=otftables and otftables.scripts
- local properties=tfmdata.properties
- if not scripts then
- properties.script=cleanvalue
- elseif scripts[value] then
- properties.script=cleanvalue
- else
- properties.script="dflt"
+function helpers.appendcommands(commands,...)
+ insert(commands,1,push)
+ insert(commands,pop)
+ for i=1,select("#",...) do
+ local s=select(i,...)
+ if s then
+ insert(commands,s)
end
end
+ return commands
end
-registerotffeature {
- name="mode",
- description="mode",
- initializers={
- base=setmode,
- node=setmode,
- plug=setmode,
- }
-}
-registerotffeature {
- name="language",
- description="language",
- initializers={
- base=setlanguage,
- node=setlanguage,
- plug=setlanguage,
- }
-}
-registerotffeature {
- name="script",
- description="script",
- initializers={
- base=setscript,
- node=setscript,
- plug=setscript,
- }
-}
-otftables.featuretypes=allocate {
- gpos_single="position",
- gpos_pair="position",
- gpos_cursive="position",
- gpos_mark2base="position",
- gpos_mark2ligature="position",
- gpos_mark2mark="position",
- gpos_context="position",
- gpos_contextchain="position",
- gsub_single="substitution",
- gsub_multiple="substitution",
- gsub_alternate="substitution",
- gsub_ligature="substitution",
- gsub_context="substitution",
- gsub_contextchain="substitution",
- gsub_reversecontextchain="substitution",
- gsub_reversesub="substitution",
+local char=setmetatableindex(function(t,k)
+ local v={ "slot",0,k }
+ t[k]=v
+ return v
+end)
+local right=setmetatableindex(function(t,k)
+ local v={ "right",k }
+ t[k]=v
+ return v
+end)
+local left=setmetatableindex(function(t,k)
+ local v={ "right",-k }
+ t[k]=v
+ return v
+end)
+local down=setmetatableindex(function(t,k)
+ local v={ "down",k }
+ t[k]=v
+ return v
+end)
+local up=setmetatableindex(function(t,k)
+ local v={ "down",-k }
+ t[k]=v
+ return v
+end)
+helpers.commands=utilities.storage.allocate {
+ char=char,
+ right=right,
+ left=left,
+ down=down,
+ up=up,
+ push=push,
+ pop=pop,
+ dummy=dummy,
}
-function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
- if featuretype=="position" then
- local default=scripts.dflt
- if default then
- if autoscript=="position" or autoscript==true then
- return default
- else
- report_otf("script feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=scripts.dflt
- if default then
- if autoscript=="substitution" or autoscript==true then
- return default
- end
- end
- end
-end
-function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
- if featuretype=="position" then
- local default=languages.dflt
- if default then
- if autolanguage=="position" or autolanguage==true then
- return default
- else
- report_otf("language feature %s not applied, enable default positioning")
- end
- else
- end
- elseif featuretype=="substitution" then
- local default=languages.dflt
- if default then
- if autolanguage=="substitution" or autolanguage==true then
- return default
- end
- end
- end
-end
end -- closure
@@ -7881,21 +11214,21 @@ if not modules then modules={} end modules ['font-otr']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local next,type,unpack=next,type,unpack
-local byte,lower,char,strip,gsub=string.byte,string.lower,string.char,string.strip,string.gsub
-local bittest=bit32.btest
-local concat,remove,unpack,fastcopy=table.concat,table.remov,table.unpack,table.fastcopy
-local floor,abs,sqrt,round=math.floor,math.abs,math.sqrt,math.round
+local next,type,tonumber=next,type,tonumber
+local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub
+local floor,round=math.floor,math.round
local 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
local lpegmatch=lpeg.match
+local rshift=bit32.rshift
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
-local stripstring=string.strip
+local stripstring=string.nospaces
local utf16_to_utf8_be=utf.utf16_to_utf8_be
local report=logs.reporter("otf reader")
local trace_cmap=false
+local trace_cmap_detail=false
fonts=fonts or {}
local handlers=fonts.handlers or {}
fonts.handlers=handlers
@@ -7920,27 +11253,50 @@ local readulong=streamreader.readcardinal4
local readshort=streamreader.readinteger2
local readlong=streamreader.readinteger4
local readfixed=streamreader.readfixed4
+local read2dot14=streamreader.read2dot14
local readfword=readshort
local readufword=readushort
local readoffset=readushort
-local read2dot14=streamreader.read2dot14
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
function streamreader.readtag(f)
- return lower(strip(readstring(f,4)))
-end
+ return lower(stripstring(readstring(f,4)))
+end
+local short=2
+local ushort=2
+local ulong=4
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ openfile=streamreader.open
+ closefile=streamreader.close
+ setposition=streamreader.setposition
+ skipshort=streamreader.skipshort
+ readbytes=streamreader.readbytes
+ readstring=streamreader.readstring
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readuint=streamreader.readcardinal3
+ readulong=streamreader.readcardinal4
+ readshort=streamreader.readinteger2
+ readlong=streamreader.readinteger4
+ readfixed=streamreader.readfixed4
+ read2dot14=streamreader.read2dot14
+ readfword=readshort
+ readufword=readushort
+ readoffset=readushort
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+ function streamreader.readtag(f)
+ return lower(stripstring(readstring(f,4)))
+ end
+end)
local function readlongdatetime(f)
local a,b,c,d,e,f,g,h=readbytes(f,8)
return 0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
end
local tableversion=0.004
readers.tableversion=tableversion
-local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
-local reportedskipped={}
-local function reportskippedtable(tag)
- if not reportedskipped[tag] then
- report("loading of table %a skipped (reported once only)",tag)
- reportedskipped[tag]=true
- end
-end
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local reservednames={ [0]="copyright",
"family",
"subfamily",
@@ -7966,6 +11322,7 @@ local reservednames={ [0]="copyright",
"wwssubfamily",
"lightbackgroundpalette",
"darkbackgroundpalette",
+ "variationspostscriptnameprefix",
}
local platforms={ [0]="unicode",
"macintosh",
@@ -8131,6 +11488,37 @@ local panosewidths={
[ 8]="verycondensed",
[ 9]="monospaced",
}
+local helpers={}
+readers.helpers=helpers
+local function gotodatatable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable=fontdata.tables[tag]
+ if datatable then
+ local tableoffset=datatable.offset
+ setposition(f,tableoffset)
+ return tableoffset
+ end
+ end
+end
+local function reportskippedtable(f,fontdata,tag,criterium)
+ if criterium and f then
+ local datatable=fontdata.tables[tag]
+ if datatable then
+ report("loading of table %a skipped",tag)
+ end
+ end
+end
+local function setvariabledata(fontdata,tag,data)
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ variabledata[tag]=data
+ else
+ fontdata.variabledata={ [tag]=data }
+ end
+end
+helpers.gotodatatable=gotodatatable
+helpers.setvariabledata=setvariabledata
+helpers.reportskippedtable=reportskippedtable
local platformnames={
postscriptname=true,
fullname=true,
@@ -8141,13 +11529,12 @@ local platformnames={
compatiblefullname=true,
}
function readers.name(f,fontdata,specification)
- local datatable=fontdata.tables.name
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"name",true)
+ if tableoffset then
local format=readushort(f)
local nofnames=readushort(f)
local offset=readushort(f)
- local start=datatable.offset+offset
+ local start=tableoffset+offset
local namelists={
unicode={},
windows={},
@@ -8166,19 +11553,17 @@ function readers.name(f,fontdata,specification)
local encoding=encodings[encoding]
local language=languages[language]
if encoding and language then
- local name=reservednames[readushort(f)]
- if name then
- namelist[#namelist+1]={
- platform=platform,
- encoding=encoding,
- language=language,
- name=name,
- length=readushort(f),
- offset=start+readushort(f),
- }
- else
- skipshort(f,2)
- end
+ local index=readushort(f)
+ local name=reservednames[index]
+ namelist[#namelist+1]={
+ platform=platform,
+ encoding=encoding,
+ language=language,
+ name=name,
+ index=index,
+ length=readushort(f),
+ offset=start+readushort(f),
+ }
else
skipshort(f,3)
end
@@ -8194,12 +11579,14 @@ function readers.name(f,fontdata,specification)
end
local names={}
local done={}
+ local extras={}
local function filter(platform,e,l)
local namelist=namelists[platform]
for i=1,#namelist do
local name=namelist[i]
local nametag=name.name
- if not done[nametag] then
+ local index=name.index
+ if not done[nametag or i] then
local encoding=name.encoding
local language=name.language
if (not e or encoding==e) and (not l or language==l) then
@@ -8212,13 +11599,16 @@ function readers.name(f,fontdata,specification)
if decoder then
content=decoder(content)
end
- names[nametag]={
- content=content,
- platform=platform,
- encoding=encoding,
- language=language,
- }
- done[nametag]=true
+ if nametag then
+ names[nametag]={
+ content=content,
+ platform=platform,
+ encoding=encoding,
+ language=language,
+ }
+ end
+ extras[index]=content
+ done[nametag or i]=true
end
end
end
@@ -8229,6 +11619,7 @@ function readers.name(f,fontdata,specification)
filter("macintosh")
filter("unicode")
fontdata.names=names
+ fontdata.extras=extras
if specification.platformnames then
local collected={}
for platform,namelist in next,namelists do
@@ -8276,9 +11667,8 @@ local function getname(fontdata,key)
end
end
readers["os/2"]=function(f,fontdata)
- local datatable=fontdata.tables["os/2"]
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"os/2",true)
+ if tableoffset then
local version=readushort(f)
local windowsmetrics={
version=version,
@@ -8328,9 +11718,8 @@ readers["os/2"]=function(f,fontdata)
end
end
readers.head=function(f,fontdata)
- local datatable=fontdata.tables.head
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"head",true)
+ if tableoffset then
local fontheader={
version=readfixed(f),
revision=readfixed(f),
@@ -8357,178 +11746,155 @@ readers.head=function(f,fontdata)
fontdata.nofglyphs=0
end
readers.hhea=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.hhea
- if datatable then
- setposition(f,datatable.offset)
- fontdata.horizontalheader={
- version=readfixed(f),
- ascender=readfword(f),
- descender=readfword(f),
- linegap=readfword(f),
- maxadvancewidth=readufword(f),
- minleftsidebearing=readfword(f),
- minrightsidebearing=readfword(f),
- maxextent=readfword(f),
- caretsloperise=readshort(f),
- caretsloperun=readshort(f),
- caretoffset=readshort(f),
- reserved_1=readshort(f),
- reserved_2=readshort(f),
- reserved_3=readshort(f),
- reserved_4=readshort(f),
- metricdataformat=readshort(f),
- nofmetrics=readushort(f),
- }
- else
- fontdata.horizontalheader={
- nofmetrics=0,
- }
- end
+ local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details)
+ if tableoffset then
+ fontdata.horizontalheader={
+ version=readfixed(f),
+ ascender=readfword(f),
+ descender=readfword(f),
+ linegap=readfword(f),
+ maxadvancewidth=readufword(f),
+ minleftsidebearing=readfword(f),
+ minrightsidebearing=readfword(f),
+ maxextent=readfword(f),
+ caretsloperise=readshort(f),
+ caretsloperun=readshort(f),
+ caretoffset=readshort(f),
+ reserved_1=readshort(f),
+ reserved_2=readshort(f),
+ reserved_3=readshort(f),
+ reserved_4=readshort(f),
+ metricdataformat=readshort(f),
+ nofmetrics=readushort(f),
+ }
+ else
+ fontdata.horizontalheader={
+ nofmetrics=0,
+ }
end
end
readers.vhea=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.vhea
- if datatable then
- setposition(f,datatable.offset)
- local version=readfixed(f)
- fontdata.verticalheader={
+ local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details)
+ if tableoffset then
+ fontdata.verticalheader={
+ version=readfixed(f),
+ ascender=readfword(f),
+ descender=readfword(f),
+ linegap=readfword(f),
+ maxadvanceheight=readufword(f),
+ mintopsidebearing=readfword(f),
+ minbottomsidebearing=readfword(f),
+ maxextent=readfword(f),
+ caretsloperise=readshort(f),
+ caretsloperun=readshort(f),
+ caretoffset=readshort(f),
+ reserved_1=readshort(f),
+ reserved_2=readshort(f),
+ reserved_3=readshort(f),
+ reserved_4=readshort(f),
+ metricdataformat=readshort(f),
+ nofmetrics=readushort(f),
+ }
+ else
+ fontdata.verticalheader={
+ nofmetrics=0,
+ }
+ end
+end
+readers.maxp=function(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"maxp",specification.details)
+ if tableoffset then
+ local version=readfixed(f)
+ local nofglyphs=readushort(f)
+ fontdata.nofglyphs=nofglyphs
+ if version==0.5 then
+ fontdata.maximumprofile={
version=version,
- ascender=readfword(f),
- descender=readfword(f),
- linegap=readfword(f),
- maxadvanceheight=readufword(f),
- mintopsidebearing=readfword(f),
- minbottomsidebearing=readfword(f),
- maxextent=readfword(f),
- caretsloperise=readshort(f),
- caretsloperun=readshort(f),
- caretoffset=readshort(f),
- reserved_1=readshort(f),
- reserved_2=readshort(f),
- reserved_3=readshort(f),
- reserved_4=readshort(f),
- metricdataformat=readshort(f),
- nofmetrics=readushort(f),
+ nofglyphs=nofglyphs,
+ }
+ elseif version==1.0 then
+ fontdata.maximumprofile={
+ version=version,
+ nofglyphs=nofglyphs,
+ points=readushort(f),
+ contours=readushort(f),
+ compositepoints=readushort(f),
+ compositecontours=readushort(f),
+ zones=readushort(f),
+ twilightpoints=readushort(f),
+ storage=readushort(f),
+ functiondefs=readushort(f),
+ instructiondefs=readushort(f),
+ stackelements=readushort(f),
+ sizeofinstructions=readushort(f),
+ componentelements=readushort(f),
+ componentdepth=readushort(f),
}
else
- fontdata.verticalheader={
- nofmetrics=0,
+ fontdata.maximumprofile={
+ version=version,
+ nofglyphs=0,
}
end
end
end
-readers.maxp=function(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.maxp
- if datatable then
- setposition(f,datatable.offset)
- local version=readfixed(f)
- local nofglyphs=readushort(f)
- fontdata.nofglyphs=nofglyphs
- if version==0.5 then
- fontdata.maximumprofile={
- version=version,
- nofglyphs=nofglyphs,
- }
- return
- elseif version==1.0 then
- fontdata.maximumprofile={
- version=version,
- nofglyphs=nofglyphs,
- points=readushort(f),
- contours=readushort(f),
- compositepoints=readushort(f),
- compositecontours=readushort(f),
- zones=readushort(f),
- twilightpoints=readushort(f),
- storage=readushort(f),
- functiondefs=readushort(f),
- instructiondefs=readushort(f),
- stackelements=readushort(f),
- sizeofinstructions=readushort(f),
- componentelements=readushort(f),
- componentdepth=readushort(f),
- }
- return
- end
- end
- fontdata.maximumprofile={
- version=version,
- nofglyphs=0,
- }
- end
-end
readers.hmtx=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.hmtx
- if datatable then
- setposition(f,datatable.offset)
- local horizontalheader=fontdata.horizontalheader
- local nofmetrics=horizontalheader.nofmetrics
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local width=0
- local leftsidebearing=0
- for i=0,nofmetrics-1 do
- local glyph=glyphs[i]
- width=readshort(f)
- leftsidebearing=readshort(f)
- if width~=0 then
- glyph.width=width
- end
+ local tableoffset=gotodatatable(f,fontdata,"hmtx",specification.glyphs)
+ if tableoffset then
+ local horizontalheader=fontdata.horizontalheader
+ local nofmetrics=horizontalheader.nofmetrics
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local width=0
+ local leftsidebearing=0
+ for i=0,nofmetrics-1 do
+ local glyph=glyphs[i]
+ width=readshort(f)
+ leftsidebearing=readshort(f)
+ if width~=0 then
+ glyph.width=width
end
- for i=nofmetrics,nofglyphs-1 do
- local glyph=glyphs[i]
- if width~=0 then
- glyph.width=width
- end
+ end
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph=glyphs[i]
+ if width~=0 then
+ glyph.width=width
end
end
end
end
readers.vmtx=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.vmtx
- if datatable then
- setposition(f,datatable.offset)
- local verticalheader=fontdata.verticalheader
- local nofmetrics=verticalheader.nofmetrics
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local vheight=0
- local vdefault=verticalheader.ascender+verticalheader.descender
- local topsidebearing=0
- for i=0,nofmetrics-1 do
- local glyph=glyphs[i]
- vheight=readshort(f)
- topsidebearing=readshort(f)
- if vheight~=0 and vheight~=vdefault then
- glyph.vheight=vheight
- end
+ local tableoffset=gotodatatable(f,fontdata,"vmtx",specification.glyphs)
+ if tableoffset then
+ local verticalheader=fontdata.verticalheader
+ local nofmetrics=verticalheader.nofmetrics
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local vheight=0
+ local vdefault=verticalheader.ascender+verticalheader.descender
+ local topsidebearing=0
+ for i=0,nofmetrics-1 do
+ local glyph=glyphs[i]
+ vheight=readshort(f)
+ topsidebearing=readshort(f)
+ if vheight~=0 and vheight~=vdefault then
+ glyph.vheight=vheight
end
- for i=nofmetrics,nofglyphs-1 do
- local glyph=glyphs[i]
- if vheight~=0 and vheight~=vdefault then
- glyph.vheight=vheight
- end
+ end
+ for i=nofmetrics,nofglyphs-1 do
+ local glyph=glyphs[i]
+ if vheight~=0 and vheight~=vdefault then
+ glyph.vheight=vheight
end
end
end
end
readers.vorg=function(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.vorg
- if datatable then
- report("todo: %s","vorg")
- end
- end
+ reportskippedtable(f,fontdata,"vorg",specification.glyphs)
end
readers.post=function(f,fontdata,specification)
- local datatable=fontdata.tables.post
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"post",true)
+ if tableoffset then
local version=readfixed(f)
fontdata.postscript={
version=version,
@@ -8585,9 +11951,7 @@ readers.post=function(f,fontdata,specification)
end
end
readers.cff=function(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cff")
- end
+ reportskippedtable(f,fontdata,"cff",specification.glyphs)
end
local formatreaders={}
local duplicatestoo=true
@@ -8599,11 +11963,13 @@ local sequence={
{ 0,0,6 },
{ 3,0,6 },
{ 0,5,14 },
+{ 0,4,12 },
{ 3,10,13 },
}
local supported={}
for i=1,#sequence do
- local sp,se,sf=unpack(sequence[i])
+ local si=sequence[i]
+ local sp,se,sf=si[1],si[2],si[3]
local p=supported[sp]
if not p then
p={}
@@ -8622,32 +11988,17 @@ formatreaders[4]=function(f,fontdata,offset)
local language=readushort(f)
local nofsegments=readushort(f)/2
skipshort(f,3)
- local endchars={}
- local startchars={}
- local deltas={}
- local offsets={}
- local indices={}
local mapping=fontdata.mapping
local glyphs=fontdata.glyphs
local duplicates=fontdata.duplicates
local nofdone=0
- for i=1,nofsegments do
- endchars[i]=readushort(f)
- end
+ local endchars=readcardinaltable(f,nofsegments,ushort)
local reserved=readushort(f)
- for i=1,nofsegments do
- startchars[i]=readushort(f)
- end
- for i=1,nofsegments do
- deltas[i]=readshort(f)
- end
- for i=1,nofsegments do
- offsets[i]=readushort(f)
- end
- local size=(length-2*2-5*2-4*nofsegments*2)/2
- for i=1,size-1 do
- indices[i]=readushort(f)
- end
+ local startchars=readcardinaltable(f,nofsegments,ushort)
+ local deltas=readcardinaltable(f,nofsegments,ushort)
+ local offsets=readcardinaltable(f,nofsegments,ushort)
+ local size=(length-2*2-5*2-4*2*nofsegments)/2
+ local indices=readcardinaltable(f,size-1,ushort)
for segment=1,nofsegments do
local startchar=startchars[segment]
local endchar=endchars[segment]
@@ -8657,7 +12008,7 @@ formatreaders[4]=function(f,fontdata,offset)
elseif startchar==0xFFFF and offset==0 then
elseif offset==0xFFFF then
elseif offset==0 then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar+delta)%65536)
end
for unicode=startchar,endchar do
@@ -8689,7 +12040,7 @@ formatreaders[4]=function(f,fontdata,offset)
end
else
local shift=(segment-nofsegments+offset/2)-startchar
- if trace_cmap then
+ if trace_cmap_detail then
report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536)
end
for unicode=startchar,endchar do
@@ -8737,7 +12088,7 @@ formatreaders[6]=function(f,fontdata,offset)
local count=readushort(f)
local stop=start+count-1
local nofdone=0
- if trace_cmap then
+ if trace_cmap_detail then
report("format 6 from %C to %C",2,start,stop)
end
for unicode=start,stop do
@@ -8770,7 +12121,7 @@ formatreaders[12]=function(f,fontdata,offset)
local first=readulong(f)
local last=readulong(f)
local index=readulong(f)
- if trace_cmap then
+ if trace_cmap_detail then
report("format 12 from %C to %C starts at index %i",first,last,index)
end
for unicode=first,last do
@@ -8809,7 +12160,7 @@ formatreaders[13]=function(f,fontdata,offset)
local last=readulong(f)
local index=readulong(f)
if first<privateoffset then
- if trace_cmap then
+ if trace_cmap_detail then
report("format 13 from %C to %C get index %i",first,last,index)
end
local glyph=glyphs[index]
@@ -8899,75 +12250,81 @@ local function checkcmap(f,fontdata,records,platform,encoding,format)
local p=platforms[platform]
local e=encodings[p]
local n=reader(f,fontdata,data) or 0
- report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ if trace_cmap then
+ report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n)
+ end
return n
end
function readers.cmap(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.cmap
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- local noftables=readushort(f)
- local records={}
- local unicodecid=false
- local variantcid=false
- local variants={}
- local duplicates=fontdata.duplicates or {}
- fontdata.duplicates=duplicates
- for i=1,noftables do
- local platform=readushort(f)
- local encoding=readushort(f)
- local offset=readulong(f)
- local record=records[platform]
- if not record then
- records[platform]={
- [encoding]={
- offsets={ offset },
- formats={},
- }
+ local tableoffset=gotodatatable(f,fontdata,"cmap",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local noftables=readushort(f)
+ local records={}
+ local unicodecid=false
+ local variantcid=false
+ local variants={}
+ local duplicates=fontdata.duplicates or {}
+ fontdata.duplicates=duplicates
+ for i=1,noftables do
+ local platform=readushort(f)
+ local encoding=readushort(f)
+ local offset=readulong(f)
+ local record=records[platform]
+ if not record then
+ records[platform]={
+ [encoding]={
+ offsets={ offset },
+ formats={},
+ }
+ }
+ else
+ local subtables=record[encoding]
+ if not subtables then
+ record[encoding]={
+ offsets={ offset },
+ formats={},
}
else
- local subtables=record[encoding]
- if not subtables then
- record[encoding]={
- offsets={ offset },
- formats={},
- }
- else
- local offsets=subtables.offsets
- offsets[#offsets+1]=offset
- end
+ local offsets=subtables.offsets
+ offsets[#offsets+1]=offset
end
end
+ end
+ if trace_cmap then
report("found cmaps:")
- for platform,record in sortedhash(records) do
- local p=platforms[platform]
- local e=encodings[p]
- local sp=supported[platform]
- local ps=p or "?"
+ end
+ for platform,record in sortedhash(records) do
+ local p=platforms[platform]
+ local e=encodings[p]
+ local sp=supported[platform]
+ local ps=p or "?"
+ if trace_cmap then
if sp then
report(" platform %i: %s",platform,ps)
else
report(" platform %i: %s (unsupported)",platform,ps)
end
- for encoding,subtables in sortedhash(record) do
- local se=sp and sp[encoding]
- local es=e and e[encoding] or "?"
+ end
+ for encoding,subtables in sortedhash(record) do
+ local se=sp and sp[encoding]
+ local es=e and e[encoding] or "?"
+ if trace_cmap then
if se then
report(" encoding %i: %s",encoding,es)
else
report(" encoding %i: %s (unsupported)",encoding,es)
end
- local offsets=subtables.offsets
- local formats=subtables.formats
- for i=1,#offsets do
- local offset=tableoffset+offsets[i]
- setposition(f,offset)
- formats[readushort(f)]=offset
- end
- record[encoding]=formats
+ end
+ local offsets=subtables.offsets
+ local formats=subtables.formats
+ for i=1,#offsets do
+ local offset=tableoffset+offsets[i]
+ setposition(f,offset)
+ formats[readushort(f)]=offset
+ end
+ record[encoding]=formats
+ if trace_cmap then
local list=sortedkeys(formats)
for i=1,#list do
if not (se and se[list[i]]) then
@@ -8977,112 +12334,110 @@ function readers.cmap(f,fontdata,specification)
report(" formats: % t",list)
end
end
- local ok=false
- for i=1,#sequence do
- local sp,se,sf=unpack(sequence[i])
- if checkcmap(f,fontdata,records,sp,se,sf)>0 then
- ok=true
- end
- end
- if not ok then
- report("no useable unicode cmap found")
+ end
+ local ok=false
+ for i=1,#sequence do
+ local si=sequence[i]
+ local sp,se,sf=si[1],si[2],si[3]
+ if checkcmap(f,fontdata,records,sp,se,sf)>0 then
+ ok=true
end
- fontdata.cidmaps={
- version=version,
- noftables=noftables,
- records=records,
- }
- else
- fontdata.cidmaps={}
end
+ if not ok then
+ report("no useable unicode cmap found")
+ end
+ fontdata.cidmaps={
+ version=version,
+ noftables=noftables,
+ records=records,
+ }
+ else
+ fontdata.cidmaps={}
end
end
function readers.loca(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("loca")
- end
+ reportskippedtable(f,fontdata,"loca",specification.glyphs)
end
function readers.glyf(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("glyf")
- end
+ reportskippedtable(f,fontdata,"glyf",specification.glyphs)
end
function readers.colr(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("colr")
- end
+ reportskippedtable(f,fontdata,"colr",specification.glyphs)
end
function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("cpal")
- end
+ reportskippedtable(f,fontdata,"cpal",specification.glyphs)
end
function readers.svg(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("svg")
- end
+ reportskippedtable(f,fontdata,"svg",specification.glyphs)
+end
+function readers.sbix(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"sbix",specification.glyphs)
+end
+function readers.cbdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cbdt",specification.glyphs)
+end
+function readers.cblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"cblc",specification.glyphs)
+end
+function readers.ebdt(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebdt",specification.glyphs)
+end
+function readers.ebsc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"ebsc",specification.glyphs)
+end
+function readers.eblc(f,fontdata,specification)
+ reportskippedtable(f,fontdata,"eblc",specification.glyphs)
end
function readers.kern(f,fontdata,specification)
- if specification.kerns then
- local datatable=fontdata.tables.kern
- if datatable then
- setposition(f,datatable.offset)
+ local tableoffset=gotodatatable(f,fontdata,"kern",specification.kerns)
+ if tableoffset then
+ local version=readushort(f)
+ local noftables=readushort(f)
+ for i=1,noftables do
local version=readushort(f)
- local noftables=readushort(f)
- for i=1,noftables do
- local version=readushort(f)
- local length=readushort(f)
- local coverage=readushort(f)
- local format=bit32.rshift(coverage,8)
- if format==0 then
- local nofpairs=readushort(f)
- local searchrange=readushort(f)
- local entryselector=readushort(f)
- local rangeshift=readushort(f)
- local kerns={}
- local glyphs=fontdata.glyphs
- for i=1,nofpairs do
- local left=readushort(f)
- local right=readushort(f)
- local kern=readfword(f)
- local glyph=glyphs[left]
- local kerns=glyph.kerns
- if kerns then
- kerns[right]=kern
- else
- glyph.kerns={ [right]=kern }
- end
+ local length=readushort(f)
+ local coverage=readushort(f)
+ local format=rshift(coverage,8)
+ if format==0 then
+ local nofpairs=readushort(f)
+ local searchrange=readushort(f)
+ local entryselector=readushort(f)
+ local rangeshift=readushort(f)
+ local kerns={}
+ local glyphs=fontdata.glyphs
+ for i=1,nofpairs do
+ local left=readushort(f)
+ local right=readushort(f)
+ local kern=readfword(f)
+ local glyph=glyphs[left]
+ local kerns=glyph.kerns
+ if kerns then
+ kerns[right]=kern
+ else
+ glyph.kerns={ [right]=kern }
end
- elseif format==2 then
- report("todo: kern classes")
- else
- report("todo: kerns")
end
+ elseif format==2 then
+ report("todo: kern classes")
+ else
+ report("todo: kerns")
end
end
end
end
function readers.gdef(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gdef")
- end
+ reportskippedtable(f,fontdata,"gdef",specification.details)
end
function readers.gsub(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gsub")
- end
+ reportskippedtable(f,fontdata,"gsub",specification.details)
end
function readers.gpos(f,fontdata,specification)
- if specification.details then
- reportskippedtable("gpos")
- end
+ reportskippedtable(f,fontdata,"gpos",specification.details)
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- reportskippedtable("math")
- end
+ reportskippedtable(f,fontdata,"math",specification.details)
end
-local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
+local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames)
local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata
local names=fontdata.names
local info=nil
@@ -9106,6 +12461,25 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
if not familyname then familyname=family end
if not subfamilyname then subfamilyname=subfamily end
end
+ if platformnames then
+ platformnames=fontdata.platformnames
+ end
+ if instancenames then
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata and variabledata.instances
+ if instances then
+ instancenames={}
+ for i=1,#instances do
+ instancenames[i]=lower(stripstring(instances[i].subfamily))
+ end
+ else
+ instancenames=nil
+ end
+ else
+ instancenames=nil
+ end
+ end
info={
subfontindex=fontdata.subfontindex or sub or 0,
version=getname(fontdata,"version"),
@@ -9133,7 +12507,8 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo)
capheight=metrics.capheight,
ascender=metrics.typoascender,
descender=metrics.typodescender,
- platformnames=platformnames and fontdata.platformnames or nil,
+ platformnames=platformnames or nil,
+ instancenames=instancenames or nil,
}
if metricstoo then
local keys={
@@ -9187,6 +12562,7 @@ local function loadtables(f,specification,offset)
entryselector=readushort(f),
rangeshift=readushort(f),
tables=tables,
+ foundtables=false,
}
for i=1,fontdata.noftables do
local tag=lower(stripstring(readstring(f,4)))
@@ -9202,7 +12578,8 @@ local function loadtables(f,specification,offset)
length=length,
}
end
- if tables.cff then
+ fontdata.foundtables=sortedkeys(tables)
+ if tables.cff or tables.cff2 then
fontdata.format="opentype"
else
fontdata.format="truetype"
@@ -9220,12 +12597,25 @@ local function prepareglyps(fontdata)
fontdata.glyphs=glyphs
fontdata.mapping={}
end
+local function readtable(tag,f,fontdata,specification,...)
+ local reader=readers[tag]
+ if reader then
+ reader(f,fontdata,specification,...)
+ end
+end
+local variablefonts_supported=(context and true) or (logs and logs.application and true) or false
local function readdata(f,offset,specification)
local fontdata=loadtables(f,specification,offset)
if specification.glyphs then
prepareglyps(fontdata)
end
- readers["name"](f,fontdata,specification)
+ if not variablefonts_supported then
+ specification.instance=nil
+ specification.variable=nil
+ specification.factors=nil
+ end
+ fontdata.temporary={}
+ readtable("name",f,fontdata,specification)
local askedname=specification.askedname
if askedname then
local fullname=getname(fontdata,"fullname") or ""
@@ -9235,27 +12625,95 @@ local function readdata(f,offset,specification)
return
end
end
- readers["os/2"](f,fontdata,specification)
- readers["head"](f,fontdata,specification)
- readers["maxp"](f,fontdata,specification)
- readers["hhea"](f,fontdata,specification)
- readers["vhea"](f,fontdata,specification)
- readers["hmtx"](f,fontdata,specification)
- readers["vmtx"](f,fontdata,specification)
- readers["vorg"](f,fontdata,specification)
- readers["post"](f,fontdata,specification)
- readers["cff" ](f,fontdata,specification)
- readers["cmap"](f,fontdata,specification)
- readers["loca"](f,fontdata,specification)
- readers["glyf"](f,fontdata,specification)
- readers["colr"](f,fontdata,specification)
- readers["cpal"](f,fontdata,specification)
- readers["svg" ](f,fontdata,specification)
- readers["kern"](f,fontdata,specification)
- readers["gdef"](f,fontdata,specification)
- readers["gsub"](f,fontdata,specification)
- readers["gpos"](f,fontdata,specification)
- readers["math"](f,fontdata,specification)
+ readtable("stat",f,fontdata,specification)
+ readtable("avar",f,fontdata,specification)
+ readtable("fvar",f,fontdata,specification)
+ if variablefonts_supported then
+ local variabledata=fontdata.variabledata
+ if variabledata then
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ if axis and (not instances or #instances==0) then
+ instances={}
+ variabledata.instances=instances
+ local function add(n,subfamily,value)
+ local values={}
+ for i=1,#axis do
+ local a=axis[i]
+ values[i]={
+ axis=a.tag,
+ value=i==n and value or a.default,
+ }
+ end
+ instances[#instances+1]={
+ subfamily=subfamily,
+ values=values,
+ }
+ end
+ for i=1,#axis do
+ local a=axis[i]
+ local tag=a.tag
+ add(i,"default"..tag,a.default)
+ add(i,"minimum"..tag,a.minimum)
+ add(i,"maximum"..tag,a.maximum)
+ end
+ end
+ end
+ if not specification.factors then
+ local instance=specification.instance
+ if type(instance)=="string" then
+ local factors=helpers.getfactors(fontdata,instance)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ fontdata.instance=instance
+ report("user instance: %s, factors: % t",instance,factors)
+ else
+ report("user instance: %s, bad factors",instance)
+ end
+ end
+ end
+ if not fontdata.factors then
+ if fontdata.variabledata then
+ local factors=helpers.getfactors(fontdata,true)
+ if factors then
+ specification.factors=factors
+ fontdata.factors=factors
+ end
+ else
+ end
+ end
+ end
+ readtable("os/2",f,fontdata,specification)
+ readtable("head",f,fontdata,specification)
+ readtable("maxp",f,fontdata,specification)
+ readtable("hhea",f,fontdata,specification)
+ readtable("vhea",f,fontdata,specification)
+ readtable("hmtx",f,fontdata,specification)
+ readtable("vmtx",f,fontdata,specification)
+ readtable("vorg",f,fontdata,specification)
+ readtable("post",f,fontdata,specification)
+ readtable("mvar",f,fontdata,specification)
+ readtable("hvar",f,fontdata,specification)
+ readtable("vvar",f,fontdata,specification)
+ readtable("gdef",f,fontdata,specification)
+ readtable("cff",f,fontdata,specification)
+ readtable("cff2",f,fontdata,specification)
+ readtable("cmap",f,fontdata,specification)
+ readtable("loca",f,fontdata,specification)
+ readtable("glyf",f,fontdata,specification)
+ readtable("colr",f,fontdata,specification)
+ readtable("cpal",f,fontdata,specification)
+ readtable("svg",f,fontdata,specification)
+ readtable("sbix",f,fontdata,specification)
+ readtable("cbdt",f,fontdata,specification)
+ readtable("cblc",f,fontdata,specification)
+ readtable("ebdt",f,fontdata,specification)
+ readtable("eblc",f,fontdata,specification)
+ readtable("kern",f,fontdata,specification)
+ readtable("gsub",f,fontdata,specification)
+ readtable("gpos",f,fontdata,specification)
+ readtable("math",f,fontdata,specification)
fontdata.locations=nil
fontdata.tables=nil
fontdata.cidmaps=nil
@@ -9282,12 +12740,9 @@ local function loadfontdata(specification)
fontdata=readdata(f,0,specification)
elseif version=="ttcf" then
local subfont=tonumber(specification.subfont)
- local offsets={}
local ttcversion=readulong(f)
local nofsubfonts=readulong(f)
- for i=1,nofsubfonts do
- offsets[i]=readulong(f)
- end
+ local offsets=readcardinaltable(f,nofsubfonts,ulong)
if subfont then
if subfont>=1 and subfont<=nofsubfonts then
fontdata=readdata(f,offsets[subfont],specification)
@@ -9332,7 +12787,7 @@ local function loadfontdata(specification)
return fontdata or {}
end
end
-local function loadfont(specification,n)
+local function loadfont(specification,n,instance)
if type(specification)=="string" then
specification={
filename=specification,
@@ -9341,10 +12796,12 @@ local function loadfont(specification,n)
glyphs=true,
shapes=true,
kerns=true,
+ variable=true,
globalkerns=true,
lookups=true,
subfont=n or true,
tounicode=false,
+ instance=instance
}
end
if specification.shapes or specification.lookups or specification.kerns then
@@ -9359,6 +12816,10 @@ local function loadfont(specification,n)
if specification.platformnames then
specification.platformnames=true
end
+ if specification.instance or instance then
+ specification.variable=true
+ specification.instance=specification.instance or instance
+ end
local function message(str)
report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback())
end
@@ -9367,11 +12828,14 @@ local function loadfont(specification,n)
return result
end
end
-function readers.loadshapes(filename,n)
+function readers.loadshapes(filename,n,instance,streams)
local fontdata=loadfont {
filename=filename,
shapes=true,
+ streams=streams,
+ variable=true,
subfont=n,
+ instance=instance,
}
if fontdata then
for k,v in next,fontdata.glyphs do
@@ -9392,13 +12856,15 @@ function readers.loadshapes(filename,n)
units=0,
}
end
-function readers.loadfont(filename,n)
+function readers.loadfont(filename,n,instance)
local fontdata=loadfont {
filename=filename,
glyphs=true,
shapes=false,
lookups=true,
+ variable=true,
subfont=n,
+ instance=instance,
}
if fontdata then
return {
@@ -9410,11 +12876,13 @@ function readers.loadfont(filename,n)
descriptions=fontdata.descriptions,
format=fontdata.format,
goodies={},
- metadata=getinfo(fontdata,n,false,false,true),
+ metadata=getinfo(fontdata,n,false,false,true,true),
properties={
hasitalics=fontdata.hasitalics or false,
maxcolorclass=fontdata.maxcolorclass,
hascolor=fontdata.hascolor or false,
+ instance=fontdata.instance,
+ factors=fontdata.factors,
},
resources={
filename=filename,
@@ -9432,6 +12900,9 @@ function readers.loadfont(filename,n)
mathconstants=fontdata.mathconstants,
colorpalettes=fontdata.colorpalettes,
svgshapes=fontdata.svgshapes,
+ sbixshapes=fontdata.sbixshapes,
+ variabledata=fontdata.variabledata,
+ foundtables=fontdata.foundtables,
},
}
end
@@ -9440,6 +12911,7 @@ function readers.getinfo(filename,specification)
local subfont=nil
local platformnames=false
local rawfamilynames=false
+ local instancenames=true
if type(specification)=="table" then
subfont=tonumber(specification.subfont)
platformnames=specification.platformnames
@@ -9451,19 +12923,20 @@ function readers.getinfo(filename,specification)
filename=filename,
details=true,
platformnames=platformnames,
+ instancenames=true,
}
if fontdata then
local subfonts=fontdata.subfonts
if not subfonts then
- return getinfo(fontdata,nil,platformnames,rawfamilynames)
+ return getinfo(fontdata,nil,platformnames,rawfamilynames,false,instancenames)
elseif not subfont then
local info={}
for i=1,#subfonts do
- info[i]=getinfo(fontdata,i,platformnames,rawfamilynames)
+ info[i]=getinfo(fontdata,i,platformnames,rawfamilynames,false,instancenames)
end
return info
elseif subfont>=1 and subfont<=#subfonts then
- return getinfo(fontdata,subfont,platformnames,rawfamilynames)
+ return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames)
else
return {
filename=filename,
@@ -9514,6 +12987,1199 @@ end -- closure
do -- begin closure to overcome local limits and interference
+if not modules then modules={} end modules ['font-oti']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local lower=string.lower
+local fonts=fonts
+local constructors=fonts.constructors
+local otf=constructors.handlers.otf
+local otffeatures=constructors.features.otf
+local registerotffeature=otffeatures.register
+local otftables=otf.tables or {}
+otf.tables=otftables
+local allocate=utilities.storage.allocate
+registerotffeature {
+ name="features",
+ description="initialization of feature handler",
+ default=true,
+}
+local function setmode(tfmdata,value)
+ if value then
+ tfmdata.properties.mode=lower(value)
+ end
+end
+otf.modeinitializer=setmode
+local function setlanguage(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local languages=otftables and otftables.languages
+ local properties=tfmdata.properties
+ if not languages then
+ properties.language=cleanvalue
+ elseif languages[value] then
+ properties.language=cleanvalue
+ else
+ properties.language="dflt"
+ end
+ end
+end
+local function setscript(tfmdata,value)
+ if value then
+ local cleanvalue=lower(value)
+ local scripts=otftables and otftables.scripts
+ local properties=tfmdata.properties
+ if not scripts then
+ properties.script=cleanvalue
+ elseif scripts[value] then
+ properties.script=cleanvalue
+ else
+ properties.script="dflt"
+ end
+ end
+end
+registerotffeature {
+ name="mode",
+ description="mode",
+ initializers={
+ base=setmode,
+ node=setmode,
+ plug=setmode,
+ }
+}
+registerotffeature {
+ name="language",
+ description="language",
+ initializers={
+ base=setlanguage,
+ node=setlanguage,
+ plug=setlanguage,
+ }
+}
+registerotffeature {
+ name="script",
+ description="script",
+ initializers={
+ base=setscript,
+ node=setscript,
+ plug=setscript,
+ }
+}
+otftables.featuretypes=allocate {
+ gpos_single="position",
+ gpos_pair="position",
+ gpos_cursive="position",
+ gpos_mark2base="position",
+ gpos_mark2ligature="position",
+ gpos_mark2mark="position",
+ gpos_context="position",
+ gpos_contextchain="position",
+ gsub_single="substitution",
+ gsub_multiple="substitution",
+ gsub_alternate="substitution",
+ gsub_ligature="substitution",
+ gsub_context="substitution",
+ gsub_contextchain="substitution",
+ gsub_reversecontextchain="substitution",
+ gsub_reversesub="substitution",
+}
+function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts)
+ if featuretype=="position" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="position" or autoscript==true then
+ return default
+ else
+ report_otf("script feature %s not applied, enable default positioning")
+ end
+ else
+ end
+ elseif featuretype=="substitution" then
+ local default=scripts.dflt
+ if default then
+ if autoscript=="substitution" or autoscript==true then
+ return default
+ end
+ end
+ end
+end
+function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages)
+ if featuretype=="position" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="position" or autolanguage==true then
+ return default
+ else
+ report_otf("language feature %s not applied, enable default positioning")
+ end
+ else
+ end
+ elseif featuretype=="substitution" then
+ local default=languages.dflt
+ if default then
+ if autolanguage=="substitution" or autolanguage==true then
+ return default
+ end
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ["font-ott"]={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files",
+}
+local type,next,tonumber,tostring,rawget,rawset=type,next,tonumber,tostring,rawget,rawset
+local gsub,lower,format,match,gmatch,find=string.gsub,string.lower,string.format,string.match,string.gmatch,string.find
+local sequenced=table.sequenced
+local is_boolean=string.is_boolean
+local setmetatableindex=table.setmetatableindex
+local setmetatablenewindex=table.setmetatablenewindex
+local allocate=utilities.storage.allocate
+local fonts=fonts
+local otf=fonts.handlers.otf
+local otffeatures=otf.features
+local tables=otf.tables or {}
+otf.tables=tables
+local statistics=otf.statistics or {}
+otf.statistics=statistics
+local scripts=allocate {
+ ["arab"]="arabic",
+ ["armi"]="imperial aramaic",
+ ["armn"]="armenian",
+ ["avst"]="avestan",
+ ["bali"]="balinese",
+ ["bamu"]="bamum",
+ ["batk"]="batak",
+ ["beng"]="bengali",
+ ["bng2"]="bengali variant 2",
+ ["bopo"]="bopomofo",
+ ["brah"]="brahmi",
+ ["brai"]="braille",
+ ["bugi"]="buginese",
+ ["buhd"]="buhid",
+ ["byzm"]="byzantine music",
+ ["cakm"]="chakma",
+ ["cans"]="canadian syllabics",
+ ["cari"]="carian",
+ ["cham"]="cham",
+ ["cher"]="cherokee",
+ ["copt"]="coptic",
+ ["cprt"]="cypriot syllabary",
+ ["cyrl"]="cyrillic",
+ ["deva"]="devanagari",
+ ["dev2"]="devanagari variant 2",
+ ["dsrt"]="deseret",
+ ["egyp"]="egyptian heiroglyphs",
+ ["ethi"]="ethiopic",
+ ["geor"]="georgian",
+ ["glag"]="glagolitic",
+ ["goth"]="gothic",
+ ["grek"]="greek",
+ ["gujr"]="gujarati",
+ ["gjr2"]="gujarati variant 2",
+ ["guru"]="gurmukhi",
+ ["gur2"]="gurmukhi variant 2",
+ ["hang"]="hangul",
+ ["hani"]="cjk ideographic",
+ ["hano"]="hanunoo",
+ ["hebr"]="hebrew",
+ ["ital"]="old italic",
+ ["jamo"]="hangul jamo",
+ ["java"]="javanese",
+ ["kali"]="kayah li",
+ ["kana"]="hiragana and katakana",
+ ["khar"]="kharosthi",
+ ["khmr"]="khmer",
+ ["knda"]="kannada",
+ ["knd2"]="kannada variant 2",
+ ["kthi"]="kaithi",
+ ["lana"]="tai tham",
+ ["lao" ]="lao",
+ ["latn"]="latin",
+ ["lepc"]="lepcha",
+ ["limb"]="limbu",
+ ["linb"]="linear b",
+ ["lisu"]="lisu",
+ ["lyci"]="lycian",
+ ["lydi"]="lydian",
+ ["mand"]="mandaic and mandaean",
+ ["math"]="mathematical alphanumeric symbols",
+ ["merc"]="meroitic cursive",
+ ["mero"]="meroitic hieroglyphs",
+ ["mlym"]="malayalam",
+ ["mlm2"]="malayalam variant 2",
+ ["mong"]="mongolian",
+ ["mtei"]="meitei Mayek",
+ ["musc"]="musical symbols",
+ ["mym2"]="myanmar variant 2",
+ ["mymr"]="myanmar",
+ ["nko" ]='n"ko',
+ ["ogam"]="ogham",
+ ["olck"]="ol chiki",
+ ["orkh"]="old turkic and orkhon runic",
+ ["orya"]="oriya",
+ ["ory2"]="odia variant 2",
+ ["osma"]="osmanya",
+ ["phag"]="phags-pa",
+ ["phli"]="inscriptional pahlavi",
+ ["phnx"]="phoenician",
+ ["prti"]="inscriptional parthian",
+ ["rjng"]="rejang",
+ ["runr"]="runic",
+ ["samr"]="samaritan",
+ ["sarb"]="old south arabian",
+ ["saur"]="saurashtra",
+ ["shaw"]="shavian",
+ ["shrd"]="sharada",
+ ["sinh"]="sinhala",
+ ["sora"]="sora sompeng",
+ ["sund"]="sundanese",
+ ["sylo"]="syloti nagri",
+ ["syrc"]="syriac",
+ ["tagb"]="tagbanwa",
+ ["takr"]="takri",
+ ["tale"]="tai le",
+ ["talu"]="tai lu",
+ ["taml"]="tamil",
+ ["tavt"]="tai viet",
+ ["telu"]="telugu",
+ ["tel2"]="telugu variant 2",
+ ["tfng"]="tifinagh",
+ ["tglg"]="tagalog",
+ ["thaa"]="thaana",
+ ["thai"]="thai",
+ ["tibt"]="tibetan",
+ ["tml2"]="tamil variant 2",
+ ["ugar"]="ugaritic cuneiform",
+ ["vai" ]="vai",
+ ["xpeo"]="old persian cuneiform",
+ ["xsux"]="sumero-akkadian cuneiform",
+ ["yi" ]="yi",
+}
+local languages=allocate {
+ ["aba" ]="abaza",
+ ["abk" ]="abkhazian",
+ ["ach" ]="acholi",
+ ["acr" ]="achi",
+ ["ady" ]="adyghe",
+ ["afk" ]="afrikaans",
+ ["afr" ]="afar",
+ ["agw" ]="agaw",
+ ["aio" ]="aiton",
+ ["aka" ]="akan",
+ ["als" ]="alsatian",
+ ["alt" ]="altai",
+ ["amh" ]="amharic",
+ ["ang" ]="anglo-saxon",
+ ["apph"]="phonetic transcription—americanist conventions",
+ ["ara" ]="arabic",
+ ["arg" ]="aragonese",
+ ["ari" ]="aari",
+ ["ark" ]="rakhine",
+ ["asm" ]="assamese",
+ ["ast" ]="asturian",
+ ["ath" ]="athapaskan",
+ ["avr" ]="avar",
+ ["awa" ]="awadhi",
+ ["aym" ]="aymara",
+ ["azb" ]="torki",
+ ["aze" ]="azerbaijani",
+ ["bad" ]="badaga",
+ ["bad0"]="banda",
+ ["bag" ]="baghelkhandi",
+ ["bal" ]="balkar",
+ ["ban" ]="balinese",
+ ["bar" ]="bavarian",
+ ["bau" ]="baulé",
+ ["bbc" ]="batak toba",
+ ["bbr" ]="berber",
+ ["bch" ]="bench",
+ ["bcr" ]="bible cree",
+ ["bdy" ]="bandjalang",
+ ["bel" ]="belarussian",
+ ["bem" ]="bemba",
+ ["ben" ]="bengali",
+ ["bgc" ]="haryanvi",
+ ["bgq" ]="bagri",
+ ["bgr" ]="bulgarian",
+ ["bhi" ]="bhili",
+ ["bho" ]="bhojpuri",
+ ["bik" ]="bikol",
+ ["bil" ]="bilen",
+ ["bis" ]="bislama",
+ ["bjj" ]="kanauji",
+ ["bkf" ]="blackfoot",
+ ["bli" ]="baluchi",
+ ["blk" ]="pa'o karen",
+ ["bln" ]="balante",
+ ["blt" ]="balti",
+ ["bmb" ]="bambara (bamanankan)",
+ ["bml" ]="bamileke",
+ ["bos" ]="bosnian",
+ ["bpy" ]="bishnupriya manipuri",
+ ["bre" ]="breton",
+ ["brh" ]="brahui",
+ ["bri" ]="braj bhasha",
+ ["brm" ]="burmese",
+ ["brx" ]="bodo",
+ ["bsh" ]="bashkir",
+ ["bti" ]="beti",
+ ["bts" ]="batak simalungun",
+ ["bug" ]="bugis",
+ ["cak" ]="kaqchikel",
+ ["cat" ]="catalan",
+ ["cbk" ]="zamboanga chavacano",
+ ["ceb" ]="cebuano",
+ ["cgg" ]="chiga",
+ ["cha" ]="chamorro",
+ ["che" ]="chechen",
+ ["chg" ]="chaha gurage",
+ ["chh" ]="chattisgarhi",
+ ["chi" ]="chichewa (chewa, nyanja)",
+ ["chk" ]="chukchi",
+ ["chk0"]="chuukese",
+ ["cho" ]="choctaw",
+ ["chp" ]="chipewyan",
+ ["chr" ]="cherokee",
+ ["chu" ]="chuvash",
+ ["chy" ]="cheyenne",
+ ["cmr" ]="comorian",
+ ["cop" ]="coptic",
+ ["cor" ]="cornish",
+ ["cos" ]="corsican",
+ ["cpp" ]="creoles",
+ ["cre" ]="cree",
+ ["crr" ]="carrier",
+ ["crt" ]="crimean tatar",
+ ["csb" ]="kashubian",
+ ["csl" ]="church slavonic",
+ ["csy" ]="czech",
+ ["ctg" ]="chittagonian",
+ ["cuk" ]="san blas kuna",
+ ["dan" ]="danish",
+ ["dar" ]="dargwa",
+ ["dax" ]="dayi",
+ ["dcr" ]="woods cree",
+ ["deu" ]="german",
+ ["dgo" ]="dogri",
+ ["dgr" ]="dogri",
+ ["dhg" ]="dhangu",
+ ["dhv" ]="divehi (dhivehi, maldivian)",
+ ["diq" ]="dimli",
+ ["div" ]="divehi (dhivehi, maldivian)",
+ ["djr" ]="zarma",
+ ["djr0"]="djambarrpuyngu",
+ ["dng" ]="dangme",
+ ["dnj" ]="dan",
+ ["dnk" ]="dinka",
+ ["dri" ]="dari",
+ ["duj" ]="dhuwal",
+ ["dun" ]="dungan",
+ ["dzn" ]="dzongkha",
+ ["ebi" ]="ebira",
+ ["ecr" ]="eastern cree",
+ ["edo" ]="edo",
+ ["efi" ]="efik",
+ ["ell" ]="greek",
+ ["emk" ]="eastern maninkakan",
+ ["eng" ]="english",
+ ["erz" ]="erzya",
+ ["esp" ]="spanish",
+ ["esu" ]="central yupik",
+ ["eti" ]="estonian",
+ ["euq" ]="basque",
+ ["evk" ]="evenki",
+ ["evn" ]="even",
+ ["ewe" ]="ewe",
+ ["fan" ]="french antillean",
+ ["fan0"]=" fang",
+ ["far" ]="persian",
+ ["fat" ]="fanti",
+ ["fin" ]="finnish",
+ ["fji" ]="fijian",
+ ["fle" ]="dutch (flemish)",
+ ["fne" ]="forest nenets",
+ ["fon" ]="fon",
+ ["fos" ]="faroese",
+ ["fra" ]="french",
+ ["frc" ]="cajun french",
+ ["fri" ]="frisian",
+ ["frl" ]="friulian",
+ ["frp" ]="arpitan",
+ ["fta" ]="futa",
+ ["ful" ]="fulah",
+ ["fuv" ]="nigerian fulfulde",
+ ["gad" ]="ga",
+ ["gae" ]="scottish gaelic (gaelic)",
+ ["gag" ]="gagauz",
+ ["gal" ]="galician",
+ ["gar" ]="garshuni",
+ ["gaw" ]="garhwali",
+ ["gez" ]="ge'ez",
+ ["gih" ]="githabul",
+ ["gil" ]="gilyak",
+ ["gil0"]="kiribati (gilbertese)",
+ ["gkp" ]="kpelle (guinea)",
+ ["glk" ]="gilaki",
+ ["gmz" ]="gumuz",
+ ["gnn" ]="gumatj",
+ ["gog" ]="gogo",
+ ["gon" ]="gondi",
+ ["grn" ]="greenlandic",
+ ["gro" ]="garo",
+ ["gua" ]="guarani",
+ ["guc" ]="wayuu",
+ ["guf" ]="gupapuyngu",
+ ["guj" ]="gujarati",
+ ["guz" ]="gusii",
+ ["hai" ]="haitian (haitian creole)",
+ ["hal" ]="halam",
+ ["har" ]="harauti",
+ ["hau" ]="hausa",
+ ["haw" ]="hawaiian",
+ ["hay" ]="haya",
+ ["haz" ]="hazaragi",
+ ["hbn" ]="hammer-banna",
+ ["her" ]="herero",
+ ["hil" ]="hiligaynon",
+ ["hin" ]="hindi",
+ ["hma" ]="high mari",
+ ["hmn" ]="hmong",
+ ["hmo" ]="hiri motu",
+ ["hnd" ]="hindko",
+ ["ho" ]="ho",
+ ["hri" ]="harari",
+ ["hrv" ]="croatian",
+ ["hun" ]="hungarian",
+ ["hye" ]="armenian",
+ ["hye0"]="armenian east",
+ ["iba" ]="iban",
+ ["ibb" ]="ibibio",
+ ["ibo" ]="igbo",
+ ["ido" ]="ido",
+ ["ijo" ]="ijo languages",
+ ["ile" ]="interlingue",
+ ["ilo" ]="ilokano",
+ ["ina" ]="interlingua",
+ ["ind" ]="indonesian",
+ ["ing" ]="ingush",
+ ["inu" ]="inuktitut",
+ ["ipk" ]="inupiat",
+ ["ipph"]="phonetic transcription—ipa conventions",
+ ["iri" ]="irish",
+ ["irt" ]="irish traditional",
+ ["isl" ]="icelandic",
+ ["ism" ]="inari sami",
+ ["ita" ]="italian",
+ ["iwr" ]="hebrew",
+ ["jam" ]="jamaican creole",
+ ["jan" ]="japanese",
+ ["jav" ]="javanese",
+ ["jbo" ]="lojban",
+ ["jii" ]="yiddish",
+ ["jud" ]="ladino",
+ ["jul" ]="jula",
+ ["kab" ]="kabardian",
+ ["kab0"]="kabyle",
+ ["kac" ]="kachchi",
+ ["kal" ]="kalenjin",
+ ["kan" ]="kannada",
+ ["kar" ]="karachay",
+ ["kat" ]="georgian",
+ ["kaz" ]="kazakh",
+ ["kde" ]="makonde",
+ ["kea" ]="kabuverdianu (crioulo)",
+ ["keb" ]="kebena",
+ ["kek" ]="kekchi",
+ ["kge" ]="khutsuri georgian",
+ ["kha" ]="khakass",
+ ["khk" ]="khanty-kazim",
+ ["khm" ]="khmer",
+ ["khs" ]="khanty-shurishkar",
+ ["kht" ]="khamti shan",
+ ["khv" ]="khanty-vakhi",
+ ["khw" ]="khowar",
+ ["kik" ]="kikuyu (gikuyu)",
+ ["kir" ]="kirghiz (kyrgyz)",
+ ["kis" ]="kisii",
+ ["kiu" ]="kirmanjki",
+ ["kjd" ]="southern kiwai",
+ ["kjp" ]="eastern pwo karen",
+ ["kkn" ]="kokni",
+ ["klm" ]="kalmyk",
+ ["kmb" ]="kamba",
+ ["kmn" ]="kumaoni",
+ ["kmo" ]="komo",
+ ["kms" ]="komso",
+ ["knr" ]="kanuri",
+ ["kod" ]="kodagu",
+ ["koh" ]="korean old hangul",
+ ["kok" ]="konkani",
+ ["kom" ]="komi",
+ ["kon" ]="kikongo",
+ ["kon0"]="kongo",
+ ["kop" ]="komi-permyak",
+ ["kor" ]="korean",
+ ["kos" ]="kosraean",
+ ["koz" ]="komi-zyrian",
+ ["kpl" ]="kpelle",
+ ["kri" ]="krio",
+ ["krk" ]="karakalpak",
+ ["krl" ]="karelian",
+ ["krm" ]="karaim",
+ ["krn" ]="karen",
+ ["krt" ]="koorete",
+ ["ksh" ]="kashmiri",
+ ["ksh0"]="ripuarian",
+ ["ksi" ]="khasi",
+ ["ksm" ]="kildin sami",
+ ["ksw" ]="s’gaw karen",
+ ["kua" ]="kuanyama",
+ ["kui" ]="kui",
+ ["kul" ]="kulvi",
+ ["kum" ]="kumyk",
+ ["kur" ]="kurdish",
+ ["kuu" ]="kurukh",
+ ["kuy" ]="kuy",
+ ["kyk" ]="koryak",
+ ["kyu" ]="western kayah",
+ ["lad" ]="ladin",
+ ["lah" ]="lahuli",
+ ["lak" ]="lak",
+ ["lam" ]="lambani",
+ ["lao" ]="lao",
+ ["lat" ]="latin",
+ ["laz" ]="laz",
+ ["lcr" ]="l-cree",
+ ["ldk" ]="ladakhi",
+ ["lez" ]="lezgi",
+ ["lij" ]="ligurian",
+ ["lim" ]="limburgish",
+ ["lin" ]="lingala",
+ ["lis" ]="lisu",
+ ["ljp" ]="lampung",
+ ["lki" ]="laki",
+ ["lma" ]="low mari",
+ ["lmb" ]="limbu",
+ ["lmo" ]="lombard",
+ ["lmw" ]="lomwe",
+ ["lom" ]="loma",
+ ["lrc" ]="luri",
+ ["lsb" ]="lower sorbian",
+ ["lsm" ]="lule sami",
+ ["lth" ]="lithuanian",
+ ["ltz" ]="luxembourgish",
+ ["lua" ]="luba-lulua",
+ ["lub" ]="luba-katanga",
+ ["lug" ]="ganda",
+ ["luh" ]="luyia",
+ ["luo" ]="luo",
+ ["lvi" ]="latvian",
+ ["mad" ]="madura",
+ ["mag" ]="magahi",
+ ["mah" ]="marshallese",
+ ["maj" ]="majang",
+ ["mak" ]="makhuwa",
+ ["mal" ]="malayalam reformed",
+ ["mam" ]="mam",
+ ["man" ]="mansi",
+ ["map" ]="mapudungun",
+ ["mar" ]="marathi",
+ ["maw" ]="marwari",
+ ["mbn" ]="mbundu",
+ ["mch" ]="manchu",
+ ["mcr" ]="moose cree",
+ ["mde" ]="mende",
+ ["mdr" ]="mandar",
+ ["men" ]="me'en",
+ ["mer" ]="meru",
+ ["mfe" ]="morisyen",
+ ["min" ]="minangkabau",
+ ["miz" ]="mizo",
+ ["mkd" ]="macedonian",
+ ["mkr" ]="makasar",
+ ["mkw" ]="kituba",
+ ["mle" ]="male",
+ ["mlg" ]="malagasy",
+ ["mln" ]="malinke",
+ ["mly" ]="malay",
+ ["mnd" ]="mandinka",
+ ["mng" ]="mongolian",
+ ["mni" ]="manipuri",
+ ["mnk" ]="maninka",
+ ["mnx" ]="manx",
+ ["moh" ]="mohawk",
+ ["mok" ]="moksha",
+ ["mol" ]="moldavian",
+ ["mon" ]="mon",
+ ["mor" ]="moroccan",
+ ["mos" ]="mossi",
+ ["mri" ]="maori",
+ ["mth" ]="maithili",
+ ["mts" ]="maltese",
+ ["mun" ]="mundari",
+ ["mus" ]="muscogee",
+ ["mwl" ]="mirandese",
+ ["mww" ]="hmong daw",
+ ["myn" ]="mayan",
+ ["mzn" ]="mazanderani",
+ ["nag" ]="naga-assamese",
+ ["nah" ]="nahuatl",
+ ["nan" ]="nanai",
+ ["nap" ]="neapolitan",
+ ["nas" ]="naskapi",
+ ["nau" ]="nauruan",
+ ["nav" ]="navajo",
+ ["ncr" ]="n-cree",
+ ["ndb" ]="ndebele",
+ ["ndc" ]="ndau",
+ ["ndg" ]="ndonga",
+ ["nds" ]="low saxon",
+ ["nep" ]="nepali",
+ ["new" ]="newari",
+ ["nga" ]="ngbaka",
+ ["ngr" ]="nagari",
+ ["nhc" ]="norway house cree",
+ ["nis" ]="nisi",
+ ["niu" ]="niuean",
+ ["nkl" ]="nyankole",
+ ["nko" ]="n'ko",
+ ["nld" ]="dutch",
+ ["noe" ]="nimadi",
+ ["nog" ]="nogai",
+ ["nor" ]="norwegian",
+ ["nov" ]="novial",
+ ["nsm" ]="northern sami",
+ ["nso" ]="sotho, northern",
+ ["nta" ]="northern tai",
+ ["nto" ]="esperanto",
+ ["nym" ]="nyamwezi",
+ ["nyn" ]="norwegian nynorsk",
+ ["oci" ]="occitan",
+ ["ocr" ]="oji-cree",
+ ["ojb" ]="ojibway",
+ ["ori" ]="odia",
+ ["oro" ]="oromo",
+ ["oss" ]="ossetian",
+ ["paa" ]="palestinian aramaic",
+ ["pag" ]="pangasinan",
+ ["pal" ]="pali",
+ ["pam" ]="pampangan",
+ ["pan" ]="punjabi",
+ ["pap" ]="palpa",
+ ["pap0"]="papiamentu",
+ ["pas" ]="pashto",
+ ["pau" ]="palauan",
+ ["pcc" ]="bouyei",
+ ["pcd" ]="picard",
+ ["pdc" ]="pennsylvania german",
+ ["pgr" ]="polytonic greek",
+ ["phk" ]="phake",
+ ["pih" ]="norfolk",
+ ["pil" ]="filipino",
+ ["plg" ]="palaung",
+ ["plk" ]="polish",
+ ["pms" ]="piemontese",
+ ["pnb" ]="western panjabi",
+ ["poh" ]="pocomchi",
+ ["pon" ]="pohnpeian",
+ ["pro" ]="provencal",
+ ["ptg" ]="portuguese",
+ ["pwo" ]="western pwo karen",
+ ["qin" ]="chin",
+ ["quc" ]="k’iche’",
+ ["quh" ]="quechua (bolivia)",
+ ["quz" ]="quechua",
+ ["qvi" ]="quechua (ecuador)",
+ ["qwh" ]="quechua (peru)",
+ ["raj" ]="rajasthani",
+ ["rar" ]="rarotongan",
+ ["rbu" ]="russian buriat",
+ ["rcr" ]="r-cree",
+ ["rej" ]="rejang",
+ ["ria" ]="riang",
+ ["rif" ]="tarifit",
+ ["rit" ]="ritarungo",
+ ["rkw" ]="arakwal",
+ ["rms" ]="romansh",
+ ["rmy" ]="vlax romani",
+ ["rom" ]="romanian",
+ ["roy" ]="romany",
+ ["rsy" ]="rusyn",
+ ["rtm" ]="rotuman",
+ ["rua" ]="kinyarwanda",
+ ["run" ]="rundi",
+ ["rup" ]="aromanian",
+ ["rus" ]="russian",
+ ["sad" ]="sadri",
+ ["san" ]="sanskrit",
+ ["sas" ]="sasak",
+ ["sat" ]="santali",
+ ["say" ]="sayisi",
+ ["scn" ]="sicilian",
+ ["sco" ]="scots",
+ ["sek" ]="sekota",
+ ["sel" ]="selkup",
+ ["sga" ]="old irish",
+ ["sgo" ]="sango",
+ ["sgs" ]="samogitian",
+ ["shi" ]="tachelhit",
+ ["shn" ]="shan",
+ ["sib" ]="sibe",
+ ["sid" ]="sidamo",
+ ["sig" ]="silte gurage",
+ ["sks" ]="skolt sami",
+ ["sky" ]="slovak",
+ ["sla" ]="slavey",
+ ["slv" ]="slovenian",
+ ["sml" ]="somali",
+ ["smo" ]="samoan",
+ ["sna" ]="sena",
+ ["sna0"]="shona",
+ ["snd" ]="sindhi",
+ ["snh" ]="sinhala (sinhalese)",
+ ["snk" ]="soninke",
+ ["sog" ]="sodo gurage",
+ ["sop" ]="songe",
+ ["sot" ]="sotho, southern",
+ ["sqi" ]="albanian",
+ ["srb" ]="serbian",
+ ["srd" ]="sardinian",
+ ["srk" ]="saraiki",
+ ["srr" ]="serer",
+ ["ssl" ]="south slavey",
+ ["ssm" ]="southern sami",
+ ["stq" ]="saterland frisian",
+ ["suk" ]="sukuma",
+ ["sun" ]="sundanese",
+ ["sur" ]="suri",
+ ["sva" ]="svan",
+ ["sve" ]="swedish",
+ ["swa" ]="swadaya aramaic",
+ ["swk" ]="swahili",
+ ["swz" ]="swati",
+ ["sxt" ]="sutu",
+ ["sxu" ]="upper saxon",
+ ["syl" ]="sylheti",
+ ["syr" ]="syriac",
+ ["szl" ]="silesian",
+ ["tab" ]="tabasaran",
+ ["taj" ]="tajiki",
+ ["tam" ]="tamil",
+ ["tat" ]="tatar",
+ ["tcr" ]="th-cree",
+ ["tdd" ]="dehong dai",
+ ["tel" ]="telugu",
+ ["tet" ]="tetum",
+ ["tgl" ]="tagalog",
+ ["tgn" ]="tongan",
+ ["tgr" ]="tigre",
+ ["tgy" ]="tigrinya",
+ ["tha" ]="thai",
+ ["tht" ]="tahitian",
+ ["tib" ]="tibetan",
+ ["tiv" ]="tiv",
+ ["tkm" ]="turkmen",
+ ["tmh" ]="tamashek",
+ ["tmn" ]="temne",
+ ["tna" ]="tswana",
+ ["tne" ]="tundra nenets",
+ ["tng" ]="tonga",
+ ["tod" ]="todo",
+ ["tod0"]="toma",
+ ["tpi" ]="tok pisin",
+ ["trk" ]="turkish",
+ ["tsg" ]="tsonga",
+ ["tua" ]="turoyo aramaic",
+ ["tul" ]="tulu",
+ ["tuv" ]="tuvin",
+ ["tvl" ]="tuvalu",
+ ["twi" ]="twi",
+ ["tyz" ]="tày",
+ ["tzm" ]="tamazight",
+ ["tzo" ]="tzotzil",
+ ["udm" ]="udmurt",
+ ["ukr" ]="ukrainian",
+ ["umb" ]="umbundu",
+ ["urd" ]="urdu",
+ ["usb" ]="upper sorbian",
+ ["uyg" ]="uyghur",
+ ["uzb" ]="uzbek",
+ ["vec" ]="venetian",
+ ["ven" ]="venda",
+ ["vit" ]="vietnamese",
+ ["vol" ]="volapük",
+ ["vro" ]="võro",
+ ["wa" ]="wa",
+ ["wag" ]="wagdi",
+ ["war" ]="waray-waray",
+ ["wcr" ]="west-cree",
+ ["wel" ]="welsh",
+ ["wlf" ]="wolof",
+ ["wln" ]="walloon",
+ ["xbd" ]="lü",
+ ["xhs" ]="xhosa",
+ ["xjb" ]="minjangbal",
+ ["xog" ]="soga",
+ ["xpe" ]="kpelle (liberia)",
+ ["yak" ]="sakha",
+ ["yao" ]="yao",
+ ["yap" ]="yapese",
+ ["yba" ]="yoruba",
+ ["ycr" ]="y-cree",
+ ["yic" ]="yi classic",
+ ["yim" ]="yi modern",
+ ["zea" ]="zealandic",
+ ["zgh" ]="standard morrocan tamazigh",
+ ["zha" ]="zhuang",
+ ["zhh" ]="chinese, hong kong sar",
+ ["zhp" ]="chinese phonetic",
+ ["zhs" ]="chinese simplified",
+ ["zht" ]="chinese traditional",
+ ["znd" ]="zande",
+ ["zul" ]="zulu",
+ ["zza" ]="zazaki",
+}
+local features=allocate {
+ ["aalt"]="access all alternates",
+ ["abvf"]="above-base forms",
+ ["abvm"]="above-base mark positioning",
+ ["abvs"]="above-base substitutions",
+ ["afrc"]="alternative fractions",
+ ["akhn"]="akhands",
+ ["blwf"]="below-base forms",
+ ["blwm"]="below-base mark positioning",
+ ["blws"]="below-base substitutions",
+ ["c2pc"]="petite capitals from capitals",
+ ["c2sc"]="small capitals from capitals",
+ ["calt"]="contextual alternates",
+ ["case"]="case-sensitive forms",
+ ["ccmp"]="glyph composition/decomposition",
+ ["cfar"]="conjunct form after ro",
+ ["cjct"]="conjunct forms",
+ ["clig"]="contextual ligatures",
+ ["cpct"]="centered cjk punctuation",
+ ["cpsp"]="capital spacing",
+ ["cswh"]="contextual swash",
+ ["curs"]="cursive positioning",
+ ["dflt"]="default processing",
+ ["dist"]="distances",
+ ["dlig"]="discretionary ligatures",
+ ["dnom"]="denominators",
+ ["dtls"]="dotless forms",
+ ["expt"]="expert forms",
+ ["falt"]="final glyph alternates",
+ ["fin2"]="terminal forms #2",
+ ["fin3"]="terminal forms #3",
+ ["fina"]="terminal forms",
+ ["flac"]="flattened accents over capitals",
+ ["frac"]="fractions",
+ ["fwid"]="full width",
+ ["half"]="half forms",
+ ["haln"]="halant forms",
+ ["halt"]="alternate half width",
+ ["hist"]="historical forms",
+ ["hkna"]="horizontal kana alternates",
+ ["hlig"]="historical ligatures",
+ ["hngl"]="hangul",
+ ["hojo"]="hojo kanji forms",
+ ["hwid"]="half width",
+ ["init"]="initial forms",
+ ["isol"]="isolated forms",
+ ["ital"]="italics",
+ ["jalt"]="justification alternatives",
+ ["jp04"]="jis2004 forms",
+ ["jp78"]="jis78 forms",
+ ["jp83"]="jis83 forms",
+ ["jp90"]="jis90 forms",
+ ["kern"]="kerning",
+ ["lfbd"]="left bounds",
+ ["liga"]="standard ligatures",
+ ["ljmo"]="leading jamo forms",
+ ["lnum"]="lining figures",
+ ["locl"]="localized forms",
+ ["ltra"]="left-to-right alternates",
+ ["ltrm"]="left-to-right mirrored forms",
+ ["mark"]="mark positioning",
+ ["med2"]="medial forms #2",
+ ["medi"]="medial forms",
+ ["mgrk"]="mathematical greek",
+ ["mkmk"]="mark to mark positioning",
+ ["mset"]="mark positioning via substitution",
+ ["nalt"]="alternate annotation forms",
+ ["nlck"]="nlc kanji forms",
+ ["nukt"]="nukta forms",
+ ["numr"]="numerators",
+ ["onum"]="old style figures",
+ ["opbd"]="optical bounds",
+ ["ordn"]="ordinals",
+ ["ornm"]="ornaments",
+ ["palt"]="proportional alternate width",
+ ["pcap"]="petite capitals",
+ ["pkna"]="proportional kana",
+ ["pnum"]="proportional figures",
+ ["pref"]="pre-base forms",
+ ["pres"]="pre-base substitutions",
+ ["pstf"]="post-base forms",
+ ["psts"]="post-base substitutions",
+ ["pwid"]="proportional widths",
+ ["qwid"]="quarter widths",
+ ["rand"]="randomize",
+ ["rclt"]="required contextual alternates",
+ ["rkrf"]="rakar forms",
+ ["rlig"]="required ligatures",
+ ["rphf"]="reph form",
+ ["rtbd"]="right bounds",
+ ["rtla"]="right-to-left alternates",
+ ["rtlm"]="right to left mirrored forms",
+ ["rvrn"]="required variation alternates",
+ ["ruby"]="ruby notation forms",
+ ["salt"]="stylistic alternates",
+ ["sinf"]="scientific inferiors",
+ ["size"]="optical size",
+ ["smcp"]="small capitals",
+ ["smpl"]="simplified forms",
+ ["ssty"]="script style",
+ ["stch"]="stretching glyph decomposition",
+ ["subs"]="subscript",
+ ["sups"]="superscript",
+ ["swsh"]="swash",
+ ["titl"]="titling",
+ ["tjmo"]="trailing jamo forms",
+ ["tnam"]="traditional name forms",
+ ["tnum"]="tabular figures",
+ ["trad"]="traditional forms",
+ ["twid"]="third widths",
+ ["unic"]="unicase",
+ ["valt"]="alternate vertical metrics",
+ ["vatu"]="vattu variants",
+ ["vert"]="vertical writing",
+ ["vhal"]="alternate vertical half metrics",
+ ["vjmo"]="vowel jamo forms",
+ ["vkna"]="vertical kana alternates",
+ ["vkrn"]="vertical kerning",
+ ["vpal"]="proportional alternate vertical metrics",
+ ["vrt2"]="vertical rotation",
+ ["zero"]="slashed zero",
+ ["trep"]="traditional tex replacements",
+ ["tlig"]="traditional tex ligatures",
+ ["ss.."]="stylistic set ..",
+ ["cv.."]="character variant ..",
+ ["js.."]="justification ..",
+ ["dv.."]="devanagari ..",
+ ["ml.."]="malayalam ..",
+}
+local baselines=allocate {
+ ["hang"]="hanging baseline",
+ ["icfb"]="ideographic character face bottom edge baseline",
+ ["icft"]="ideographic character face tope edige baseline",
+ ["ideo"]="ideographic em-box bottom edge baseline",
+ ["idtp"]="ideographic em-box top edge baseline",
+ ["math"]="mathematical centered baseline",
+ ["romn"]="roman baseline"
+}
+tables.scripts=scripts
+tables.languages=languages
+tables.features=features
+tables.baselines=baselines
+local acceptscripts=true directives.register("otf.acceptscripts",function(v) acceptscripts=v end)
+local acceptlanguages=true directives.register("otf.acceptlanguages",function(v) acceptlanguages=v end)
+local report_checks=logs.reporter("fonts","checks")
+if otffeatures.features then
+ for k,v in next,otffeatures.features do
+ features[k]=v
+ end
+ otffeatures.features=features
+end
+local function swapped(h)
+ local r={}
+ for k,v in next,h do
+ r[gsub(v,"[^a-z0-9]","")]=k
+ end
+ return r
+end
+local verbosescripts=allocate(swapped(scripts ))
+local verboselanguages=allocate(swapped(languages))
+local verbosefeatures=allocate(swapped(features ))
+local verbosebaselines=allocate(swapped(baselines))
+local function resolve(t,k)
+ if k then
+ k=gsub(lower(k),"[^a-z0-9]","")
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ end
+end
+setmetatableindex(verbosescripts,resolve)
+setmetatableindex(verboselanguages,resolve)
+setmetatableindex(verbosefeatures,resolve)
+setmetatableindex(verbosebaselines,resolve)
+setmetatableindex(scripts,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
+ end
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptscripts then
+ report_checks("registering extra script %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+setmetatableindex(languages,function(t,k)
+ if k then
+ k=lower(k)
+ if k=="dflt" then
+ return k
+ end
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ v=rawget(t,v)
+ if v then
+ return v
+ elseif acceptlanguages then
+ report_checks("registering extra language %a",k)
+ rawset(t,k,k)
+ return k
+ end
+ end
+ return "dflt"
+end)
+if setmetatablenewindex then
+ setmetatablenewindex(languages,"ignore")
+ setmetatablenewindex(scripts,"ignore")
+ setmetatablenewindex(baselines,"ignore")
+end
+local function resolve(t,k)
+ if k then
+ k=lower(k)
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ k=gsub(k," ","")
+ local v=rawget(t,k)
+ if v then
+ return v
+ end
+ local tag,dd=match(k,"(..)(%d+)")
+ if tag and dd then
+ local v=rawget(t,tag)
+ if v then
+ return v
+ else
+ local v=rawget(t,tag.."..")
+ if v then
+ return (gsub(v,"%.%.",tonumber(dd)))
+ end
+ end
+ end
+ end
+ return k
+end
+setmetatableindex(features,resolve)
+local function assign(t,k,v)
+ if k and v then
+ v=lower(v)
+ rawset(t,k,v)
+ end
+end
+if setmetatablenewindex then
+ setmetatablenewindex(features,assign)
+end
+local checkers={
+ rand=function(v)
+ return v==true and "random" or v
+ end
+}
+if not storage then
+ return
+end
+local usedfeatures=statistics.usedfeatures or {}
+statistics.usedfeatures=usedfeatures
+table.setmetatableindex(usedfeatures,function(t,k) if k then local v={} t[k]=v return v end end)
+storage.register("fonts/otf/usedfeatures",usedfeatures,"fonts.handlers.otf.statistics.usedfeatures" )
+local normalizedaxis=otf.readers.helpers.normalizedaxis or function(s) return s end
+function otffeatures.normalize(features)
+ if features then
+ local h={}
+ for key,value in next,features do
+ local k=lower(key)
+ if k=="language" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.language=rawget(verboselanguages,v) or (languages[v] and v) or "dflt"
+ elseif k=="script" then
+ local v=gsub(lower(value),"[^a-z0-9]","")
+ h.script=rawget(verbosescripts,v) or (scripts[v] and v) or "dflt"
+ elseif k=="axis" then
+ h[k]=normalizedaxis(value)
+ if not callbacks.supported.glyph_stream_provider then
+ h.variableshapes=true
+ end
+ else
+ local uk=usedfeatures[key]
+ local uv=uk[value]
+ if uv then
+ else
+ uv=tonumber(value)
+ if uv then
+ elseif type(value)=="string" then
+ local b=is_boolean(value)
+ if type(b)=="nil" then
+ uv=lower(value)
+ else
+ uv=b
+ end
+ elseif type(value)=="table" then
+ uv=sequenced(t,",")
+ else
+ uv=value
+ end
+ if not rawget(features,k) then
+ k=rawget(verbosefeatures,k) or k
+ end
+ local c=checkers[k]
+ if c then
+ uv=c(uv) or vc
+ end
+ uk[value]=uv
+ end
+ h[k]=uv
+ end
+ end
+ return h
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
if not modules then modules={} end modules ['font-cff']={
version=1.001,
comment="companion to font-ini.mkiv",
@@ -9522,15 +14188,15 @@ if not modules then modules={} end modules ['font-cff']={
license="see context related readme files"
}
local next,type,tonumber=next,type,tonumber
-local byte=string.byte
+local byte,char,gmatch=string.byte,string.char,string.gmatch
local concat,remove=table.concat,table.remove
-local floor,abs,round,ceil=math.floor,math.abs,math.round,math.ceil
+local floor,abs,round,ceil,min,max=math.floor,math.abs,math.round,math.ceil,math.min,math.max
local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct
local lpegmatch=lpeg.match
local formatters=string.formatters
+local bytetable=string.bytetable
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
-local readbytes=streamreader.readbytes
local readstring=streamreader.readstring
local readbyte=streamreader.readcardinal1
local readushort=streamreader.readcardinal2
@@ -9538,6 +14204,18 @@ local readuint=streamreader.readcardinal3
local readulong=streamreader.readcardinal4
local setposition=streamreader.setposition
local getposition=streamreader.getposition
+local readbytetable=streamreader.readbytetable
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ readstring=streamreader.readstring
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readuint=streamreader.readcardinal3
+ readulong=streamreader.readcardinal4
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ readbytetable=streamreader.readbytetable
+end)
local setmetatableindex=table.setmetatableindex
local trace_charstrings=false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings=v end)
local report=logs.reporter("otf reader","cff")
@@ -9546,6 +14224,8 @@ local parsecharstring
local parsecharstrings
local resetcharstrings
local parseprivates
+local startparsing
+local stopparsing
local defaultstrings={ [0]=
".notdef","space","exclam","quotedbl","numbersign","dollar","percent",
"ampersand","quoteright","parenleft","parenright","asterisk","plus",
@@ -9621,18 +14301,24 @@ local cffreaders={
}
local function readheader(f)
local offset=getposition(f)
+ local major=readbyte(f)
local header={
offset=offset,
- major=readbyte(f),
+ major=major,
minor=readbyte(f),
size=readbyte(f),
- osize=readbyte(f),
}
+ if major==1 then
+ header.dsize=readbyte(f)
+ elseif major==2 then
+ header.dsize=readushort(f)
+ else
+ end
setposition(f,offset+header.size)
return header
end
-local function readlengths(f)
- local count=readushort(f)
+local function readlengths(f,longcount)
+ local count=longcount and readulong(f) or readushort(f)
if count==0 then
return {}
end
@@ -9646,7 +14332,12 @@ local function readlengths(f)
local previous=read(f)
for i=1,count do
local offset=read(f)
- lengths[i]=offset-previous
+ local length=offset-previous
+ if length<0 then
+ report("bad offset: %i",length)
+ length=0
+ end
+ lengths[i]=length
previous=offset
end
return lengths
@@ -9711,7 +14402,7 @@ do
end+P("\16")/function()
result.encoding=stack[top]
top=0
- end+P("\17")/function()
+ end+P("\17")/function()
result.charstrings=stack[top]
top=0
end+P("\18")/function()
@@ -9722,10 +14413,20 @@ do
top=0
end+P("\19")/function()
result.subroutines=stack[top]
+ top=0
end+P("\20")/function()
result.defaultwidthx=stack[top]
+ top=0
end+P("\21")/function()
result.nominalwidthx=stack[top]
+ top=0
+ end
++P("\24")/function()
+ result.vstore=stack[top]
+ top=0
+ end+P("\25")/function()
+ result.maxstack=stack[top]
+ top=0
end
local p_double=P("\12")*(
P("\00")/function()
@@ -9749,7 +14450,7 @@ do
end+P("\06")/function()
result.charstringtype=stack[top]
top=0
- end+P("\07")/function()
+ end+P("\07")/function()
result.fontmatrix={ unpack(stack,1,6) }
top=0
end+P("\08")/function()
@@ -9787,10 +14488,10 @@ do
end+P("\35")/function()
result.cid.uidbase=stack[top]
top=0
- end+P("\36")/function()
+ end+P("\36")/function()
result.cid.fdarray=stack[top]
top=0
- end+P("\37")/function()
+ end+P("\37")/function()
result.cid.fdselect=stack[top]
top=0
end+P("\38")/function()
@@ -9855,12 +14556,12 @@ do
local p_dictionary=(
p_byte+p_positive+p_negative+p_short+p_long+p_nibbles+p_single+p_double+p_unsupported
)^1
- parsedictionaries=function(data,dictionaries)
+ parsedictionaries=function(data,dictionaries,what)
stack={}
strings=data.strings
for i=1,#dictionaries do
top=0
- result={
+ result=what=="cff" and {
monospaced=false,
italicangle=0,
underlineposition=-100,
@@ -9878,6 +14579,12 @@ do
fonttype=0,
count=8720,
}
+ } or {
+ charstringtype=2,
+ charset=0,
+ vstore=0,
+ cid={
+ },
}
lpegmatch(p_dictionary,dictionaries[i])
dictionaries[i]=result
@@ -9919,6 +14626,9 @@ do
local stems=0
local globalbias=0
local localbias=0
+ local nominalwidth=0
+ local defaultwidth=0
+ local charset=false
local globals=false
local locals=false
local depth=1
@@ -9929,6 +14639,12 @@ do
local checked=false
local keepcurve=false
local version=2
+ local regions=false
+ local nofregions=0
+ local region=false
+ local factors=false
+ local axis=false
+ local vsindex=0
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
end
@@ -9939,14 +14655,14 @@ do
report("%w%-10s : %s",depth*2,where,tostring(value))
end
end
- local function moveto(x,y)
+ local function xymoveto()
if keepcurve then
r=r+1
result[r]={ x,y,"m" }
end
if checked then
- if x<xmin then xmin=x elseif x>xmax then xmax=x end
- if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if x>xmax then xmax=x elseif x<xmin then xmin=x end
+ if y>ymax then ymax=y elseif y<ymin then ymin=y end
else
xmin=x
ymin=y
@@ -9955,14 +14671,55 @@ do
checked=true
end
end
- local function lineto(x,y)
+ local function xmoveto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"m" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif x>xmax then
+ xmax=x
+ elseif x<xmin then
+ xmin=x
+ end
+ end
+ local function ymoveto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"m" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif y>ymax then
+ ymax=y
+ elseif y<ymin then
+ ymin=y
+ end
+ end
+ local function moveto()
+ if trace_charstrings then
+ showstate("moveto")
+ end
+ top=0
+ xymoveto()
+ end
+ local function xylineto()
if keepcurve then
r=r+1
result[r]={ x,y,"l" }
end
if checked then
- if x<xmin then xmin=x elseif x>xmax then xmax=x end
- if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if x>xmax then xmax=x elseif x<xmin then xmin=x end
+ if y>ymax then ymax=y elseif y<ymin then ymin=y end
else
xmin=x
ymin=y
@@ -9971,14 +14728,51 @@ do
checked=true
end
end
- local function curveto(x1,y1,x2,y2,x3,y3)
+ local function xlineto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"l" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif x>xmax then
+ xmax=x
+ elseif x<xmin then
+ xmin=x
+ end
+ end
+ local function ylineto()
+ if keepcurve then
+ r=r+1
+ result[r]={ x,y,"l" }
+ end
+ if not checked then
+ xmin=x
+ ymin=y
+ xmax=x
+ ymax=y
+ checked=true
+ elseif y>ymax then
+ ymax=y
+ elseif y<ymin then
+ ymin=y
+ end
+ end
+ local function xycurveto(x1,y1,x2,y2,x3,y3)
+ if trace_charstrings then
+ showstate("curveto")
+ end
if keepcurve then
r=r+1
result[r]={ x1,y1,x2,y2,x3,y3,"c" }
end
if checked then
- if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
- if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x1>xmax then xmax=x1 elseif x1<xmin then xmin=x1 end
+ if y1>ymax then ymax=y1 elseif y1<ymin then ymin=y1 end
else
xmin=x1
ymin=y1
@@ -9986,21 +14780,21 @@ do
ymax=y1
checked=true
end
- if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
- if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
- if x3<xmin then xmin=x3 elseif x3>xmax then xmax=x3 end
- if y3<ymin then ymin=y3 elseif y3>ymax then ymax=y3 end
+ if x2>xmax then xmax=x2 elseif x2<xmin then xmin=x2 end
+ if y2>ymax then ymax=y2 elseif y2<ymin then ymin=y2 end
+ if x3>xmax then xmax=x3 elseif x3<xmin then xmin=x3 end
+ if y3>ymax then ymax=y3 elseif y3<ymin then ymin=y3 end
end
local function rmoveto()
- if top>2 then
- if not width then
+ if not width then
+ if top>2 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("rmoveto")
@@ -10008,43 +14802,43 @@ do
x=x+stack[top-1]
y=y+stack[top]
top=0
- moveto(x,y)
+ xymoveto()
end
local function hmoveto()
- if top>1 then
- if not width then
+ if not width then
+ if top>1 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("hmoveto")
end
x=x+stack[top]
top=0
- moveto(x,y)
+ xmoveto()
end
local function vmoveto()
- if top>1 then
- if not width then
+ if not width then
+ if top>1 then
width=stack[1]
if trace_charstrings then
- showvalue("width",width)
+ showvalue("backtrack width",width)
end
+ else
+ width=true
end
- elseif not width then
- width=true
end
if trace_charstrings then
showstate("vmoveto")
end
y=y+stack[top]
top=0
- moveto(x,y)
+ ymoveto()
end
local function rlineto()
if trace_charstrings then
@@ -10053,20 +14847,7 @@ do
for i=1,top,2 do
x=x+stack[i]
y=y+stack[i+1]
- lineto(x,y)
- end
- top=0
- end
- local function xlineto(swap)
- for i=1,top do
- if swap then
- x=x+stack[i]
- swap=false
- else
- y=y+stack[i]
- swap=true
- end
- lineto(x,y)
+ xylineto()
end
top=0
end
@@ -10074,13 +14855,47 @@ do
if trace_charstrings then
showstate("hlineto")
end
- xlineto(true)
+ if top==1 then
+ x=x+stack[1]
+ xlineto()
+ else
+ local swap=true
+ for i=1,top do
+ if swap then
+ x=x+stack[i]
+ xlineto()
+ swap=false
+ else
+ y=y+stack[i]
+ ylineto()
+ swap=true
+ end
+ end
+ end
+ top=0
end
local function vlineto()
if trace_charstrings then
showstate("vlineto")
end
- xlineto(false)
+ if top==1 then
+ y=y+stack[1]
+ ylineto()
+ else
+ local swap=false
+ for i=1,top do
+ if swap then
+ x=x+stack[i]
+ xlineto()
+ swap=false
+ else
+ y=y+stack[i]
+ ylineto()
+ swap=true
+ end
+ end
+ end
+ top=0
end
local function rrcurveto()
if trace_charstrings then
@@ -10091,9 +14906,9 @@ do
local ay=y+stack[i+1]
local bx=ax+stack[i+2]
local by=ay+stack[i+3]
- x=bx+stack[i+4]
- y=by+stack[i+5]
- curveto(ax,ay,bx,by,x,y)
+ x=bx+stack[i+4]
+ y=by+stack[i+5]
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -10103,17 +14918,17 @@ do
end
local s=1
if top%2~=0 then
- y=y+stack[1]
+ y=y+stack[1]
s=2
end
for i=s,top,4 do
- local ax=x+stack[i]
+ local ax=x+stack[i]
local ay=y
local bx=ax+stack[i+1]
local by=ay+stack[i+2]
- x=bx+stack[i+3]
+ x=bx+stack[i+3]
y=by
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -10124,17 +14939,17 @@ do
local s=1
local d=0
if top%2~=0 then
- d=stack[1]
+ d=stack[1]
s=2
end
for i=s,top,4 do
local ax=x+d
- local ay=y+stack[i]
+ local ay=y+stack[i]
local bx=ax+stack[i+1]
local by=ay+stack[i+2]
x=bx
- y=by+stack[i+3]
- curveto(ax,ay,bx,by,x,y)
+ y=by+stack[i+3]
+ xycurveto(ax,ay,bx,by,x,y)
d=0
end
top=0
@@ -10144,7 +14959,6 @@ do
if last then
top=top-1
end
- local sw=swap
for i=1,top,4 do
local ax,ay,bx,by
if swap then
@@ -10172,7 +14986,7 @@ do
end
swap=true
end
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
top=0
end
@@ -10199,11 +15013,11 @@ do
local by=ay+stack[i+3]
x=bx+stack[i+4]
y=by+stack[i+5]
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
end
x=x+stack[top-1]
y=y+stack[top]
- lineto(x,y)
+ xylineto()
top=0
end
local function rlinecurve()
@@ -10214,7 +15028,7 @@ do
for i=1,top-6,2 do
x=x+stack[i]
y=y+stack[i+1]
- lineto(x,y)
+ xylineto()
end
end
local ax=x+stack[top-5]
@@ -10223,7 +15037,7 @@ do
local by=ay+stack[top-2]
x=bx+stack[top-1]
y=by+stack[top]
- curveto(ax,ay,bx,by,x,y)
+ xycurveto(ax,ay,bx,by,x,y)
top=0
end
local function flex()
@@ -10236,33 +15050,33 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by+stack[6]
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[7]
local dy=cy+stack[8]
local ex=dx+stack[9]
local ey=dy+stack[10]
x=ex+stack[11]
y=ey+stack[12]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function hflex()
if trace_charstrings then
showstate("hflex")
end
- local ax=x+stack[1]
+ local ax=x+stack[1]
local ay=y
local bx=ax+stack[2]
local by=ay+stack[3]
local cx=bx+stack[4]
local cy=by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[5]
local dy=by
local ex=dx+stack[6]
local ey=y
x=ex+stack[7]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function hflex1()
@@ -10275,13 +15089,13 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[6]
local dy=by
local ex=dx+stack[7]
local ey=dy+stack[8]
x=ex+stack[9]
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function flex1()
@@ -10294,7 +15108,7 @@ do
local by=ay+stack[4]
local cx=bx+stack[5]
local cy=by+stack[6]
- curveto(ax,ay,bx,by,cx,cy)
+ xycurveto(ax,ay,bx,by,cx,cy)
local dx=cx+stack[7]
local dy=cy+stack[8]
local ex=dx+stack[9]
@@ -10304,7 +15118,7 @@ do
else
y=ey+stack[11]
end
- curveto(dx,dy,ex,ey,x,y)
+ xycurveto(dx,dy,ex,ey,x,y)
top=0
end
local function getstem()
@@ -10439,6 +15253,92 @@ do
end
top=0
end
+ local reginit=false
+ local function updateregions(n)
+ if regions then
+ local current=regions[n] or regions[1]
+ nofregions=#current
+ if axis and n~=reginit then
+ factors={}
+ for i=1,nofregions do
+ local region=current[i]
+ local s=1
+ for j=1,#axis do
+ local f=axis[j]
+ local r=region[j]
+ local start=r.start
+ local peak=r.peak
+ local stop=r.stop
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ factors[i]=s
+ end
+ end
+ end
+ reginit=n
+ end
+ local function setvsindex()
+ local vsindex=stack[top]
+ if trace_charstrings then
+ showstate(formatters["vsindex %i"](vsindex))
+ end
+ updateregions(vsindex)
+ top=top-1
+ end
+ local function blend()
+ local n=stack[top]
+ top=top-1
+ if axis then
+ if trace_charstrings then
+ local t=top-nofregions*n
+ local m=t-n
+ for i=1,n do
+ local k=m+i
+ local d=m+n+(i-1)*nofregions
+ local old=stack[k]
+ local new=old
+ for r=1,nofregions do
+ new=new+stack[d+r]*factors[r]
+ end
+ stack[k]=new
+ showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
+ end
+ top=t
+ elseif n==1 then
+ top=top-nofregions
+ local v=stack[top]
+ for r=1,nofregions do
+ v=v+stack[top+r]*factors[r]
+ end
+ stack[top]=v
+ else
+ top=top-nofregions*n
+ local d=top
+ local k=top-n
+ for i=1,n do
+ k=k+1
+ local v=stack[k]
+ for r=1,nofregions do
+ v=v+stack[d+r]*factors[r]
+ end
+ stack[k]=v
+ d=d+nofregions
+ end
+ end
+ else
+ end
+ end
local actions={ [0]=unsupported,
getstem,
unsupported,
@@ -10454,8 +15354,8 @@ do
unsupported,
hsbw,
unsupported,
- unsupported,
- unsupported,
+ setvsindex,
+ blend,
unsupported,
getstem,
getmask,
@@ -10487,8 +15387,80 @@ do
[036]=hflex1,
[037]=flex1,
}
- local p_bytes=Ct((P(1)/byte)^0)
- local function call(scope,list,bias,process)
+ local c_endchar=char(14)
+ local passon do
+ local rshift=bit32.rshift
+ local band=bit32.band
+ local round=math.round
+ local encode=table.setmetatableindex(function(t,i)
+ for i=-2048,-1130 do
+ t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ for i=-1131,-108 do
+ local v=0xFB00-i-108
+ t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=-107,107 do
+ t[i]=char(i+139)
+ end
+ for i=108,1131 do
+ local v=0xF700+i-108
+ t[i]=char(band(rshift(v,8),0xFF),band(v,0xFF))
+ end
+ for i=1132,2048 do
+ t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF))
+ end
+ return t[i]
+ end)
+ local function setvsindex()
+ local vsindex=stack[top]
+ updateregions(vsindex)
+ top=top-1
+ end
+ local function blend()
+ local n=stack[top]
+ top=top-1
+ if not axis then
+ elseif n==1 then
+ top=top-nofregions
+ local v=stack[top]
+ for r=1,nofregions do
+ v=v+stack[top+r]*factors[r]
+ end
+ stack[top]=round(v)
+ else
+ top=top-nofregions*n
+ local d=top
+ local k=top-n
+ for i=1,n do
+ k=k+1
+ local v=stack[k]
+ for r=1,nofregions do
+ v=v+stack[d+r]*factors[r]
+ end
+ stack[k]=round(v)
+ d=d+nofregions
+ end
+ end
+ end
+ passon=function(operation)
+ if operation==15 then
+ setvsindex()
+ elseif operation==16 then
+ blend()
+ else
+ for i=1,top do
+ r=r+1
+ result[r]=encode[stack[i]]
+ end
+ r=r+1
+ result[r]=char(operation)
+ top=0
+ end
+ end
+ end
+ local process
+ local function call(scope,list,bias)
depth=depth+1
if top==0 then
showstate(formatters["unknown %s call"](scope))
@@ -10501,10 +15473,6 @@ do
end
local tab=list[index]
if tab then
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- list[index]=tab
- end
process(tab)
else
showstate(formatters["unknown %s call %i"](scope,index))
@@ -10513,50 +15481,50 @@ do
end
depth=depth-1
end
- local function process(tab)
+ local justpass=false
+ process=function(tab)
local i=1
local n=#tab
while i<=n do
local t=tab[i]
- if t>=32 and t<=246 then
- top=top+1
- stack[top]=t-139
- i=i+1
- elseif t>=247 and t<=250 then
+ if t>=32 then
top=top+1
- stack[top]=(t-247)*256+tab[i+1]+108
- i=i+2
- elseif t>=251 and t<=254 then
- top=top+1
- stack[top]=-(t-251)*256-tab[i+1]-108
- i=i+2
+ if t<=246 then
+ stack[top]=t-139
+ i=i+1
+ elseif t<=250 then
+ stack[top]=t*256-63124+tab[i+1]
+ i=i+2
+ elseif t<=254 then
+ stack[top]=-t*256+64148-tab[i+1]
+ i=i+2
+ else
+ local n=0x100*tab[i+1]+tab[i+2]
+ if n>=0x8000 then
+ stack[top]=n-0x10000+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ else
+ stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
+ end
+ i=i+5
+ end
elseif t==28 then
top=top+1
local n=0x100*tab[i+1]+tab[i+2]
if n>=0x8000 then
- stack[top]=n-0xFFFF-1
+ stack[top]=n-0x10000
else
stack[top]=n
end
i=i+3
- elseif t==255 then
- local n=0x100*tab[i+1]+tab[i+2]
- top=top+1
- if n>=0x8000 then
- stack[top]=n-0xFFFF-1+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- else
- stack[top]=n+(0x100*tab[i+3]+tab[i+4])/0xFFFF
- end
- i=i+5
- elseif t==11 then
+ elseif t==11 then
if trace_charstrings then
showstate("return")
end
return
elseif t==10 then
- call("local",locals,localbias,process)
+ call("local",locals,localbias)
i=i+1
- elseif t==14 then
+ elseif t==14 then
if width then
elseif top>0 then
width=stack[1]
@@ -10571,7 +15539,7 @@ do
end
return
elseif t==29 then
- call("global",globals,globalbias,process)
+ call("global",globals,globalbias)
i=i+1
elseif t==12 then
i=i+1
@@ -10586,20 +15554,25 @@ do
top=0
end
i=i+1
+ elseif justpass then
+ passon(t)
+ i=i+1
else
local a=actions[t]
if a then
local s=a(t)
if s then
- i=i+s
+ i=i+s+1
+ else
+ i=i+1
end
else
if trace_charstrings then
showvalue("<action>",t)
end
top=0
+ i=i+1
end
- i=i+1
end
end
end
@@ -10615,96 +15588,15 @@ do
((l<1240 and 107) or (l<33900 and 1131) or 32768)+1
end
end
- parsecharstrings=function(data,glyphs,doshapes,tversion)
- local dictionary=data.dictionaries[1]
- local charstrings=dictionary.charstrings
- local charset=dictionary.charset
- local private=dictionary.private or { data={} }
- keepcurve=doshapes
- version=tversion
- stack={}
- glyphs=glyphs or {}
- strings=data.strings
- globals=data.routines or {}
- locals=dictionary.subroutines or {}
- globalbias,localbias=setbias(globals,locals)
- local nominalwidth=private.data.nominalwidthx or 0
- local defaultwidth=private.data.defaultwidthx or 0
- for i=1,#charstrings do
- local tab=charstrings[i]
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- end
- local index=i-1
- x=0
- y=0
- width=false
- r=0
- top=0
- stems=0
- result={}
- xmin=0
- xmax=0
- ymin=0
- ymax=0
- checked=false
- if trace_charstrings then
- report("glyph: %i",index)
- report("data: % t",tab)
- end
- process(tab)
- local boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
- if width==true or width==false then
- width=defaultwidth
- else
- width=nominalwidth+width
- end
- local glyph=glyphs[index]
- if not glyph then
- glyphs[index]={
- segments=doshapes~=false and result or nil,
- boundingbox=boundingbox,
- width=width,
- name=charset[index],
- }
- else
- glyph.segments=doshapes~=false and result or nil
- glyph.boundingbox=boundingbox
- if not glyph.width then
- glyph.width=width
- end
- if charset and not glyph.name then
- glyph.name=charset[index]
- end
- end
- if trace_charstrings then
- report("width: %s",tostring(width))
- report("boundingbox: % t",boundingbox)
- end
- charstrings[i]=nil
- end
- return glyphs
- end
- parsecharstring=function(data,dictionary,tab,glyphs,index,doshapes,tversion)
- local private=dictionary.private
- keepcurve=doshapes
- version=tversion
- strings=data.strings
- locals=dictionary.subroutines or {}
- globals=data.routines or {}
- globalbias,localbias=setbias(globals,locals)
- local nominalwidth=private and private.data.nominalwidthx or 0
- local defaultwidth=private and private.data.defaultwidthx or 0
- if type(tab)=="string" then
- tab=lpegmatch(p_bytes,tab)
- end
+ local function processshape(tab,index)
+ tab=bytetable(tab)
x=0
y=0
width=false
r=0
top=0
stems=0
- result={}
+ result={}
xmin=0
xmax=0
ymin=0
@@ -10712,26 +15604,35 @@ do
checked=false
if trace_charstrings then
report("glyph: %i",index)
- report("data: % t",tab)
+ report("data : % t",tab)
+ end
+ if regions then
+ updateregions(vsindex)
end
process(tab)
- local boundingbox={ xmin,ymin,xmax,ymax }
+ local boundingbox={
+ round(xmin),
+ round(ymin),
+ round(xmax),
+ round(ymax),
+ }
if width==true or width==false then
width=defaultwidth
else
width=nominalwidth+width
end
- index=index-1
local glyph=glyphs[index]
- if not glyph then
- glyphs[index]={
- segments=doshapes~=false and result or nil,
- boundingbox=boundingbox,
- width=width,
- name=charset[index],
- }
- else
- glyph.segments=doshapes~=false and result or nil
+ if justpass then
+ r=r+1
+ result[r]=c_endchar
+ local stream=concat(result)
+ if glyph then
+ glyph.stream=stream
+ else
+ glyphs[index]={ stream=stream }
+ end
+ elseif glyph then
+ glyph.segments=keepcurve~=false and result or nil
glyph.boundingbox=boundingbox
if not glyph.width then
glyph.width=width
@@ -10739,22 +15640,93 @@ do
if charset and not glyph.name then
glyph.name=charset[index]
end
+ elseif keepcurve then
+ glyphs[index]={
+ segments=result,
+ boundingbox=boundingbox,
+ width=width,
+ name=charset and charset[index] or nil,
+ }
+ else
+ glyphs[index]={
+ boundingbox=boundingbox,
+ width=width,
+ name=charset and charset[index] or nil,
+ }
end
if trace_charstrings then
- report("width: %s",tostring(width))
+ report("width : %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
end
- resetcharstrings=function()
+ startparsing=function(fontdata,data,streams)
+ reginit=false
+ axis=false
+ regions=data.regions
+ justpass=streams==true
+ if regions then
+ regions={ regions }
+ axis=data.factors or false
+ end
+ end
+ stopparsing=function(fontdata,data)
+ stack={}
+ glyphs=false
result={}
top=0
- stack={}
+ locals=false
+ globals=false
+ strings=false
+ end
+ local function setwidths(private)
+ if not private then
+ return 0,0
+ end
+ local privatedata=private.data
+ if not privatedata then
+ return 0,0
+ end
+ return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0
+ end
+ parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams)
+ local dictionary=data.dictionaries[1]
+ local charstrings=dictionary.charstrings
+ keepcurve=doshapes
+ version=tversion
+ strings=data.strings
+ globals=data.routines or {}
+ locals=dictionary.subroutines or {}
+ charset=dictionary.charset
+ vsindex=dictionary.vsindex or 0
+ glyphs=glphs or {}
+ globalbias,localbias=setbias(globals,locals)
+ nominalwidth,defaultwidth=setwidths(dictionary.private)
+ startparsing(fontdata,data,streams)
+ for index=1,#charstrings do
+ processshape(charstrings[index],index-1)
+ charstrings[index]=nil
+ end
+ stopparsing(fontdata,data)
+ return glyphs
+ end
+ parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion)
+ keepcurve=doshapes
+ version=tversion
+ strings=data.strings
+ globals=data.routines or {}
+ locals=dictionary.subroutines or {}
+ charset=false
+ vsindex=dictionary.vsindex or 0
+ glyphs=glphs or {}
+ globalbias,localbias=setbias(globals,locals)
+ nominalwidth,defaultwidth=setwidths(dictionary.private)
+ processshape(tab,index-1)
end
end
local function readglobals(f,data)
local routines=readlengths(f)
for i=1,#routines do
- routines[i]=readstring(f,routines[i])
+ routines[i]=readbytetable(f,routines[i])
end
data.routines=routines
end
@@ -10766,7 +15738,7 @@ local function readcharsets(f,data,dictionary)
local strings=data.strings
local nofglyphs=data.nofglyphs
local charsetoffset=dictionary.charset
- if charsetoffset~=0 then
+ if charsetoffset and charsetoffset~=0 then
setposition(f,header.offset+charsetoffset)
local format=readbyte(f)
local charset={ [0]=".notdef" }
@@ -10792,6 +15764,9 @@ local function readcharsets(f,data,dictionary)
else
report("cff parser: unsupported charset format %a",format)
end
+ else
+ dictionary.nocharset=true
+ dictionary.charset=nil
end
end
local function readprivates(f,data)
@@ -10812,7 +15787,7 @@ local function readlocals(f,data,dictionary)
setposition(f,header.offset+private.offset+subroutineoffset)
local subroutines=readlengths(f)
for i=1,#subroutines do
- subroutines[i]=readstring(f,subroutines[i])
+ subroutines[i]=readbytetable(f,subroutines[i])
end
dictionary.subroutines=subroutines
private.data.subroutines=nil
@@ -10823,15 +15798,16 @@ local function readlocals(f,data,dictionary)
dictionary.subroutines={}
end
end
-local function readcharstrings(f,data)
+local function readcharstrings(f,data,what)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
- local type=dictionary.charstringtype
+ local stringtype=dictionary.charstringtype
local offset=dictionary.charstrings
- if type==2 then
+ if type(offset)~="number" then
+ elseif stringtype==2 then
setposition(f,header.offset+offset)
- local charstrings=readlengths(f)
+ local charstrings=readlengths(f,what=="cff2")
local nofglyphs=#charstrings
for i=1,nofglyphs do
charstrings[i]=readstring(f,charstrings[i])
@@ -10839,7 +15815,7 @@ local function readcharstrings(f,data)
data.nofglyphs=nofglyphs
dictionary.charstrings=charstrings
else
- report("unsupported charstr type %i",type)
+ report("unsupported charstr type %i",stringtype)
data.nofglyphs=0
dictionary.charstrings={}
end
@@ -10857,29 +15833,36 @@ local function readcidprivates(f,data)
end
parseprivates(data,dictionaries)
end
-local function readnoselect(f,data,glyphs,doshapes,version)
+readers.parsecharstrings=parsecharstrings
+local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
- readcharsets(f,data,dictionary)
+ readcharstrings(f,data,version)
+ if version=="cff2" then
+ dictionary.charset=nil
+ else
+ readencodings(f,data)
+ readcharsets(f,data,dictionary)
+ end
readprivates(f,data)
parseprivates(data,data.dictionaries)
readlocals(f,data,dictionary)
- parsecharstrings(data,glyphs,doshapes,version)
- resetcharstrings()
+ startparsing(fontdata,data,streams)
+ parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
+ stopparsing(fontdata,data)
end
-readers.parsecharstrings=parsecharstrings
-local function readfdselect(f,data,glyphs,doshapes,version)
+local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
local header=data.header
local dictionaries=data.dictionaries
local dictionary=dictionaries[1]
local cid=dictionary.cid
local cidselect=cid and cid.fdselect
readglobals(f,data)
- readcharstrings(f,data)
- readencodings(f,data)
+ readcharstrings(f,data,version)
+ if version~="cff2" then
+ readencodings(f,data)
+ end
local charstrings=dictionary.charstrings
local fdindex={}
local nofglyphs=data.nofglyphs
@@ -10928,68 +15911,133 @@ local function readfdselect(f,data,glyphs,doshapes,version)
for i=1,#dictionaries do
readlocals(f,data,dictionaries[i])
end
+ startparsing(fontdata,data,streams)
for i=1,#charstrings do
- parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+ charstrings[i]=nil
end
- resetcharstrings()
+ stopparsing(fontdata,data)
end
end
+local gotodatatable=readers.helpers.gotodatatable
+local function cleanup(data,dictionaries)
+end
function readers.cff(f,fontdata,specification)
- if specification.details then
- local datatable=fontdata.tables.cff
- if datatable then
- local offset=datatable.offset
- local glyphs=fontdata.glyphs
- if not f then
- report("invalid filehandle")
- return
- end
- if offset then
- setposition(f,offset)
- end
- local header=readheader(f)
- if header.major>1 then
- report("version mismatch")
- return
- end
- local names=readfontnames(f)
- local dictionaries=readtopdictionaries(f)
- local strings=readstrings(f)
- local data={
- header=header,
- names=names,
- dictionaries=dictionaries,
- strings=strings,
- nofglyphs=fontdata.nofglyphs,
- }
- parsedictionaries(data,data.dictionaries)
- local d=dictionaries[1]
- local c=d.cid
- fontdata.cffinfo={
- familynamename=d.familyname,
- fullname=d.fullname,
- boundingbox=d.boundingbox,
- weight=d.weight,
- italicangle=d.italicangle,
- underlineposition=d.underlineposition,
- underlinethickness=d.underlinethickness,
- monospaced=d.monospaced,
- }
- fontdata.cidinfo=c and {
- registry=c.registry,
- ordering=c.ordering,
- supplement=c.supplement,
- }
- if not specification.glyphs then
+ local tableoffset=gotodatatable(f,fontdata,"cff",specification.details)
+ if tableoffset then
+ local header=readheader(f)
+ if header.major~=1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local glyphs=fontdata.glyphs
+ local names=readfontnames(f)
+ local dictionaries=readtopdictionaries(f)
+ local strings=readstrings(f)
+ local data={
+ header=header,
+ names=names,
+ dictionaries=dictionaries,
+ strings=strings,
+ nofglyphs=fontdata.nofglyphs,
+ }
+ parsedictionaries(data,dictionaries,"cff")
+ local dic=dictionaries[1]
+ local cid=dic.cid
+ fontdata.cffinfo={
+ familynamename=dic.familyname,
+ fullname=dic.fullname,
+ boundingbox=dic.boundingbox,
+ weight=dic.weight,
+ italicangle=dic.italicangle,
+ underlineposition=dic.underlineposition,
+ underlinethickness=dic.underlinethickness,
+ monospaced=dic.monospaced,
+ }
+ fontdata.cidinfo=cid and {
+ registry=cid.registry,
+ ordering=cid.ordering,
+ supplement=cid.supplement,
+ }
+ if specification.glyphs then
+ local all=specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff")
else
- local cid=d.cid
- if cid and cid.fdselect then
- readfdselect(f,data,glyphs,specification.shapes or false)
- else
- readnoselect(f,data,glyphs,specification.shapes or false)
- end
+ readnoselect(f,fontdata,data,glyphs,all,"cff")
end
end
+ cleanup(data,dictionaries)
+ end
+end
+function readers.cff2(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"cff2",specification.glyphs)
+ if tableoffset then
+ local header=readheader(f)
+ if header.major~=2 then
+ report("only version %s is supported for table %a",2,"cff2")
+ return
+ end
+ local glyphs=fontdata.glyphs
+ local dictionaries={ readstring(f,header.dsize) }
+ local data={
+ header=header,
+ dictionaries=dictionaries,
+ nofglyphs=fontdata.nofglyphs,
+ }
+ parsedictionaries(data,dictionaries,"cff2")
+ local offset=dictionaries[1].vstore
+ if offset>0 then
+ local storeoffset=dictionaries[1].vstore+data.header.offset+2
+ local regions,deltas=readers.helpers.readvariationdata(f,storeoffset,factors)
+ data.regions=regions
+ data.deltas=deltas
+ else
+ data.regions={}
+ data.deltas={}
+ end
+ data.factors=specification.factors
+ local cid=data.dictionaries[1].cid
+ local all=specification.shapes or false
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ else
+ readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
+ end
+ cleanup(data,dictionaries)
+ end
+end
+function readers.cffcheck(filename)
+ local f=io.open(filename,"rb")
+ if f then
+ local fontdata={
+ glyphs={},
+ }
+ local header=readheader(f)
+ if header.major~=1 then
+ report("only version %s is supported for table %a",1,"cff")
+ return
+ end
+ local names=readfontnames(f)
+ local dictionaries=readtopdictionaries(f)
+ local strings=readstrings(f)
+ local glyphs={}
+ local data={
+ header=header,
+ names=names,
+ dictionaries=dictionaries,
+ strings=strings,
+ glyphs=glyphs,
+ nofglyphs=4,
+ }
+ parsedictionaries(data,dictionaries,"cff")
+ local cid=data.dictionaries[1].cid
+ if cid and cid.fdselect then
+ readfdselect(f,fontdata,data,glyphs,false)
+ else
+ readnoselect(f,fontdata,data,glyphs,false)
+ end
+ return data
end
end
@@ -11005,9 +16053,12 @@ if not modules then modules={} end modules ['font-ttf']={
license="see context related readme files"
}
local next,type,unpack=next,type,unpack
-local bittest=bit32.btest
-local sqrt=math.sqrt
+local band,rshift=bit32.band,bit32.rshift
+local sqrt,round=math.sqrt,math.round
+local char=string.char
+local concat=table.concat
local report=logs.reporter("otf reader","ttf")
+local trace_deltas=false
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
@@ -11019,22 +16070,50 @@ local readulong=streamreader.readcardinal4
local readchar=streamreader.readinteger1
local readshort=streamreader.readinteger2
local read2dot14=streamreader.read2dot14
+local readinteger=streamreader.readinteger1
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ skipbytes=streamreader.skip
+ readbyte=streamreader.readcardinal1
+ readushort=streamreader.readcardinal2
+ readulong=streamreader.readcardinal4
+ readchar=streamreader.readinteger1
+ readshort=streamreader.readinteger2
+ read2dot14=streamreader.read2dot14
+ readinteger=streamreader.readinteger1
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+end)
+local short=2
+local ushort=2
+local ulong=4
+local helpers=readers.helpers
+local gotodatatable=helpers.gotodatatable
local function mergecomposites(glyphs,shapes)
local function merge(index,shape,components)
local contours={}
+ local points={}
local nofcontours=0
+ local nofpoints=0
+ local offset=0
+ local deltas=shape.deltas
for i=1,#components do
local component=components[i]
local subindex=component.index
local subshape=shapes[subindex]
local subcontours=subshape.contours
+ local subpoints=subshape.points
if not subcontours then
local subcomponents=subshape.components
if subcomponents then
- subcontours=merge(subindex,subshape,subcomponents)
+ subcontours,subpoints=merge(subindex,subshape,subcomponents)
end
end
- if subcontours then
+ if subpoints then
local matrix=component.matrix
local xscale=matrix[1]
local xrotate=matrix[2]
@@ -11042,35 +16121,38 @@ local function mergecomposites(glyphs,shapes)
local yscale=matrix[4]
local xoffset=matrix[5]
local yoffset=matrix[6]
+ for i=1,#subpoints do
+ local p=subpoints[i]
+ local x=p[1]
+ local y=p[2]
+ nofpoints=nofpoints+1
+ points[nofpoints]={
+ xscale*x+xrotate*y+xoffset,
+ yscale*y+yrotate*x+yoffset,
+ p[3]
+ }
+ end
for i=1,#subcontours do
- local points=subcontours[i]
- local result={}
- for i=1,#points do
- local p=points[i]
- local x=p[1]
- local y=p[2]
- result[i]={
- xscale*x+xrotate*y+xoffset,
- yscale*y+yrotate*x+yoffset,
- p[3]
- }
- end
nofcontours=nofcontours+1
- contours[nofcontours]=result
+ contours[nofcontours]=offset+subcontours[i]
end
+ offset=offset+#subpoints
else
report("missing contours composite %s, component %s of %s, glyph %s",index,i,#components,subindex)
end
end
+ shape.points=points
shape.contours=contours
shape.components=nil
- return contours
+ return contours,points
end
for index=1,#glyphs do
local shape=shapes[index]
- local components=shape.components
- if components then
- merge(index,shape,components)
+ if shape then
+ local components=shape.components
+ if components then
+ merge(index,shape,components)
+ end
end
end
end
@@ -11080,123 +16162,510 @@ local function readnothing(f,nofcontours)
}
end
local function curveto(m_x,m_y,l_x,l_y,r_x,r_y)
- return {
+ return
l_x+2/3*(m_x-l_x),l_y+2/3*(m_y-l_y),
r_x+2/3*(m_x-r_x),r_y+2/3*(m_y-r_y),
- r_x,r_y,"c"
- }
+ r_x,r_y,"c"
+end
+local function applyaxis(glyph,shape,deltas,dowidth)
+ local points=shape.points
+ if points then
+ local nofpoints=#points
+ local h=nofpoints+2
+ local l=nofpoints+1
+ local dw=0
+ local dl=0
+ for i=1,#deltas do
+ local deltaset=deltas[i]
+ local xvalues=deltaset.xvalues
+ local yvalues=deltaset.yvalues
+ local dpoints=deltaset.points
+ local factor=deltaset.factor
+ if dpoints then
+ local nofdpoints=#dpoints
+ for i=1,nofdpoints do
+ local d=dpoints[i]
+ local p=points[d]
+ if p then
+ if xvalues then
+ local x=xvalues[i]
+ if x and x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ end
+ if yvalues then
+ local y=yvalues[i]
+ if y and y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ end
+ elseif dowidth then
+ if d==h then
+ local x=xvalues[i]
+ if x then
+ dw=dw+factor*x
+ end
+ elseif d==l then
+ local x=xvalues[i]
+ if x then
+ dl=dl+factor*x
+ end
+ end
+ end
+ end
+ else
+ for i=1,nofpoints do
+ local p=points[i]
+ if xvalues then
+ local x=xvalues[i]
+ if x and x~=0 then
+ p[1]=p[1]+factor*x
+ end
+ end
+ if yvalues then
+ local y=yvalues[i]
+ if y and y~=0 then
+ p[2]=p[2]+factor*y
+ end
+ end
+ end
+ if dowidth then
+ local x=xvalues[h]
+ if x then
+ dw=dw+factor*x
+ end
+ local x=xvalues[l]
+ if x then
+ dl=dl+factor*x
+ end
+ end
+ end
+ end
+ if dowidth then
+ local width=glyph.width or 0
+ glyph.width=width+dw-dl
+ end
+ else
+ report("no points for glyph %a",glyph.name)
+ end
end
-local function contours2outlines(glyphs,shapes)
- local quadratic=true
+local quadratic=false
+local function contours2outlines_normal(glyphs,shapes)
for index=1,#glyphs do
- local glyph=glyphs[index]
local shape=shapes[index]
- local contours=shape.contours
- if contours then
- local nofcontours=#contours
- local segments={}
- local nofsegments=0
- glyph.segments=segments
- if nofcontours>0 then
- for i=1,nofcontours do
- local contour=contours[i]
- local nofcontour=#contour
- if nofcontour>0 then
- local first_pt=contour[1]
- local first_on=first_pt[3]
- if nofcontour==1 then
- first_pt[3]="m"
- nofsegments=nofsegments+1
- segments[nofsegments]=first_pt
- else
+ if shape then
+ local glyph=glyphs[index]
+ local contours=shape.contours
+ local points=shape.points
+ if contours then
+ local nofcontours=#contours
+ local segments={}
+ local nofsegments=0
+ glyph.segments=segments
+ if nofcontours>0 then
+ local px,py=0,0
+ local first=1
+ for i=1,nofcontours do
+ local last=contours[i]
+ if last>=first then
+ local first_pt=points[first]
local first_on=first_pt[3]
- local last_pt=contour[nofcontour]
- local last_on=last_pt[3]
- local start=1
- local control_pt=false
- if first_on then
- start=2
- else
- if last_on then
- first_pt=last_pt
+ if first==last then
+ first_pt[3]="m"
+ nofsegments=nofsegments+1
+ segments[nofsegments]=first_pt
+ else
+ local first_on=first_pt[3]
+ local last_pt=points[last]
+ local last_on=last_pt[3]
+ local start=1
+ local control_pt=false
+ if first_on then
+ start=2
else
- first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ if last_on then
+ first_pt=last_pt
+ else
+ first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ end
+ control_pt=first_pt
end
- control_pt=first_pt
- end
- nofsegments=nofsegments+1
- segments[nofsegments]={ first_pt[1],first_pt[2],"m" }
- local previous_pt=first_pt
- for i=start,nofcontour do
- local current_pt=contour[i]
- local current_on=current_pt[3]
- local previous_on=previous_pt[3]
- if previous_on then
- if current_on then
+ local x,y=first_pt[1],first_pt[2]
+ if not done then
+ xmin,ymin,xmax,ymax=x,y,x,y
+ done=true
+ end
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"m" }
+ if not quadratic then
+ px,py=x,y
+ end
+ local previous_pt=first_pt
+ for i=first,last do
+ local current_pt=points[i]
+ local current_on=current_pt[3]
+ local previous_on=previous_pt[3]
+ if previous_on then
+ if current_on then
+ local x,y=current_pt[1],current_pt[2]
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"l" }
+ if not quadratic then
+ px,py=x,y
+ end
+ else
+ control_pt=current_pt
+ end
+ elseif current_on then
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=current_pt[1],current_pt[2]
nofsegments=nofsegments+1
- segments[nofsegments]={ current_pt[1],current_pt[2],"l" }
+ if quadratic then
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ control_pt=false
else
+ local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2
+ local x1,y1=control_pt[1],control_pt[2]
+ nofsegments=nofsegments+1
+ if quadratic then
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
control_pt=current_pt
end
- elseif current_on then
- local ps=segments[nofsegments]
+ previous_pt=current_pt
+ end
+ if first_pt==last_pt then
+ else
nofsegments=nofsegments+1
- if quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],current_pt[1],current_pt[2],"q" }
+ local x2,y2=first_pt[1],first_pt[2]
+ if not control_pt then
+ segments[nofsegments]={ x2,y2,"l" }
+ elseif quadratic then
+ local x1,y1=control_pt[1],control_pt[2]
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
else
- local p=segments[nofsegments-1] local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],current_pt[1],current_pt[2])
+ local x1,y1=control_pt[1],control_pt[2]
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
end
- control_pt=false
+ end
+ end
+ end
+ first=last+1
+ end
+ end
+ end
+ end
+ end
+end
+local function contours2outlines_shaped(glyphs,shapes,keepcurve)
+ for index=1,#glyphs do
+ local shape=shapes[index]
+ if shape then
+ local glyph=glyphs[index]
+ local contours=shape.contours
+ local points=shape.points
+ if contours then
+ local nofcontours=#contours
+ local segments=keepcurve and {} or nil
+ local nofsegments=0
+ if keepcurve then
+ glyph.segments=segments
+ end
+ if nofcontours>0 then
+ local xmin,ymin,xmax,ymax,done=0,0,0,0,false
+ local px,py=0,0
+ local first=1
+ for i=1,nofcontours do
+ local last=contours[i]
+ if last>=first then
+ local first_pt=points[first]
+ local first_on=first_pt[3]
+ if first==last then
+ if keepcurve then
+ first_pt[3]="m"
+ nofsegments=nofsegments+1
+ segments[nofsegments]=first_pt
+ end
+ else
+ local first_on=first_pt[3]
+ local last_pt=points[last]
+ local last_on=last_pt[3]
+ local start=1
+ local control_pt=false
+ if first_on then
+ start=2
else
+ if last_on then
+ first_pt=last_pt
+ else
+ first_pt={ (first_pt[1]+last_pt[1])/2,(first_pt[2]+last_pt[2])/2,false }
+ end
+ control_pt=first_pt
+ end
+ local x,y=first_pt[1],first_pt[2]
+ if not done then
+ xmin,ymin,xmax,ymax=x,y,x,y
+ done=true
+ else
+ if x<xmin then xmin=x elseif x>xmax then xmax=x end
+ if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ end
+ if keepcurve then
nofsegments=nofsegments+1
- local halfway_x=(previous_pt[1]+current_pt[1])/2
- local halfway_y=(previous_pt[2]+current_pt[2])/2
+ segments[nofsegments]={ x,y,"m" }
+ end
+ if not quadratic then
+ px,py=x,y
+ end
+ local previous_pt=first_pt
+ for i=first,last do
+ local current_pt=points[i]
+ local current_on=current_pt[3]
+ local previous_on=previous_pt[3]
+ if previous_on then
+ if current_on then
+ local x,y=current_pt[1],current_pt[2]
+ if x<xmin then xmin=x elseif x>xmax then xmax=x end
+ if y<ymin then ymin=y elseif y>ymax then ymax=y end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x,y,"l" }
+ end
+ if not quadratic then
+ px,py=x,y
+ end
+ else
+ control_pt=current_pt
+ end
+ elseif current_on then
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=current_pt[1],current_pt[2]
+ if quadratic then
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ end
+ control_pt=false
+ else
+ local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2
+ local x1,y1=control_pt[1],control_pt[2]
+ if quadratic then
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
+ else
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
+ end
+ control_pt=current_pt
+ end
+ previous_pt=current_pt
+ end
+ if first_pt==last_pt then
+ elseif not control_pt then
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ first_pt[1],first_pt[2],"l" }
+ end
+ else
+ local x1,y1=control_pt[1],control_pt[2]
+ local x2,y2=first_pt[1],first_pt[2]
+ if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end
+ if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end
if quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],halfway_x,halfway_y,"q" }
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,"q" }
+ end
else
- local p=segments[nofsegments-1] local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],halfway_x,halfway_y)
+ x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2)
+ if x2<xmin then xmin=x2 elseif x2>xmax then xmax=x2 end
+ if y2<ymin then ymin=y2 elseif y2>ymax then ymax=y2 end
+ if px<xmin then xmin=px elseif px>xmax then xmax=px end
+ if py<ymin then ymin=py elseif py>ymax then ymax=py end
+ if keepcurve then
+ nofsegments=nofsegments+1
+ segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" }
+ end
end
- control_pt=current_pt
end
- previous_pt=current_pt
end
- if first_pt==last_pt then
+ end
+ first=last+1
+ end
+ glyph.boundingbox={ round(xmin),round(ymin),round(xmax),round(ymax) }
+ end
+ end
+ end
+ end
+end
+local c_zero=char(0)
+local s_zero=char(0,0)
+local function toushort(n)
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+local function toshort(n)
+ if n<0 then
+ n=n+0x10000
+ end
+ return char(band(rshift(n,8),0xFF),band(n,0xFF))
+end
+local function repackpoints(glyphs,shapes)
+ local noboundingbox={ 0,0,0,0 }
+ local result={}
+ for index=1,#glyphs do
+ local shape=shapes[index]
+ if shape then
+ local r=0
+ local glyph=glyphs[index]
+ if false then
+ else
+ local contours=shape.contours
+ local nofcontours=contours and #contours or 0
+ local boundingbox=glyph.boundingbox or noboundingbox
+ r=r+1 result[r]=toshort(nofcontours)
+ r=r+1 result[r]=toshort(boundingbox[1])
+ r=r+1 result[r]=toshort(boundingbox[2])
+ r=r+1 result[r]=toshort(boundingbox[3])
+ r=r+1 result[r]=toshort(boundingbox[4])
+ if nofcontours>0 then
+ for i=1,nofcontours do
+ r=r+1 result[r]=toshort(contours[i]-1)
+ end
+ r=r+1 result[r]=s_zero
+ local points=shape.points
+ local currentx=0
+ local currenty=0
+ local xpoints={}
+ local ypoints={}
+ local x=0
+ local y=0
+ local lastflag=nil
+ local nofflags=0
+ for i=1,#points do
+ local pt=points[i]
+ local px=pt[1]
+ local py=pt[2]
+ local fl=pt[3] and 0x01 or 0x00
+ if px==currentx then
+ fl=fl+0x10
+ else
+ local dx=round(px-currentx)
+ if dx<-255 or dx>255 then
+ x=x+1 xpoints[x]=toshort(dx)
+ elseif dx<0 then
+ fl=fl+0x02
+ x=x+1 xpoints[x]=char(-dx)
+ elseif dx>0 then
+ fl=fl+0x12
+ x=x+1 xpoints[x]=char(dx)
else
- nofsegments=nofsegments+1
- if not control_pt then
- segments[nofsegments]={ first_pt[1],first_pt[2],"l" }
- elseif quadratic then
- segments[nofsegments]={ control_pt[1],control_pt[2],first_pt[1],first_pt[2],"q" }
- else
- local p=last_pt local n=#p
- segments[nofsegments]=curveto(control_pt[1],control_pt[2],p[n-2],p[n-1],first_pt[1],first_pt[2])
- end
+ fl=fl+0x02
+ x=x+1 xpoints[x]=c_zero
end
end
+ if py==currenty then
+ fl=fl+0x20
+ else
+ local dy=round(py-currenty)
+ if dy<-255 or dy>255 then
+ y=y+1 ypoints[y]=toshort(dy)
+ elseif dy<0 then
+ fl=fl+0x04
+ y=y+1 ypoints[y]=char(-dy)
+ elseif dy>0 then
+ fl=fl+0x24
+ y=y+1 ypoints[y]=char(dy)
+ else
+ fl=fl+0x04
+ y=y+1 ypoints[y]=c_zero
+ end
+ end
+ currentx=px
+ currenty=py
+ if lastflag==fl then
+ nofflags=nofflags+1
+ else
+ if nofflags==1 then
+ r=r+1 result[r]=char(lastflag)
+ elseif nofflags==2 then
+ r=r+1 result[r]=char(lastflag,lastflag)
+ elseif nofflags>2 then
+ lastflag=lastflag+0x08
+ r=r+1 result[r]=char(lastflag,nofflags-1)
+ end
+ nofflags=1
+ lastflag=fl
+ end
end
+ if nofflags==1 then
+ r=r+1 result[r]=char(lastflag)
+ elseif nofflags==2 then
+ r=r+1 result[r]=char(lastflag,lastflag)
+ elseif nofflags>2 then
+ lastflag=lastflag+0x08
+ r=r+1 result[r]=char(lastflag,nofflags-1)
+ end
+ r=r+1 result[r]=concat(xpoints)
+ r=r+1 result[r]=concat(ypoints)
end
end
+ glyph.stream=concat(result,"",1,r)
+ else
end
end
end
-local function readglyph(f,nofcontours)
+local function readglyph(f,nofcontours)
local points={}
- local endpoints={}
local instructions={}
local flags={}
+ local contours={}
for i=1,nofcontours do
- endpoints[i]=readshort(f)+1
+ contours[i]=readshort(f)+1
end
- local nofpoints=endpoints[nofcontours]
+ local nofpoints=contours[nofcontours]
local nofinstructions=readushort(f)
skipbytes(f,nofinstructions)
local i=1
while i<=nofpoints do
local flag=readbyte(f)
flags[i]=flag
- if bittest(flag,0x0008) then
+ if band(flag,0x08)~=0 then
for j=1,readbyte(f) do
i=i+1
flags[i]=flag
@@ -11207,8 +16676,8 @@ local function readglyph(f,nofcontours)
local x=0
for i=1,nofpoints do
local flag=flags[i]
- local short=bittest(flag,0x0002)
- local same=bittest(flag,0x0010)
+ local short=band(flag,0x02)~=0
+ local same=band(flag,0x10)~=0
if short then
if same then
x=x+readbyte(f)
@@ -11219,13 +16688,13 @@ local function readglyph(f,nofcontours)
else
x=x+readshort(f)
end
- points[i]={ x,y,bittest(flag,0x0001) }
+ points[i]={ x,0,band(flag,0x01)~=0 }
end
local y=0
for i=1,nofpoints do
local flag=flags[i]
- local short=bittest(flag,0x0004)
- local same=bittest(flag,0x0020)
+ local short=band(flag,0x04)~=0
+ local same=band(flag,0x20)~=0
if short then
if same then
y=y+readbyte(f)
@@ -11238,15 +16707,11 @@ local function readglyph(f,nofcontours)
end
points[i][2]=y
end
- local first=1
- for i=1,#endpoints do
- local last=endpoints[i]
- endpoints[i]={ unpack(points,first,last) }
- first=last+1
- end
return {
type="glyph",
- contours=endpoints,
+ points=points,
+ contours=contours,
+ nofpoints=nofpoints,
}
end
local function readcomposite(f)
@@ -11256,8 +16721,8 @@ local function readcomposite(f)
while true do
local flags=readushort(f)
local index=readushort(f)
- local f_xyarg=bittest(flags,0x0002)
- local f_offset=bittest(flags,0x0800)
+ local f_xyarg=band(flags,0x0002)~=0
+ local f_offset=band(flags,0x0800)~=0
local xscale=1
local xrotate=0
local yrotate=0
@@ -11267,7 +16732,7 @@ local function readcomposite(f)
local base=false
local reference=false
if f_xyarg then
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
xoffset=readshort(f)
yoffset=readshort(f)
else
@@ -11275,7 +16740,7 @@ local function readcomposite(f)
yoffset=readchar(f)
end
else
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
base=readshort(f)
reference=readshort(f)
else
@@ -11283,21 +16748,21 @@ local function readcomposite(f)
reference=readchar(f)
end
end
- if bittest(flags,0x0008) then
+ if band(flags,0x0008)~=0 then
xscale=read2dot14(f)
yscale=xscale
if f_xyarg and f_offset then
xoffset=xoffset*xscale
yoffset=yoffset*yscale
end
- elseif bittest(flags,0x0040) then
+ elseif band(flags,0x0040)~=0 then
xscale=read2dot14(f)
yscale=read2dot14(f)
if f_xyarg and f_offset then
xoffset=xoffset*xscale
yoffset=yoffset*yscale
end
- elseif bittest(flags,0x0080) then
+ elseif band(flags,0x0080)~=0 then
xscale=read2dot14(f)
xrotate=read2dot14(f)
yrotate=read2dot14(f)
@@ -11310,16 +16775,16 @@ local function readcomposite(f)
nofcomponents=nofcomponents+1
components[nofcomponents]={
index=index,
- usemine=bittest(flags,0x0200),
- round=bittest(flags,0x0006),
+ usemine=band(flags,0x0200)~=0,
+ round=band(flags,0x0006)~=0,
base=base,
reference=reference,
matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset },
}
- if bittest(flags,0x0100) then
+ if band(flags,0x0100)~=0 then
instructions=true
end
- if not bittest(flags,0x0020) then
+ if not band(flags,0x0020)~=0 then
break
end
end
@@ -11337,15 +16802,13 @@ function readers.loca(f,fontdata,specification)
local locations={}
setposition(f,datatable.offset)
if format==1 then
- local nofglyphs=datatable.length/4-1
- -1
+ local nofglyphs=datatable.length/4-2
for i=0,nofglyphs do
locations[i]=offset+readulong(f)
end
fontdata.nofglyphs=nofglyphs
else
- local nofglyphs=datatable.length/2-1
- -1
+ local nofglyphs=datatable.length/2-2
for i=0,nofglyphs do
locations[i]=offset+readushort(f)*2
end
@@ -11356,53 +16819,317 @@ function readers.loca(f,fontdata,specification)
end
end
function readers.glyf(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.glyf
- if datatable then
- local locations=fontdata.locations
- if locations then
- local glyphs=fontdata.glyphs
- local nofglyphs=fontdata.nofglyphs
- local filesize=fontdata.filesize
- local nothing={ 0,0,0,0 }
- local shapes={}
- local loadshapes=specification.shapes
- for index=0,nofglyphs do
- local location=locations[index]
- if location>=filesize then
- report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
- fontdata.nofglyphs=index-1
- fontdata.badfont=true
- break
- elseif location>0 then
- setposition(f,location)
- local nofcontours=readshort(f)
- glyphs[index].boundingbox={
- readshort(f),
- readshort(f),
- readshort(f),
- readshort(f),
- }
- if not loadshapes then
- elseif nofcontours==0 then
- shapes[index]=readnothing(f,nofcontours)
- elseif nofcontours>0 then
- shapes[index]=readglyph(f,nofcontours)
+ local tableoffset=gotodatatable(f,fontdata,"glyf",specification.glyphs)
+ if tableoffset then
+ local locations=fontdata.locations
+ if locations then
+ local glyphs=fontdata.glyphs
+ local nofglyphs=fontdata.nofglyphs
+ local filesize=fontdata.filesize
+ local nothing={ 0,0,0,0 }
+ local shapes={}
+ local loadshapes=specification.shapes or specification.instance
+ for index=0,nofglyphs do
+ local location=locations[index]
+ if location>=filesize then
+ report("discarding %s glyphs due to glyph location bug",nofglyphs-index+1)
+ fontdata.nofglyphs=index-1
+ fontdata.badfont=true
+ break
+ elseif location>0 then
+ setposition(f,location)
+ local nofcontours=readshort(f)
+ glyphs[index].boundingbox={
+ readshort(f),
+ readshort(f),
+ readshort(f),
+ readshort(f),
+ }
+ if not loadshapes then
+ elseif nofcontours==0 then
+ shapes[index]=readnothing(f,nofcontours)
+ elseif nofcontours>0 then
+ shapes[index]=readglyph(f,nofcontours)
+ else
+ shapes[index]=readcomposite(f,nofcontours)
+ end
+ else
+ if loadshapes then
+ shapes[index]={}
+ end
+ glyphs[index].boundingbox=nothing
+ end
+ end
+ if loadshapes then
+ if readers.gvar then
+ readers.gvar(f,fontdata,specification,glyphs,shapes)
+ end
+ mergecomposites(glyphs,shapes)
+ if specification.instance then
+ if specification.streams then
+ repackpoints(glyphs,shapes)
+ else
+ contours2outlines_shaped(glyphs,shapes,specification.shapes)
+ end
+ elseif specification.shapes then
+ contours2outlines_normal(glyphs,shapes)
+ end
+ end
+ end
+ end
+end
+local function readtuplerecord(f,nofaxis)
+ local record={}
+ for i=1,nofaxis do
+ record[i]=read2dot14(f)
+ end
+ return record
+end
+local function readpoints(f)
+ local count=readbyte(f)
+ if count==0 then
+ return nil,0
+ else
+ if count<128 then
+ elseif band(count,0x80)~=0 then
+ count=band(count,0x7F)*256+readbyte(f)
+ else
+ end
+ local points={}
+ local p=0
+ local n=1
+ while p<count do
+ local control=readbyte(f)
+ local runreader=band(control,0x80)~=0 and readushort or readbyte
+ local runlength=band(control,0x7F)
+ for i=1,runlength+1 do
+ n=n+runreader(f)
+ p=p+1
+ points[p]=n
+ end
+ end
+ return points,p
+ end
+end
+local function readdeltas(f,nofpoints)
+ local deltas={}
+ local p=0
+ local z=0
+ while nofpoints>0 do
+ local control=readbyte(f)
+if not control then
+ break
+end
+ local allzero=band(control,0x80)~=0
+ local runlength=band(control,0x3F)+1
+ if allzero then
+ z=z+runlength
+ else
+ local runreader=band(control,0x40)~=0 and readshort or readinteger
+ if z>0 then
+ for i=1,z do
+ p=p+1
+ deltas[p]=0
+ end
+ z=0
+ end
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=runreader(f)
+ end
+ end
+ nofpoints=nofpoints-runlength
+ end
+ if p>0 then
+ return deltas
+ else
+ end
+end
+local function readdeltas(f,nofpoints)
+ local deltas={}
+ local p=0
+ while nofpoints>0 do
+ local control=readbyte(f)
+ if control then
+ local allzero=band(control,0x80)~=0
+ local runlength=band(control,0x3F)+1
+ if allzero then
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=0
+ end
+ else
+ local runreader=band(control,0x40)~=0 and readshort or readinteger
+ for i=1,runlength do
+ p=p+1
+ deltas[p]=runreader(f)
+ end
+ end
+ nofpoints=nofpoints-runlength
+ else
+ break
+ end
+ end
+ if p>0 then
+ return deltas
+ else
+ end
+end
+function readers.gvar(f,fontdata,specification,glyphdata,shapedata)
+ local instance=specification.instance
+ if not instance then
+ return
+ end
+ local factors=specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset=gotodatatable(f,fontdata,"gvar",specification.variable or specification.shapes)
+ if tableoffset then
+ local version=readulong(f)
+ local nofaxis=readushort(f)
+ local noftuples=readushort(f)
+ local tupleoffset=tableoffset+readulong(f)
+ local nofglyphs=readushort(f)
+ local flags=readushort(f)
+ local dataoffset=tableoffset+readulong(f)
+ local data={}
+ local tuples={}
+ local glyphdata=fontdata.glyphs
+ local dowidth=not fontdata.variabledata.hvarwidths
+ if band(flags,0x0001)~=0 then
+ for i=1,nofglyphs+1 do
+ data[i]=dataoffset+readulong(f)
+ end
+ else
+ for i=1,nofglyphs+1 do
+ data[i]=dataoffset+2*readushort(f)
+ end
+ end
+ if noftuples>0 then
+ setposition(f,tupleoffset)
+ for i=1,noftuples do
+ tuples[i]=readtuplerecord(f,nofaxis)
+ end
+ end
+ local nextoffset=false
+ local startoffset=data[1]
+ for i=1,nofglyphs do
+ nextoffset=data[i+1]
+ local glyph=glyphdata[i-1]
+ local name=trace_deltas and glyph.name
+ if startoffset==nextoffset then
+ if name then
+ report("no deltas for glyph %a",name)
+ end
+ else
+ local shape=shapedata[i-1]
+ if not shape then
+ if name then
+ report("no shape for glyph %a",name)
+ end
+ else
+ lastoffset=startoffset
+ setposition(f,startoffset)
+ local flags=readushort(f)
+ local count=band(flags,0x0FFF)
+ local offset=startoffset+readushort(f)
+ local deltas={}
+ local allpoints=(shape.nofpoints or 0)
+ local shared=false
+ local nofshared=0
+ if band(flags,0x8000)~=0 then
+ local current=getposition(f)
+ setposition(f,offset)
+ shared,nofshared=readpoints(f)
+ offset=getposition(f)
+ setposition(f,current)
+ end
+ for j=1,count do
+ local size=readushort(f)
+ local flags=readushort(f)
+ local index=band(flags,0x0FFF)
+ local haspeak=band(flags,0x8000)~=0
+ local intermediate=band(flags,0x4000)~=0
+ local private=band(flags,0x2000)~=0
+ local peak=nil
+ local start=nil
+ local stop=nil
+ local xvalues=nil
+ local yvalues=nil
+ local points=shared
+ local nofpoints=nofshared
+ if haspeak then
+ peak=readtuplerecord(f,nofaxis)
else
- shapes[index]=readcomposite(f,nofcontours)
+ if index+1>#tuples then
+ report("error, bad tuple index",index)
+ end
+ peak=tuples[index+1]
end
- else
- if loadshapes then
- shapes[index]={}
+ if intermediate then
+ start=readtuplerecord(f,nofaxis)
+ stop=readtuplerecord(f,nofaxis)
+ end
+ if size>0 then
+ local current=getposition(f)
+ setposition(f,offset)
+ if private then
+ points,nofpoints=readpoints(f)
+ end
+ if nofpoints==0 then
+ nofpoints=allpoints+4
+ end
+ if nofpoints>0 then
+ xvalues=readdeltas(f,nofpoints)
+ yvalues=readdeltas(f,nofpoints)
+ end
+ offset=offset+size
+ setposition(f,current)
+ end
+ if not xvalues and not yvalues then
+ points=nil
+ end
+ local s=1
+ for i=1,nofaxis do
+ local f=factors[i]
+ local peak=peak and peak [i] or 0
+ local start=start and start[i] or (peak<0 and peak or 0)
+ local stop=stop and stop [i] or (peak>0 and peak or 0)
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ if s==0 then
+ if name then
+ report("no deltas applied for glyph %a",name)
+ end
+ else
+ deltas[#deltas+1]={
+ factor=s,
+ points=points,
+ xvalues=xvalues,
+ yvalues=yvalues,
+ }
end
- glyphs[index].boundingbox=nothing
end
- end
- if loadshapes then
- mergecomposites(glyphs,shapes)
- contours2outlines(glyphs,shapes)
+ if shape.type=="glyph" then
+ applyaxis(glyph,shape,deltas,dowidth)
+ else
+ shape.deltas=deltas
+ end
end
end
+ startoffset=nextoffset
end
end
end
@@ -11419,34 +17146,80 @@ if not modules then modules={} end modules ['font-dsp']={
license="see context related readme files"
}
local next,type=next,type
-local bittest=bit32.btest
+local band=bit32.band
+local extract=bit32.extract
+local bor=bit32.bor
+local lshift=bit32.lshift
local rshift=bit32.rshift
-local concat=table.concat
+local gsub=string.gsub
local lower=string.lower
-local copy=table.copy
local sub=string.sub
local strip=string.strip
local tohash=table.tohash
+local concat=table.concat
+local copy=table.copy
local reversed=table.reversed
+local sort=table.sort
+local insert=table.insert
+local round=math.round
+local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
+local sequenced=table.sequenced
local report=logs.reporter("otf reader")
local readers=fonts.handlers.otf.readers
local streamreader=readers.streamreader
local setposition=streamreader.setposition
local getposition=streamreader.getposition
-local skipshort=streamreader.skipshort
local readushort=streamreader.readcardinal2
local readulong=streamreader.readcardinal4
+local readinteger=streamreader.readinteger1
local readshort=streamreader.readinteger2
-local readfword=readshort
local readstring=streamreader.readstring
local readtag=streamreader.readtag
local readbytes=streamreader.readbytes
+local readfixed=streamreader.readfixed4
+local read2dot14=streamreader.read2dot14
+local skipshort=streamreader.skipshort
+local skipbytes=streamreader.skip
+local readbytetable=streamreader.readbytetable
+local readbyte=streamreader.readbyte
+local readcardinaltable=streamreader.readcardinaltable
+local readintegertable=streamreader.readintegertable
+local readfword=readshort
+local short=2
+local ushort=2
+local ulong=4
+directives.register("fonts.streamreader",function()
+ streamreader=utilities.streams
+ setposition=streamreader.setposition
+ getposition=streamreader.getposition
+ readushort=streamreader.readcardinal2
+ readulong=streamreader.readcardinal4
+ readinteger=streamreader.readinteger1
+ readshort=streamreader.readinteger2
+ readstring=streamreader.readstring
+ readtag=streamreader.readtag
+ readbytes=streamreader.readbytes
+ readfixed=streamreader.readfixed4
+ read2dot14=streamreader.read2dot14
+ skipshort=streamreader.skipshort
+ skipbytes=streamreader.skip
+ readbytetable=streamreader.readbytetable
+ readbyte=streamreader.readbyte
+ readcardinaltable=streamreader.readcardinaltable
+ readintegertable=streamreader.readintegertable
+ readfword=readshort
+end)
local gsubhandlers={}
local gposhandlers={}
+readers.gsubhandlers=gsubhandlers
+readers.gposhandlers=gposhandlers
+local helpers=readers.helpers
+local gotodatatable=helpers.gotodatatable
+local setvariabledata=helpers.setvariabledata
local lookupidoffset=-1
local classes={
"base",
@@ -11480,6 +17253,51 @@ local chaindirections={
chainedcontext=1,
reversechainedcontextsingle=-1,
}
+local function setmetrics(data,where,tag,d)
+ local w=data[where]
+ if w then
+ local v=w[tag]
+ if v then
+ w[tag]=v+d
+ end
+ end
+end
+local variabletags={
+ hasc=function(data,d) setmetrics(data,"windowsmetrics","typoascender",d) end,
+ hdsc=function(data,d) setmetrics(data,"windowsmetrics","typodescender",d) end,
+ hlgp=function(data,d) setmetrics(data,"windowsmetrics","typolinegap",d) end,
+ hcla=function(data,d) setmetrics(data,"windowsmetrics","winascent",d) end,
+ hcld=function(data,d) setmetrics(data,"windowsmetrics","windescent",d) end,
+ vasc=function(data,d) setmetrics(data,"vhea not done","ascent",d) end,
+ vdsc=function(data,d) setmetrics(data,"vhea not done","descent",d) end,
+ vlgp=function(data,d) setmetrics(data,"vhea not done","linegap",d) end,
+ xhgt=function(data,d) setmetrics(data,"windowsmetrics","xheight",d) end,
+ cpht=function(data,d) setmetrics(data,"windowsmetrics","capheight",d) end,
+ sbxs=function(data,d) setmetrics(data,"windowsmetrics","subscriptxsize",d) end,
+ sbys=function(data,d) setmetrics(data,"windowsmetrics","subscriptysize",d) end,
+ sbxo=function(data,d) setmetrics(data,"windowsmetrics","subscriptxoffset",d) end,
+ sbyo=function(data,d) setmetrics(data,"windowsmetrics","subscriptyoffset",d) end,
+ spxs=function(data,d) setmetrics(data,"windowsmetrics","superscriptxsize",d) end,
+ spys=function(data,d) setmetrics(data,"windowsmetrics","superscriptysize",d) end,
+ spxo=function(data,d) setmetrics(data,"windowsmetrics","superscriptxoffset",d) end,
+ spyo=function(data,d) setmetrics(data,"windowsmetrics","superscriptyoffset",d) end,
+ strs=function(data,d) setmetrics(data,"windowsmetrics","strikeoutsize",d) end,
+ stro=function(data,d) setmetrics(data,"windowsmetrics","strikeoutpos",d) end,
+ unds=function(data,d) setmetrics(data,"postscript","underlineposition",d) end,
+ undo=function(data,d) setmetrics(data,"postscript","underlinethickness",d) end,
+}
+local read_cardinal={
+ streamreader.readcardinal1,
+ streamreader.readcardinal2,
+ streamreader.readcardinal3,
+ streamreader.readcardinal4,
+}
+local read_integer={
+ streamreader.readinteger1,
+ streamreader.readinteger2,
+ streamreader.readinteger3,
+ streamreader.readinteger4,
+}
local lookupnames={
gsub={
single="gsub_single",
@@ -11503,31 +17321,236 @@ local lookupnames={
}
local lookupflags=setmetatableindex(function(t,k)
local v={
- bittest(k,0x0008) and true or false,
- bittest(k,0x0004) and true or false,
- bittest(k,0x0002) and true or false,
- bittest(k,0x0001) and true or false,
+ band(k,0x0008)~=0 and true or false,
+ band(k,0x0004)~=0 and true or false,
+ band(k,0x0002)~=0 and true or false,
+ band(k,0x0001)~=0 and true or false,
}
t[k]=v
return v
end)
+local function axistofactors(str)
+ local t=settings_to_hash(str)
+ for k,v in next,t do
+ t[k]=tonumber(v) or v
+ end
+ return t
+end
+local hash=table.setmetatableindex(function(t,k)
+ local v=sequenced(axistofactors(k),",")
+ t[k]=v
+ return v
+end)
+helpers.normalizedaxishash=hash
+local cleanname=fonts.names and fonts.names.cleanname or function(name)
+ return name and (gsub(lower(name),"[^%a%d]","")) or nil
+end
+helpers.cleanname=cleanname
+function helpers.normalizedaxis(str)
+ return hash[str] or str
+end
+local function getaxisscale(segments,minimum,default,maximum,user)
+ if not minimum or not default or not maximum then
+ return false
+ end
+ if user<minimum then
+ user=minimum
+ elseif user>maximum then
+ user=maximum
+ end
+ if user<default then
+ default=- (default-user)/(default-minimum)
+ elseif user>default then
+ default=(user-default)/(maximum-default)
+ else
+ default=0
+ end
+ if not segments then
+ return default
+ end
+ local e
+ for i=1,#segments do
+ local s=segments[i]
+ if type(s)~="number" then
+ report("using default axis scale")
+ return default
+ elseif s[1]>=default then
+ if s[2]==default then
+ return default
+ else
+ e=i
+ break
+ end
+ end
+ end
+ if e then
+ local b=segments[e-1]
+ local e=segments[e]
+ return b[2]+(e[2]-b[2])*(default-b[1])/(e[1]-b[1])
+ else
+ return false
+ end
+end
+local function getfactors(data,instancespec)
+ if instancespec==true then
+ elseif type(instancespec)~="string" or instancespec=="" then
+ return
+ end
+ local variabledata=data.variabledata
+ if not variabledata then
+ return
+ end
+ local instances=variabledata.instances
+ local axis=variabledata.axis
+ local segments=variabledata.segments
+ if instances and axis then
+ local values
+ if instancespec==true then
+ values={}
+ for i=1,#axis do
+ values[i]={
+ value=axis[i].default,
+ }
+ end
+ else
+ for i=1,#instances do
+ local instance=instances[i]
+ if cleanname(instance.subfamily)==instancespec then
+ values=instance.values
+ break
+ end
+ end
+ end
+ if values then
+ local factors={}
+ for i=1,#axis do
+ local a=axis[i]
+ factors[i]=getaxisscale(segments,a.minimum,a.default,a.maximum,values[i].value)
+ end
+ return factors
+ end
+ local values=axistofactors(hash[instancespec] or instancespec)
+ if values then
+ local factors={}
+ for i=1,#axis do
+ local a=axis[i]
+ local d=a.default
+ factors[i]=getaxisscale(segments,a.minimum,d,a.maximum,values[a.name or a.tag] or d)
+ end
+ return factors
+ end
+ end
+end
+local function getscales(regions,factors)
+ local scales={}
+ for i=1,#regions do
+ local region=regions[i]
+ local s=1
+ for j=1,#region do
+ local axis=region[j]
+ local f=factors[j]
+ local start=axis.start
+ local peak=axis.peak
+ local stop=axis.stop
+ if start>peak or peak>stop then
+ elseif start<0 and stop>0 and peak~=0 then
+ elseif peak==0 then
+ elseif f<start or f>stop then
+ s=0
+ break
+ elseif f<peak then
+ s=s*(f-start)/(peak-start)
+ elseif f>peak then
+ s=s*(stop-f)/(stop-peak)
+ else
+ end
+ end
+ scales[i]=s
+ end
+ return scales
+end
+helpers.getaxisscale=getaxisscale
+helpers.getfactors=getfactors
+helpers.getscales=getscales
+helpers.axistofactors=axistofactors
+local function readvariationdata(f,storeoffset,factors)
+ local position=getposition(f)
+ setposition(f,storeoffset)
+ local format=readushort(f)
+ local regionoffset=storeoffset+readulong(f)
+ local nofdeltadata=readushort(f)
+ local deltadata=readcardinaltable(f,nofdeltadata,ulong)
+ setposition(f,regionoffset)
+ local nofaxis=readushort(f)
+ local nofregions=readushort(f)
+ local regions={}
+ for i=1,nofregions do
+ local t={}
+ for i=1,nofaxis do
+ t[i]={
+ start=read2dot14(f),
+ peak=read2dot14(f),
+ stop=read2dot14(f),
+ }
+ end
+ regions[i]=t
+ end
+ if factors then
+ for i=1,nofdeltadata do
+ setposition(f,storeoffset+deltadata[i])
+ local nofdeltasets=readushort(f)
+ local nofshorts=readushort(f)
+ local nofregions=readushort(f)
+ local usedregions={}
+ local deltas={}
+ for i=1,nofregions do
+ usedregions[i]=regions[readushort(f)+1]
+ end
+ for i=1,nofdeltasets do
+ local t=readintegertable(f,nofshorts,short)
+ for i=nofshorts+1,nofregions do
+ t[i]=readinteger(f)
+ end
+ deltas[i]=t
+ end
+ deltadata[i]={
+ regions=usedregions,
+ deltas=deltas,
+ scales=factors and getscales(usedregions,factors) or nil,
+ }
+ end
+ end
+ setposition(f,position)
+ return regions,deltadata
+end
+helpers.readvariationdata=readvariationdata
local function readcoverage(f,offset,simple)
setposition(f,offset)
local coverageformat=readushort(f)
- local coverage={}
if coverageformat==1 then
local nofcoverage=readushort(f)
if simple then
- for i=1,nofcoverage do
- coverage[i]=readushort(f)
+ if nofcoverage==1 then
+ return { readushort(f) }
+ elseif nofcoverage==2 then
+ return { readushort(f),readushort(f) }
+ else
+ return readcardinaltable(f,nofcoverage,ushort)
end
+ elseif nofcoverage==1 then
+ return { [readushort(f)]=0 }
+ elseif nofcoverage==2 then
+ return { [readushort(f)]=0,[readushort(f)]=1 }
else
+ local coverage={}
for i=0,nofcoverage-1 do
coverage[readushort(f)]=i
end
+ return coverage
end
elseif coverageformat==2 then
local nofranges=readushort(f)
+ local coverage={}
local n=simple and 1 or 0
for i=1,nofranges do
local firstindex=readushort(f)
@@ -11545,10 +17568,11 @@ local function readcoverage(f,offset,simple)
end
end
end
+ return coverage
else
report("unknown coverage format %a ",coverageformat)
+ return {}
end
- return coverage
end
local function readclassdef(f,offset,preset)
setposition(f,offset)
@@ -11603,34 +17627,150 @@ local function classtocoverage(defs)
return list
end
end
-local function readposition(f,format)
+local skips={ [0]=0,
+ 1,
+ 1,
+ 2,
+ 1,
+ 2,
+ 2,
+ 3,
+ 2,
+ 2,
+ 3,
+ 2,
+ 3,
+ 3,
+ 4,
+}
+local function readvariation(f,offset)
+ local p=getposition(f)
+ setposition(f,offset)
+ local outer=readushort(f)
+ local inner=readushort(f)
+ local format=readushort(f)
+ setposition(f,p)
+ if format==0x8000 then
+ return outer,inner
+ end
+end
+local function readposition(f,format,mainoffset,getdelta)
if format==0 then
- return nil
+ return false
end
- local x=bittest(format,0x0001) and readshort(f) or 0
- local y=bittest(format,0x0002) and readshort(f) or 0
- local h=bittest(format,0x0004) and readshort(f) or 0
- local v=bittest(format,0x0008) and readshort(f) or 0
- if x==0 and y==0 and h==0 and v==0 then
- return nil
+ if format==0x04 then
+ local h=readshort(f)
+ if h==0 then
+ return true
+ else
+ return { 0,0,h,0 }
+ end
+ end
+ if format==0x05 then
+ local x=readshort(f)
+ local h=readshort(f)
+ if x==0 and h==0 then
+ return true
+ else
+ return { x,0,h,0 }
+ end
+ end
+ if format==0x44 then
+ local h=readshort(f)
+ if getdelta then
+ local d=readshort(f)
+ if d>0 then
+ local outer,inner=readvariation(f,mainoffset+d)
+ if outer then
+ h=h+getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,1)
+ end
+ if h==0 then
+ return true
+ else
+ return { 0,0,h,0 }
+ end
+ end
+ local x=band(format,0x1)~=0 and readshort(f) or 0
+ local y=band(format,0x2)~=0 and readshort(f) or 0
+ local h=band(format,0x4)~=0 and readshort(f) or 0
+ local v=band(format,0x8)~=0 and readshort(f) or 0
+ if format>=0x10 then
+ local X=band(format,0x10)~=0 and skipshort(f) or 0
+ local Y=band(format,0x20)~=0 and skipshort(f) or 0
+ local H=band(format,0x40)~=0 and skipshort(f) or 0
+ local V=band(format,0x80)~=0 and skipshort(f) or 0
+ local s=skips[extract(format,4,4)]
+ if s>0 then
+ skipshort(f,s)
+ end
+ if getdelta then
+ if X>0 then
+ local outer,inner=readvariation(f,mainoffset+X)
+ if outer then
+ x=x+getdelta(outer,inner)
+ end
+ end
+ if Y>0 then
+ local outer,inner=readvariation(f,mainoffset+Y)
+ if outer then
+ y=y+getdelta(outer,inner)
+ end
+ end
+ if H>0 then
+ local outer,inner=readvariation(f,mainoffset+H)
+ if outer then
+ h=h+getdelta(outer,inner)
+ end
+ end
+ if V>0 then
+ local outer,inner=readvariation(f,mainoffset+V)
+ if outer then
+ v=v+getdelta(outer,inner)
+ end
+ end
+ end
+ return { x,y,h,v }
+ elseif x==0 and y==0 and h==0 and v==0 then
+ return true
else
return { x,y,h,v }
end
end
-local function readanchor(f,offset)
+local function readanchor(f,offset,getdelta)
if not offset or offset==0 then
return nil
end
setposition(f,offset)
- local format=readshort(f)
- if format==0 then
- report("invalid anchor format %i @ position %i",format,offset)
- return false
- elseif format>3 then
- report("unsupported anchor format %i @ position %i",format,offset)
- return false
+ local format=readshort(f)
+ local x=readshort(f)
+ local y=readshort(f)
+ if format==3 then
+ if getdelta then
+ local X=readshort(f)
+ local Y=readshort(f)
+ if X>0 then
+ local outer,inner=readvariation(f,offset+X)
+ if outer then
+ x=x+getdelta(outer,inner)
+ end
+ end
+ if Y>0 then
+ local outer,inner=readvariation(f,offset+Y)
+ if outer then
+ y=y+getdelta(outer,inner)
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ return { x,y }
+ else
+ return { x,y }
end
- return { readshort(f),readshort(f) }
end
local function readfirst(f,offset)
if offset then
@@ -11638,23 +17778,15 @@ local function readfirst(f,offset)
end
return { readushort(f) }
end
-local function readarray(f,offset,first)
+function readarray(f,offset)
if offset then
setposition(f,offset)
end
local n=readushort(f)
- if first then
- local t={ first }
- for i=2,n do
- t[i]=readushort(f)
- end
- return t,n
+ if n==1 then
+ return { readushort(f) },1
elseif n>0 then
- local t={}
- for i=1,n do
- t[i]=readushort(f)
- end
- return t,n
+ return readcardinaltable(f,n,ushort),n
end
end
local function readcoveragearray(f,offset,t,simple)
@@ -11695,7 +17827,13 @@ local function readlookuparray(f,noflookups,nofcurrent)
if index>length then
length=index
end
- lookups[index]=readushort(f)+1
+ local lookup=readushort(f)+1
+ local list=lookups[index]
+ if list then
+ list[#list+1]=lookup
+ else
+ lookups[index]={ lookup }
+ end
end
for index=1,length do
if not lookups[index] then
@@ -12001,10 +18139,7 @@ function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
elseif subtype==2 then
local coverage=readushort(f)
local nofreplacements=readushort(f)
- local replacements={}
- for i=1,nofreplacements do
- replacements[i]=readushort(f)
- end
+ local replacements=readcardinaltable(f,nofreplacements,ushort)
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
newindex=newindex+1
@@ -12029,18 +18164,10 @@ local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
if subtype==1 then
local coverage=readushort(f)
local nofsequence=readushort(f)
- local sequences={}
- for i=1,nofsequence do
- sequences[i]=readushort(f)
- end
+ local sequences=readcardinaltable(f,nofsequence,ushort)
for i=1,nofsequence do
setposition(f,tableoffset+sequences[i])
- local n=readushort(f)
- local s={}
- for i=1,n do
- s[i]=readushort(f)
- end
- sequences[i]=s
+ sequences[i]=readcardinaltable(f,readushort(f),ushort)
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
@@ -12072,19 +18199,20 @@ function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,no
if subtype==1 then
local coverage=readushort(f)
local nofsets=readushort(f)
- local ligatures={}
- for i=1,nofsets do
- ligatures[i]=readushort(f)
- end
+ local ligatures=readcardinaltable(f,nofsets,ushort)
for i=1,nofsets do
local offset=lookupoffset+offset+ligatures[i]
setposition(f,offset)
local n=readushort(f)
- local l={}
- for i=1,n do
- l[i]=offset+readushort(f)
+ if n==1 then
+ ligatures[i]={ offset+readushort(f) }
+ else
+ local l={}
+ for i=1,n do
+ l[i]=offset+readushort(f)
+ end
+ ligatures[i]=l
end
- ligatures[i]=l
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
@@ -12138,32 +18266,35 @@ function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffs
before=readcoveragearray(f,tableoffset,before,true)
after=readcoveragearray(f,tableoffset,after,true)
return {
- coverage={
- format="reversecoverage",
- before=before,
- current=current,
- after=after,
- replacements=replacements,
+ format="reversecoverage",
+ rules={
+ {
+ before=before,
+ current=current,
+ after=after,
+ replacements=replacements,
+ }
}
},"reversechainedcontextsingle"
else
report("unsupported subtype %a in %a substitution",subtype,"reversechainedcontextsingle")
end
end
-local function readpairsets(f,tableoffset,sets,format1,format2)
+local function readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
local done={}
for i=1,#sets do
local offset=sets[i]
local reused=done[offset]
if not reused then
- setposition(f,tableoffset+offset)
+ offset=tableoffset+offset
+ setposition(f,offset)
local n=readushort(f)
reused={}
for i=1,n do
reused[i]={
readushort(f),
- readposition(f,format1),
- readposition(f,format2)
+ readposition(f,format1,offset,getdelta),
+ readposition(f,format2,offset,getdelta),
}
end
done[offset]=reused
@@ -12172,14 +18303,14 @@ local function readpairsets(f,tableoffset,sets,format1,format2)
end
return sets
end
-local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+local function readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,mainoffset,getdelta)
local classlist1={}
for i=1,nofclasses1 do
local classlist2={}
classlist1[i]=classlist2
for j=1,nofclasses2 do
- local one=readposition(f,format1)
- local two=readposition(f,format2)
+ local one=readposition(f,format1,mainoffset,getdelta)
+ local two=readposition(f,format2,mainoffset,getdelta)
if one or two then
classlist2[j]={ one,two }
else
@@ -12193,33 +18324,34 @@ function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofg
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=readushort(f)
local format=readushort(f)
- local value=readposition(f,format)
+ local value=readposition(f,format,tableoffset,getdelta)
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
- coverage[index]=value
+ coverage[index]=value
end
return {
- format="pair",
- coverage=coverage
+ format="single",
+ coverage=coverage,
}
elseif subtype==2 then
local coverage=readushort(f)
local format=readushort(f)
- local values={}
local nofvalues=readushort(f)
+ local values={}
for i=1,nofvalues do
- values[i]=readposition(f,format)
+ values[i]=readposition(f,format,tableoffset,getdelta)
end
local coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
coverage[index]=values[newindex+1]
end
return {
- format="pair",
- coverage=coverage
+ format="single",
+ coverage=coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"single")
@@ -12229,12 +18361,13 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=readushort(f)
local format1=readushort(f)
local format2=readushort(f)
local sets=readarray(f)
- sets=readpairsets(f,tableoffset,sets,format1,format2)
+ sets=readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta)
coverage=readcoverage(f,tableoffset+coverage)
for index,newindex in next,coverage do
local set=sets[newindex+1]
@@ -12246,9 +18379,9 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first=value[2]
local second=value[3]
if first or second then
- hash[other]={ first,second }
+ hash[other]={ first,second or nil }
else
- hash[other]=nil
+ hash[other]=nil
end
end
end
@@ -12256,7 +18389,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format="pair",
- coverage=coverage
+ coverage=coverage,
}
elseif subtype==2 then
local coverage=readushort(f)
@@ -12266,7 +18399,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local classdef2=readushort(f)
local nofclasses1=readushort(f)
local nofclasses2=readushort(f)
- local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2)
+ local classlist=readpairclasssets(f,nofclasses1,nofclasses2,format1,format2,tableoffset,getdelta)
coverage=readcoverage(f,tableoffset+coverage)
classdef1=readclassdef(f,tableoffset+classdef1,coverage)
classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs)
@@ -12282,7 +18415,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
local first=offsets[1]
local second=offsets[2]
if first or second then
- hash[paired]={ first,second }
+ hash[paired]={ first,second or nil }
else
end
end
@@ -12293,7 +18426,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly
end
return {
format="pair",
- coverage=usedcoverage
+ coverage=usedcoverage,
}
elseif subtype==3 then
report("yet unsupported subtype %a in %a positioning",subtype,"pair")
@@ -12305,6 +18438,7 @@ function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local coverage=tableoffset+readushort(f)
local nofrecords=readushort(f)
@@ -12313,24 +18447,27 @@ function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nof
local entry=readushort(f)
local exit=readushort(f)
records[i]={
- entry=entry~=0 and (tableoffset+entry) or false,
- exit=exit~=0 and (tableoffset+exit ) or false,
+ entry~=0 and (tableoffset+entry) or false,
+ exit~=0 and (tableoffset+exit ) or nil,
}
end
+ local cc=(fontdata.temporary.cursivecount or 0)+1
+ fontdata.temporary.cursivecount=cc
+ cc="cc-"..cc
coverage=readcoverage(f,coverage)
for i=1,nofrecords do
local r=records[i]
records[i]={
- 1,
- readanchor(f,r.entry) or nil,
- readanchor(f,r.exit ) or nil,
+ cc,
+ readanchor(f,r[1],getdelta) or false,
+ readanchor(f,r[2],getdelta) or nil,
}
end
for index,newindex in next,coverage do
coverage[index]=records[newindex+1]
end
return {
- coverage=coverage
+ coverage=coverage,
}
else
report("unsupported subtype %a in %a positioning",subtype,"cursive")
@@ -12340,6 +18477,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local tableoffset=lookupoffset+offset
setposition(f,tableoffset)
local subtype=readushort(f)
+ local getdelta=fontdata.temporary.getdelta
if subtype==1 then
local markcoverage=tableoffset+readushort(f)
local basecoverage=tableoffset+readushort(f)
@@ -12366,7 +18504,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
for i=1,nofmarkclasses do
local mc=markclasses[i]
if mc then
- mc[2]=readanchor(f,mc[2])
+ mc[2]=readanchor(f,mc[2],getdelta)
end
end
setposition(f,baseoffset)
@@ -12414,7 +18552,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local classes=components[c]
if classes then
for i=1,nofclasses do
- local anchor=readanchor(f,classes[i])
+ local anchor=readanchor(f,classes[i],getdelta)
local bclass=baseclasses[i]
local bentry=bclass[b]
if bentry then
@@ -12456,7 +18594,7 @@ local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyp
local r=baserecords[i]
local b=basecoverage[i]
for j=1,nofclasses do
- baseclasses[j][b]=readanchor(f,r[j])
+ baseclasses[j][b]=readanchor(f,r[j],getdelta)
end
end
for index,newindex in next,markcoverage do
@@ -12499,7 +18637,7 @@ do
setposition(f,offset)
local designsize=readushort(f)
if designsize>0 then
- local fontstyle=readushort(f)
+ local fontstyleid=readushort(f)
local guimenuid=readushort(f)
local minsize=readushort(f)
local maxsize=readushort(f)
@@ -12651,10 +18789,10 @@ do
local parameters=readushort(f)
local noflookups=readushort(f)
if noflookups>0 then
- local lookups={}
+ local lookups=readcardinaltable(f,noflookups,ushort)
feature.lookups=lookups
for j=1,noflookups do
- lookups[j]=readushort(f)+1
+ lookups[j]=lookups[j]+1
end
end
if parameters>0 then
@@ -12669,14 +18807,11 @@ do
end
local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
setposition(f,lookupoffset)
- local lookups={}
local noflookups=readushort(f)
- for i=1,noflookups do
- lookups[i]=readushort(f)
- end
+ local lookups=readcardinaltable(f,noflookups,ushort)
for lookupid=1,noflookups do
- local index=lookups[lookupid]
- setposition(f,lookupoffset+index)
+ local offset=lookups[lookupid]
+ setposition(f,lookupoffset+offset)
local subtables={}
local typebits=readushort(f)
local flagbits=readushort(f)
@@ -12684,10 +18819,9 @@ do
local lookupflags=lookupflags[flagbits]
local nofsubtables=readushort(f)
for j=1,nofsubtables do
- local offset=readushort(f)
- subtables[j]=offset+index
+ subtables[j]=offset+readushort(f)
end
- local markclass=bittest(flagbits,0x0010)
+ local markclass=band(flagbits,0x0010)~=0
if markclass then
markclass=readushort(f)
end
@@ -12707,21 +18841,9 @@ do
end
return lookups
end
- local function readscriptoffsets(f,fontdata,tableoffset)
- if not tableoffset then
- return
- end
- setposition(f,tableoffset)
- local version=readulong(f)
- if version~=0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,what,fontdata.filename)
- return
- end
- return tableoffset+readushort(f),tableoffset+readushort(f),tableoffset+readushort(f)
- end
local f_lookupname=formatters["%s_%s_%s"]
- local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
- local sequences=fontdata.sequences or {}
+ local function resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ local sequences=fontdata.sequences or {}
local sublookuplist=fontdata.sublookups or {}
fontdata.sequences=sequences
fontdata.sublookups=sublookuplist
@@ -12736,6 +18858,7 @@ do
local nofglyphs=fontdata.nofglyphs or #glyphs
local noflookups=#lookups
local lookupprefix=sub(what,2,2)
+ local usedlookups=false
for lookupid=1,noflookups do
local lookup=lookups[lookupid]
local lookuptype=lookup.type
@@ -12775,6 +18898,7 @@ do
local before=rule.before
local current=rule.current
local after=rule.after
+ local replacements=rule.replacements
if before then
for i=1,#before do
before[i]=tohash(before[i])
@@ -12782,15 +18906,41 @@ do
rule.before=reversed(before)
end
if current then
- for i=1,#current do
- current[i]=tohash(current[i])
+ if replacements then
+ local first=current[1]
+ local hash={}
+ local repl={}
+ for i=1,#first do
+ local c=first[i]
+ hash[c]=true
+ repl[c]=replacements[i]
+ end
+ rule.current={ hash }
+ rule.replacements=repl
+ else
+ for i=1,#current do
+ current[i]=tohash(current[i])
+ end
end
+ else
end
if after then
for i=1,#after do
after[i]=tohash(after[i])
end
end
+ if usedlookups then
+ local lookups=rule.lookups
+ if lookups then
+ for k,v in next,lookups do
+ if v then
+ for k,v in next,v do
+ usedlookups[v]=usedlookups[v]+1
+ end
+ end
+ end
+ end
+ end
end
end
end
@@ -12837,6 +18987,9 @@ do
report("no handler for lookup %a with type %a",lookupid,lookuptype)
end
end
+ if usedlookups then
+ report("used %s lookups: % t",what,sortedkeys(usedlookups))
+ end
local reported={}
local function report_issue(i,what,sequence,kind)
local name=sequence.name
@@ -12863,42 +19016,55 @@ do
else
local length=#rlookups
for index=1,length do
- local lookupid=rlookups[index]
- if lookupid then
- local h=sublookuphash[lookupid]
- if not h then
- local lookup=lookups[lookupid]
- if lookup then
- local d=lookup.done
- if d then
- nofsublookups=nofsublookups+1
- h={
- index=nofsublookups,
- name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
- derived=true,
- steps=d.steps,
- nofsteps=d.nofsteps,
- type=d.lookuptype,
- markclass=d.markclass or nil,
- flags=d.flags,
- }
- sublookuplist[nofsublookups]=copy(h)
- sublookuphash[lookupid]=nofsublookups
- sublookupcheck[lookupid]=1
+ local lookuplist=rlookups[index]
+ if lookuplist then
+ local length=#lookuplist
+ local found={}
+ local noffound=0
+ for index=1,length do
+ local lookupid=lookuplist[index]
+ if lookupid then
+ local h=sublookuphash[lookupid]
+ if not h then
+ local lookup=lookups[lookupid]
+ if lookup then
+ local d=lookup.done
+ if d then
+ nofsublookups=nofsublookups+1
+ local l={
+ index=nofsublookups,
+ name=f_lookupname(lookupprefix,"d",lookupid+lookupidoffset),
+ derived=true,
+ steps=d.steps,
+ nofsteps=d.nofsteps,
+ type=d.lookuptype or "gsub_single",
+ markclass=d.markclass or nil,
+ flags=d.flags,
+ }
+ sublookuplist[nofsublookups]=copy(l)
+ sublookuphash[lookupid]=nofsublookups
+ sublookupcheck[lookupid]=1
+ h=nofsublookups
+ else
+ report_issue(i,what,sequence,"missing")
+ rule.lookups=nil
+ break
+ end
+ else
+ report_issue(i,what,sequence,"bad")
+ rule.lookups=nil
+ break
+ end
else
- report_issue(i,what,sequence,"missing")
- rule.lookups=nil
- break
+ sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
+ end
+ if h then
+ noffound=noffound+1
+ found[noffound]=h
end
- else
- report_issue(i,what,sequence,"bad")
- rule.lookups=nil
- break
end
- else
- sublookupcheck[lookupid]=sublookupcheck[lookupid]+1
end
- rlookups[index]=h or false
+ rlookups[index]=noffound>0 and found or false
else
rlookups[index]=false
end
@@ -12917,33 +19083,108 @@ do
end
end
end
- local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
- local datatable=fontdata.tables[what]
- if not datatable then
- return
- end
- local tableoffset=datatable.offset
- if not tableoffset then
- return
+ local function loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ setposition(f,variationsoffset)
+ local version=readulong(f)
+ local nofrecords=readulong(f)
+ local records={}
+ for i=1,nofrecords do
+ records[i]={
+ conditions=readulong(f),
+ substitutions=readulong(f),
+ }
end
- local scriptoffset,featureoffset,lookupoffset=readscriptoffsets(f,fontdata,tableoffset)
- if not scriptoffset then
- return
+ for i=1,nofrecords do
+ local record=records[i]
+ local offset=record.conditions
+ if offset==0 then
+ record.condition=nil
+ record.matchtype="always"
+ else
+ local offset=variationsoffset+offset
+ setposition(f,offset)
+ local nofconditions=readushort(f)
+ local conditions={}
+ for i=1,nofconditions do
+ conditions[i]=offset+readulong(f)
+ end
+ record.conditions=conditions
+ record.matchtype="condition"
+ end
end
- local scripts=readscriplan(f,fontdata,scriptoffset)
- local features=readfeatures(f,fontdata,featureoffset)
- local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
- if fontdata.features then
- fontdata.features[what]=scriptlangs
- else
- fontdata.features={ [what]=scriptlangs }
+ for i=1,nofrecords do
+ local record=records[i]
+ if record.matchtype=="condition" then
+ local conditions=record.conditions
+ for i=1,#conditions do
+ setposition(f,conditions[i])
+ conditions[i]={
+ format=readushort(f),
+ axis=readushort(f),
+ minvalue=read2dot14(f),
+ maxvalue=read2dot14(f),
+ }
+ end
+ end
end
- if not lookupstoo then
- return
+ for i=1,nofrecords do
+ local record=records[i]
+ local offset=record.substitutions
+ if offset==0 then
+ record.substitutions={}
+ else
+ setposition(f,variationsoffset+offset)
+ local version=readulong(f)
+ local nofsubstitutions=readushort(f)
+ local substitutions={}
+ for i=1,nofsubstitutions do
+ substitutions[readushort(f)]=readulong(f)
+ end
+ for index,alternates in sortedhash(substitutions) do
+ if index==0 then
+ record.substitutions=false
+ else
+ local tableoffset=variationsoffset+offset+alternates
+ setposition(f,tableoffset)
+ local parameters=readulong(f)
+ local noflookups=readushort(f)
+ local lookups=readcardinaltable(f,noflookups,ushort)
+ record.substitutions=lookups
+ end
+ end
+ end
end
- local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
- if lookups then
- resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what)
+ setvariabledata(fontdata,"features",records)
+ end
+ local function readscripts(f,fontdata,what,lookuptypes,lookuphandlers,lookupstoo)
+ local tableoffset=gotodatatable(f,fontdata,what,true)
+ if tableoffset then
+ local version=readulong(f)
+ local scriptoffset=tableoffset+readushort(f)
+ local featureoffset=tableoffset+readushort(f)
+ local lookupoffset=tableoffset+readushort(f)
+ local variationsoffset=version>0x00010000 and (tableoffset+readulong(f)) or 0
+ if not scriptoffset then
+ return
+ end
+ local scripts=readscriplan(f,fontdata,scriptoffset)
+ local features=readfeatures(f,fontdata,featureoffset)
+ local scriptlangs,featurehash,featureorder=reorderfeatures(fontdata,scripts,features)
+ if fontdata.features then
+ fontdata.features[what]=scriptlangs
+ else
+ fontdata.features={ [what]=scriptlangs }
+ end
+ if not lookupstoo then
+ return
+ end
+ local lookups=readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder)
+ if lookups then
+ resolvelookups(f,lookupoffset,fontdata,lookups,lookuptypes,lookuphandlers,what,tableoffset)
+ end
+ if variationsoffset>0 then
+ loadvariations(f,fontdata,variationsoffset,lookuptypes,featurehash,featureorder)
+ end
end
end
local function checkkerns(f,fontdata,specification)
@@ -12962,57 +19203,61 @@ do
report("ignoring global kern table using gpos kern feature")
return
end
- report("adding global kern table as gpos feature %a",name)
setposition(f,datatable.offset)
local version=readushort(f)
local noftables=readushort(f)
- local kerns=setmetatableindex("table")
- for i=1,noftables do
- local version=readushort(f)
- local length=readushort(f)
- local coverage=readushort(f)
- local format=bit32.rshift(coverage,8)
- if format==0 then
- local nofpairs=readushort(f)
- local searchrange=readushort(f)
- local entryselector=readushort(f)
- local rangeshift=readushort(f)
- for i=1,nofpairs do
- kerns[readushort(f)][readushort(f)]=readfword(f)
+ if noftables>1 then
+ report("adding global kern table as gpos feature %a",name)
+ local kerns=setmetatableindex("table")
+ for i=1,noftables do
+ local version=readushort(f)
+ local length=readushort(f)
+ local coverage=readushort(f)
+ local format=rshift(coverage,8)
+ if format==0 then
+ local nofpairs=readushort(f)
+ local searchrange=readushort(f)
+ local entryselector=readushort(f)
+ local rangeshift=readushort(f)
+ for i=1,nofpairs do
+ kerns[readushort(f)][readushort(f)]=readfword(f)
+ end
+ elseif format==2 then
+ else
end
- elseif format==2 then
+ end
+ local feature={ dflt={ dflt=true } }
+ if not features then
+ fontdata.features={ gpos={ [name]=feature } }
+ elseif not gposfeatures then
+ fontdata.features.gpos={ [name]=feature }
else
+ gposfeatures[name]=feature
end
- end
- local feature={ dflt={ dflt=true } }
- if not features then
- fontdata.features={ gpos={ [name]=feature } }
- elseif not gposfeatures then
- fontdata.features.gpos={ [name]=feature }
+ local sequences=fontdata.sequences
+ if not sequences then
+ sequences={}
+ fontdata.sequences=sequences
+ end
+ local nofsequences=#sequences+1
+ sequences[nofsequences]={
+ index=nofsequences,
+ name=name,
+ steps={
+ {
+ coverage=kerns,
+ format="kern",
+ },
+ },
+ nofsteps=1,
+ type="gpos_pair",
+ flags={ false,false,false,false },
+ order={ name },
+ features={ [name]=feature },
+ }
else
- gposfeatures[name]=feature
- end
- local sequences=fontdata.sequences
- if not sequences then
- sequences={}
- fontdata.sequences=sequences
+ report("ignoring empty kern table of feature %a",name)
end
- local nofsequences=#sequences+1
- sequences[nofsequences]={
- index=nofsequences,
- name=name,
- steps={
- {
- coverage=kerns,
- format="kern",
- },
- },
- nofsteps=1,
- type="gpos_pair",
- flags={ false,false,false,false },
- order={ name },
- features={ [name]=feature },
- }
end
function readers.gsub(f,fontdata,specification)
if specification.details then
@@ -13029,25 +19274,29 @@ do
end
end
function readers.gdef(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.gdef
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readulong(f)
- local classoffset=tableoffset+readushort(f)
- local attachmentoffset=tableoffset+readushort(f)
- local ligaturecarets=tableoffset+readushort(f)
- local markclassoffset=tableoffset+readushort(f)
- local marksetsoffset=version==0x00010002 and (tableoffset+readushort(f))
- local glyphs=fontdata.glyphs
- local marks={}
- local markclasses=setmetatableindex("table")
- local marksets=setmetatableindex("table")
- fontdata.marks=marks
- fontdata.markclasses=markclasses
- fontdata.marksets=marksets
- setposition(f,classoffset)
+ if not specification.glyphs then
+ return
+ end
+ local datatable=fontdata.tables.gdef
+ if datatable then
+ local tableoffset=datatable.offset
+ setposition(f,tableoffset)
+ local version=readulong(f)
+ local classoffset=readushort(f)
+ local attachmentoffset=readushort(f)
+ local ligaturecarets=readushort(f)
+ local markclassoffset=readushort(f)
+ local marksetsoffset=version>=0x00010002 and readushort(f) or 0
+ local varsetsoffset=version>=0x00010003 and readulong(f) or 0
+ local glyphs=fontdata.glyphs
+ local marks={}
+ local markclasses=setmetatableindex("table")
+ local marksets=setmetatableindex("table")
+ fontdata.marks=marks
+ fontdata.markclasses=markclasses
+ fontdata.marksets=marksets
+ if classoffset~=0 then
+ setposition(f,tableoffset+classoffset)
local classformat=readushort(f)
if classformat==1 then
local firstindex=readushort(f)
@@ -13075,7 +19324,9 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- setposition(f,markclassoffset)
+ end
+ if markclassoffset~=0 then
+ setposition(f,tableoffset+markclassoffset)
local classformat=readushort(f)
if classformat==1 then
local firstindex=readushort(f)
@@ -13094,21 +19345,45 @@ function readers.gdef(f,fontdata,specification)
end
end
end
- if marksetsoffset and marksetsoffset>tableoffset then
- setposition(f,marksetsoffset)
- local format=readushort(f)
- if format==1 then
- local nofsets=readushort(f)
- local sets={}
- for i=1,nofsets do
- sets[i]=readulong(f)
- end
- for i=1,nofsets do
- local offset=sets[i]
- if offset~=0 then
- marksets[i]=readcoverage(f,marksetsoffset+offset)
+ end
+ if marksetsoffset~=0 then
+ marksetsoffset=tableoffset+marksetsoffset
+ setposition(f,marksetsoffset)
+ local format=readushort(f)
+ if format==1 then
+ local nofsets=readushort(f)
+ local sets=readcardinaltable(f,nofsets,ulong)
+ for i=1,nofsets do
+ local offset=sets[i]
+ if offset~=0 then
+ marksets[i]=readcoverage(f,marksetsoffset+offset)
+ end
+ end
+ end
+ end
+ local factors=specification.factors
+ if (specification.variable or factors) and varsetsoffset~=0 then
+ local regions,deltas=readvariationdata(f,tableoffset+varsetsoffset,factors)
+ if factors then
+ fontdata.temporary.getdelta=function(outer,inner)
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local dd=0
+ for i=1,#scales do
+ local di=d[i]
+ if di then
+ dd=dd+scales[i]*di
+ else
+ break
+ end
+ end
+ return round(dd)
end
end
+ return 0
end
end
end
@@ -13299,14 +19574,8 @@ local function readmathvariants(f,fontdata,offset)
local hcoverage=readushort(f)
local vnofglyphs=readushort(f)
local hnofglyphs=readushort(f)
- local vconstruction={}
- local hconstruction={}
- for i=1,vnofglyphs do
- vconstruction[i]=readushort(f)
- end
- for i=1,hnofglyphs do
- hconstruction[i]=readushort(f)
- end
+ local vconstruction=readcardinaltable(f,vnofglyphs,ushort)
+ local hconstruction=readcardinaltable(f,hnofglyphs,ushort)
fontdata.mathconstants.MinConnectorOverlap=minoverlap
local function get(offset,coverage,nofglyphs,construction,kvariants,kparts,kitalic)
if coverage~=0 and nofglyphs>0 then
@@ -13355,7 +19624,7 @@ local function readmathvariants(f,fontdata,offset)
advance=readushort(f),
}
local flags=readushort(f)
- if bittest(flags,0x0001) then
+ if band(flags,0x0001)~=0 then
p.extender=1
end
parts[i]=p
@@ -13380,167 +19649,501 @@ local function readmathvariants(f,fontdata,offset)
get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic")
end
function readers.math(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.math
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readulong(f)
- if version~=0x00010000 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"math",fontdata.filename)
- return
- end
- local constants=readushort(f)
- local glyphinfo=readushort(f)
- local variants=readushort(f)
- if constants==0 then
- report("the math table of %a has no constants",fontdata.filename)
- else
- readmathconstants(f,fontdata,tableoffset+constants)
- end
- if glyphinfo~=0 then
- readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
- end
- if variants~=0 then
- readmathvariants(f,fontdata,tableoffset+variants)
- end
+ local tableoffset=gotodatatable(f,fontdata,"math",specification.glyphs)
+ if tableoffset then
+ local version=readulong(f)
+ local constants=readushort(f)
+ local glyphinfo=readushort(f)
+ local variants=readushort(f)
+ if constants==0 then
+ report("the math table of %a has no constants",fontdata.filename)
+ else
+ readmathconstants(f,fontdata,tableoffset+constants)
+ end
+ if glyphinfo~=0 then
+ readmathglyphinfo(f,fontdata,tableoffset+glyphinfo)
+ end
+ if variants~=0 then
+ readmathvariants(f,fontdata,tableoffset+variants)
end
end
end
function readers.colr(f,fontdata,specification)
- local datatable=fontdata.tables.colr
- if datatable then
- if specification.glyphs then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version~=0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
- return
- end
- if not fontdata.tables.cpal then
- report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
- fontdata.colorpalettes={}
- end
- local glyphs=fontdata.glyphs
- local nofglyphs=readushort(f)
- local baseoffset=readulong(f)
- local layeroffset=readulong(f)
+ local tableoffset=gotodatatable(f,fontdata,"colr",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ if version~=0 then
+ report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"colr",fontdata.filename)
+ return
+ end
+ if not fontdata.tables.cpal then
+ report("color table %a in font %a has no mandate %a table","colr",fontdata.filename,"cpal")
+ fontdata.colorpalettes={}
+ end
+ local glyphs=fontdata.glyphs
+ local nofglyphs=readushort(f)
+ local baseoffset=readulong(f)
+ local layeroffset=readulong(f)
+ local noflayers=readushort(f)
+ local layerrecords={}
+ local maxclass=0
+ setposition(f,tableoffset+layeroffset)
+ for i=1,noflayers do
+ local slot=readushort(f)
+ local class=readushort(f)
+ if class<0xFFFF then
+ class=class+1
+ if class>maxclass then
+ maxclass=class
+ end
+ end
+ layerrecords[i]={
+ slot=slot,
+ class=class,
+ }
+ end
+ fontdata.maxcolorclass=maxclass
+ setposition(f,tableoffset+baseoffset)
+ for i=0,nofglyphs-1 do
+ local glyphindex=readushort(f)
+ local firstlayer=readushort(f)
local noflayers=readushort(f)
- local layerrecords={}
- local maxclass=0
- setposition(f,tableoffset+layeroffset)
+ local t={}
for i=1,noflayers do
- local slot=readushort(f)
- local class=readushort(f)
- if class<0xFFFF then
- class=class+1
- if class>maxclass then
- maxclass=class
- end
- end
- layerrecords[i]={
- slot=slot,
- class=class,
- }
- end
- fontdata.maxcolorclass=maxclass
- setposition(f,tableoffset+baseoffset)
- for i=0,nofglyphs-1 do
- local glyphindex=readushort(f)
- local firstlayer=readushort(f)
- local noflayers=readushort(f)
- local t={}
- for i=1,noflayers do
- t[i]=layerrecords[firstlayer+i]
- end
- glyphs[glyphindex].colors=t
+ t[i]=layerrecords[firstlayer+i]
end
+ glyphs[glyphindex].colors=t
end
- fontdata.hascolor=true
end
+ fontdata.hascolor=true
end
function readers.cpal(f,fontdata,specification)
- if specification.glyphs then
- local datatable=fontdata.tables.cpal
- if datatable then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version>1 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"cpal",fontdata.filename)
- return
+ local tableoffset=gotodatatable(f,fontdata,"cpal",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local nofpaletteentries=readushort(f)
+ local nofpalettes=readushort(f)
+ local nofcolorrecords=readushort(f)
+ local firstcoloroffset=readulong(f)
+ local colorrecords={}
+ local palettes=readcardinaltable(f,nofpalettes,ushort)
+ if version==1 then
+ local palettettypesoffset=readulong(f)
+ local palettelabelsoffset=readulong(f)
+ local paletteentryoffset=readulong(f)
+ end
+ setposition(f,tableoffset+firstcoloroffset)
+ for i=1,nofcolorrecords do
+ local b,g,r,a=readbytes(f,4)
+ colorrecords[i]={
+ r,g,b,a~=255 and a or nil,
+ }
+ end
+ for i=1,nofpalettes do
+ local p={}
+ local o=palettes[i]
+ for j=1,nofpaletteentries do
+ p[j]=colorrecords[o+j]
end
- local nofpaletteentries=readushort(f)
- local nofpalettes=readushort(f)
- local nofcolorrecords=readushort(f)
- local firstcoloroffset=readulong(f)
- local colorrecords={}
- local palettes={}
- for i=1,nofpalettes do
- palettes[i]=readushort(f)
- end
- if version==1 then
- local palettettypesoffset=readulong(f)
- local palettelabelsoffset=readulong(f)
- local paletteentryoffset=readulong(f)
- end
- setposition(f,tableoffset+firstcoloroffset)
- for i=1,nofcolorrecords do
- local b,g,r,a=readbytes(f,4)
- colorrecords[i]={
- r,g,b,a~=255 and a or nil,
+ palettes[i]=p
+ end
+ fontdata.colorpalettes=palettes
+ end
+end
+function readers.svg(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"svg",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local glyphs=fontdata.glyphs
+ local indexoffset=tableoffset+readulong(f)
+ local reserved=readulong(f)
+ setposition(f,indexoffset)
+ local nofentries=readushort(f)
+ local entries={}
+ for i=1,nofentries do
+ entries[i]={
+ first=readushort(f),
+ last=readushort(f),
+ offset=indexoffset+readulong(f),
+ length=readulong(f),
+ }
+ end
+ for i=1,nofentries do
+ local entry=entries[i]
+ setposition(f,entry.offset)
+ entries[i]={
+ first=entry.first,
+ last=entry.last,
+ data=readstring(f,entry.length)
+ }
+ end
+ fontdata.svgshapes=entries
+ end
+ fontdata.hascolor=true
+end
+function readers.sbix(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"sbix",specification.glyphs)
+ if tableoffset then
+ local version=readushort(f)
+ local flags=readushort(f)
+ local nofstrikes=readulong(f)
+ local strikes={}
+ local nofglyphs=fontdata.nofglyphs
+ for i=1,nofstrikes do
+ strikes[i]=readulong(f)
+ end
+ local shapes={}
+ local done=0
+ for i=1,nofstrikes do
+ local strikeoffset=strikes[i]+tableoffset
+ setposition(f,strikeoffset)
+ strikes[i]={
+ ppem=readushort(f),
+ ppi=readushort(f),
+ offset=strikeoffset
}
end
- for i=1,nofpalettes do
- local p={}
- local o=palettes[i]
- for j=1,nofpaletteentries do
- p[j]=colorrecords[o+j]
+ sort(strikes,function(a,b)
+ if b.ppem==a.ppem then
+ return b.ppi<a.ppi
+ else
+ return b.ppem<a.ppem
+ end
+ end)
+ local glyphs={}
+ for i=1,nofstrikes do
+ local strike=strikes[i]
+ local strikeppem=strike.ppem
+ local strikeppi=strike.ppi
+ local strikeoffset=strike.offset
+ setposition(f,strikeoffset)
+ for i=0,nofglyphs do
+ glyphs[i]=readulong(f)
+ end
+ local glyphoffset=glyphs[0]
+ for i=0,nofglyphs-1 do
+ local nextoffset=glyphs[i+1]
+ if not shapes[i] then
+ local datasize=nextoffset-glyphoffset
+ if datasize>0 then
+ setposition(f,strikeoffset+glyphoffset)
+ shapes[i]={
+ x=readshort(f),
+ y=readshort(f),
+ tag=readtag(f),
+ data=readstring(f,datasize-8),
+ ppem=strikeppem,
+ ppi=strikeppi,
+ }
+ done=done+1
+ if done==nofglyphs then
+ break
+ end
+ end
+ end
+ glyphoffset=nextoffset
end
- palettes[i]=p
end
- fontdata.colorpalettes=palettes
- end
+ fontdata.sbixshapes=shapes
end
end
-function readers.svg(f,fontdata,specification)
- local datatable=fontdata.tables.svg
- if datatable then
- if specification.glyphs then
- local tableoffset=datatable.offset
- setposition(f,tableoffset)
- local version=readushort(f)
- if version~=0 then
- report("table version %a of %a is not supported (yet), maybe font %s is bad",version,"svg",fontdata.filename)
- return
- end
- local glyphs=fontdata.glyphs
- local indexoffset=tableoffset+readulong(f)
- local reserved=readulong(f)
- setposition(f,indexoffset)
- local nofentries=readushort(f)
- local entries={}
- for i=1,nofentries do
- entries[i]={
- first=readushort(f),
- last=readushort(f),
- offset=indexoffset+readulong(f),
- length=readulong(f),
+function readers.stat(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"stat",true)
+ if tableoffset then
+ local extras=fontdata.extras
+ local version=readulong(f)
+ local axissize=readushort(f)
+ local nofaxis=readushort(f)
+ local axisoffset=readulong(f)
+ local nofvalues=readushort(f)
+ local valuesoffset=readulong(f)
+ local fallbackname=extras[readushort(f)]
+ local axis={}
+ local values={}
+ setposition(f,tableoffset+axisoffset)
+ for i=1,nofaxis do
+ local tag=readtag(f)
+ axis[i]={
+ tag=tag,
+ name=lower(extras[readushort(f)] or tag),
+ ordering=readushort(f),
+ variants={}
+ }
+ end
+ setposition(f,tableoffset+valuesoffset)
+ for i=1,nofvalues do
+ values[i]=readushort(f)
+ end
+ for i=1,nofvalues do
+ setposition(f,tableoffset+valuesoffset+values[i])
+ local format=readushort(f)
+ local index=readushort(f)+1
+ local flags=readushort(f)
+ local name=lower(extras[readushort(f)] or "no name")
+ local value=readfixed(f)
+ local variant
+ if format==1 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
}
+ elseif format==2 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
+ minimum=readfixed(f),
+ maximum=readfixed(f),
+ }
+ elseif format==3 then
+ variant={
+ flags=flags,
+ name=name,
+ value=value,
+ link=readfixed(f),
+ }
+ end
+ insert(axis[index].variants,variant)
+ end
+ sort(axis,function(a,b)
+ return a.ordering<b.ordering
+ end)
+ for i=1,#axis do
+ local a=axis[i]
+ sort(a.variants,function(a,b)
+ return a.name<b.name
+ end)
+ a.ordering=nil
+ end
+ setvariabledata(fontdata,"designaxis",axis)
+ setvariabledata(fontdata,"fallbackname",fallbackname)
+ end
+end
+function readers.avar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"avar",true)
+ if tableoffset then
+ local function collect()
+ local nofvalues=readushort(f)
+ local values={}
+ local lastfrom=false
+ local lastto=false
+ for i=1,nofvalues do
+ local f,t=read2dot14(f),read2dot14(f)
+ if lastfrom and f<=lastfrom then
+ elseif lastto and t>=lastto then
+ else
+ values[#values+1]={ f,t }
+ lastfrom,lastto=f,t
+ end
+ end
+ nofvalues=#values
+ if nofvalues>2 then
+ local some=values[1]
+ if some[1]==-1 and some[2]==-1 then
+ some=values[nofvalues]
+ if some[1]==1 and some[2]==1 then
+ for i=2,nofvalues-1 do
+ some=values[i]
+ if some[1]==0 and some[2]==0 then
+ return values
+ end
+ end
+ end
+ end
end
- for i=1,nofentries do
- local entry=entries[i]
- setposition(f,entry.offset)
- entries[i]={
- first=entry.first,
- last=entry.last,
- data=readstring(f,entry.length)
+ return false
+ end
+ local majorversion=readushort(f)
+ local minorversion=readushort(f)
+ local reserved=readushort(f)
+ local nofaxis=readushort(f)
+ local segments={}
+ for i=1,nofaxis do
+ segments[i]=collect()
+ end
+ setvariabledata(fontdata,"segments",segments)
+ end
+end
+function readers.fvar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"fvar",true)
+ if tableoffset then
+ local version=readulong(f)
+ local offsettoaxis=tableoffset+readushort(f)
+ local reserved=skipshort(f)
+ local nofaxis=readushort(f)
+ local sizeofaxis=readushort(f)
+ local nofinstances=readushort(f)
+ local sizeofinstances=readushort(f)
+ local extras=fontdata.extras
+ local axis={}
+ local instances={}
+ setposition(f,offsettoaxis)
+ for i=1,nofaxis do
+ axis[i]={
+ tag=readtag(f),
+ minimum=readfixed(f),
+ default=readfixed(f),
+ maximum=readfixed(f),
+ flags=readushort(f),
+ name=lower(extras[readushort(f)] or "bad name"),
+ }
+ local n=sizeofaxis-20
+ if n>0 then
+ skipbytes(f,n)
+ elseif n<0 then
+ end
+ end
+ local nofbytes=2+2+2+nofaxis*4
+ local readpsname=nofbytes<=sizeofinstances
+ local skippable=sizeofinstances-nofbytes
+ for i=1,nofinstances do
+ local subfamid=readushort(f)
+ local flags=readushort(f)
+ local values={}
+ for i=1,nofaxis do
+ values[i]={
+ axis=axis[i].tag,
+ value=readfixed(f),
}
end
- fontdata.svgshapes=entries
+ local psnameid=readpsname and readushort(f) or 0xFFFF
+ if subfamid==2 or subfamid==17 then
+ elseif subfamid==0xFFFF then
+ subfamid=nil
+ elseif subfamid<=256 or subfamid>=32768 then
+ subfamid=nil
+ end
+ if psnameid==6 then
+ elseif psnameid==0xFFFF then
+ psnameid=nil
+ elseif psnameid<=256 or psnameid>=32768 then
+ psnameid=nil
+ end
+ instances[i]={
+ subfamily=extras[subfamid],
+ psname=psnameid and extras[psnameid] or nil,
+ values=values,
+ }
+ if skippable>0 then
+ skipbytes(f,skippable)
+ end
+ end
+ setvariabledata(fontdata,"axis",axis)
+ setvariabledata(fontdata,"instances",instances)
+ end
+end
+function readers.hvar(f,fontdata,specification)
+ local factors=specification.factors
+ if not factors then
+ return
+ end
+ local tableoffset=gotodatatable(f,fontdata,"hvar",specification.variable)
+ if not tableoffset then
+ return
+ end
+ local version=readulong(f)
+ local variationoffset=tableoffset+readulong(f)
+ local advanceoffset=tableoffset+readulong(f)
+ local lsboffset=tableoffset+readulong(f)
+ local rsboffset=tableoffset+readulong(f)
+ local regions={}
+ local variations={}
+ local innerindex={}
+ local outerindex={}
+ if variationoffset>0 then
+ regions,deltas=readvariationdata(f,variationoffset,factors)
+ end
+ if not regions then
+ return
+ end
+ if advanceoffset>0 then
+ setposition(f,advanceoffset)
+ local format=readushort(f)
+ local mapcount=readushort(f)
+ local entrysize=rshift(band(format,0x0030),4)+1
+ local nofinnerbits=band(format,0x000F)+1
+ local innermask=lshift(1,nofinnerbits)-1
+ local readcardinal=read_cardinal[entrysize]
+ for i=0,mapcount-1 do
+ local mapdata=readcardinal(f)
+ outerindex[i]=rshift(mapdata,nofinnerbits)
+ innerindex[i]=band(mapdata,innermask)
+ end
+ setvariabledata(fontdata,"hvarwidths",true)
+ local glyphs=fontdata.glyphs
+ for i=0,fontdata.nofglyphs-1 do
+ local glyph=glyphs[i]
+ local width=glyph.width
+ if width then
+ local outer=outerindex[i] or 0
+ local inner=innerindex[i] or i
+ if outer and inner then
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local deltaw=0
+ for i=1,#scales do
+ local di=d[i]
+ if di then
+ deltaw=deltaw+scales[i]*di
+ else
+ break
+ end
+ end
+ glyph.width=width+round(deltaw)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+function readers.vvar(f,fontdata,specification)
+ if not specification.variable then
+ return
+ end
+end
+function readers.mvar(f,fontdata,specification)
+ local tableoffset=gotodatatable(f,fontdata,"mvar",specification.variable)
+ if tableoffset then
+ local version=readulong(f)
+ local reserved=skipshort(f,1)
+ local recordsize=readushort(f)
+ local nofrecords=readushort(f)
+ local offsettostore=tableoffset+readushort(f)
+ local dimensions={}
+ local factors=specification.factors
+ if factors then
+ local regions,deltas=readvariationdata(f,offsettostore,factors)
+ for i=1,nofrecords do
+ local tag=readtag(f)
+ local var=variabletags[tag]
+ if var then
+ local outer=readushort(f)
+ local inner=readushort(f)
+ local delta=deltas[outer+1]
+ if delta then
+ local d=delta.deltas[inner+1]
+ if d then
+ local scales=delta.scales
+ local dd=0
+ for i=1,#scales do
+ dd=dd+scales[i]*d[i]
+ end
+ var(fontdata,round(dd))
+ end
+ end
+ else
+ skipshort(f,2)
+ end
+ if recordsize>8 then
+ skipbytes(recordsize-8)
+ end
+ end
end
- fontdata.hascolor=true
end
end
@@ -13563,6 +20166,7 @@ local formatters=string.formatters
local sortedkeys=table.sortedkeys
local sortedhash=table.sortedhash
local tohash=table.tohash
+local setmetatableindex=table.setmetatableindex
local report=logs.reporter("otf reader")
local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end)
local readers=fonts.handlers.otf.readers
@@ -13573,7 +20177,7 @@ local f_index=formatters["I%05X"]
local f_character_y=formatters["%C"]
local f_character_n=formatters["[ %C ]"]
local check_duplicates=true
-local check_soft_hyphen=false
+local check_soft_hyphen=true
directives.register("otf.checksofthyphen",function(v)
check_soft_hyphen=v
end)
@@ -14123,7 +20727,7 @@ local function checklookups(fontdata,missing,nofmissing)
end
end
if next(done) then
- report("not unicoded: % t",table.sortedkeys(done))
+ report("not unicoded: % t",sortedkeys(done))
end
end
end
@@ -14133,7 +20737,6 @@ local function unifymissing(fontdata)
require("font-agl")
end
local unicodes={}
- local private=fontdata.private
local resources=fontdata.resources
resources.unicodes=unicodes
for unicode,d in next,fontdata.descriptions do
@@ -14171,8 +20774,8 @@ local function unifyglyphs(fontdata,usenames)
end
for index=1,#glyphs do
local glyph=glyphs[index]
- local unicode=glyph.unicode
- if not unicode then
+ local unicode=glyph.unicode
+ if not unicode or unicode>=private or (unicode>=0xE000 and unicode<=0xF8FF) or unicode==0xFFFE or unicode==0xFFFF then
unicode=private
if names then
local name=glyph.name or f_private(unicode)
@@ -14295,9 +20898,9 @@ function readers.getcomponents(fontdata)
end
end
for i=1,#steps do
- local coverage=steps[i].coverage
- if coverage then
- for k,v in next,coverage do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
traverse(k,k,v)
end
end
@@ -14360,7 +20963,7 @@ function readers.rehash(fontdata,hashmethod)
copyduplicates(fontdata)
unifymissing(fontdata)
else
- fontdata.hashmethod="unicode"
+ fontdata.hashmethod="unicodes"
local indices=unifyglyphs(fontdata)
unifyresources(fontdata,indices)
copyduplicates(fontdata)
@@ -14375,10 +20978,10 @@ function readers.checkhash(fontdata)
elseif hashmethod=="names" and fontdata.names then
unifyresources(fontdata,fontdata.names)
copyduplicates(fontdata)
- fontdata.hashmethod="unicode"
+ fontdata.hashmethod="unicodes"
fontdata.names=nil
else
- readers.rehash(fontdata,"unicode")
+ readers.rehash(fontdata,"unicodes")
end
end
function readers.addunicodetable(fontdata)
@@ -14512,13 +21115,14 @@ function readers.pack(data)
return nt
end
end
- local function pack_flat(v)
- local tag=tabstr_flat(v)
+ local function pack_normal_cc(v)
+ local tag=tabstr_normal(v)
local ht=h[tag]
if ht then
c[ht]=c[ht]+1
return ht
else
+ v[1]=0
nt=nt+1
t[nt]=v
h[tag]=nt
@@ -14526,8 +21130,8 @@ function readers.pack(data)
return nt
end
end
- local function pack_boolean(v)
- local tag=tabstr_boolean(v)
+ local function pack_flat(v)
+ local tag=tabstr_flat(v)
local ht=h[tag]
if ht then
c[ht]=c[ht]+1
@@ -14568,6 +21172,20 @@ function readers.pack(data)
return nt
end
end
+ local function pack_boolean(v)
+ local tag=tabstr_boolean(v)
+ local ht=h[tag]
+ if ht then
+ c[ht]=c[ht]+1
+ return ht
+ else
+ nt=nt+1
+ t[nt]=v
+ h[tag]=nt
+ c[nt]=1
+ return nt
+ end
+ end
local function pack_final(v)
if c[v]<=criterium then
return t[v]
@@ -14584,6 +21202,22 @@ function readers.pack(data)
end
end
end
+ local function pack_final_cc(v)
+ if c[v]<=criterium then
+ return t[v]
+ else
+ local hv=hh[v]
+ if hv then
+ return hv
+ else
+ ntt=ntt+1
+ tt[ntt]=t[v]
+ hh[v]=ntt
+ cc[ntt]=c[v]
+ return ntt
+ end
+ end
+ end
local function success(stage,pass)
if nt==0 then
if trace_loading or trace_packing then
@@ -14629,9 +21263,9 @@ function readers.pack(data)
end
local function packers(pass)
if pass==1 then
- return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed
+ return pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc
else
- return pack_final,pack_final,pack_final,pack_final,pack_final
+ return pack_final,pack_final,pack_final,pack_final,pack_final,pack_final_cc
end
end
local resources=data.resources
@@ -14639,6 +21273,7 @@ function readers.pack(data)
local sublookups=resources.sublookups
local features=resources.features
local palettes=resources.colorpalettes
+ local variable=resources.variabledata
local chardata=characters and characters.data
local descriptions=data.descriptions or data.glyphs
if not descriptions then
@@ -14648,7 +21283,7 @@ function readers.pack(data)
if trace_packing then
report_otf("start packing: stage 1, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
for unicode,description in next,descriptions do
local boundingbox=description.boundingbox
if boundingbox then
@@ -14678,28 +21313,30 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
+ if step.format=="pair" then
for g1,d1 in next,c do
- c[g1]=pack_normal(d1)
+ for g2,d2 in next,d1 do
+ local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end
+ local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end
+ end
end
else
for g1,d1 in next,c do
- for g2,d2 in next,d1 do
- local f=d2[1] if f then d2[1]=pack_indexed(f) end
- local s=d2[2] if s then d2[2]=pack_indexed(s) end
- end
+ c[g1]=pack_normal(d1)
end
end
end
elseif kind=="gpos_single" then
local c=step.coverage
if c then
- if step.format=="kern" then
- step.coverage=pack_normal(c)
- else
+ if step.format=="single" then
for g1,d1 in next,c do
- c[g1]=pack_indexed(d1)
+ if d1 and d1~=true then
+ c[g1]=pack_indexed(d1)
+ end
end
+ else
+ step.coverage=pack_normal(c)
end
end
elseif kind=="gpos_cursive" then
@@ -14750,7 +21387,6 @@ function readers.pack(data)
local r=rule.before if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
local r=rule.after if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
local r=rule.current if r then for i=1,#r do r[i]=pack_boolean(r[i]) end end
- local r=rule.lookups if r then rule.lookups=pack_mixed (r) end
local r=rule.replacements if r then rule.replacements=pack_flat (r) end
end
end
@@ -14790,6 +21426,45 @@ function readers.pack(data)
end
end
end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ v[j]=pack_normal(v[j])
+ end
+ end
+ end
+ local function packdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ for j=1,#d do
+ d[j]=pack_indexed(d[j])
+ end
+ di.regions=pack_indexed(di.regions)
+ end
+ end
+ local regions=main.regions
+ if regions then
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ r[j]=pack_normal(r[j])
+ end
+ end
+ end
+ end
+ end
+ packdeltas(variable.global)
+ packdeltas(variable.horizontal)
+ packdeltas(variable.vertical)
+ packdeltas(variable.metrics)
+ end
if not success(1,pass) then
return
end
@@ -14799,7 +21474,7 @@ function readers.pack(data)
if trace_packing then
report_otf("start packing: stage 2, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
for unicode,description in next,descriptions do
local math=description.math
if math then
@@ -14821,8 +21496,7 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
for g2,d2 in next,d1 do
d1[g2]=pack_normal(d2)
@@ -14830,6 +21504,15 @@ function readers.pack(data)
end
end
end
+ elseif kind=="gpos_mark2ligature" then
+ local c=step.baseclasses
+ if c then
+ for g1,d1 in next,c do
+ for g2,d2 in next,d1 do
+ d1[g2]=pack_normal(d2)
+ end
+ end
+ end
end
local rules=step.rules
if rules then
@@ -14853,14 +21536,26 @@ function readers.pack(data)
if sublookups then
packthem(sublookups)
end
- if not success(2,pass) then
+ if variable then
+ local function unpackdeltas(main)
+ if main then
+ local regions=main.regions
+ if regions then
+ main.regions=pack_normal(regions)
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
end
end
for pass=1,2 do
if trace_packing then
report_otf("start packing: stage 3, pass %s",pass)
end
- local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass)
+ local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed,pack_normal_cc=packers(pass)
local function packthem(sequences)
for i=1,#sequences do
local sequence=sequences[i]
@@ -14873,13 +21568,19 @@ function readers.pack(data)
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
c[g1]=pack_normal(d1)
end
end
end
+ elseif kind=="gpos_cursive" then
+ local c=step.coverage
+ if c then
+ for g1,d1 in next,c do
+ c[g1]=pack_normal_cc(d1)
+ end
+ end
end
end
end
@@ -14911,6 +21612,7 @@ function readers.unpack(data)
local sublookups=resources.sublookups
local features=resources.features
local palettes=resources.colorpalettes
+ local variable=resources.variabledata
local unpacked={}
setmetatable(unpacked,unpacked_mt)
for unicode,description in next,descriptions do
@@ -14947,20 +21649,26 @@ function readers.unpack(data)
local features=sequence.features
local flags=sequence.flags
local markclass=sequence.markclass
+ if features then
+ local tv=tables[features]
+ if tv then
+ sequence.features=tv
+ features=tv
+ end
+ for script,feature in next,features do
+ local tv=tables[feature]
+ if tv then
+ features[script]=tv
+ end
+ end
+ end
if steps then
for i=1,#steps do
local step=steps[i]
if kind=="gpos_pair" then
local c=step.coverage
if c then
- if step.format=="kern" then
- for g1,d1 in next,c do
- local tv=tables[d1]
- if tv then
- c[g1]=tv
- end
- end
- else
+ if step.format=="pair" then
for g1,d1 in next,c do
local tv=tables[d1]
if tv then
@@ -14977,29 +21685,41 @@ function readers.unpack(data)
local s=tables[d2[2]] if s then d2[2]=s end
end
end
+ else
+ for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ c[g1]=tv
+ end
+ end
end
end
elseif kind=="gpos_single" then
local c=step.coverage
if c then
- if step.format=="kern" then
- local tv=tables[c]
- if tv then
- step.coverage=tv
- end
- else
+ if step.format=="single" then
for g1,d1 in next,c do
local tv=tables[d1]
if tv then
c[g1]=tv
end
end
+ else
+ local tv=tables[c]
+ if tv then
+ step.coverage=tv
+ end
end
end
elseif kind=="gpos_cursive" then
local c=step.coverage
if c then
for g1,d1 in next,c do
+ local tv=tables[d1]
+ if tv then
+ d1=tv
+ c[g1]=d1
+ end
local f=tables[d1[2]] if f then d1[2]=f end
local s=tables[d1[3]] if s then d1[3]=s end
end
@@ -15030,6 +21750,11 @@ function readers.unpack(data)
if c then
for g1,d1 in next,c do
for g2,d2 in next,d1 do
+ local tv=tables[d2]
+ if tv then
+ d2=tv
+ d1[g2]=d2
+ end
for g3,d3 in next,d2 do
local tv=tables[d2[g3]]
if tv then
@@ -15095,13 +21820,6 @@ function readers.unpack(data)
end
end
end
- local lookups=rule.lookups
- if lookups then
- local tv=tables[lookups]
- if tv then
- rule.lookups=tv
- end
- end
local replacements=rule.replacements
if replacements then
local tv=tables[replacements]
@@ -15113,19 +21831,6 @@ function readers.unpack(data)
end
end
end
- if features then
- local tv=tables[features]
- if tv then
- sequence.features=tv
- features=tv
- end
- for script,feature in next,features do
- local tv=tables[feature]
- if tv then
- features[script]=tv
- end
- end
- end
if order then
local tv=tables[order]
if tv then
@@ -15167,6 +21872,63 @@ function readers.unpack(data)
end
end
end
+ if variable then
+ local instances=variable.instances
+ if instances then
+ for i=1,#instances do
+ local v=instances[i].values
+ for j=1,#v do
+ local tv=tables[v[j]]
+ if tv then
+ v[j]=tv
+ end
+ end
+ end
+ end
+ local function unpackdeltas(main)
+ if main then
+ local deltas=main.deltas
+ if deltas then
+ for i=1,#deltas do
+ local di=deltas[i]
+ local d=di.deltas
+ local r=di.regions
+ for j=1,#d do
+ local tv=tables[d[j]]
+ if tv then
+ d[j]=tv
+ end
+ end
+ local tv=di.regions
+ if tv then
+ di.regions=tv
+ end
+ end
+ end
+ local regions=main.regions
+ if regions then
+ local tv=tables[regions]
+ if tv then
+ main.regions=tv
+ regions=tv
+ end
+ for i=1,#regions do
+ local r=regions[i]
+ for j=1,#r do
+ local tv=tables[r[j]]
+ if tv then
+ r[j]=tv
+ end
+ end
+ end
+ end
+ end
+ end
+ unpackdeltas(variable.global)
+ unpackdeltas(variable.horizontal)
+ unpackdeltas(variable.vertical)
+ unpackdeltas(variable.metrics)
+ end
data.tables=nil
end
end
@@ -15205,9 +21967,12 @@ local function mergesteps_1(lookup,strict)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- if not target[k] then
- target[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ if not target[k] then
+ target[k]=v
+ end
end
end
end
@@ -15216,7 +21981,7 @@ local function mergesteps_1(lookup,strict)
lookup.steps={ first }
return nofsteps-1
end
-local function mergesteps_2(lookup,strict)
+local function mergesteps_2(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
local first=steps[1]
@@ -15232,69 +21997,62 @@ local function mergesteps_2(lookup,strict)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- local tk=target[k]
- if tk then
- for k,v in next,v do
- if not tk[k] then
- tk[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ for kk,vv in next,v do
+ if tk[kk]==nil then
+ tk[kk]=vv
+ end
end
+ else
+ target[k]=v
end
- else
- target[k]=v
end
end
end
lookup.nofsteps=1
+ lookup.merged=true
lookup.steps={ first }
return nofsteps-1
end
local function mergesteps_3(lookup,strict)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
- local first=steps[1]
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
- local baseclasses={}
local coverage={}
- local used={}
for i=1,nofsteps do
- local offset=i*10
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=coverage[k]
+ if tk then
+ report("quitting merge due to multiple checks")
+ return nofsteps
+ else
+ coverage[k]=v
+ end
+ end
+ end
+ end
+ local first=steps[1]
+ local baseclasses={}
+ for i=1,nofsteps do
+ local offset=i*10
local step=steps[i]
for k,v in sortedhash(step.baseclasses) do
baseclasses[offset+k]=v
end
for k,v in next,step.coverage do
- local tk=coverage[k]
- if tk then
- for k,v in next,v do
- if not tk[k] then
- tk[k]=v
- local c=offset+v[1]
- v[1]=c
- if not used[c] then
- used[c]=true
- end
- end
- end
- else
- coverage[k]=v
- local c=offset+v[1]
- v[1]=c
- if not used[c] then
- used[c]=true
- end
- end
- end
- end
- for k,v in next,baseclasses do
- if not used[k] then
- baseclasses[k]=nil
- report("discarding not used baseclass %i",k)
+ v[1]=offset+v[1]
end
end
first.baseclasses=baseclasses
first.coverage=coverage
lookup.nofsteps=1
+ lookup.merged=true
lookup.steps={ first }
return nofsteps-1
end
@@ -15321,12 +22079,15 @@ local function mergesteps_4(lookup)
report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
local target=first.coverage
for i=2,nofsteps do
- for k,v in next,steps[i].coverage do
- local tk=target[k]
- if tk then
- nested(v,tk)
- else
- target[k]=v
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ nested(v,tk)
+ else
+ target[k]=v
+ end
end
end
end
@@ -15334,67 +22095,139 @@ local function mergesteps_4(lookup)
lookup.steps={ first }
return nofsteps-1
end
+local function mergesteps_5(lookup)
+ local steps=lookup.steps
+ local nofsteps=lookup.nofsteps
+ local first=steps[1]
+ report("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name)
+ local target=first.coverage
+ local hash=nil
+ for k,v in next,target do
+ hash=v[1]
+ break
+ end
+ for i=2,nofsteps do
+ local c=steps[i].coverage
+ if c then
+ for k,v in next,c do
+ local tk=target[k]
+ if tk then
+ if not tk[2] then
+ tk[2]=v[2]
+ end
+ if not tk[3] then
+ tk[3]=v[3]
+ end
+ else
+ target[k]=v
+ v[1]=hash
+ end
+ end
+ end
+ end
+ lookup.nofsteps=1
+ lookup.merged=true
+ lookup.steps={ first }
+ return nofsteps-1
+end
local function checkkerns(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
+ local kerned=0
for i=1,nofsteps do
local step=steps[i]
if step.format=="pair" then
local coverage=step.coverage
local kerns=true
for g1,d1 in next,coverage do
- if d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
+ if d1==true then
+ elseif not d1 then
+ elseif d1[1]~=0 or d1[2]~=0 or d1[4]~=0 then
kerns=false
break
end
end
if kerns then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
+ local c={}
for g1,d1 in next,coverage do
- coverage[g1]=d1[3]
+ if d1 and d1~=true then
+ c[g1]=d1[3]
+ end
end
- step.format="kern"
+ step.coverage=c
+ step.format="move"
+ kerned=kerned+1
end
end
end
+ return kerned
end
local function checkpairs(lookup)
local steps=lookup.steps
local nofsteps=lookup.nofsteps
local kerned=0
- for i=1,nofsteps do
- local step=steps[i]
- if step.format=="pair" then
- local coverage=step.coverage
- local kerns=true
- for g1,d1 in next,coverage do
- for g2,d2 in next,d1 do
- if d2[2] then
- kerns=false
- break
- else
- local v=d2[1]
- if v[1]~=0 or v[2]~=0 or v[4]~=0 then
- kerns=false
- break
- end
+ local function onlykerns(step)
+ local coverage=step.coverage
+ for g1,d1 in next,coverage do
+ for g2,d2 in next,d1 do
+ if d2[2] then
+ return false
+ else
+ local v=d2[1]
+ if v==true then
+ elseif v and (v[1]~=0 or v[2]~=0 or v[4]~=0) then
+ return false
end
end
end
- if kerns then
+ end
+ return coverage
+ end
+ for i=1,nofsteps do
+ local step=steps[i]
+ if step.format=="pair" then
+ local coverage=onlykerns(step)
+ if coverage then
report("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name)
for g1,d1 in next,coverage do
+ local d={}
for g2,d2 in next,d1 do
- d1[g2]=d2[1][3]
+ local v=d2[1]
+ if v==true then
+ elseif v then
+ d[g2]=v[3]
+ end
end
+ coverage[g1]=d
end
- step.format="kern"
+ step.format="move"
kerned=kerned+1
end
end
end
return kerned
end
+local compact_pairs=true
+local compact_singles=true
+local merge_pairs=true
+local merge_singles=true
+local merge_substitutions=true
+local merge_alternates=true
+local merge_multiples=true
+local merge_ligatures=true
+local merge_cursives=true
+local merge_marks=true
+directives.register("otf.compact.pairs",function(v) compact_pairs=v end)
+directives.register("otf.compact.singles",function(v) compact_singles=v end)
+directives.register("otf.merge.pairs",function(v) merge_pairs=v end)
+directives.register("otf.merge.singles",function(v) merge_singles=v end)
+directives.register("otf.merge.substitutions",function(v) merge_substitutions=v end)
+directives.register("otf.merge.alternates",function(v) merge_alternates=v end)
+directives.register("otf.merge.multiples",function(v) merge_multiples=v end)
+directives.register("otf.merge.ligatures",function(v) merge_ligatures=v end)
+directives.register("otf.merge.cursives",function(v) merge_cursives=v end)
+directives.register("otf.merge.marks",function(v) merge_marks=v end)
function readers.compact(data)
if not data or data.compacted then
return
@@ -15411,23 +22244,64 @@ function readers.compact(data)
for i=1,#lookups do
local lookup=lookups[i]
local nofsteps=lookup.nofsteps
+ local kind=lookup.type
allsteps=allsteps+nofsteps
if nofsteps>1 then
- local kind=lookup.type
- if kind=="gsub_single" or kind=="gsub_alternate" or kind=="gsub_multiple" then
- merged=merged+mergesteps_1(lookup)
+ local merg=merged
+ if kind=="gsub_single" then
+ if merge_substitutions then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_alternate" then
+ if merge_alternates then
+ merged=merged+mergesteps_1(lookup)
+ end
+ elseif kind=="gsub_multiple" then
+ if merge_multiples then
+ merged=merged+mergesteps_1(lookup)
+ end
elseif kind=="gsub_ligature" then
- merged=merged+mergesteps_4(lookup)
+ if merge_ligatures then
+ merged=merged+mergesteps_4(lookup)
+ end
elseif kind=="gpos_single" then
- merged=merged+mergesteps_1(lookup,true)
- checkkerns(lookup)
+ if merge_singles then
+ merged=merged+mergesteps_1(lookup,true)
+ end
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
elseif kind=="gpos_pair" then
- merged=merged+mergesteps_2(lookup,true)
- kerned=kerned+checkpairs(lookup)
+ if merge_pairs then
+ merged=merged+mergesteps_2(lookup)
+ end
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
elseif kind=="gpos_cursive" then
- merged=merged+mergesteps_2(lookup)
+ if merge_cursives then
+ merged=merged+mergesteps_5(lookup)
+ end
elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then
- merged=merged+mergesteps_3(lookup)
+ if merge_marks then
+ merged=merged+mergesteps_3(lookup)
+ end
+ end
+ if merg~=merged then
+ lookup.merged=true
+ end
+ elseif nofsteps==1 then
+ local kern=kerned
+ if kind=="gpos_single" then
+ if compact_singles then
+ kerned=kerned+checkkerns(lookup)
+ end
+ elseif kind=="gpos_pair" then
+ if compact_pairs then
+ kerned=kerned+checkpairs(lookup)
+ end
+ end
+ if kern~=kerned then
end
end
end
@@ -15444,6 +22318,72 @@ function readers.compact(data)
report("%i steps of %i steps turned from pairs into kerns",kerned,allsteps)
end
end
+local function mergesteps(t,k)
+ if k=="merged" then
+ local merged={}
+ for i=1,#t do
+ local step=t[i]
+ local coverage=step.coverage
+ for k in next,coverage do
+ local m=merged[k]
+ if m then
+ m[2]=i
+ else
+ merged[k]={ i,i }
+ end
+ end
+ end
+ t.merged=merged
+ return merged
+ end
+end
+local function checkmerge(sequence)
+ local steps=sequence.steps
+ if steps then
+ setmetatableindex(steps,mergesteps)
+ end
+end
+local function checkflags(sequence,resources)
+ if not sequence.skiphash then
+ local flags=sequence.flags
+ if flags then
+ local skipmark=flags[1]
+ local skipligature=flags[2]
+ local skipbase=flags[3]
+ local markclass=sequence.markclass
+ local skipsome=skipmark or skipligature or skipbase or markclass or false
+ if skipsome then
+ sequence.skiphash=setmetatableindex(function(t,k)
+ local c=resources.classes[k]
+ local v=c==skipmark
+ or (markclass and c=="mark" and not markclass[k])
+ or c==skipligature
+ or c==skipbase
+ or false
+ t[k]=v
+ return v
+ end)
+ else
+ sequence.skiphash=false
+ end
+ else
+ sequence.skiphash=false
+ end
+ end
+end
+local function checksteps(sequence)
+ local steps=sequence.steps
+ if steps then
+ for i=1,#steps do
+ steps[i].index=i
+ end
+ end
+end
+if fonts.helpers then
+ fonts.helpers.checkmerge=checkmerge
+ fonts.helpers.checkflags=checkflags
+ fonts.helpers.checksteps=checksteps
+end
function readers.expand(data)
if not data or data.expanded then
return
@@ -15488,6 +22428,7 @@ function readers.expand(data)
local sequence=sequences[i]
local steps=sequence.steps
if steps then
+ local nofsteps=sequence.nofsteps
local kind=sequence.type
local markclass=sequence.markclass
if markclass then
@@ -15498,7 +22439,7 @@ function readers.expand(data)
sequence.markclass=markclasses[markclass]
end
end
- for i=1,sequence.nofsteps do
+ for i=1,nofsteps do
local step=steps[i]
local baseclasses=step.baseclasses
if baseclasses then
@@ -15514,13 +22455,14 @@ function readers.expand(data)
end
local rules=step.rules
if rules then
- local rulehash={}
+ local rulehash={ n=0 }
local rulesize=0
local coverage={}
local lookuptype=sequence.type
+ local nofrules=#rules
step.coverage=coverage
- for nofrules=1,#rules do
- local rule=rules[nofrules]
+ for currentrule=1,nofrules do
+ local rule=rules[currentrule]
local current=rule.current
local before=rule.before
local after=rule.after
@@ -15548,21 +22490,26 @@ function readers.expand(data)
local lookups=rule.lookups or false
local subtype=nil
if lookups then
- for k,v in next,lookups do
- local lookup=sublookups[v]
- if lookup then
- lookups[k]=lookup
- if not subtype then
- subtype=lookup.type
+ for i=1,#lookups do
+ local lookups=lookups[i]
+ if lookups then
+ for k,v in next,lookups do
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]=lookup
+ if not subtype then
+ subtype=lookup.type
+ end
+ else
+ end
end
- else
end
end
end
if sequence[1] then
- rulesize=rulesize+1
- rulehash[rulesize]={
- nofrules,
+ sequence.n=#sequence
+ local ruledata={
+ currentrule,
lookuptype,
sequence,
start,
@@ -15571,16 +22518,36 @@ function readers.expand(data)
replacements,
subtype,
}
- for unic in next,sequence[start] do
- local cu=coverage[unic]
- if not cu then
- coverage[unic]=rulehash
+ rulesize=rulesize+1
+ rulehash[rulesize]=ruledata
+ rulehash.n=rulesize
+ if true then
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ local n=#cu+1
+ cu[n]=ruledata
+ cu.n=n
+ else
+ coverage[unic]={ ruledata,n=1 }
+ end
+ end
+ else
+ for unic in next,sequence[start] do
+ local cu=coverage[unic]
+ if cu then
+ else
+ coverage[unic]=rulehash
+ end
end
end
end
end
end
end
+ checkmerge(sequence)
+ checkflags(sequence,resources)
+ checksteps(sequence)
end
end
end
@@ -15600,7 +22567,7 @@ if not modules then modules={} end modules ['font-otl']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
}
-local gmatch,find,match,lower,strip=string.gmatch,string.find,string.match,string.lower,string.strip
+local lower=string.lower
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
local derivetable=table.derive
@@ -15619,11 +22586,13 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
-otf.version=3.027
+otf.version=3.104
otf.cache=containers.define("fonts","otl",otf.version,true)
otf.svgcache=containers.define("fonts","svg",otf.version,true)
+otf.sbixcache=containers.define("fonts","sbix",otf.version,true)
otf.pdfcache=containers.define("fonts","pdf",otf.version,true)
otf.svgenabled=false
+otf.sbixenabled=false
local otfreaders=otf.readers
local hashes=fonts.hashes
local definers=fonts.definers
@@ -15637,6 +22606,7 @@ local forceload=false
local cleanup=0
local syncspace=true
local forcenotdef=false
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
local wildcard="*"
local default="dflt"
@@ -15648,17 +22618,31 @@ registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or
registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
-registerotfenhancer("check extra features",function() end)
-function otf.load(filename,sub,featurefile)
- local featurefile=nil
+registerotfenhancer("check extra features",function() end)
+local checkmemory=utilities.lua and utilities.lua.checkmemory
+local threshold=100
+local tracememory=false
+registertracker("fonts.otf.loader.memory",function(v) tracememory=v end)
+if not checkmemory then
+ local collectgarbage=collectgarbage
+ checkmemory=function(previous,threshold)
+ local current=collectgarbage("count")
+ if previous then
+ local checked=(threshold or 64)*1024
+ if current-previous>checked then
+ collectgarbage("collect")
+ current=collectgarbage("count")
+ end
+ end
+ return current
+ end
+end
+function otf.load(filename,sub,instance)
local base=file.basename(file.removesuffix(filename))
- local name=file.removesuffix(base)
+ local name=file.removesuffix(base)
local attr=lfs.attributes(filename)
local size=attr and attr.size or 0
local time=attr and attr.modification or 0
- if featurefile then
- name=name.."@"..file.removesuffix(file.basename(featurefile))
- end
if sub=="" then
sub=false
end
@@ -15666,27 +22650,10 @@ function otf.load(filename,sub,featurefile)
if sub then
hash=hash.."-"..sub
end
- hash=containers.cleanname(hash)
- local featurefiles
- if featurefile then
- featurefiles={}
- for s in gmatch(featurefile,"[^,]+") do
- local name=resolvers.findfile(file.addsuffix(s,'fea'),'fea') or ""
- if name=="" then
- report_otf("loading error, no featurefile %a",s)
- else
- local attr=lfs.attributes(name)
- featurefiles[#featurefiles+1]={
- name=name,
- size=attr and attr.size or 0,
- time=attr and attr.modification or 0,
- }
- end
- end
- if #featurefiles==0 then
- featurefiles=nil
- end
+ if instance then
+ hash=hash.."-"..instance
end
+ hash=containers.cleanname(hash)
local data=containers.read(otf.cache,hash)
local reload=not data or data.size~=size or data.time~=time or data.tableversion~=otfreaders.tableversion
if forceload then
@@ -15696,10 +22663,15 @@ function otf.load(filename,sub,featurefile)
if reload then
report_otf("loading %a, hash %a",filename,hash)
starttiming(otfreaders)
- data=otfreaders.loadfont(filename,sub or 1)
+ data=otfreaders.loadfont(filename,sub or 1,instance)
if data then
+ local used=checkmemory()
local resources=data.resources
local svgshapes=resources.svgshapes
+ local sbixshapes=resources.sbixshapes
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
if svgshapes then
resources.svgshapes=nil
if otf.svgenabled then
@@ -15713,17 +22685,49 @@ function otf.load(filename,sub,featurefile)
timestamp=timestamp,
}
end
+ if cleanup>1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
+ end
+ if sbixshapes then
+ resources.sbixshapes=nil
+ if otf.sbixenabled then
+ local timestamp=os.date()
+ containers.write(otf.sbixcache,hash,{
+ sbixshapes=sbixshapes,
+ timestamp=timestamp,
+ })
+ data.properties.sbix={
+ hash=hash,
+ timestamp=timestamp,
+ }
+ end
+ if cleanup>1 then
+ collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
+ end
end
otfreaders.compact(data)
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.rehash(data,"unicodes")
otfreaders.addunicodetable(data)
otfreaders.extend(data)
+ if cleanup==0 then
+ checkmemory(used,threshold,tracememory)
+ end
otfreaders.pack(data)
report_otf("loading done")
report_otf("saving %a in cache",filename)
data=containers.write(otf.cache,hash,data)
if cleanup>1 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
stoptiming(otfreaders)
if elapsedtime then
@@ -15731,10 +22735,14 @@ function otf.load(filename,sub,featurefile)
end
if cleanup>3 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
data=containers.read(otf.cache,hash)
if cleanup>2 then
collectgarbage("collect")
+ else
+ checkmemory(used,threshold,tracememory)
end
else
data=nil
@@ -15750,9 +22758,20 @@ function otf.load(filename,sub,featurefile)
otfreaders.addunicodetable(data)
otfenhancers.apply(data,filename,data)
if applyruntimefixes then
- applyruntimefixes(filename,data)
+ applyruntimefixes(filename,data)
end
data.metadata.math=data.resources.mathconstants
+ local classes=data.resources.classes
+ if not classes then
+ local descriptions=data.descriptions
+ classes=setmetatableindex(function(t,k)
+ local d=descriptions[k]
+ local v=(d and d.class or "base") or false
+ t[k]=v
+ return v
+ end)
+ data.resources.classes=classes
+ end
end
return data
end
@@ -15796,7 +22815,7 @@ local function copytotfm(data,cache_id)
end
if mathspecs then
for unicode,character in next,characters do
- local d=descriptions[unicode]
+ local d=descriptions[unicode]
local m=d.math
if m then
local italic=m.italic
@@ -15849,6 +22868,7 @@ local function copytotfm(data,cache_id)
local fontname=metadata.fontname
local fullname=metadata.fullname or fontname
local psname=fontname or fullname
+ local subfont=metadata.subfontindex
local units=metadata.units or 1000
if units==0 then
units=1000
@@ -15936,6 +22956,8 @@ local function copytotfm(data,cache_id)
properties.fullname=fullname
properties.psname=psname
properties.name=filename or fullname
+ properties.subfont=subfont
+ properties.private=properties.private or data.private or privateoffset
return {
characters=characters,
descriptions=descriptions,
@@ -15984,7 +23006,8 @@ local function otftotfm(specification)
local subindex=specification.subindex
local filename=specification.filename
local features=specification.features.normal
- local rawdata=otf.load(filename,sub,features and features.featurefile)
+ local instance=specification.instance or (features and features.axis)
+ local rawdata=otf.load(filename,sub,instance)
if rawdata and next(rawdata) then
local descriptions=rawdata.descriptions
rawdata.lookuphash={}
@@ -16027,7 +23050,7 @@ local function checkmathsize(tfmdata,mathsize)
local parameters=tfmdata.parameters
parameters.scriptpercentage=mathdata.ScriptPercentScaleDown
parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown
- parameters.mathsize=mathsize
+ parameters.mathsize=mathsize
end
end
registerotffeature {
@@ -16209,6 +23232,7 @@ otf.coverup={
multiple=justset,
kern=justset,
pair=justset,
+ single=justset,
ligature=function(coverage,unicode,ligature)
local first=ligature[1]
local tree=coverage[first]
@@ -16264,6 +23288,7 @@ local otf=fonts.handlers.otf
local otffeatures=otf.features
local registerotffeature=otffeatures.register
otf.defaultbasealternate="none"
+local getprivate=fonts.constructors.getprivate
local wildcard="*"
local default="dflt"
local formatters=string.formatters
@@ -16297,19 +23322,31 @@ end
local function cref(feature,sequence)
return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name)
end
-local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
- report_prepare("%s: base alternate %s => %s (%S => %S)",
- cref(feature,sequence),
- gref(descriptions,unicode),
- replacement and gref(descriptions,replacement),
- value,
- comment)
-end
local function report_substitution(feature,sequence,descriptions,unicode,substitution)
- report_prepare("%s: base substitution %s => %S",
- cref(feature,sequence),
- gref(descriptions,unicode),
- gref(descriptions,substitution))
+ if unicode==substitution then
+ report_prepare("%s: base substitution %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base substitution %s => %S",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ gref(descriptions,substitution))
+ end
+end
+local function report_alternate(feature,sequence,descriptions,unicode,replacement,value,comment)
+ if unicode==replacement then
+ report_prepare("%s: base alternate %s maps onto itself",
+ cref(feature,sequence),
+ gref(descriptions,unicode))
+ else
+ report_prepare("%s: base alternate %s => %s (%S => %S)",
+ cref(feature,sequence),
+ gref(descriptions,unicode),
+ replacement and gref(descriptions,replacement),
+ value,
+ comment)
+ end
end
local function report_ligature(feature,sequence,descriptions,unicode,ligature)
report_prepare("%s: base ligature %s => %S",
@@ -16342,13 +23379,11 @@ local function registerbasefeature(feature,value)
applied[#applied+1]=feature.."="..tostring(value)
end
local function makefake(tfmdata,name,present)
- local resources=tfmdata.resources
- local private=resources.private
+ local private=getprivate(tfmdata)
local character={ intermediate=true,ligatures={} }
resources.unicodes[name]=private
tfmdata.characters[private]=character
tfmdata.descriptions[private]={ name=name }
- resources.private=private+1
present[name]=private
return character
end
@@ -16414,37 +23449,44 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
if kind=="gsub_single" then
for i=1,#steps do
for unicode,data in next,steps[i].coverage do
- if trace_singles then
- report_substitution(feature,sequence,descriptions,unicode,data)
- end
+ if unicode~=data then
changed[unicode]=data
+ end
+ if trace_singles then
+ report_substitution(feature,sequence,descriptions,unicode,data)
+ end
end
end
elseif kind=="gsub_alternate" then
for i=1,#steps do
for unicode,data in next,steps[i].coverage do
- if not changed[unicode] then
- local replacement=data[alternate]
- if replacement then
+ local replacement=data[alternate]
+ if replacement then
+ if unicode~=replacement then
changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
- end
- elseif defaultalt=="first" then
- replacement=data[1]
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"normal")
+ end
+ elseif defaultalt=="first" then
+ replacement=data[1]
+ if unicode~=replacement then
+ changed[unicode]=replacement
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ elseif defaultalt=="last" then
+ replacement=data[#data]
+ if unicode~=replacement then
changed[unicode]=replacement
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- elseif defaultalt=="last" then
- replacement=data[#data]
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
- end
- else
- if trace_alternatives then
- report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
- end
+ end
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,defaultalt)
+ end
+ else
+ if trace_alternatives then
+ report_alternate(feature,sequence,descriptions,unicode,replacement,value,"unknown")
end
end
end
@@ -16491,7 +23533,8 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
if kind=="gpos_pair" then
for i=1,#steps do
local step=steps[i]
- if step.format=="kern" then
+ local format=step.format
+ if format=="kern" or format=="move" then
for unicode,data in next,steps[i].coverage do
local character=characters[unicode]
local kerns=character.kerns
@@ -16519,9 +23562,11 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
local character=characters[unicode]
local kerns=character.kerns
for otherunicode,kern in next,data do
- if not kern[2] and not (kerns and kerns[otherunicode]) then
+ local other=kern[2]
+ if other==true or (not other and not (kerns and kerns[otherunicode])) then
local kern=kern[1]
- if kern[1]~=0 or kern[2]~=0 or kern[4]~=0 then
+ if kern==true then
+ elseif kern[1]~=0 or kern[2]~=0 or kern[4]~=0 then
else
kern=kern[3]
if kern~=0 then
@@ -16546,6 +23591,51 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist
end
local function initializehashes(tfmdata)
end
+local function checkmathreplacements(tfmdata,fullname,fixitalics)
+ if tfmdata.mathparameters then
+ local characters=tfmdata.characters
+ local changed=tfmdata.changed
+ if next(changed) then
+ if trace_preparing or trace_baseinit then
+ report_prepare("checking math replacements for %a",fullname)
+ end
+ for unicode,replacement in next,changed do
+ local u=characters[unicode]
+ local r=characters[replacement]
+ local n=u.next
+ local v=u.vert_variants
+ local h=u.horiz_variants
+ if fixitalics then
+ local ui=u.italic
+ if ui and not r.italic then
+ if trace_preparing then
+ report_prepare("using %i units of italic correction from %C for %U",ui,unicode,replacement)
+ end
+ r.italic=ui
+ end
+ end
+ if n and not r.next then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","incremental step",unicode,replacement)
+ end
+ r.next=n
+ end
+ if v and not r.vert_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","vertical variants",unicode,replacement)
+ end
+ r.vert_variants=v
+ end
+ if h and not r.horiz_variants then
+ if trace_preparing then
+ report_prepare("forcing %s for %C substituted by %U","horizontal variants",unicode,replacement)
+ end
+ r.horiz_variants=h
+ end
+ end
+ end
+ end
+end
local function featuresinitializer(tfmdata,value)
if true then
local starttime=trace_preparing and os.clock()
@@ -16562,6 +23652,8 @@ local function featuresinitializer(tfmdata,value)
local rawfeatures=rawresources and rawresources.features
local basesubstitutions=rawfeatures and rawfeatures.gsub
local basepositionings=rawfeatures and rawfeatures.gpos
+ local substitutionsdone=false
+ local positioningsdone=false
if basesubstitutions or basepositionings then
local sequences=tfmdata.resources.sequences
for s=1,#sequences do
@@ -16582,12 +23674,14 @@ local function featuresinitializer(tfmdata,value)
end
preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ substitutionsdone=true
elseif basepositionings and basepositionings[feature] then
if trace_preparing then
report_prepare("filtering base %a feature %a for %a with value %a","pos",feature,fullname,value)
end
preparepositionings(tfmdata,feature,value,validlookups,lookuplist)
registerbasefeature(feature,value)
+ positioningsdone=true
end
end
end
@@ -16595,6 +23689,9 @@ local function featuresinitializer(tfmdata,value)
end
end
end
+ if substitutionsdone then
+ checkmathreplacements(tfmdata,fullname,features.fixitalics)
+ end
registerbasehash(tfmdata)
end
if trace_preparing then
@@ -16624,20 +23721,21 @@ if not modules then modules={} end modules ['font-otj']={
license="see context related readme files",
}
if not nodes.properties then return end
-local next,rawget=next,rawget
+local next,rawget,tonumber=next,rawget,tonumber
local fastcopy=table.fastcopy
local registertracker=trackers.register
+local registerdirective=directives.register
local trace_injections=false registertracker("fonts.injections",function(v) trace_injections=v end)
local trace_marks=false registertracker("fonts.injections.marks",function(v) trace_marks=v end)
local trace_cursive=false registertracker("fonts.injections.cursive",function(v) trace_cursive=v end)
local trace_spaces=false registertracker("fonts.injections.spaces",function(v) trace_spaces=v end)
-local use_advance=false directives.register("fonts.injections.advance",function(v) use_advance=v end)
local report_injections=logs.reporter("fonts","injections")
local report_spaces=logs.reporter("fonts","spaces")
local attributes,nodes,node=attributes,nodes,node
fonts=fonts
local hashes=fonts.hashes
local fontdata=hashes.identifiers
+local fontmarks=hashes.marks
nodes.injections=nodes.injections or {}
local injections=nodes.injections
local tracers=nodes.tracers
@@ -16650,31 +23748,62 @@ local kern_code=nodecodes.kern
local glue_code=nodecodes.glue
local nuts=nodes.nuts
local nodepool=nuts.pool
-local newkern=nodepool.kern
local tonode=nuts.tonode
local tonut=nuts.tonut
-local getfield=nuts.getfield
local setfield=nuts.setfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getid=nuts.getid
local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
+local getoffsets=nuts.getoffsets
local getboth=nuts.getboth
-local ischar=nuts.is_char
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
-local traverse_id=nuts.traverse_id
-local traverse_char=nuts.traverse_char
+local setoffsets=nuts.setoffsets
+local ischar=nuts.is_char
+local getkern=nuts.getkern
+local setkern=nuts.setkern
+local setlink=nuts.setlink
+local setwidth=nuts.setwidth
+local getwidth=nuts.getwidth
+local nextchar=nuts.traversers.char
+local nextglue=nuts.traversers.glue
local insert_node_before=nuts.insert_before
local insert_node_after=nuts.insert_after
local properties=nodes.properties.data
-function injections.installnewkern(nk)
- newkern=nk or newkern
-end
+local fontkern=nuts.pool and nuts.pool.fontkern
+local italickern=nuts.pool and nuts.pool.italickern
+local useitalickerns=false
+directives.register("fonts.injections.useitalics",function(v)
+ if v then
+ report_injections("using italics for space kerns (tracing only)")
+ end
+ useitalickerns=v
+end)
+do if not fontkern then
+ local thekern=nuts.new("kern",0)
+ local setkern=nuts.setkern
+ local copy_node=nuts.copy_node
+ fontkern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
+do if not italickern then
+ local thekern=nuts.new("kern",3)
+ local setkern=nuts.setkern
+ local copy_node=nuts.copy_node
+ italickern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
+function injections.installnewkern() end
local nofregisteredkerns=0
-local nofregisteredpairs=0
+local nofregisteredpositions=0
local nofregisteredmarks=0
local nofregisteredcursives=0
local keepregisteredcounts=false
@@ -16683,7 +23812,7 @@ function injections.keepcounts()
end
function injections.resetcounts()
nofregisteredkerns=0
- nofregisteredpairs=0
+ nofregisteredpositions=0
nofregisteredmarks=0
nofregisteredcursives=0
keepregisteredcounts=false
@@ -16706,7 +23835,7 @@ function injections.copy(target,source)
if tp then
tp.injections=si
else
- propertydata[target]={
+ properties[target]={
injections=si,
}
end
@@ -16724,7 +23853,7 @@ function injections.copy(target,source)
end
end
end
-function injections.setligaindex(n,index)
+function injections.setligaindex(n,index)
local p=rawget(properties,n)
if p then
local i=p.injections
@@ -16753,7 +23882,7 @@ function injections.getligaindex(n,default)
end
return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
local dx=factor*(exit[1]-entry[1])
local dy=-factor*(exit[2]-entry[2])
local ws=tfmstart.width
@@ -16806,17 +23935,17 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
end
return dx,dy,nofregisteredcursives
end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
- local x=factor*spec[1]
- local y=factor*spec[2]
- local w=factor*spec[3]
- local h=factor*spec[4]
+function injections.setposition(kind,current,factor,rlmode,spec,injection)
+ local x=factor*(spec[1] or 0)
+ local y=factor*(spec[2] or 0)
+ local w=factor*(spec[3] or 0)
+ local h=factor*(spec[4] or 0)
if x~=0 or w~=0 or y~=0 or h~=0 then
local yoffset=y-h
local leftkern=x
local rightkern=w-x
if leftkern~=0 or rightkern~=0 or yoffset~=0 then
- nofregisteredpairs=nofregisteredpairs+1
+ nofregisteredpositions=nofregisteredpositions+1
if rlmode and rlmode<0 then
leftkern,rightkern=rightkern,leftkern
end
@@ -16825,7 +23954,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
end
local p=rawget(properties,current)
if p then
- local i=rawget(p,injection)
+ local i=p[injection]
if i then
if leftkern~=0 then
i.leftkern=(i.leftkern or 0)+leftkern
@@ -16862,7 +23991,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
},
}
end
- return x,y,w,h,nofregisteredpairs
+ return x,y,w,h,nofregisteredpositions
end
end
return x,y,w,h
@@ -16876,7 +24005,7 @@ function injections.setkern(current,factor,rlmode,x,injection)
injection="injections"
end
if p then
- local i=rawget(p,injection)
+ local i=p[injection]
if i then
i.leftkern=dx+(i.leftkern or 0)
else
@@ -16896,6 +24025,54 @@ function injections.setkern(current,factor,rlmode,x,injection)
return 0,0
end
end
+function injections.setmove(current,factor,rlmode,x,injection)
+ local dx=factor*x
+ if dx~=0 then
+ nofregisteredkerns=nofregisteredkerns+1
+ local p=rawget(properties,current)
+ if not injection then
+ injection="injections"
+ end
+ if rlmode and rlmode<0 then
+ if p then
+ local i=p[injection]
+ if i then
+ i.rightkern=dx+(i.rightkern or 0)
+ else
+ p[injection]={
+ rightkern=dx,
+ }
+ end
+ else
+ properties[current]={
+ [injection]={
+ rightkern=dx,
+ },
+ }
+ end
+ else
+ if p then
+ local i=p[injection]
+ if i then
+ i.leftkern=dx+(i.leftkern or 0)
+ else
+ p[injection]={
+ leftkern=dx,
+ }
+ end
+ else
+ properties[current]={
+ [injection]={
+ leftkern=dx,
+ },
+ }
+ end
+ end
+ return dx,nofregisteredkerns
+ else
+ return 0,0
+ end
+end
function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
nofregisteredmarks=nofregisteredmarks+1
@@ -16908,9 +24085,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmar
if i then
if i.markmark then
else
- i.markx=dx
- i.marky=dy
- i.markdir=rlmode or 0
+ if dx~=0 then
+ i.markx=dx
+ end
+ if y~=0 then
+ i.marky=dy
+ end
+ if rlmode then
+ i.markdir=rlmode
+ end
i.markbase=nofregisteredmarks
i.markbasenode=base
i.markmark=mkmk
@@ -16953,7 +24136,7 @@ local function show(n,what,nested,symbol)
if n then
local p=rawget(properties,n)
if p then
- local i=rawget(p,what)
+ local i=p[what]
if i then
local leftkern=i.leftkern or 0
local rightkern=i.rightkern or 0
@@ -16993,15 +24176,16 @@ local function show(n,what,nested,symbol)
end
local function showsub(n,what,where)
report_injections("begin subrun: %s",where)
- for n in traverse_id(glyph_code,n) do
+ for n in nextchar,n do
showchar(n,where)
show(n,what,where," ")
end
report_injections("end subrun")
end
local function trace(head,where)
- report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered",
- where or "",nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
+ report_injections()
+ report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
+ where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
local n=head
while n do
local id=getid(n)
@@ -17035,11 +24219,12 @@ local function show_result(head)
while current do
local id=getid(current)
if id==glyph_code then
- report_injections("char: %C, width %p, xoffset %p, yoffset %p",
- getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+ local w=getwidth(current)
+ local x,y=getoffsets(current)
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
skipping=false
elseif id==kern_code then
- report_injections("kern: %p",getfield(current,"kern"))
+ report_injections("kern: %p",getkern(current))
skipping=false
elseif not skipping then
report_injections()
@@ -17047,9 +24232,9 @@ local function show_result(head)
end
current=getnext(current)
end
+ report_injections()
end
local function inject_kerns_only(head,where)
- head=tonut(head)
if trace_injections then
trace(head,"kerns")
end
@@ -17057,7 +24242,6 @@ local function inject_kerns_only(head,where)
local prev=nil
local next=nil
local prevdisc=nil
- local prevglyph=nil
local pre=nil
local post=nil
local replace=nil
@@ -17065,128 +24249,99 @@ local function inject_kerns_only(head,where)
local posttail=nil
local replacetail=nil
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(current,"xoffset",leftkern)
- setfield(current,"xadvance",leftkern)
- else
- insert_node_before(head,current,newkern(leftkern))
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ head=insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ if prevdisc then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
end
- if prevdisc then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(post,"xadvance",leftkern)
- else
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
- end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- if use_advance then
- setfield(replace,"xadvance",leftkern)
- else
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
- end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
end
end
prevdisc=nil
- prevglyph=current
+ elseif char==false then
+ prevdisc=nil
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(pre,"xoffset",leftkern)
- setfield(pre,"xadvance",leftkern)
- else
- pre=insert_node_before(pre,n,newkern(leftkern))
- done=true
- end
+ pre=insert_node_before(pre,n,fontkern(leftkern))
+ done=true
end
end
end
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(post,"xoffset",leftkern)
- setfield(post,"xadvance",leftkern)
- else
- post=insert_node_before(post,n,newkern(leftkern))
- done=true
- end
+ post=insert_node_before(post,n,fontkern(leftkern))
+ done=true
end
end
end
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- if use_advance then
- setfield(replace,"xoffset",leftkern)
- setfield(replace,"xadvance",leftkern)
- else
- replace=insert_node_before(replace,n,newkern(leftkern))
- done=true
- end
+ replace=insert_node_before(replace,n,fontkern(leftkern))
+ done=true
end
end
end
@@ -17195,10 +24350,8 @@ local function inject_kerns_only(head,where)
if done then
setdisc(current,pre,post,replace)
end
- prevglyph=nil
prevdisc=current
else
- prevglyph=nil
prevdisc=nil
end
prev=current
@@ -17209,12 +24362,14 @@ local function inject_kerns_only(head,where)
else
nofregisteredkerns=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
-local function inject_pairs_only(head,where)
- head=tonut(head)
+local function inject_positions_only(head,where)
if trace_injections then
- trace(head,"pairs")
+ trace(head,"positions")
end
local current=head
local prev=nil
@@ -17228,99 +24383,105 @@ local function inject_pairs_only(head,where)
local posttail=nil
local replacetail=nil
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local yoffset=i.yoffset
- if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
- end
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- head=insert_node_before(head,current,newkern(leftkern))
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local yoffset=i.yoffset
+ if yoffset and yoffset~=0 then
+ setoffsets(current,false,yoffset)
+ end
+ local leftkern=i.leftkern
+ local rightkern=i.rightkern
+ if leftkern and leftkern~=0 then
+ if rightkern and leftkern==-rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern=0
+ else
+ head=insert_node_before(head,current,fontkern(leftkern))
end
+ end
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ else
+ local i=p.emptyinjections
+ if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(head,current,newkern(rightkern))
- end
- else
- local i=p.emptyinjections
- if i then
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- if next and getid(next)==disc_code then
- if replace then
- else
- setfield(next,"replace",newkern(rightkern))
- end
+ if next and getid(next)==disc_code then
+ if replace then
+ else
+ setfield(next,"replace",fontkern(rightkern))
end
end
end
end
- if prevdisc then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
+ end
+ if prevdisc then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
+ end
end
end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
end
end
prevdisc=nil
prevglyph=current
+ elseif char==false then
+ prevdisc=nil
+ prevglyph=current
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- pre=insert_node_before(pre,n,newkern(leftkern))
+ pre=insert_node_before(pre,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done=true
end
end
@@ -17328,23 +24489,23 @@ local function inject_pairs_only(head,where)
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- post=insert_node_before(post,n,newkern(leftkern))
+ post=insert_node_before(post,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done=true
end
end
@@ -17352,23 +24513,23 @@ local function inject_pairs_only(head,where)
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- replace=insert_node_before(replace,n,newkern(leftkern))
+ replace=insert_node_before(replace,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done=true
end
end
@@ -17383,7 +24544,7 @@ local function inject_pairs_only(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- pre=insert_node_before(pre,pre,newkern(rightkern))
+ pre=insert_node_before(pre,pre,fontkern(rightkern))
done=true
end
end
@@ -17396,7 +24557,7 @@ local function inject_pairs_only(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- replace=insert_node_before(replace,replace,newkern(rightkern))
+ replace=insert_node_before(replace,replace,fontkern(rightkern))
done=true
end
end
@@ -17418,23 +24579,20 @@ local function inject_pairs_only(head,where)
if keepregisteredcounts then
keepregisteredcounts=false
else
- nofregisteredkerns=0
+ nofregisteredpositions=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
local function showoffset(n,flag)
- local o=getfield(n,"xoffset")
- if o==0 then
- o=getfield(n,"yoffset")
- end
- if o~=0 then
- setcolor(n,flag and "darkred" or "darkgreen")
- else
- resetcolor(n)
+ local x,y=getoffsets(n)
+ if x~=0 or y~=0 then
+ setcolor(n,"darkgray")
end
end
local function inject_everything(head,where)
- head=tonut(head)
if trace_injections then
trace(head,"everything")
end
@@ -17442,8 +24600,6 @@ local function inject_everything(head,where)
local hasmarks=nofregisteredmarks>0
local current=head
local last=nil
- local font=font
- local markdata=nil
local prev=nil
local next=nil
local prevdisc=nil
@@ -17461,7 +24617,8 @@ local function inject_everything(head,where)
local marks={}
local nofmarks=0
local function processmark(p,n,pn)
- local px=getfield(p,"xoffset")
+ local px,py=getoffsets(p)
+ local nx,ny=getoffsets(n)
local ox=0
local rightkern=nil
local pp=rawget(properties,p)
@@ -17471,212 +24628,232 @@ local function inject_everything(head,where)
rightkern=pp.rightkern
end
end
+ local markdir=pn.markdir
if rightkern then
- if pn.markdir<0 then
- ox=px-pn.markx-rightkern
+ ox=px-(pn.markx or 0)-rightkern
+ if markdir and markdir<0 then
+ if not pn.markmark then
+ ox=ox+(pn.leftkern or 0)
+ end
else
if false then
local leftkern=pp.leftkern
if leftkern then
- ox=px-pn.markx-leftkern
- else
- ox=px-pn.markx
+ ox=ox-leftkern
end
- else
- ox=px-pn.markx
end
end
else
- ox=px-pn.markx
+ ox=px-(pn.markx or 0)
+ if markdir and markdir<0 then
+ if not pn.markmark then
+ local leftkern=pn.leftkern
+ if leftkern then
+ ox=ox+leftkern
+ end
+ end
+ end
if pn.checkmark then
- local wn=getfield(n,"width")
- if wn~=0 then
+ local wn=getwidth(n)
+ if wn and wn~=0 then
wn=wn/2
if trace_injections then
report_injections("correcting non zero width mark %C",getchar(n))
end
- insert_node_before(n,n,newkern(-wn))
- insert_node_after(n,n,newkern(-wn))
+ insert_node_before(n,n,fontkern(-wn))
+ insert_node_after(n,n,fontkern(-wn))
end
end
end
- local oy=getfield(n,"yoffset")+getfield(p,"yoffset")+pn.marky
- setfield(n,"xoffset",ox)
- setfield(n,"yoffset",oy)
+ local oy=ny+py+(pn.marky or 0)
+ if not pn.markmark then
+ local yoffset=pn.yoffset
+ if yoffset then
+ oy=oy+yoffset
+ end
+ end
+ setoffsets(n,ox,oy)
if trace_marks then
showoffset(n,true)
end
end
while current do
- local id=getid(current)
local next=getnext(current)
- if id==glyph_code then
- if getsubtype(current)<256 then
- local p=rawget(properties,current)
- if p then
- local i=p.injections
- if i then
- local pm=i.markbasenode
- if pm then
- nofmarks=nofmarks+1
- marks[nofmarks]=current
- else
- local yoffset=i.yoffset
- if yoffset and yoffset~=0 then
- setfield(current,"yoffset",yoffset)
- end
- if hascursives then
- local cursivex=i.cursivex
- if cursivex then
- if cursiveanchor then
- if cursivex~=0 then
- i.leftkern=(i.leftkern or 0)+cursivex
- end
- if maxc==0 then
- minc=1
- maxc=1
- glyphs[1]=cursiveanchor
- else
- maxc=maxc+1
- glyphs[maxc]=cursiveanchor
- end
- properties[cursiveanchor].cursivedy=i.cursivey
- last=current
+ local char,id=ischar(current)
+ if char then
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ local pm=i.markbasenode
+ if pm then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=current
+ else
+ local yoffset=i.yoffset
+ if yoffset and yoffset~=0 then
+ setoffsets(current,false,yoffset)
+ end
+ if hascursives then
+ local cursivex=i.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex~=0 then
+ i.leftkern=(i.leftkern or 0)+cursivex
+ end
+ if maxc==0 then
+ minc=1
+ maxc=1
+ glyphs[1]=cursiveanchor
else
- maxc=0
+ maxc=maxc+1
+ glyphs[maxc]=cursiveanchor
end
- elseif maxc>0 then
- local ny=getfield(current,"yoffset")
+ properties[cursiveanchor].cursivedy=i.cursivey
+ last=current
+ else
+ maxc=0
+ end
+ elseif maxc>0 then
+ local nx,ny=getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setoffsets(ti,false,ny)
+ if trace_cursive then
+ showoffset(ti)
+ end
+ end
+ maxc=0
+ cursiveanchor=nil
+ end
+ if i.cursiveanchor then
+ cursiveanchor=current
+ else
+ if maxc>0 then
+ local nx,ny=getoffsets(current)
for i=maxc,minc,-1 do
local ti=glyphs[i]
ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
+ setoffsets(ti,false,ny)
if trace_cursive then
showoffset(ti)
end
end
maxc=0
- cursiveanchor=nil
- end
- if i.cursiveanchor then
- cursiveanchor=current
- else
- if maxc>0 then
- local ny=getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti=glyphs[i]
- ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
- if trace_cursive then
- showoffset(ti)
- end
- end
- maxc=0
- end
- cursiveanchor=nil
end
+ cursiveanchor=nil
end
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_before(head,current,newkern(leftkern))
- end
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- insert_node_after(head,current,newkern(rightkern))
+ end
+ local leftkern=i.leftkern
+ local rightkern=i.rightkern
+ if leftkern and leftkern~=0 then
+ if rightkern and leftkern==-rightkern then
+ setoffsets(current,leftkern,false)
+ rightkern=0
+ else
+ head=insert_node_before(head,current,fontkern(leftkern))
end
end
- else
- local i=p.emptyinjections
- if i then
- local rightkern=i.rightkern
- if rightkern and rightkern~=0 then
- if next and getid(next)==disc_code then
- if replace then
- else
- setfield(next,"replace",newkern(rightkern))
- end
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ end
+ else
+ local i=p.emptyinjections
+ if i then
+ local rightkern=i.rightkern
+ if rightkern and rightkern~=0 then
+ if next and getid(next)==disc_code then
+ if replace then
+ else
+ setfield(next,"replace",fontkern(rightkern))
end
end
end
end
- if prevdisc then
- if p then
- local done=false
- if post then
- local i=p.postinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(post,posttail,newkern(leftkern))
- done=true
- end
+ end
+ if prevdisc then
+ if p then
+ local done=false
+ if post then
+ local i=p.postinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(posttail,fontkern(leftkern))
+ done=true
end
end
- if replace then
- local i=p.replaceinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- insert_node_after(replace,replacetail,newkern(leftkern))
- done=true
- end
- end
- else
- local i=p.emptyinjections
- if i then
- local leftkern=i.leftkern
- if leftkern and leftkern~=0 then
- setfield(prev,"replace",newkern(leftkern))
- end
+ end
+ if replace then
+ local i=p.replaceinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setlink(replacetail,fontkern(leftkern))
+ done=true
end
end
- if done then
- setdisc(prevdisc,pre,post,replace)
+ else
+ local i=p.emptyinjections
+ if i then
+ local leftkern=i.leftkern
+ if leftkern and leftkern~=0 then
+ setfield(prev,"replace",fontkern(leftkern))
+ end
end
end
- end
- else
- if hascursives and maxc>0 then
- local ny=getfield(current,"yoffset")
- for i=maxc,minc,-1 do
- local ti=glyphs[i]
- ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+ if done then
+ setdisc(prevdisc,pre,post,replace)
end
- maxc=0
- cursiveanchor=nil
end
end
+ else
+ if hascursives and maxc>0 then
+ local nx,ny=getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ local xi,yi=getoffsets(ti)
+ setoffsets(ti,xi,yi+ny)
+ end
+ maxc=0
+ cursiveanchor=nil
+ end
end
prevdisc=nil
prevglyph=current
+ elseif char==false then
+ prevdisc=nil
+ prevglyph=current
elseif id==disc_code then
pre,post,replace,pretail,posttail,replacetail=getdisc(current,true)
local done=false
if pre then
- for n in traverse_char(pre) do
+ for n in nextchar,pre do
local p=rawget(properties,n)
if p then
local i=p.injections or p.preinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- pre=insert_node_before(pre,n,newkern(leftkern))
+ pre=insert_node_before(pre,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(pre,n,newkern(rightkern))
+ insert_node_after(pre,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -17684,29 +24861,29 @@ local function inject_everything(head,where)
end
end
if post then
- for n in traverse_char(post) do
+ for n in nextchar,post do
local p=rawget(properties,n)
if p then
local i=p.injections or p.postinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- post=insert_node_before(post,n,newkern(leftkern))
+ post=insert_node_before(post,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(post,n,newkern(rightkern))
+ insert_node_after(post,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -17714,29 +24891,29 @@ local function inject_everything(head,where)
end
end
if replace then
- for n in traverse_char(replace) do
+ for n in nextchar,replace do
local p=rawget(properties,n)
if p then
local i=p.injections or p.replaceinjections
if i then
local yoffset=i.yoffset
if yoffset and yoffset~=0 then
- setfield(n,"yoffset",yoffset)
+ setoffsets(n,false,yoffset)
end
local leftkern=i.leftkern
if leftkern and leftkern~=0 then
- replace=insert_node_before(replace,n,newkern(leftkern))
+ replace=insert_node_before(replace,n,fontkern(leftkern))
done=true
end
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- insert_node_after(replace,n,newkern(rightkern))
+ insert_node_after(replace,n,fontkern(rightkern))
done=true
end
if hasmarks then
local pm=i.markbasenode
if pm then
- processmark(pm,current,i)
+ processmark(pm,n,i)
end
end
end
@@ -17751,7 +24928,7 @@ local function inject_everything(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- pre=insert_node_before(pre,pre,newkern(rightkern))
+ pre=insert_node_before(pre,pre,fontkern(rightkern))
done=true
end
end
@@ -17764,7 +24941,7 @@ local function inject_everything(head,where)
if i then
local rightkern=i.rightkern
if rightkern and rightkern~=0 then
- replace=insert_node_before(replace,replace,newkern(rightkern))
+ replace=insert_node_before(replace,replace,fontkern(rightkern))
done=true
end
end
@@ -17784,11 +24961,11 @@ local function inject_everything(head,where)
current=next
end
if hascursives and maxc>0 then
- local ny=getfield(last,"yoffset")
+ local nx,ny=getoffsets(last)
for i=maxc,minc,-1 do
local ti=glyphs[i]
ny=ny+properties[ti].cursivedy
- setfield(ti,"yoffset",ny)
+ setoffsets(ti,false,ny)
if trace_cursive then
showoffset(ti)
end
@@ -17808,11 +24985,14 @@ local function inject_everything(head,where)
keepregisteredcounts=false
else
nofregisteredkerns=0
- nofregisteredpairs=0
+ nofregisteredpositions=0
nofregisteredmarks=0
nofregisteredcursives=0
end
- return tonode(head),true
+ if trace_injections then
+ show_result(head)
+ end
+ return head
end
local triggers=false
function nodes.injections.setspacekerns(font,sequence)
@@ -17824,16 +25004,9 @@ function nodes.injections.setspacekerns(font,sequence)
end
local getthreshold
if context then
- local threshold=1
- local parameters=fonts.hashes.parameters
- directives.register("otf.threshold",function(v) threshold=tonumber(v) or 1 end)
- getthreshold=function(font)
- local p=parameters[font]
- local f=p.factor
- local s=p.spacing
- local t=threshold*(s and s.width or p.space or 0)-2
- return t>0 and t or 0,f
- end
+
+--removed
+
else
injections.threshold=0
getthreshold=function(font)
@@ -17845,17 +25018,21 @@ else
end
end
injections.getthreshold=getthreshold
-function injections.isspace(n,threshold)
- if getid(n)==glue_code then
- local w=getfield(n,"width")
+function injections.isspace(n,threshold,id)
+ if (id or getid(n))==glue_code then
+ local w=getwidth(n)
if threshold and w>threshold then
return 32
end
end
end
+local getspaceboth=getboth
+function injections.installgetspaceboth(gb)
+ getspaceboth=gb or getboth
+end
local function injectspaces(head)
if not triggers then
- return head,false
+ return head
end
local lastfont=nil
local spacekerns=nil
@@ -17872,10 +25049,10 @@ local function injectspaces(head)
threshold,
factor=getthreshold(font)
end
- for n in traverse_id(glue_code,tonut(head)) do
- local prev,next=getboth(n)
- local prevchar=ischar(prev)
- local nextchar=ischar(next)
+ for n in nextglue,head do
+ local prev,next=getspaceboth(n)
+ local prevchar=prev and ischar(prev)
+ local nextchar=next and ischar(next)
if nextchar then
local font=getfont(next)
local trig=triggers[font]
@@ -17901,38 +25078,64 @@ local function injectspaces(head)
end
end
if leftkern then
- local old=getfield(n,"width")
+ local old=getwidth(n)
if old>threshold then
if rightkern then
- local new=old+(leftkern+rightkern)*factor
- if trace_spaces then
- report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ if useitalickerns then
+ local lnew=leftkern*factor
+ local rnew=rightkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
+ end
+ head=insert_node_before(head,n,italickern(lnew))
+ insert_node_after(head,n,italickern(rnew))
+ else
+ local new=old+(leftkern+rightkern)*factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
- leftkern=false
+ rightkern=false
else
- local new=old+leftkern*factor
- if trace_spaces then
- report_spaces("%C [%p -> %p]",prevchar,old,new)
+ if useitalickerns then
+ local new=leftkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",prevchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ local new=old+leftkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p]",prevchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
end
leftkern=false
elseif rightkern then
- local old=getfield(n,"width")
+ local old=getwidth(n)
if old>threshold then
- local new=old+rightkern*factor
- if trace_spaces then
- report_spaces("[%p -> %p] %C",nextchar,old,new)
+ if useitalickerns then
+ local new=rightkern*factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",nextchar,old,new)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ local new=old+rightkern*factor
+ if trace_spaces then
+ report_spaces("[%p -> %p] %C",nextchar,old,new)
+ end
+ setwidth(n,new)
end
- setfield(n,"width",new)
end
rightkern=false
end
end
triggers=false
- return head,true
+ return head
end
function injections.handler(head,where)
if triggers then
@@ -17943,18 +25146,18 @@ function injections.handler(head,where)
report_injections("injection variant %a","everything")
end
return inject_everything(head,where)
- elseif nofregisteredpairs>0 then
+ elseif nofregisteredpositions>0 then
if trace_injections then
- report_injections("injection variant %a","pairs")
+ report_injections("injection variant %a","positions")
end
- return inject_pairs_only(head,where)
+ return inject_positions_only(head,where)
elseif nofregisteredkerns>0 then
if trace_injections then
report_injections("injection variant %a","kerns")
end
return inject_kerns_only(head,where)
else
- return head,false
+ return head
end
end
@@ -17964,7 +25167,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-ota']={
version=1.001,
- comment="companion to font-otf.lua (analysing)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
@@ -17982,7 +25185,6 @@ analyzers.methods=methods
local a_state=attributes.private('state')
local nuts=nodes.nuts
local tonut=nuts.tonut
-local getfield=nuts.getfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getprev=nuts.getprev
@@ -17992,7 +25194,6 @@ local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
local ischar=nuts.is_char
-local traverse_id=nuts.traverse_id
local end_of_math=nuts.end_of_math
local nodecodes=nodes.nodecodes
local disc_code=nodecodes.disc
@@ -18008,7 +25209,7 @@ local s_fina=3 local s_pref=9
local s_isol=4 local s_blwf=10
local s_mark=5 local s_pstf=11
local s_rest=6
-local states={
+local states=allocate {
init=s_init,
medi=s_medi,
med2=s_medi,
@@ -18024,7 +25225,7 @@ local states={
blwf=s_blwf,
pstf=s_pstf,
}
-local features={
+local features=allocate {
init=s_init,
medi=s_medi,
med2=s_medi,
@@ -18156,7 +25357,7 @@ local function warning(current,what)
arab_warned[char]=true
end
end
-local mappers={
+local mappers=allocate {
l=s_init,
d=s_medi,
c=s_medi,
@@ -18355,12 +25556,14 @@ local type,next,tonumber=type,next,tonumber
local random=math.random
local formatters=string.formatters
local insert=table.insert
-local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes
local registertracker=trackers.register
-local registerdirective=directives.register
+local logs=logs
+local trackers=trackers
+local nodes=nodes
+local attributes=attributes
local fonts=fonts
local otf=fonts.handlers.otf
-local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end)
+local tracers=nodes.tracers
local trace_singles=false registertracker("otf.singles",function(v) trace_singles=v end)
local trace_multiples=false registertracker("otf.multiples",function(v) trace_multiples=v end)
local trace_alternatives=false registertracker("otf.alternatives",function(v) trace_alternatives=v end)
@@ -18374,30 +25577,32 @@ local trace_bugs=false registertracker("otf.bugs",function(v) trace_bugs=v end)
local trace_details=false registertracker("otf.details",function(v) trace_details=v end)
local trace_steps=false registertracker("otf.steps",function(v) trace_steps=v end)
local trace_skips=false registertracker("otf.skips",function(v) trace_skips=v end)
-local trace_directions=false registertracker("otf.directions",function(v) trace_directions=v end)
local trace_plugins=false registertracker("otf.plugins",function(v) trace_plugins=v end)
+local trace_chains=false registertracker("otf.chains",function(v) trace_chains=v end)
local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kernruns=v end)
-local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end)
local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end)
local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end)
-local optimizekerns=true
-local alwaysdisc=true registerdirective("otf.alwaysdisc",function(v) alwaysdisc=v end)
+local forcediscretionaries=false
+local forcepairadvance=false
+directives.register("otf.forcediscretionaries",function(v)
+ forcediscretionaries=v
+end)
+directives.register("otf.forcepairadvance",function(v)
+ forcepairadvance=v
+end)
local report_direct=logs.reporter("fonts","otf direct")
local report_subchain=logs.reporter("fonts","otf subchain")
local report_chain=logs.reporter("fonts","otf chain")
local report_process=logs.reporter("fonts","otf process")
local report_warning=logs.reporter("fonts","otf warning")
local report_run=logs.reporter("fonts","otf run")
-registertracker("otf.replacements","otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
-registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
-registertracker("otf.actions","otf.replacements,otf.positions")
-registertracker("otf.injections","nodes.injections")
-registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+registertracker("otf.substitutions","otf.singles","otf.multiples","otf.alternatives","otf.ligatures")
+registertracker("otf.positions","otf.marks","otf.kerns","otf.cursive")
+registertracker("otf.actions","otf.substitutions","otf.positions")
+registertracker("otf.sample","otf.steps","otf.substitutions","otf.positions","otf.analyzing")
+registertracker("otf.sample.silent","otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing")
local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
local getfield=nuts.getfield
-local setfield=nuts.setfield
local getnext=nuts.getnext
local setnext=nuts.setnext
local getprev=nuts.getprev
@@ -18417,22 +25622,28 @@ local setchar=nuts.setchar
local getdisc=nuts.getdisc
local setdisc=nuts.setdisc
local setlink=nuts.setlink
+local getcomponents=nuts.getcomponents
+local setcomponents=nuts.setcomponents
+local getdir=nuts.getdir
+local getwidth=nuts.getwidth
local ischar=nuts.is_char
+local usesfont=nuts.uses_font
local insert_node_after=nuts.insert_after
local copy_node=nuts.copy
local copy_node_list=nuts.copy_list
+local remove_node=nuts.remove
local find_node_tail=nuts.tail
local flush_node_list=nuts.flush_list
local flush_node=nuts.flush_node
local end_of_math=nuts.end_of_math
-local traverse_nodes=nuts.traverse
-local traverse_id=nuts.traverse_id
-local remove_node=nuts.remove
+local set_components=nuts.set_components
+local take_components=nuts.take_components
+local count_components=nuts.count_components
+local copy_no_components=nuts.copy_no_components
+local copy_only_glyphs=nuts.copy_only_glyphs
+local setmetatable=setmetatable
local setmetatableindex=table.setmetatableindex
-local zwnj=0x200C
-local zwj=0x200D
-local wildcard="*"
-local default="dflt"
+local nextnode=nuts.traversers.node
local nodecodes=nodes.nodecodes
local glyphcodes=nodes.glyphcodes
local disccodes=nodes.disccodes
@@ -18444,21 +25655,20 @@ local dir_code=nodecodes.dir
local localpar_code=nodecodes.localpar
local discretionary_code=disccodes.discretionary
local ligature_code=glyphcodes.ligature
-local privateattribute=attributes.private
-local a_state=privateattribute('state')
+local a_state=attributes.private('state')
+local a_noligature=attributes.private("noligature")
local injections=nodes.injections
local setmark=injections.setmark
local setcursive=injections.setcursive
local setkern=injections.setkern
-local setpair=injections.setpair
+local setmove=injections.setmove
+local setposition=injections.setposition
local resetinjection=injections.reset
local copyinjection=injections.copy
local setligaindex=injections.setligaindex
local getligaindex=injections.getligaindex
-local cursonce=true
-local fonthashes=fonts.hashes
-local fontdata=fonthashes.identifiers
-local fontfeatures=fonthashes.features
+local fontdata=fonts.hashes.identifiers
+local fontfeatures=fonts.hashes.features
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local onetimemessage=fonts.loggers.onetimemessage or function() end
@@ -18468,98 +25678,91 @@ local tfmdata=false
local characters=false
local descriptions=false
local marks=false
+local classes=false
local currentfont=false
local factor=0
local threshold=0
local checkmarks=false
+local discs=false
+local spaces=false
local sweepnode=nil
-local sweepprev=nil
-local sweepnext=nil
-local sweephead={}
-local notmatchpre={}
-local notmatchpost={}
-local notmatchreplace={}
+local sweephead={}
+local notmatchpre={}
+local notmatchpost={}
+local notmatchreplace={}
local handlers={}
local isspace=injections.isspace
local getthreshold=injections.getthreshold
-local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
-local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
-local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
-local function checkdisccontent(d)
- local pre,post,replace=getdisc(d)
- if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end
- if post then for n in traverse_id(glue_code,post) do print("pos",nodes.idstostring(post)) break end end
- if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
-end
+local checkstep=(tracers and tracers.steppers.check) or function() end
+local registerstep=(tracers and tracers.steppers.register) or function() end
+local registermessage=(tracers and tracers.steppers.message) or function() end
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_direct(...)
end
local function logwarning(...)
report_direct(...)
end
-local f_unicode=formatters["%U"]
-local f_uniname=formatters["%U (%s)"]
-local f_unilist=formatters["% t (% t)"]
-local function gref(n)
- if type(n)=="number" then
- local description=descriptions[n]
- local name=description and description.name
- if name then
- return f_uniname(n,name)
- else
- return f_unicode(n)
- end
- elseif n then
- local num,nam={},{}
- for i=1,#n do
- local ni=n[i]
- if tonumber(ni) then
- local di=descriptions[ni]
- num[i]=f_unicode(ni)
- nam[i]=di and di.name or "-"
+local gref do
+ local f_unicode=formatters["U+%X"]
+ local f_uniname=formatters["U+%X (%s)"]
+ local f_unilist=formatters["% t"]
+ gref=function(n)
+ if type(n)=="number" then
+ local description=descriptions[n]
+ local name=description and description.name
+ if name then
+ return f_uniname(n,name)
+ else
+ return f_unicode(n)
+ end
+ elseif n then
+ local t={}
+ for i=1,#n do
+ local ni=n[i]
+ if tonumber(ni) then
+ local di=descriptions[ni]
+ local nn=di and di.name
+ if nn then
+ t[#t+1]=f_uniname(ni,nn)
+ else
+ t[#t+1]=f_unicode(ni)
+ end
+ end
end
+ return f_unilist(t)
+ else
+ return "<error in node mode tracing>"
end
- return f_unilist(num,nam)
- else
- return "<error in node mode tracing>"
end
end
local function cref(dataset,sequence,index)
if not dataset then
return "no valid dataset"
- elseif index then
- return formatters["feature %a, type %a, chain lookup %a, index %a"](dataset[4],sequence.type,sequence.name,index)
+ end
+ local merged=sequence.merged and "merged " or ""
+ if index then
+ return formatters["feature %a, type %a, %schain lookup %a, index %a"](
+ dataset[4],sequence.type,merged,sequence.name,index)
else
- return formatters["feature %a, type %a, chain lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %schain lookup %a"](
+ dataset[4],sequence.type,merged,sequence.name)
end
end
local function pref(dataset,sequence)
- return formatters["feature %a, type %a, lookup %a"](dataset[4],sequence.type,sequence.name)
+ return formatters["feature %a, type %a, %slookup %a"](
+ dataset[4],sequence.type,sequence.merged and "merged " or "",sequence.name)
end
local function mref(rlmode)
- if not rlmode or rlmode==0 then
- return "---"
- elseif rlmode==-1 or rlmode=="+TRT" then
- return "r2l"
- else
+ if not rlmode or rlmode>=0 then
return "l2r"
- end
-end
-local function copy_glyph(g)
- local components=getfield(g,"components")
- if components then
- setfield(g,"components")
- local n=copy_node(g)
- copyinjection(n,g)
- setfield(g,"components",components)
- return n
else
- local n=copy_node(g)
- copyinjection(n,g)
- return n
+ return "r2l"
end
end
local function flattendisk(head,disc)
@@ -18583,7 +25786,6 @@ local function flattendisk(head,disc)
elseif next then
return next,next
else
- return
end
else
if replace then
@@ -18605,15 +25807,34 @@ local function appenddisc(disc,list)
if post then
setlink(posttail,posthead)
else
- post=phead
+ post=posthead
end
if replace then
setlink(replacetail,replacehead)
else
- replace=rhead
+ replace=replacehead
end
setdisc(disc,pre,post,replace)
end
+local take_components=getcomponents
+local set_components=setcomponents
+local function count_components(start,marks)
+ if getid(start)~=glyph_code then
+ return 0
+ elseif getsubtype(start)==ligature_code then
+ local i=0
+ local components=getcomponents(start)
+ while components do
+ i=i+count_components(components,marks)
+ components=getnext(components)
+ end
+ return i
+ elseif not marks[getchar(start)] then
+ return 1
+ else
+ return 0
+ end
+end
local function markstoligature(head,start,stop,char)
if start==stop and getchar(start)==char then
return head,start
@@ -18622,38 +25843,19 @@ local function markstoligature(head,start,stop,char)
local next=getnext(stop)
setprev(start)
setnext(stop)
- local base=copy_glyph(start)
+ local base=copy_no_components(start,copyinjection)
if head==start then
head=base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",start)
- setlink(prev,base)
- setlink(base,next)
+ set_components(base,start)
+ setlink(prev,base,next)
return head,base
end
end
-local function getcomponentindex(start)
- if getid(start)~=glyph_code then
- return 0
- elseif getsubtype(start)==ligature_code then
- local i=0
- local components=getfield(start,"components")
- while components do
- i=i+getcomponentindex(components)
- components=getnext(components)
- end
- return i
- elseif not marks[getchar(start)] then
- return 1
- else
- return 0
- end
-end
-local a_noligature=attributes.private("noligature")
-local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound)
+local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks)
if getattr(start,a_noligature)==1 then
return head,start
end
@@ -18662,31 +25864,22 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setchar(start,char)
return head,start
end
- local components=getfield(start,"components")
- if components then
- end
local prev=getprev(start)
local next=getnext(stop)
local comp=start
setprev(start)
setnext(stop)
- local base=copy_glyph(start)
+ local base=copy_no_components(start,copyinjection)
if start==head then
head=base
end
resetinjection(base)
setchar(base,char)
setsubtype(base,ligature_code)
- setfield(base,"components",comp)
- if prev then
- setnext(prev,base)
- end
- if next then
- setprev(next,base)
- end
- setboth(base,prev,next)
+ set_components(base,comp)
+ setlink(prev,base,next)
if not discfound then
- local deletemarks=markflag~="mark"
+ local deletemarks=not skiphash or hasmarks
local components=start
local baseindex=0
local componentindex=0
@@ -18696,14 +25889,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local char=getchar(start)
if not marks[char] then
baseindex=baseindex+componentindex
- componentindex=getcomponentindex(start)
- elseif not deletemarks then
+ componentindex=count_components(start,marks)
+ elseif not deletemarks then
setligaindex(start,baseindex+getligaindex(start,componentindex))
if trace_marks then
logwarning("%s: keep mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start))
end
local n=copy_node(start)
- copyinjection(n,start)
+ copyinjection(n,start)
head,current=insert_node_after(head,current,n)
elseif trace_marks then
logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char))
@@ -18731,27 +25924,14 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local discprev,discnext=getboth(discfound)
if discprev and discnext then
local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true)
- if not replace then
+ if not replace then
local prev=getprev(base)
- local current=comp
- local previous=nil
- local copied=nil
- while current do
- if getid(current)==glyph_code then
- local n=copy_node(current)
- if copied then
- setlink(previous,n)
- else
- copied=n
- end
- previous=n
- end
- current=getnext(current)
- end
- setprev(discnext)
- setnext(discprev)
+ local comp=take_components(base)
+ local copied=copy_only_glyphs(comp)
if pre then
setlink(discprev,pre)
+ else
+ setnext(discprev)
end
pre=comp
if post then
@@ -18759,19 +25939,24 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setprev(post)
else
post=discnext
+ setprev(discnext)
end
- setlink(prev,discfound)
- setlink(discfound,next)
+ setlink(prev,discfound,next)
setboth(base)
- setfield(base,"components",copied)
- setdisc(discfound,pre,post,base)
- base=prev
+ set_components(base,copied)
+ replace=base
+ if forcediscretionaries then
+ setdisc(discfound,pre,post,replace,discretionary_code)
+ else
+ setdisc(discfound,pre,post,replace)
+ end
+ base=prev
end
end
end
return head,base
end
-local function multiple_glyphs(head,start,multiple,ignoremarks,what)
+local function multiple_glyphs(head,start,multiple,skiphash,what,stop)
local nofmultiples=#multiple
if nofmultiples>0 then
resetinjection(start)
@@ -18807,7 +25992,9 @@ local function multiple_glyphs(head,start,multiple,ignoremarks,what)
end
local function get_alternative_glyph(start,alternatives,value)
local n=#alternatives
- if value=="random" then
+ if n==1 then
+ return alternatives[1],trace_alternatives and "1 (only one present)"
+ elseif value=="random" then
local r=getrandom and getrandom("glyph",1,n) or random(1,n)
return alternatives[r],trace_alternatives and formatters["value %a, taking %a"](value,r)
elseif value=="first" then
@@ -18862,20 +26049,20 @@ function handlers.gsub_alternate(head,start,dataset,sequence,alternative)
end
return head,start,true
end
-function handlers.gsub_multiple(head,start,dataset,sequence,multiple)
+function handlers.gsub_multiple(head,start,dataset,sequence,multiple,rlmode,skiphash)
if trace_multiples then
logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple))
end
- return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1])
+ return multiple_glyphs(head,start,multiple,skiphash,dataset[1])
end
-function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
+function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skiphash)
local current=getnext(start)
if not current then
return head,start,false,nil
end
local stop=nil
local startchar=getchar(start)
- if marks[startchar] then
+ if skiphash and skiphash[startchar] then
while current do
local char=ischar(current,currentfont)
if char then
@@ -18905,14 +26092,14 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
else
end
end
- else
- local skipmark=sequence.flags[1]
+ else
local discfound=false
local lastdisc=nil
+ local hasmarks=marks[startchar]
while current do
local char,id=ischar(current,currentfont)
if char then
- if skipmark and marks[char] then
+ if skiphash and skiphash[char] then
current=getnext(current)
else
local lg=ligature[char]
@@ -18921,6 +26108,9 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
discfound=lastdisc
lastdisc=nil
end
+ if marks[char] then
+ hasmarks=true
+ end
stop=current
ligature=lg
current=getnext(current)
@@ -18931,13 +26121,16 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
elseif char==false then
break
elseif id==disc_code then
- local replace=getfield(current,"replace")
+ local replace=getfield(current,"replace")
if replace then
while replace do
local char,id=ischar(replace,currentfont)
if char then
local lg=ligature[char]
if lg then
+ if marks[char] then
+ hasmarks=true
+ end
ligature=lg
replace=getnext(replace)
else
@@ -18960,10 +26153,10 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
if stop then
if trace_ligatures then
local stopchar=getchar(stop)
- head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(lig))
else
- head,start=toligature(head,start,stop,lig,dataset,sequence,skipmark,discfound)
+ head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,discfound,hasmarks)
end
else
resetinjection(start)
@@ -18978,83 +26171,81 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature)
end
return head,start,false,discfound
end
-function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local startchar=getchar(start)
- if step.format=="pair" then
- local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns,injection)
+ local format=step.format
+ if format=="single" or type(kerns)=="table" then
+ local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by %s xy (%p,%p) and wh (%p,%p)",pref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
end
else
- local k=setkern(start,factor,rlmode,kerns,injection)
+ local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: shifting single %s by %s %p",pref(dataset,sequence),gref(startchar),format,k)
end
end
- return head,start,false
+ return head,start,true
end
-function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,injection)
+function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection)
local snext=getnext(start)
if not snext then
return head,start,false
else
local prev=start
- local done=false
while snext do
local nextchar=ischar(snext,currentfont)
if nextchar then
- local krn=kerns[nextchar]
- if not krn and marks[nextchar] then
+ if skiphash and skiphash[nextchar] then
prev=snext
snext=getnext(snext)
- elseif not krn then
- break
- elseif step.format=="pair" then
- local a,b=krn[1],krn[2]
- if optimizekerns then
- if not b and a[1]==0 and a[2]==0 and a[4]==0 then
- local k=setkern(snext,factor,rlmode,a[3],injection)
+ else
+ local krn=kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format=step.format
+ if format=="pair" then
+ local a,b=krn[1],krn[2]
+ if a==true then
+ elseif a then
+ local x,y,w,h=setposition(1,start,factor,rlmode,a,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
+ local startchar=getchar(start)
+ 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")
end
- done=true
- break
end
- end
- if a and #a>0 then
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,injection)
- if trace_kerns then
- local startchar=getchar(start)
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ if b==true then
+ start=snext
+ elseif b then
+ local x,y,w,h=setposition(2,snext,factor,rlmode,b,injection)
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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")
+ end
+ start=snext
+ elseif forcepairadvance then
+ start=snext
end
- end
- if b and #b>0 then
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
+ return head,start,true
+ elseif krn~=0 then
+ local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn,injection)
if trace_kerns then
- local startchar=getchar(snext)
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
+ logprocess("%s: inserting %s %p between %s and %s as %s",pref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar),injection or "injections")
end
+ return head,start,true
+ else
+ break
end
- done=true
- break
- elseif krn~=0 then
- local k=setkern(snext,factor,rlmode,krn,injection)
- if trace_kerns then
- logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections")
- end
- done=true
- break
- else
- break
end
else
break
end
end
- return head,start,done
+ return head,start,false
end
end
-function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -19089,10 +26280,12 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
local ma=markanchors[2]
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head,start,true
+ elseif trace_bugs then
+ logwarning("%s: mark %s is not anchored to %s",pref(dataset,sequence),gref(markchar),gref(basechar))
end
elseif trace_bugs then
logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),1)
@@ -19105,7 +26298,7 @@ function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode)
end
return head,start,false
end
-function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -19144,8 +26337,8 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
if ba then
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- pref(dataset,sequence),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ logprocess("%s, index %s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ pref(dataset,sequence),index,bound,gref(markchar),gref(basechar),index,dx,dy)
end
return head,start,true
else
@@ -19168,7 +26361,7 @@ function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlm
end
return head,start,false
end
-function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
+function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash)
local markchar=getchar(start)
if marks[markchar] then
local base=getprev(start)
@@ -19191,8 +26384,8 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
local ma=markanchors[2]
local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- pref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ pref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
end
return head,start,true
end
@@ -19203,8 +26396,7 @@ function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode)
end
return head,start,false
end
-function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,step,i)
- local done=false
+function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step)
local startchar=getchar(start)
if marks[startchar] then
if trace_cursive then
@@ -19212,11 +26404,11 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
else
local nxt=getnext(start)
- while not done and nxt do
+ while nxt do
local nextchar=ischar(nxt,currentfont)
if not nextchar then
break
- elseif marks[nextchar] then
+ elseif marks[nextchar] then
nxt=getnext(nxt)
else
local exit=exitanchors[3]
@@ -19225,11 +26417,12 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
if entry then
entry=entry[2]
if entry then
- local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ local r2lflag=sequence.flags[4]
+ local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ 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))
end
- done=true
+ return head,start,true
end
end
end
@@ -19237,12 +26430,15 @@ function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,st
end
end
end
- return head,start,done
+ return head,start,false
end
local chainprocs={}
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_subchain(...)
end
@@ -19250,11 +26446,14 @@ local logwarning=report_subchain
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_chain(...)
end
local logwarning=report_chain
-local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
+local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode,skiphash)
local char=getchar(start)
local replacement=replacements[char]
if replacement then
@@ -19269,509 +26468,551 @@ local function reversesub(head,start,stop,dataset,sequence,replacements,rlmode)
end
end
chainprocs.reversesub=reversesub
+local function reportzerosteps(dataset,sequence)
+ logwarning("%s: no steps",cref(dataset,sequence))
+end
local function reportmoresteps(dataset,sequence)
logwarning("%s: more than 1 step",cref(dataset,sequence))
end
-function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,chainindex)
+local function getmapping(dataset,sequence,currentlookup)
local steps=currentlookup.steps
local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+ if nofsteps==0 then
+ reportzerosteps(dataset,sequence)
+ currentlookup.mapping=false
+ return false
+ else
+ if nofsteps>1 then
+ reportmoresteps(dataset,sequence)
+ end
+ local mapping=steps[1].coverage
+ currentlookup.mapping=mapping
+ currentlookup.format=steps[1].format
+ return mapping
end
- local current=start
- while current do
- local currentchar=ischar(current)
- if currentchar then
- local replacement=steps[1].coverage[currentchar]
- if not replacement or replacement=="" then
- if trace_bugs then
- logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
+end
+function chainprocs.gsub_remove(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ if trace_chains then
+ logprocess("%s: removing character %s",cref(dataset,sequence,chainindex),gref(getchar(start)))
+ end
+ head,start=remove_node(head,start,true)
+ return head,getprev(start),true
+end
+function chainprocs.gsub_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local current=start
+ while current do
+ local currentchar=ischar(current)
+ if currentchar then
+ local replacement=mapping[currentchar]
+ if not replacement or replacement=="" then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(dataset,sequence,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
+ end
+ resetinjection(current)
+ setchar(current,replacement)
end
+ return head,start,true
+ elseif currentchar==false then
+ break
+ elseif current==stop then
+ break
else
- if trace_singles then
- logprocess("%s: replacing single %s by %s",cref(dataset,sequence,chainindex),gref(currentchar),gref(replacement))
- end
- resetinjection(current)
- setchar(current,replacement)
+ current=getnext(current)
end
- return head,start,true
- elseif currentchar==false then
- break
- elseif current==stop then
- break
- else
- current=getnext(current)
end
end
return head,start,false
end
-function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local replacement=steps[1].coverage[startchar]
- if not replacement or replacement=="" then
- if trace_bugs then
- logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
- end
- else
- if trace_multiples then
- logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ if mapping then
+ local kind=dataset[4]
+ local what=dataset[1]
+ local value=what==true and tfmdata.shared.features[kind] or what
+ local current=start
+ while current do
+ local currentchar=ischar(current)
+ if currentchar then
+ local alternatives=mapping[currentchar]
+ if alternatives then
+ local choice,comment=get_alternative_glyph(current,alternatives,value)
+ if choice then
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(currentchar),choice,gref(choice),comment)
+ end
+ resetinjection(start)
+ setchar(start,choice)
+ else
+ if trace_alternatives then
+ logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(currentchar),comment)
+ end
+ end
+ end
+ return head,start,true
+ elseif currentchar==false then
+ break
+ elseif current==stop then
+ break
+ else
+ current=getnext(current)
+ end
end
- return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1])
end
return head,start,false
end
-function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlookup)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local kind=dataset[4]
- local what=dataset[1]
- local value=what==true and tfmdata.shared.features[kind] or what
- local current=start
- while current do
- local currentchar=ischar(current)
- if currentchar then
- local alternatives=steps[1].coverage[currentchar]
- if alternatives then
- local choice,comment=get_alternative_glyph(current,alternatives,value)
- if choice then
- if trace_alternatives then
- logprocess("%s: replacing %s by alternative %a to %s, %s",cref(dataset,sequence),gref(char),choice,gref(choice),comment)
- end
- resetinjection(start)
- setchar(start,choice)
- else
- if trace_alternatives then
- logwarning("%s: no variant %a for %s, %s",cref(dataset,sequence),value,gref(char),comment)
- end
- end
+ if mapping then
+ local startchar=getchar(start)
+ local replacement=mapping[startchar]
+ if not replacement or replacement=="" then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(dataset,sequence),gref(startchar))
end
- return head,start,true
- elseif currentchar==false then
- break
- elseif current==stop then
- break
else
- current=getnext(current)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement))
+ end
+ return multiple_glyphs(head,start,replacement,skiphash,dataset[1],stop)
end
end
return head,start,false
end
-function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gsub_ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local ligatures=steps[1].coverage[startchar]
- if not ligatures then
- if trace_bugs then
- logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
- end
- else
- local current=getnext(start)
- local discfound=false
- local last=stop
- local nofreplacements=1
- local skipmark=currentlookup.flags[1]
- while current do
- local id=getid(current)
- if id==disc_code then
- if not discfound then
- discfound=current
- end
- if current==stop then
- break
- else
- current=getnext(current)
- end
- else
- local schar=getchar(current)
- if skipmark and marks[schar] then
+ if mapping then
+ local startchar=getchar(start)
+ local ligatures=mapping[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(dataset,sequence,chainindex),gref(startchar))
+ end
+ else
+ local hasmarks=marks[startchar]
+ local current=getnext(start)
+ local discfound=false
+ local last=stop
+ local nofreplacements=1
+ while current do
+ local id=getid(current)
+ if id==disc_code then
+ if not discfound then
+ discfound=current
+ end
+ if current==stop then
+ break
+ else
current=getnext(current)
+ end
else
- local lg=ligatures[schar]
- if lg then
- ligatures=lg
- last=current
- nofreplacements=nofreplacements+1
- if current==stop then
- break
- else
+ local schar=getchar(current)
+ if skiphash and skiphash[schar] then
current=getnext(current)
- end
else
- break
+ local lg=ligatures[schar]
+ if lg then
+ ligatures=lg
+ last=current
+ nofreplacements=nofreplacements+1
+ if marks[char] then
+ hasmarks=true
+ end
+ if current==stop then
+ break
+ else
+ current=getnext(current)
+ end
+ else
+ break
+ end
end
end
end
- end
- local ligature=ligatures.ligature
- if ligature then
- if chainindex then
- stop=last
- end
- if trace_ligatures then
+ local ligature=ligatures.ligature
+ if ligature then
+ if chainindex then
+ stop=last
+ end
+ if trace_ligatures then
+ if start==stop then
+ logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ end
+ end
+ head,start=toligature(head,start,stop,ligature,dataset,sequence,skiphash,discfound,hasmarks)
+ return head,start,true,nofreplacements,discfound
+ elseif trace_bugs then
if start==stop then
- logprocess("%s: replacing character %s by ligature %s case 3",cref(dataset,sequence,chainindex),gref(startchar),gref(ligature))
+ logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
else
- logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)),gref(ligature))
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
end
end
- head,start=toligature(head,start,stop,ligature,dataset,sequence,skipmark,discfound)
- return head,start,true,nofreplacements,discfound
- elseif trace_bugs then
- if start==stop then
- logwarning("%s: replacing character %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar))
- else
- logwarning("%s: replacing character %s upto %s by ligature fails",cref(dataset,sequence,chainindex),gref(startchar),gref(getchar(stop)))
- end
end
end
return head,start,false,0,false
end
-function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_single(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local step=steps[1]
- local kerns=step.coverage[startchar]
- if not kerns then
- elseif step.format=="pair" then
- local dx,dy,w,h=setpair(start,factor,rlmode,sequence.flags[4],kerns)
- if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),dx,dy,w,h)
- end
- else
- local k=setkern(start,factor,rlmode,kerns,injection)
- if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ if mapping then
+ local startchar=getchar(start)
+ local kerns=mapping[startchar]
+ if kerns then
+ local format=currentlookup.format
+ if format=="single" then
+ local dx,dy,w,h=setposition(0,start,factor,rlmode,kerns)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),format,dx,dy,w,h)
+ end
+ else
+ local k=(format=="move" and setmove or setkern)(start,factor,rlmode,kerns,injection)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %s %p",cref(dataset,sequence),gref(startchar),format,k)
+ end
+ end
+ return head,start,true
end
end
return head,start,false
end
-function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,chainindex)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local snext=getnext(start)
- if snext then
- local startchar=getchar(start)
- local step=steps[1]
- local kerns=step.coverage[startchar]
- if kerns then
- local prev=start
- local done=false
- while snext do
- local nextchar=ischar(snext,currentfont)
- if not nextchar then
- break
- end
- local krn=kerns[nextchar]
- if not krn and marks[nextchar] then
- prev=snext
- snext=getnext(snext)
- elseif not krn then
- break
- elseif step.format=="pair" then
- local a,b=krn[1],krn[2]
- if optimizekerns then
- if not b and a[1]==0 and a[2]==0 and a[4]==0 then
- local k=setkern(snext,factor,rlmode,a[3],"injections")
+ if mapping then
+ local snext=getnext(start)
+ if snext then
+ local startchar=getchar(start)
+ local kerns=mapping[startchar]
+ if kerns then
+ local prev=start
+ while snext do
+ local nextchar=ischar(snext,currentfont)
+ if not nextchar then
+ break
+ end
+ if skiphash and skiphash[nextchar] then
+ prev=snext
+ snext=getnext(snext)
+ else
+ local krn=kerns[nextchar]
+ if not krn then
+ break
+ end
+ local format=currentlookup.format
+ if format=="pair" then
+ local a,b=krn[1],krn[2]
+ if a==true then
+ elseif a then
+ local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections")
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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)
+ end
+ end
+ if b==true then
+ start=snext
+ elseif b then
+ local x,y,w,h=setposition(2,snext,factor,rlmode,b,"injections")
+ if trace_kerns then
+ local startchar=getchar(start)
+ 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)
+ end
+ start=snext
+ elseif forcepairadvance then
+ start=snext
+ end
+ return head,start,true
+ elseif krn~=0 then
+ local k=(format=="move" and setmove or setkern)(snext,factor,rlmode,krn)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar))
end
- done=true
+ return head,start,true
+ else
break
end
end
- if a and #a>0 then
- local startchar=getchar(start)
- local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,"injections")
- if trace_kerns then
- 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)
- end
- end
- if b and #b>0 then
- local startchar=getchar(start)
- local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
- if trace_kerns then
- 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)
- end
- end
- done=true
- break
- elseif krn~=0 then
- local k=setkern(snext,factor,rlmode,krn)
- if trace_kerns then
- logprocess("%s: inserting kern %s between %s and %s",cref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar))
- end
- done=true
- break
- else
- break
end
end
- return head,start,done
end
end
return head,start,false
end
-function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base=getprev(base)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+function chainprocs.gpos_mark2base(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base=getprev(base)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ end
+ return head,start,false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),1)
+ logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
end
return head,start,false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",pref(dataset,sequence),gref(markchar),2)
- end
- return head,start,false
end
end
- end
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basechar %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if marks[basechar] then
- while base do
- base=getprev(base)
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- if not marks[basechar] then
- break
+function chainprocs.gpos_mark2ligature(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if marks[basechar] then
+ while base do
+ base=getprev(base)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ end
+ return head,start,false
end
else
if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,1)
+ logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
end
return head,start,false
end
- else
- if trace_bugs then
- logwarning("%s: no base for mark %s, case %i",cref(dataset,sequence),markchar,2)
- end
- return head,start,false
end
end
- end
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local index=getligaindex(start)
- ba=ba[index]
- if ba then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)",
- cref(dataset,sequence),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local index=getligaindex(start)
+ ba=ba[index]
+ if ba then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],false,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to baselig %s at index %s => (%p,%p)",
+ cref(dataset,sequence),a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
end
+ elseif trace_bugs then
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),1)
+ logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s, prev node is no char, case %i",cref(dataset,sequence),2)
+ logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
- end
- local markchar=getchar(start)
- if marks[markchar] then
- local markanchors=steps[1].coverage[markchar]
- if markanchors then
- local base=getprev(start)
- local slc=getligaindex(start)
- if slc then
- while base do
- local blc=getligaindex(base)
- if blc and blc~=slc then
- base=getprev(base)
- else
- break
+function chainprocs.gpos_mark2mark(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
+ end
+ if mapping then
+ local markchar=getchar(start)
+ if marks[markchar] then
+ local markanchors=mapping[markchar]
+ if markanchors then
+ local base=getprev(start)
+ local slc=getligaindex(start)
+ if slc then
+ while base do
+ local blc=getligaindex(base)
+ if blc and blc~=slc then
+ base=getprev(base)
+ else
+ break
+ end
end
end
- end
- if base then
- local basechar=ischar(base,currentfont)
- if basechar then
- local ba=markanchors[1][basechar]
- if ba then
- local ma=markanchors[2]
- if ma then
- local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
- if trace_marks then
- logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
- cref(dataset,sequence),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ if base then
+ local basechar=ischar(base,currentfont)
+ if basechar then
+ local ba=markanchors[1][basechar]
+ if ba then
+ local ma=markanchors[2]
+ if ma then
+ local dx,dy,bound=setmark(start,base,factor,rlmode,ba,ma,characters[basechar],true,checkmarks)
+ if trace_marks then
+ logprocess("%s, bound %s, anchoring mark %s to basemark %s => (%p,%p)",
+ cref(dataset,sequence),bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return head,start,true
end
- return head,start,true
end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),1)
+ logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
end
elseif trace_bugs then
- logwarning("%s: prev node is no mark, case %i",cref(dataset,sequence),2)
+ logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
end
elseif trace_bugs then
- logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar))
+ logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
- elseif trace_bugs then
- logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar))
end
return head,start,false
end
-function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode)
- local steps=currentlookup.steps
- local nofsteps=currentlookup.nofsteps
- if nofsteps>1 then
- reportmoresteps(dataset,sequence)
+function chainprocs.gpos_cursive(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash,chainindex)
+ local mapping=currentlookup.mapping
+ if mapping==nil then
+ mapping=getmapping(dataset,sequence,currentlookup)
end
- local startchar=getchar(start)
- local exitanchors=steps[1].coverage[startchar]
- if exitanchors then
- local done=false
- if marks[startchar] then
- if trace_cursive then
- logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
- end
- else
- local nxt=getnext(start)
- while not done and nxt do
- local nextchar=ischar(nxt,currentfont)
- if not nextchar then
- break
- elseif marks[nextchar] then
- nxt=getnext(nxt)
- else
- local exit=exitanchors[3]
- if exit then
- local entry=exitanchors[1][nextchar]
- if entry then
- entry=entry[2]
+ if mapping then
+ local startchar=getchar(start)
+ local exitanchors=mapping[startchar]
+ if exitanchors then
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(dataset,sequence),gref(startchar))
+ end
+ else
+ local nxt=getnext(start)
+ while nxt do
+ local nextchar=ischar(nxt,currentfont)
+ if not nextchar then
+ break
+ elseif marks[nextchar] then
+ nxt=getnext(nxt)
+ else
+ local exit=exitanchors[3]
+ if exit then
+ local entry=exitanchors[1][nextchar]
if entry then
- local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
- if trace_cursive then
- logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in %s mode",pref(dataset,sequence),gref(startchar),gref(nextchar),dx,dy,anchor,bound,mref(rlmode))
+ entry=entry[2]
+ if entry then
+ local r2lflag=sequence.flags[4]
+ local dx,dy,bound=setcursive(start,nxt,factor,rlmode,exit,entry,characters[startchar],characters[nextchar],r2lflag)
+ if trace_cursive then
+ 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))
+ end
+ return head,start,true
end
- done=true
- break
end
+ elseif trace_bugs then
+ onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
end
- elseif trace_bugs then
- onetimemessage(currentfont,startchar,"no entry anchors",report_fonts)
+ break
end
- break
end
end
- end
- return head,start,done
- else
- if trace_cursive and trace_details then
+ elseif trace_cursive and trace_details then
logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone)
end
- return head,start,false
end
+ return head,start,false
end
local function show_skip(dataset,sequence,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2])
end
-local new_kern=nuts.pool.kern
+local userkern=nuts.pool and nuts.pool.newkern
+do if not userkern then
+ local thekern=nuts.new("kern",1)
+ local setkern=nuts.setkern
+ userkern=function(k)
+ local n=copy_node(thekern)
+ setkern(n,k)
+ return n
+ end
+end end
local function checked(head)
local current=head
while current do
if getid(current)==glue_code then
- local kern=new_kern(getfield(current,"width"))
+ local kern=userkern(getwidth(current))
if head==current then
local next=getnext(current)
if next then
@@ -19782,8 +27023,7 @@ local function checked(head)
current=next
else
local prev,next=getboth(current)
- setlink(prev,kern)
- setlink(kern,next)
+ setlink(prev,kern,next)
flush_node(current)
current=next
end
@@ -19799,7 +27039,95 @@ local function setdiscchecked(d,pre,post,replace)
if replace then replace=checked(replace) end
setdisc(d,pre,post,replace)
end
-local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
+local noflags={ false,false,false,false }
+local function chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+ local size=ck[5]-ck[4]+1
+ local chainlookups=ck[6]
+ local done=false
+ if chainlookups then
+ if size==1 then
+ local chainlookup=chainlookups[1]
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local chainkind=chainstep.type
+ local chainproc=chainprocs[chainkind]
+ if chainproc then
+ local ok
+ head,start,ok=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash)
+ if ok then
+ done=true
+ end
+ else
+ logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
+ end
+ end
+ else
+ local i=1
+ local laststart=start
+ local nofchainlookups=#chainlookups
+ while start do
+ if skiphash then
+ while start do
+ local char=ischar(start,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ start=getnext(start)
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ end
+ local chainlookup=chainlookups[i]
+ if chainlookup then
+ for j=1,#chainlookup do
+ local chainstep=chainlookup[j]
+ local chainkind=chainstep.type
+ local chainproc=chainprocs[chainkind]
+ if chainproc then
+ local ok,n
+ head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainstep,rlmode,skiphash,i)
+ if ok then
+ done=true
+ if n and n>1 and i+n>nofchainlookups then
+ i=size
+ break
+ end
+ end
+ else
+ logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
+ end
+ end
+ else
+ end
+ i=i+1
+ if i>size or not start then
+ break
+ elseif start then
+ laststart=start
+ start=getnext(start)
+ end
+ end
+ if not start then
+ start=laststart
+ end
+ end
+ else
+ local replacements=ck[7]
+ if replacements then
+ head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode,skiphash)
+ else
+ done=true
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(dataset,sequence))
+ end
+ end
+ end
+ return head,start,done
+end
+local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck)
if not start then
return head,start,false
end
@@ -19812,7 +27140,6 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local sweepnode=sweepnode
local sweeptype=sweeptype
local sweepoverflow=false
- local checkdisc=getprev(head)
local keepdisc=not sweepnode
local lookaheaddisc=nil
local backtrackdisc=nil
@@ -19835,18 +27162,22 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
elseif id==disc_code then
if keepdisc then
keepdisc=false
- if notmatchpre[current]~=notmatchreplace[current] then
- lookaheaddisc=current
- end
+ lookaheaddisc=current
local replace=getfield(current,"replace")
- while replace and i<=l do
- if getid(replace)==glyph_code then
- i=i+1
+ if not replace then
+ sweepoverflow=true
+ sweepnode=current
+ current=getnext(current)
+ else
+ while replace and i<=l do
+ if getid(replace)==glyph_code then
+ i=i+1
+ end
+ replace=getnext(replace)
end
- replace=getnext(replace)
+ current=getnext(replace)
end
last=current
- current=getnext(c)
else
head,current=flattendisk(head,current)
end
@@ -19904,7 +27235,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if notmatchpre[current]~=notmatchreplace[current] then
lookaheaddisc=current
end
- local replace=getfield(c,"replace")
+ local replace=getfield(current,"replace")
while replace and i<s do
if getid(replace)==glyph_code then
i=i+1
@@ -19965,7 +27296,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
end
end
end
- local ok=false
+ local done=false
if lookaheaddisc then
local cf=start
local cl=getprev(lookaheaddisc)
@@ -19982,37 +27313,44 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
- setprev(lookaheaddisc,cprev)
- if cprev then
- setnext(cprev,lookaheaddisc)
- end
+ setlink(cprev,lookaheaddisc)
setprev(cf)
setnext(cl)
if startishead then
head=lookaheaddisc
end
local pre,post,replace=getdisc(lookaheaddisc)
- local new=copy_node_list(cf)
+ local new=copy_node_list(cf)
local cnew=new
+ if pre then
+ setlink(find_node_tail(cf),pre)
+ end
+ if replace then
+ local tail=find_node_tail(new)
+ setlink(tail,replace)
+ end
for i=1,insertedmarks do
cnew=getnext(cnew)
end
+ cl=start
local clast=cnew
for i=f,l do
+ cl=getnext(cl)
clast=getnext(clast)
end
if not notmatchpre[lookaheaddisc] then
- cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ cf,start,ok=chainrun(cf,start,cl,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if not notmatchreplace[lookaheaddisc] then
- new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
- end
- if pre then
- setlink(cl,pre)
- end
- if replace then
- local tail=find_node_tail(new)
- setlink(tail,replace)
+ local ok=false
+ new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if hasglue then
setdiscchecked(lookaheaddisc,cf,post,new)
@@ -20020,8 +27358,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(lookaheaddisc,cf,post,new)
end
start=getprev(lookaheaddisc)
- sweephead[cf]=getnext(clast)
- sweephead[new]=getnext(last)
+ sweephead[cf]=getnext(clast) or false
+ sweephead[new]=getnext(cl) or false
elseif backtrackdisc then
local cf=getnext(backtrackdisc)
local cl=start
@@ -20037,10 +27375,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
break
end
end
- if cnext then
- setprev(cnext,backtrackdisc)
- end
- setnext(backtrackdisc,cnext)
+ setlink(backtrackdisc,cnext)
setprev(cf)
setnext(cl)
local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true)
@@ -20054,10 +27389,18 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
clast=getnext(clast)
end
if not notmatchpost[backtrackdisc] then
- cf,start,ok=chainproc(cf,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ cf,start,ok=chainrun(cf,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if not notmatchreplace[backtrackdisc] then
- new,cnew,ok=chainproc(new,cnew,clast,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ new,cnew,ok=chainrun(new,cnew,clast,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
if post then
setlink(posttail,cf)
@@ -20075,492 +27418,413 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setdisc(backtrackdisc,pre,post,replace)
end
start=getprev(backtrackdisc)
- sweephead[post]=getnext(clast)
- sweephead[replace]=getnext(last)
+ sweephead[post]=getnext(clast) or false
+ sweephead[replace]=getnext(last) or false
else
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,k)
+ local ok=false
+ head,start,ok=chainrun(head,start,last,dataset,sequence,rlmode,skiphash,ck)
+ if ok then
+ done=true
+ end
end
- return head,start,ok
+ return head,start,done
end
-local noflags={ false,false,false,false }
-local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
+local function chaintrac(head,start,dataset,sequence,rlmode,skiphash,ck,match,discseen,sweepnode)
+ local rule=ck[1]
+ local lookuptype=ck[8] or ck[2]
+ local nofseq=#ck[3]
+ local first=ck[4]
+ local last=ck[5]
+ local char=getchar(start)
+ logwarning("%s: rule %s %s at char %s for (%s,%s,%s) chars, lookuptype %a, %sdisc seen, %ssweeping",
+ cref(dataset,sequence),rule,match and "matches" or "nomatch",
+ gref(char),first-1,last-first+1,nofseq-last,lookuptype,
+ discseen and "" or "no ",sweepnode and "" or "not ")
+end
+local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode,skiphash)
local sweepnode=sweepnode
local sweeptype=sweeptype
+ local postreplace
+ local prereplace
+ local checkdisc
+ local discseen
+ if sweeptype then
+ if sweeptype=="replace" then
+ postreplace=true
+ prereplace=true
+ else
+ postreplace=sweeptype=="post"
+ prereplace=sweeptype=="pre"
+ end
+ checkdisc=getprev(head)
+ end
local currentfont=currentfont
- local diskseen=false
- local checkdisc=getprev(head)
- local flags=sequence.flags or noflags
- local done=false
- local skipmark=flags[1]
- local skipligature=flags[2]
- local skipbase=flags[3]
- local markclass=sequence.markclass
- local skipped=false
- for k=1,#contexts do
- local match=true
- local current=start
- local last=start
+ local skipped
+ local startprev,
+ startnext=getboth(start)
+ local done
+ local nofcontexts=contexts.n
+ local startchar=nofcontext==1 or ischar(start,currentfont)
+ for k=1,nofcontexts do
local ck=contexts[k]
local seq=ck[3]
- local s=#seq
- local size=1
- if s==1 then
- local char=ischar(current,currentfont)
- if char then
- match=seq[1][char]
- end
- else
- local f=ck[4]
- local l=ck[5]
- size=l-f+1
- if size>1 then
- local discfound=nil
- local n=f+1
- last=getnext(last)
- while n<=l do
- if not last and (sweeptype=="post" or sweeptype=="replace") then
- last=getnext(sweepnode)
- sweeptype=nil
- end
- if last then
- local char,id=ischar(last,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class or "base"
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- last=getnext(last)
- elseif seq[n][char] then
- if n<l then
- last=getnext(last)
- end
- n=n+1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
- break
- end
+ local f=ck[4]
+ if not startchar or not seq[f][startchar] then
+ goto next
+ end
+ local s=seq.n
+ local l=ck[5]
+ local current=start
+ local last=start
+ if l>f then
+ local discfound
+ local n=f+1
+ last=startnext
+ while n<=l do
+ if postreplace and not last then
+ last=getnext(sweepnode)
+ sweeptype=nil
+ end
+ if last then
+ local char,id=ischar(last,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ last=getnext(last)
+ elseif seq[n][char] then
+ if n<l then
+ last=getnext(last)
+ end
+ n=n+1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- match=false
+ break
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=last
- notmatchpre[last]=nil
- notmatchpost[last]=true
- notmatchreplace[last]=nil
- local pre,post,replace=getdisc(last)
- if pre then
- local n=n
- while pre do
- if seq[n][getchar(pre)] then
- n=n+1
- pre=getnext(pre)
- if n>l then
- break
- end
- else
- notmatchpre[last]=true
+ else
+ goto next
+ end
+ elseif id==disc_code then
+ discseen=true
+ discfound=last
+ notmatchpre[last]=nil
+ notmatchpost[last]=true
+ notmatchreplace[last]=nil
+ local pre,post,replace=getdisc(last)
+ if pre then
+ local n=n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n=n+1
+ if n>l then
break
end
- end
- if n<=l then
+ pre=getnext(pre)
+ else
notmatchpre[last]=true
+ break
end
- else
- notmatchpre[last]=true
end
- if replace then
- while replace do
- if seq[n][getchar(replace)] then
- n=n+1
- replace=getnext(replace)
- if n>l then
- break
- end
+ else
+ notmatchpre[last]=true
+ end
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ if n>l then
+ break
+ end
+ replace=getnext(replace)
+ else
+ notmatchreplace[last]=true
+ if notmatchpre[last] then
+ goto next
else
- notmatchreplace[last]=true
- match=not notmatchpre[last]
break
end
end
- match=not notmatchpre[last]
end
- last=getnext(last)
- else
- match=false
- break
+ if notmatchpre[last] then
+ goto next
+ end
end
+ last=getnext(last)
else
- match=false
- break
+ goto next
end
+ else
+ goto next
end
end
- if match and f>1 then
- local prev=getprev(start)
+ end
+ if f>1 then
+ if startprev then
+ local prev=startprev
+ if prereplace and prev==checkdisc then
+ prev=getprev(sweepnode)
+ end
if prev then
- if prev==checkdisc and (sweeptype=="pre" or sweeptype=="replace") then
- prev=getprev(sweepnode)
- end
- if prev then
- local discfound=nil
- local n=f-1
- while n>=1 do
- if prev then
- local char,id=ischar(prev,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- prev=getprev(prev)
- elseif seq[n][char] then
- if n>1 then
- prev=getprev(prev)
- end
- n=n-1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
- end
- break
- end
+ local discfound
+ local n=f-1
+ while n>=1 do
+ if prev then
+ local char,id=ischar(prev,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ prev=getprev(prev)
+ elseif seq[n][char] then
+ if n>1 then
+ prev=getprev(prev)
+ end
+ n=n-1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpost[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpost[discfound]
- else
- match=false
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpost[discfound] then
+ goto next
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=prev
- notmatchpre[prev]=true
- notmatchpost[prev]=nil
- notmatchreplace[prev]=nil
- local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
- if pre~=start and post~=start and replace~=start then
- if post then
- local n=n
- while posttail do
- if seq[n][getchar(posttail)] then
- n=n-1
- if posttail==post then
- break
- else
- posttail=getprev(posttail)
- if n<1 then
- break
- end
- end
- else
- notmatchpost[prev]=true
+ else
+ goto next
+ end
+ break
+ elseif id==disc_code then
+ discseen=true
+ discfound=prev
+ notmatchpre[prev]=true
+ notmatchpost[prev]=nil
+ notmatchreplace[prev]=nil
+ local pre,post,replace,pretail,posttail,replacetail=getdisc(prev,true)
+ if pre~=start and post~=start and replace~=start then
+ if post then
+ local n=n
+ while posttail do
+ if seq[n][getchar(posttail)] then
+ n=n-1
+ if posttail==post or n<1 then
break
+ else
+ posttail=getprev(posttail)
end
- end
- if n>=1 then
+ else
notmatchpost[prev]=true
+ break
end
- else
+ end
+ if n>=1 then
notmatchpost[prev]=true
end
- if replace then
- while replacetail do
- if seq[n][getchar(replacetail)] then
- n=n-1
- if replacetail==replace then
- break
- else
- replacetail=getprev(replacetail)
- if n<1 then
- break
- end
- end
+ else
+ notmatchpost[prev]=true
+ end
+ if replace then
+ while replacetail do
+ if seq[n][getchar(replacetail)] then
+ n=n-1
+ if replacetail==replace or n<1 then
+ break
+ else
+ replacetail=getprev(replacetail)
+ end
+ else
+ notmatchreplace[prev]=true
+ if notmatchpost[prev] then
+ goto next
else
- notmatchreplace[prev]=true
- match=not notmatchpost[prev]
break
end
end
- if not match then
- break
- end
end
+ else
+ notmatchreplace[prev]=true
end
- prev=getprev(prev)
- elseif seq[n][32] and isspace(prev,threshold) then
+ end
+ prev=getprev(prev)
+ elseif id==glue_code then
+ local sn=seq[n]
+ if (sn[32] and spaces[prev]) or sn[0xFFFC] then
n=n-1
prev=getprev(prev)
else
- match=false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n=n-1
+ prev=getprev(prev)
else
- match=false
- break
+ goto next
end
+ else
+ goto next
end
- else
- match=false
end
else
- match=false
+ goto next
end
+ else
+ goto next
end
- if match and s>l then
- local current=last and getnext(last)
- if not current then
- if sweeptype=="post" or sweeptype=="replace" then
- current=getnext(sweepnode)
- end
- end
- if current then
- local discfound=nil
- local n=l+1
- while n<=s do
- if current then
- local char,id=ischar(current,currentfont)
- if char then
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- skipped=true
- if trace_skips then
- show_skip(dataset,sequence,char,ck,class)
- end
- current=getnext(current)
- elseif seq[n][char] then
- if n<s then
- current=getnext(current)
- end
- n=n+1
- else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
- break
- end
+ end
+ if s>l then
+ local current=last and getnext(last)
+ if not current and postreplace then
+ current=getnext(sweepnode)
+ end
+ if current then
+ local discfound
+ local n=l+1
+ while n<=s do
+ if current then
+ local char,id=ischar(current,currentfont)
+ if char then
+ if skiphash and skiphash[char] then
+ skipped=true
+ if trace_skips then
+ show_skip(dataset,sequence,char,ck,classes[char])
+ end
+ current=getnext(current)
+ elseif seq[n][char] then
+ if n<s then
+ current=getnext(current)
+ end
+ n=n+1
+ elseif discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
- else
- match=false
- end
break
end
- elseif char==false then
- if discfound then
- notmatchreplace[discfound]=true
- match=not notmatchpre[discfound]
+ else
+ goto next
+ end
+ elseif char==false then
+ if discfound then
+ notmatchreplace[discfound]=true
+ if notmatchpre[discfound] then
+ goto next
else
- match=false
+ break
end
- break
- elseif id==disc_code then
- diskseen=true
- discfound=current
- notmatchpre[current]=nil
- notmatchpost[current]=true
- notmatchreplace[current]=nil
- local pre,post,replace=getdisc(current)
- if pre then
- local n=n
- while pre do
- if seq[n][getchar(pre)] then
- n=n+1
- pre=getnext(pre)
- if n>s then
- break
- end
- else
- notmatchpre[current]=true
+ else
+ goto next
+ end
+ elseif id==disc_code then
+ discseen=true
+ discfound=current
+ notmatchpre[current]=nil
+ notmatchpost[current]=true
+ notmatchreplace[current]=nil
+ local pre,post,replace=getdisc(current)
+ if pre then
+ local n=n
+ while pre do
+ if seq[n][getchar(pre)] then
+ n=n+1
+ if n>s then
break
+ else
+ pre=getnext(pre)
end
- end
- if n<=s then
+ else
notmatchpre[current]=true
+ break
end
- else
+ end
+ if n<=s then
notmatchpre[current]=true
end
- if replace then
- while replace do
- if seq[n][getchar(replace)] then
- n=n+1
+ else
+ notmatchpre[current]=true
+ end
+ if replace then
+ while replace do
+ if seq[n][getchar(replace)] then
+ n=n+1
+ if n>s then
+ break
+ else
replace=getnext(replace)
- if n>s then
- break
- end
+ end
+ else
+ notmatchreplace[current]=true
+ if notmatchpre[current] then
+ goto next
else
- notmatchreplace[current]=true
- match=notmatchpre[current]
break
end
end
- if not match then
- break
- end
- else
end
- current=getnext(current)
- elseif seq[n][32] and isspace(current,threshold) then
+ else
+ notmatchreplace[current]=true
+ end
+ current=getnext(current)
+ elseif id==glue_code then
+ local sn=seq[n]
+ if (sn[32] and spaces[current]) or sn[0xFFFC] then
n=n+1
current=getnext(current)
else
- match=false
- break
+ goto next
end
+ elseif seq[n][0xFFFC] then
+ n=n+1
+ current=getnext(current)
else
- match=false
- break
- end
- end
- else
- match=false
- end
- end
- end
- if match then
- local diskchain=diskseen or sweepnode
- if trace_contexts then
- local rule=ck[1]
- local lookuptype=ck[8] or ck[2]
- local first=ck[4]
- local last=ck[5]
- local char=getchar(start)
- logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a",
- cref(dataset,sequence),rule,gref(char),first-1,last-first+1,s-last,lookuptype)
- end
- local chainlookups=ck[6]
- if chainlookups then
- local nofchainlookups=#chainlookups
- if size==1 then
- local chainlookup=chainlookups[1]
- local chainkind=chainlookup.type
- local chainproc=chainprocs[chainkind]
- if chainproc then
- local ok
- if diskchain then
- head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,1,ck,chainproc)
- else
- head,start,ok=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,1)
- end
- if ok then
- done=true
+ goto next
end
else
- logprocess("%s: %s is not yet supported (1)",cref(dataset,sequence),chainkind)
- end
- else
- local i=1
- while start do
- if skipped then
- while start do
- local char=getchar(start)
- local ccd=descriptions[char]
- if ccd then
- local class=ccd.class or "base"
- if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
- start=getnext(start)
- else
- break
- end
- else
- break
- end
- end
- end
- local chainlookup=chainlookups[i]
- if chainlookup then
- local chainkind=chainlookup.type
- local chainproc=chainprocs[chainkind]
- if chainproc then
- local ok,n
- if diskchain then
- head,start,ok=chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,i,ck,chainproc)
- else
- head,start,ok,n=chainproc(head,start,last,dataset,sequence,chainlookup,rlmode,i)
- end
- if ok then
- done=true
- if n and n>1 and i+n>nofchainlookups then
- break
- end
- end
- else
- logprocess("%s: %s is not yet supported (2)",cref(dataset,sequence),chainkind)
- end
- end
- i=i+1
- if i>size or not start then
- break
- elseif start then
- start=getnext(start)
- end
+ goto next
end
end
else
- local replacements=ck[7]
- if replacements then
- head,start,done=reversesub(head,start,last,dataset,sequence,replacements,rlmode)
- else
- done=true
- if trace_contexts then
- logprocess("%s: skipping match",cref(dataset,sequence))
- end
- end
- end
- if done then
- break
+ goto next
end
end
+ if trace_contexts then
+ chaintrac(head,start,dataset,sequence,rlmode,skipped and skiphash,ck,true,discseen,sweepnode)
+ end
+ if discseen or sweepnode then
+ head,start,done=chaindisk(head,start,dataset,sequence,rlmode,skipped and skiphash,ck)
+ else
+ head,start,done=chainrun(head,start,last,dataset,sequence,rlmode,skipped and skiphash,ck)
+ end
+ if done then
+ break
+ end
+ ::next::
end
- if diskseen then
+ if discseen then
notmatchpre={}
notmatchpost={}
notmatchreplace={}
@@ -20572,13 +27836,18 @@ handlers.gsub_contextchain=handle_contextchain
handlers.gsub_reversecontextchain=handle_contextchain
handlers.gpos_contextchain=handle_contextchain
handlers.gpos_context=handle_contextchain
-local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode)
+local function chained_contextchain(head,start,stop,dataset,sequence,currentlookup,rlmode,skiphash)
local steps=currentlookup.steps
local nofsteps=currentlookup.nofsteps
if nofsteps>1 then
reportmoresteps(dataset,sequence)
end
- return handle_contextchain(head,start,dataset,sequence,currentlookup,rlmode)
+ local l=steps[1].coverage[getchar(start)]
+ if l then
+ return handle_contextchain(head,start,dataset,sequence,l,rlmode,skiphash)
+ else
+ return head,start,false
+ end
end
chainprocs.gsub_context=chained_contextchain
chainprocs.gsub_contextchain=chained_contextchain
@@ -20586,22 +27855,17 @@ chainprocs.gsub_reversecontextchain=chained_contextchain
chainprocs.gpos_contextchain=chained_contextchain
chainprocs.gpos_context=chained_contextchain
local missing=setmetatableindex("table")
+local logwarning=report_process
+local resolved={}
local function logprocess(...)
if trace_steps then
registermessage(...)
+ if trace_steps=="silent" then
+ return
+ end
end
report_process(...)
end
-local logwarning=report_process
-local function report_missing_coverage(dataset,sequence)
- local t=missing[currentfont]
- if not t[sequence] then
- t[sequence]=true
- logwarning("missing coverage for feature %a, lookup %a, type %a, font %a, name %a",
- dataset[4],sequence.name,sequence.type,currentfont,tfmdata.properties.fullname)
- end
-end
-local resolved={}
local sequencelists=setmetatableindex(function(t,font)
local sequences=fontdata[font].resources.sequences
if not sequences or not next(sequences) then
@@ -20610,75 +27874,79 @@ local sequencelists=setmetatableindex(function(t,font)
t[font]=sequences
return sequences
end)
-local autofeatures=fonts.analyzers.features
-local featuretypes=otf.tables.featuretypes
-local defaultscript=otf.features.checkeddefaultscript
-local defaultlanguage=otf.features.checkeddefaultlanguage
-local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
- local features=sequence.features
- if features then
- local order=sequence.order
- if order then
- local featuretype=featuretypes[sequence.type or "unknown"]
- for i=1,#order do
- local kind=order[i]
- local valid=enabled[kind]
- if valid then
- local scripts=features[kind]
- local languages=scripts and (
- scripts[script] or
- scripts[wildcard] or
- (autoscript and defaultscript(featuretype,autoscript,scripts))
- )
- local enabled=languages and (
- languages[language] or
- languages[wildcard] or
- (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
- )
- if enabled then
- return { valid,autofeatures[kind] or false,sequence,kind }
+do
+ local autofeatures=fonts.analyzers.features
+ local featuretypes=otf.tables.featuretypes
+ local defaultscript=otf.features.checkeddefaultscript
+ local defaultlanguage=otf.features.checkeddefaultlanguage
+ local wildcard="*"
+ local default="dflt"
+ local function initialize(sequence,script,language,enabled,autoscript,autolanguage)
+ local features=sequence.features
+ if features then
+ local order=sequence.order
+ if order then
+ local featuretype=featuretypes[sequence.type or "unknown"]
+ for i=1,#order do
+ local kind=order[i]
+ local valid=enabled[kind]
+ if valid then
+ local scripts=features[kind]
+ local languages=scripts and (
+ scripts[script] or
+ scripts[wildcard] or
+ (autoscript and defaultscript(featuretype,autoscript,scripts))
+ )
+ local enabled=languages and (
+ languages[language] or
+ languages[wildcard] or
+ (autolanguage and defaultlanguage(featuretype,autolanguage,languages))
+ )
+ if enabled then
+ return { valid,autofeatures[kind] or false,sequence,kind }
+ end
end
end
+ else
end
- else
end
+ return false
end
- return false
-end
-function otf.dataset(tfmdata,font)
- local shared=tfmdata.shared
- local properties=tfmdata.properties
- local language=properties.language or "dflt"
- local script=properties.script or "dflt"
- local enabled=shared.features
- local autoscript=enabled and enabled.autoscript
- local autolanguage=enabled and enabled.autolanguage
- local res=resolved[font]
- if not res then
- res={}
- resolved[font]=res
- end
- local rs=res[script]
- if not rs then
- rs={}
- res[script]=rs
- end
- local rl=rs[language]
- if not rl then
- rl={
- }
- rs[language]=rl
- local sequences=tfmdata.resources.sequences
- if sequences then
- for s=1,#sequences do
- local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
- if v then
- rl[#rl+1]=v
+ function otf.dataset(tfmdata,font)
+ local shared=tfmdata.shared
+ local properties=tfmdata.properties
+ local language=properties.language or "dflt"
+ local script=properties.script or "dflt"
+ local enabled=shared.features
+ local autoscript=enabled and enabled.autoscript
+ local autolanguage=enabled and enabled.autolanguage
+ local res=resolved[font]
+ if not res then
+ res={}
+ resolved[font]=res
+ end
+ local rs=res[script]
+ if not rs then
+ rs={}
+ res[script]=rs
+ end
+ local rl=rs[language]
+ if not rl then
+ rl={
+ }
+ rs[language]=rl
+ local sequences=tfmdata.resources.sequences
+ if sequences then
+ for s=1,#sequences do
+ local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage)
+ if v then
+ rl[#rl+1]=v
+ end
end
end
end
+ return rl
end
- return rl
end
local function report_disc(what,n)
report_run("%s: %s > %s",what,n,languages.serializediscretionary(n))
@@ -20711,13 +27979,12 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
if prev then
- local nest=getprev(pre)
setlink(prev,pre)
if k_run(prevmarks,"preinjections",pre,font,attr,...) then
done=true
end
- setprev(pre,nest)
- setnext(prev,disc)
+ setprev(pre)
+ setlink(prev,disc)
end
end
if post then
@@ -20730,7 +27997,7 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
setnext(posttail)
- setprev(next,disc)
+ setlink(disc,next)
end
end
if replace then
@@ -20738,13 +28005,12 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
if prev then
- local nest=getprev(replace)
setlink(prev,replace)
if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then
done=true
end
- setprev(replace,nest)
- setnext(prev,disc)
+ setprev(replace)
+ setlink(prev,disc)
end
if next then
setlink(replacetail,next)
@@ -20752,19 +28018,21 @@ local function kernrun(disc,k_run,font,attr,...)
done=true
end
setnext(replacetail)
- setprev(next,disc)
+ setlink(disc,next)
end
elseif prev and next then
setlink(prev,next)
if k_run(prevmarks,"emptyinjections",next,font,attr,...) then
done=true
end
- setlink(prev,disc)
- setlink(disc,next)
+ setlink(prev,disc,next)
+ end
+ if done and trace_testruns then
+ report_disc("done",disc)
end
return nextstart,done
end
-local function comprun(disc,c_run,...)
+local function comprun(disc,c_run,...)
if trace_compruns then
report_disc("comp",disc)
end
@@ -20800,6 +28068,9 @@ local function comprun(disc,c_run,...)
sweepnode=nil
sweeptype=nil
if renewed then
+ if trace_testruns then
+ report_disc("done",disc)
+ end
setdisc(disc,pre,post,replace)
end
return getnext(disc),renewed
@@ -20813,22 +28084,66 @@ local function testrun(disc,t_run,c_run,...)
return
end
local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
- local done=false
- if replace and prev then
- setlink(replacetail,next)
- local ok,overflow=t_run(replace,next,...)
- if ok and overflow then
- setfield(disc,"replace")
- setlink(prev,replace)
- setboth(disc)
- flush_node_list(disc)
- return replace,true
+ local renewed=false
+ if (post or replace) and prev then
+ if post then
+ setlink(posttail,next)
else
- setnext(replacetail)
- setprev(next,disc)
+ post=next
end
+ if replace then
+ setlink(replacetail,next)
+ else
+ replace=next
+ end
+ local d_post=t_run(post,next,...)
+ local d_replace=t_run(replace,next,...)
+ if d_post>0 or d_replace>0 then
+ local d=d_replace>d_post and d_replace or d_post
+ local head=getnext(disc)
+ local tail=head
+ for i=1,d do
+ local nx=getnext(tail)
+ local id=getid(nx)
+ if id==disc_code then
+ head,tail=flattendisk(head,nx)
+ elseif id==glyph_code then
+ tail=nx
+ else
+ break
+ end
+ end
+ next=getnext(tail)
+ setnext(tail)
+ setprev(head)
+ local new=copy_node_list(head)
+ if posttail then
+ setlink(posttail,head)
+ else
+ post=head
+ end
+ if replacetail then
+ setlink(replacetail,new)
+ else
+ replace=new
+ end
+ else
+ if posttail then
+ setnext(posttail)
+ else
+ post=nil
+ end
+ if replacetail then
+ setnext(replacetail)
+ else
+ replace=nil
+ end
+ end
+ setlink(disc,next)
+ end
+ if trace_testruns then
+ report_disc("more",disc)
end
- local renewed=false
if pre then
sweepnode=disc
sweeptype="pre"
@@ -20860,30 +28175,34 @@ local function testrun(disc,t_run,c_run,...)
sweeptype=nil
if renewed then
setdisc(disc,pre,post,replace)
- return next,true
- else
- return next,done
+ if trace_testruns then
+ report_disc("done",disc)
+ end
end
+ return getnext(disc),renewed
end
local nesting=0
-local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
local done=false
local sweep=sweephead[head]
if sweep then
start=sweep
- sweephead[head]=nil
+ sweephead[head]=false
else
start=head
end
while start do
- local char=ischar(start,font)
+ local char,id=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
if not a or (a==attr) then
local lookupmatch=lookupcache[char]
if lookupmatch then
local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
if ok then
done=true
end
@@ -20905,46 +28224,91 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm
return head,done
end
local function t_run_single(start,stop,font,attr,lookupcache)
+ local lastd=nil
while start~=stop do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ local startnext=getnext(start)
if not a or (a==attr) then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local s=getnext(start)
+ local s=startnext
+ local ss=nil
+ local sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
local l=nil
local d=0
while s do
- if s==stop then
- d=1
- elseif d>0 then
- d=d+1
- end
- local lg=lookupmatch[getchar(s)]
- if lg then
- l=lg
- s=getnext(s)
+ local char=ischar(s,font)
+ if char then
+ local lg=lookupmatch[char]
+ if lg then
+ if sstop then
+ d=1
+ elseif d>0 then
+ d=d+1
+ end
+ l=lg
+ s=getnext(s)
+ sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
+ else
+ break
+ end
else
break
end
end
- if l and l.ligature then
- return true,d>1
+ if l and l.ligature then
+ lastd=d
end
+ else
end
else
end
- start=getnext(start)
+ if lastd then
+ return lastd
+ end
+ start=startnext
else
break
end
end
+ return 0
end
-local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- local a=attr and getattr(sub,0)
+local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ local a
+ if attr then
+ a=getattr(sub,0)
+ end
if not a or (a==attr) then
- for n in traverse_nodes(sub) do
+ for n in nextnode,sub do
if n==last then
break
end
@@ -20952,7 +28316,7 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
if char then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection)
+ local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
if ok then
return true
end
@@ -20961,37 +28325,36 @@ local function k_run_single(sub,injection,last,font,attr,lookupcache,step,datase
end
end
end
-local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
+local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
local done=false
local sweep=sweephead[head]
if sweep then
start=sweep
- sweephead[head]=nil
+ sweephead[head]=false
else
start=head
end
while start do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
if not a or (a==attr) then
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- done=true
- break
- elseif not start then
- break
- end
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ done=true
+ break
+ elseif not start then
+ break
end
- else
- report_missing_coverage(dataset,sequence)
end
end
if start then
@@ -21011,54 +28374,94 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm
return head,done
end
local function t_run_multiple(start,stop,font,attr,steps,nofsteps)
+ local lastd=nil
while start~=stop do
local char=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ local startnext=getnext(start)
if not a or (a==attr) then
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local s=getnext(start)
- local l=nil
- local d=0
- while s do
- if s==stop then
- d=1
- elseif d>0 then
- d=d+1
- end
- local lg=lookupmatch[getchar(s)]
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local s=startnext
+ local ss=nil
+ local sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
+ local l=nil
+ local d=0
+ while s do
+ local char=ischar(s)
+ if char then
+ local lg=lookupmatch[char]
if lg then
+ if sstop then
+ d=1
+ elseif d>0 then
+ d=d+1
+ end
l=lg
s=getnext(s)
+ sstop=s==stop
+ if not s then
+ s=ss
+ ss=nil
+ end
+ while getid(s)==disc_code do
+ ss=getnext(s)
+ s=getfield(s,"replace")
+ if not s then
+ s=ss
+ ss=nil
+ end
+ end
else
break
end
- end
- if l and l.ligature then
- return true,d>1
+ else
+ break
end
end
- else
- report_missing_coverage(dataset,sequence)
+ if l and l.ligature then
+ lastd=d
+ end
end
end
else
end
- start=getnext(start)
+ if lastd then
+ return lastd
+ end
+ start=startnext
else
break
end
end
+ return 0
end
-local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- local a=attr and getattr(sub,0)
+local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ local a
+ if attr then
+ a=getattr(sub,0)
+ end
if not a or (a==attr) then
- for n in traverse_nodes(sub) do
+ for n in nextnode,sub do
if n==last then
break
end
@@ -21067,16 +28470,12 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
for i=1,nofsteps do
local step=steps[i]
local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local h,d,ok=handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection)
- if ok then
- return true
- end
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local h,d,ok=handler(sub,n,dataset,sequence,lookupmatch,rlmode,skiphash,step,injection)
+ if ok then
+ return true
end
- else
- report_missing_coverage(dataset,sequence)
end
end
end
@@ -21084,176 +28483,194 @@ local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,datase
end
end
local function txtdirstate(start,stack,top,rlparmode)
- local dir=getfield(start,"dir")
- local new=1
+ local nxt=getnext(start)
+ local dir=getdir(start)
if dir=="+TRT" then
top=top+1
stack[top]=dir
- new=-1
+ return nxt,top,-1
elseif dir=="+TLT" then
top=top+1
stack[top]=dir
+ return nxt,top,1
elseif dir=="-TRT" or dir=="-TLT" then
- top=top-1
- if stack[top]=="+TRT" then
- new=-1
+ if top==1 then
+ return nxt,0,rlparmode
+ else
+ top=top-1
+ if stack[top]=="+TRT" then
+ return nxt,top,-1
+ else
+ return nxt,top,1
+ end
end
else
- new=rlparmode
+ return nxt,top,rlparmode
end
- if trace_directions then
- report_process("directions after txtdir %a: parmode %a, txtmode %a, level %a",dir,mref(rlparmode),mref(new),top)
- end
- return getnext(start),top,new
end
local function pardirstate(start)
- local dir=getfield(start,"dir")
- local new=0
+ local nxt=getnext(start)
+ local dir=getdir(start)
if dir=="TLT" then
- new=1
+ return nxt,1,1
elseif dir=="TRT" then
- new=-1
- end
- if trace_directions then
- report_process("directions after pardir %a: parmode %a",dir,mref(new))
+ return nxt,-1,-1
+ else
+ return nxt,0,0
end
- return getnext(start),new,new
end
otf.helpers=otf.helpers or {}
otf.helpers.txtdirstate=txtdirstate
otf.helpers.pardirstate=pardirstate
-local function featuresprocessor(head,font,attr)
- local sequences=sequencelists[font]
- if not sequencelists then
- return head,false
- end
- nesting=nesting+1
- if nesting==1 then
- currentfont=font
- tfmdata=fontdata[font]
- descriptions=tfmdata.descriptions
- characters=tfmdata.characters
- marks=tfmdata.resources.marks
- threshold,
- factor=getthreshold(font)
- checkmarks=tfmdata.properties.checkmarks
- elseif currentfont~=font then
- report_warning("nested call with a different font, level %s, quitting",nesting)
- nesting=nesting-1
- return head,false
- end
- head=tonut(head)
- if trace_steps then
- checkstep(head)
- end
- local rlmode=0
- local done=false
- local datasets=otf.dataset(tfmdata,font,attr)
- local forcedisc=alwaysdisc or not attr
- local dirstack={}
- sweephead={}
- for s=1,#datasets do
- local dataset=datasets[s]
- local attribute=dataset[2]
- local sequence=dataset[3]
- local rlparmode=0
- local topstack=0
- local success=false
- local typ=sequence.type
- local gpossing=typ=="gpos_single" or typ=="gpos_pair"
- local handler=handlers[typ]
- local steps=sequence.steps
- local nofsteps=sequence.nofsteps
- if not steps then
- local h,d,ok=handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr)
- if ok then
- success=true
- if h then
+do
+ local fastdisc=true
+ local testdics=false
+ directives.register("otf.fastdisc",function(v) fastdisc=v end)
+ local otfdataset=nil
+ local getfastdisc={ __index=function(t,k)
+ local v=usesfont(k,currentfont)
+ t[k]=v
+ return v
+ end }
+ local getfastspace={ __index=function(t,k)
+ local v=isspace(k,threshold) or false
+ t[k]=v
+ return v
+ end }
+ function otf.featuresprocessor(head,font,attr,direction,n)
+ local sequences=sequencelists[font]
+ nesting=nesting+1
+ if nesting==1 then
+ currentfont=font
+ tfmdata=fontdata[font]
+ descriptions=tfmdata.descriptions
+ characters=tfmdata.characters
+ local resources=tfmdata.resources
+ marks=resources.marks
+ classes=resources.classes
+ threshold,
+ factor=getthreshold(font)
+ checkmarks=tfmdata.properties.checkmarks
+ if not otfdataset then
+ otfdataset=otf.dataset
+ end
+ discs=fastdisc and n and n>1 and setmetatable({},getfastdisc)
+ spaces=setmetatable({},getfastspace)
+ elseif currentfont~=font then
+ report_warning("nested call with a different font, level %s, quitting",nesting)
+ nesting=nesting-1
+ return head,false
+ end
+ if trace_steps then
+ checkstep(head)
+ end
+ local initialrl=direction=="TRT" and -1 or 0
+ local datasets=otfdataset(tfmdata,font,attr)
+ local dirstack={ nil }
+ sweephead={}
+ for s=1,#datasets do
+ local dataset=datasets[s]
+ local attribute=dataset[2]
+ local sequence=dataset[3]
+ local rlparmode=initialrl
+ local topstack=0
+ local typ=sequence.type
+ local gpossing=typ=="gpos_single" or typ=="gpos_pair"
+ local forcetestrun=typ=="gsub_ligature"
+ local handler=handlers[typ]
+ local steps=sequence.steps
+ local nofsteps=sequence.nofsteps
+ local skiphash=sequence.skiphash
+ if not steps then
+ local h,ok=handler(head,dataset,sequence,initialrl,font,attr)
+ if h and h~=head then
head=h
end
- end
- elseif typ=="gsub_reversecontextchain" then
- local start=find_node_tail(head)
- while start do
- local char=ischar(start,font)
- if char then
- local a=attr and getattr(start,0)
- if not a or (a==attr) then
- for i=1,nofsteps do
- local step=steps[i]
- local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success=true
- break
+ elseif typ=="gsub_reversecontextchain" then
+ local start=find_node_tail(head)
+ local rlmode=0
+ local merged=steps.merged
+ while start do
+ local char=ischar(start,font)
+ if char then
+ local m=merged[char]
+ if m then
+ local a
+ if attr then
+ a=getattr(start,0)
+ end
+ if not a or (a==attr) then
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ end
end
end
+ if start then
+ start=getprev(start)
+ end
else
- report_missing_coverage(dataset,sequence)
+ start=getprev(start)
end
- end
- if start then
+ else
start=getprev(start)
end
else
start=getprev(start)
end
- else
- start=getprev(start)
end
- end
- else
- local start=head
- rlmode=0
- if nofsteps==1 then
- local step=steps[1]
- local lookupcache=step.coverage
- if not lookupcache then
- report_missing_coverage(dataset,sequence)
- else
+ else
+ local start=head
+ local rlmode=initialrl
+ if nofsteps==1 then
+ local step=steps[1]
+ local lookupcache=step.coverage
while start do
local char,id=ischar(start,font)
if char then
- local a=attr and getattr(start,0)
- if a then
- a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
+ if skiphash and skiphash[char] then
+ start=getnext(start)
else
- a=not attribute or getprop(start,a_state)==attribute
- end
- if a then
local lookupmatch=lookupcache[char]
if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
- if ok then
- success=true
+ local a
+ if attr then
+ if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then
+ a=true
+ end
+ elseif not attribute or getprop(start,a_state)==attribute then
+ a=true
end
- end
- if start then
+ if a then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if start then
+ start=getnext(start)
+ end
+ else
+ start=getnext(start)
+ end
+ else
start=getnext(start)
end
- else
- start=getnext(start)
end
- elseif char==false then
+ elseif char==false or id==glue_code then
start=getnext(start)
elseif id==disc_code then
- local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
- if a then
+ if not discs or discs[start]==true then
local ok
if gpossing then
- start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- elseif typ=="gsub_ligature" then
- start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
+ start,ok=kernrun(start,k_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start,ok=testrun(start,t_run_single,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
else
- start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,handler)
- end
- if ok then
- success=true
+ start,ok=comprun(start,c_run_single,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler)
end
else
start=getnext(start)
@@ -21268,110 +28685,197 @@ local function featuresprocessor(head,font,attr)
start=getnext(start)
end
end
- end
- else
- while start do
- local char,id=ischar(start,font)
- if char then
- local a=attr and getattr(start,0)
- if a then
- a=(a==attr) and (not attribute or getprop(start,a_state)==attribute)
- else
- a=not attribute or getprop(start,a_state)==attribute
- end
- if a then
- for i=1,nofsteps do
- local step=steps[i]
- local lookupcache=step.coverage
- if lookupcache then
- local lookupmatch=lookupcache[char]
- if lookupmatch then
- local ok
- head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,step,i)
- if ok then
- success=true
- break
- elseif not start then
- break
+ else
+ local merged=steps.merged
+ while start do
+ local char,id=ischar(start,font)
+ if char then
+ if skiphash and skiphash[char] then
+ start=getnext(start)
+ else
+ local m=merged[char]
+ if m then
+ local a
+ if attr then
+ if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then
+ a=true
end
+ elseif not attribute or getprop(start,a_state)==attribute then
+ a=true
+ end
+ if a then
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ elseif not start then
+ break
+ end
+ end
+ end
+ if start then
+ start=getnext(start)
+ end
+ else
+ start=getnext(start)
end
else
- report_missing_coverage(dataset,sequence)
+ start=getnext(start)
end
end
- if start then
+ elseif char==false or id==glue_code then
+ start=getnext(start)
+ elseif id==disc_code then
+ if not discs or discs[start]==true then
+ local ok
+ if gpossing then
+ start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ elseif forcetestrun then
+ start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ else
+ start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler)
+ end
+ else
start=getnext(start)
end
+ elseif id==math_code then
+ start=getnext(end_of_math(start))
+ elseif id==dir_code then
+ start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id==localpar_code then
+ start,rlparmode,rlmode=pardirstate(start)
else
start=getnext(start)
end
- elseif char==false then
+ end
+ end
+ end
+ if trace_steps then
+ registerstep(head)
+ end
+ end
+ nesting=nesting-1
+ return head
+ end
+ function otf.datasetpositionprocessor(head,font,direction,dataset)
+ currentfont=font
+ tfmdata=fontdata[font]
+ descriptions=tfmdata.descriptions
+ characters=tfmdata.characters
+ local resources=tfmdata.resources
+ marks=resources.marks
+ classes=resources.classes
+ threshold,
+ factor=getthreshold(font)
+ checkmarks=tfmdata.properties.checkmarks
+ if type(dataset)=="number" then
+ dataset=otfdataset(tfmdata,font,0)[dataset]
+ end
+ local sequence=dataset[3]
+ local typ=sequence.type
+ local handler=handlers[typ]
+ local steps=sequence.steps
+ local nofsteps=sequence.nofsteps
+ local done=false
+ local dirstack={ nil }
+ local start=head
+ local initialrl=direction=="TRT" and -1 or 0
+ local rlmode=initialrl
+ local rlparmode=initialrl
+ local topstack=0
+ local merged=steps.merged
+ local position=0
+ while start do
+ local char,id=ischar(start,font)
+ if char then
+ position=position+1
+ local m=merged[char]
+ if m then
+ if skiphash and skiphash[char] then
start=getnext(start)
- elseif id==disc_code then
- local a=forcedisc or getsubtype(start)==discretionary_code or getattr(start,0)==attr
- if a then
- local ok
- if gpossing then
- start,ok=kernrun(start,k_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- elseif typ=="gsub_ligature" then
- start,ok=testrun(start,t_run_multiple,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- else
- start,ok=comprun(start,c_run_multiple,font,attr,steps,nofsteps,dataset,sequence,rlmode,handler)
- end
- if ok then
- success=true
+ else
+ for i=m[1],m[2] do
+ local step=steps[i]
+ local lookupcache=step.coverage
+ local lookupmatch=lookupcache[char]
+ if lookupmatch then
+ local ok
+ head,start,ok=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step)
+ if ok then
+ break
+ elseif not start then
+ break
+ end
end
- else
+ end
+ if start then
start=getnext(start)
end
- elseif id==math_code then
- start=getnext(end_of_math(start))
- elseif id==dir_code then
- start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
- elseif id==localpar_code then
- start,rlparmode,rlmode=pardirstate(start)
- else
- start=getnext(start)
end
+ else
+ start=getnext(start)
end
+ elseif char==false or id==glue_code then
+ start=getnext(start)
+ elseif id==math_code then
+ start=getnext(end_of_math(start))
+ elseif id==dir_code then
+ start,topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode)
+ elseif id==localpar_code then
+ start,rlparmode,rlmode=pardirstate(start)
+ else
+ start=getnext(start)
end
end
- if success then
- done=true
- end
- if trace_steps then
- registerstep(head)
- end
+ return head
end
- nesting=nesting-1
- head=tonode(head)
- return head,done
end
local plugins={}
otf.plugins=plugins
+local report=logs.reporter("fonts")
function otf.registerplugin(name,f)
if type(name)=="string" and type(f)=="function" then
plugins[name]={ name,f }
+ report()
+ report("plugin %a has been loaded, please be aware of possible side effects",name)
+ report()
+ if logs.pushtarget then
+ logs.pushtarget("log")
+ end
+ report("Plugins are not officially supported unless stated otherwise. This is because")
+ report("they bypass the regular font handling and therefore some features in ConTeXt")
+ report("(especially those related to fonts) might not work as expected or might not work")
+ report("at all. Some plugins are for testing and development only and might change")
+ report("whenever we feel the need for it.")
+ report()
+ if logs.poptarget then
+ logs.poptarget()
+ end
end
end
-local function plugininitializer(tfmdata,value)
+function otf.plugininitializer(tfmdata,value)
if type(value)=="string" then
tfmdata.shared.plugin=plugins[value]
end
end
-local function pluginprocessor(head,font)
+function otf.pluginprocessor(head,font,attr,direction)
local s=fontdata[font].shared
local p=s and s.plugin
if p then
if trace_plugins then
report_process("applying plugin %a",p[1])
end
- return p[2](head,font)
+ return p[2](head,font,attr,direction)
else
return head,false
end
end
-local function featuresinitializer(tfmdata,value)
+function otf.featuresinitializer(tfmdata,value)
end
registerotffeature {
name="features",
@@ -21379,53 +28883,87 @@ registerotffeature {
default=true,
initializers={
position=1,
- node=featuresinitializer,
- plug=plugininitializer,
+ node=otf.featuresinitializer,
+ plug=otf.plugininitializer,
},
processors={
- node=featuresprocessor,
- plug=pluginprocessor,
+ node=otf.featuresprocessor,
+ plug=otf.pluginprocessor,
}
}
-otf.nodemodeinitializer=featuresinitializer
-otf.featuresprocessor=featuresprocessor
otf.handlers=handlers
local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end
+local tag="kern"
if fontfeatures then
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local features=fontfeatures[font]
- local enabled=features and features.spacekern and features.kern
+ local enabled=features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head,start,enabled
+ return head,enabled
end
else
- function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)
+ function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr)
local shared=fontdata[font].shared
local features=shared and shared.features
- local enabled=features and features.spacekern and features.kern
+ local enabled=features and features.spacekern and features[tag]
if enabled then
setspacekerns(font,sequence)
end
- return head,start,enabled
+ return head,enabled
end
end
local function hasspacekerns(data)
- local sequences=data.resources.sequences
- for i=1,#sequences do
- local sequence=sequences[i]
- local steps=sequence.steps
- if steps and sequence.features.kern then
- for i=1,#steps do
- local coverage=steps[i].coverage
- if not coverage then
- elseif coverage[32] then
- return true
- else
- for k,v in next,coverage do
- if v[32] then
- return true
+ local resources=data.resources
+ local sequences=resources.sequences
+ local validgpos=resources.features.gpos
+ if validgpos and sequences then
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local steps=sequence.steps
+ if steps and sequence.features[tag] then
+ local kind=sequence.type
+ if kind=="gpos_pair" or kind=="gpos_single" then
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ local rules=step.rules
+ if rules then
+ elseif not coverage then
+ elseif kind=="gpos_single" then
+ elseif kind=="gpos_pair" then
+ local format=step.format
+ if format=="move" or format=="kern" then
+ local kerns=coverage[32]
+ if kerns then
+ return true
+ end
+ for k,v in next,coverage do
+ if v[32] then
+ return true
+ end
+ end
+ elseif format=="pair" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ local one=v[1]
+ if one and one~=true then
+ return true
+ end
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ local one=kern[1]
+ if one and one~=true then
+ return true
+ end
+ end
+ end
+ end
end
end
end
@@ -21443,103 +28981,110 @@ otf.readers.registerextender {
local function spaceinitializer(tfmdata,value)
local resources=tfmdata.resources
local spacekerns=resources and resources.spacekerns
- local properties=tfmdata.properties
if value and spacekerns==nil then
+ local rawdata=tfmdata.shared and tfmdata.shared.rawdata
+ local properties=rawdata.properties
if properties and properties.hasspacekerns then
local sequences=resources.sequences
- local left={}
- local right={}
- local last=0
- local feat=nil
- for i=1,#sequences do
- local sequence=sequences[i]
- local steps=sequence.steps
- if steps then
- local kern=sequence.features.kern
- if kern then
- if feat then
- for script,languages in next,kern do
- local f=feat[script]
- if f then
- for l in next,languages do
- f[l]=true
- end
- else
- feat[script]=languages
- end
- end
- else
- feat=kern
- end
- for i=1,#steps do
- local step=steps[i]
- local coverage=step.coverage
- local rules=step.rules
- local format=step.format
- if rules then
- elseif coverage then
- local single=format==gpos_single
- local kerns=coverage[32]
- if kerns then
- for k,v in next,kerns do
- if type(v)~="table" then
- right[k]=v
- elseif single then
- right[k]=v[3]
- else
- local one=v[1]
- if one then
- right[k]=one[3]
+ local validgpos=resources.features.gpos
+ if validgpos and sequences then
+ local left={}
+ local right={}
+ local last=0
+ local feat=nil
+ for i=1,#sequences do
+ local sequence=sequences[i]
+ local steps=sequence.steps
+ if steps then
+ local kern=sequence.features[tag]
+ if kern then
+ local kind=sequence.type
+ if kind=="gpos_pair" or kind=="gpos_single" then
+ if feat then
+ for script,languages in next,kern do
+ local f=feat[script]
+ if f then
+ for l in next,languages do
+ f[l]=true
end
+ else
+ feat[script]=languages
end
end
+ else
+ feat=kern
end
- for k,v in next,coverage do
- local kern=v[32]
- if kern then
- if type(kern)~="table" then
- left[k]=kern
- elseif single then
- left[k]=v[3]
- else
- local one=v[1]
- if one then
- left[k]=one[3]
+ for i=1,#steps do
+ local step=steps[i]
+ local coverage=step.coverage
+ local rules=step.rules
+ if rules then
+ elseif not coverage then
+ elseif kind=="gpos_single" then
+ elseif kind=="gpos_pair" then
+ local format=step.format
+ if format=="move" or format=="kern" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ right[k]=v
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ left[k]=kern
+ end
+ end
+ elseif format=="pair" then
+ local kerns=coverage[32]
+ if kerns then
+ for k,v in next,kerns do
+ local one=v[1]
+ if one and one~=true then
+ right[k]=one[3]
+ end
+ end
+ end
+ for k,v in next,coverage do
+ local kern=v[32]
+ if kern then
+ local one=kern[1]
+ if one and one~=true then
+ left[k]=one[3]
+ end
+ end
end
end
end
end
+ last=i
end
+ else
end
- last=i
end
- else
end
- end
- left=next(left) and left or false
- right=next(right) and right or false
- if left or right then
- spacekerns={
- left=left,
- right=right,
- }
- if last>0 then
- local triggersequence={
- features={ kern=feat or { dflt={ dflt=true,} } },
- flags=noflags,
- name="trigger_space_kerns",
- order={ "kern" },
- type="trigger_space_kerns",
+ left=next(left) and left or false
+ right=next(right) and right or false
+ if left or right then
+ spacekerns={
left=left,
right=right,
}
- insert(sequences,last,triggersequence)
+ if last>0 then
+ local triggersequence={
+ features={ [tag]=feat or { dflt={ dflt=true,} } },
+ flags=noflags,
+ name="trigger_space_kerns",
+ order={ tag },
+ type="trigger_space_kerns",
+ left=left,
+ right=right,
+ }
+ insert(sequences,last,triggersequence)
+ end
end
- else
- spacekerns=false
end
- else
- spacekerns=false
end
resources.spacekerns=spacekerns
end
@@ -21579,7 +29124,7 @@ if not modules then modules={} end modules ['font-osd']={
}
local insert,imerge,copy=table.insert,table.imerge,table.copy
local next,type=next,type
-local report_devanagari=logs.reporter("otf","devanagari")
+local report=logs.reporter("otf","devanagari")
fonts=fonts or {}
fonts.analyzers=fonts.analyzers or {}
fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } }
@@ -21589,8 +29134,6 @@ local methods=fonts.analyzers.methods
local otffeatures=fonts.constructors.features.otf
local registerotffeature=otffeatures.register
local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
local getnext=nuts.getnext
local getprev=nuts.getprev
local getboth=nuts.getboth
@@ -21616,6 +29159,9 @@ local fontdata=fonts.hashes.identifiers
local a_state=attributes.private('state')
local a_syllabe=attributes.private('syllabe')
local dotted_circle=0x25CC
+local c_nbsp=0x00A0
+local c_zwnj=0x200C
+local c_zwj=0x200D
local states=fonts.analyzers.states
local s_rphf=states.rphf
local s_half=states.half
@@ -21629,214 +29175,156 @@ replace_all_nbsp=function(head)
end
return replace_all_nbsp(head)
end
-local xprocesscharacters=nil
+local processcharacters=nil
if context then
- xprocesscharacters=function(head,font)
- xprocesscharacters=nodes.handlers.characters
- return xprocesscharacters(head,font)
- end
+
+--removed
+
else
- xprocesscharacters=function(head,font)
- xprocesscharacters=nodes.handlers.nodepass
- return xprocesscharacters(head,font)
- end
-end
-local function processcharacters(head,font)
- return tonut(xprocesscharacters(tonode(head)))
-end
-local consonant={
- [0x0915]=true,[0x0916]=true,[0x0917]=true,[0x0918]=true,
- [0x0919]=true,[0x091A]=true,[0x091B]=true,[0x091C]=true,
- [0x091D]=true,[0x091E]=true,[0x091F]=true,[0x0920]=true,
- [0x0921]=true,[0x0922]=true,[0x0923]=true,[0x0924]=true,
- [0x0925]=true,[0x0926]=true,[0x0927]=true,[0x0928]=true,
- [0x0929]=true,[0x092A]=true,[0x092B]=true,[0x092C]=true,
- [0x092D]=true,[0x092E]=true,[0x092F]=true,[0x0930]=true,
- [0x0931]=true,[0x0932]=true,[0x0933]=true,[0x0934]=true,
- [0x0935]=true,[0x0936]=true,[0x0937]=true,[0x0938]=true,
- [0x0939]=true,[0x0958]=true,[0x0959]=true,[0x095A]=true,
- [0x095B]=true,[0x095C]=true,[0x095D]=true,[0x095E]=true,
- [0x095F]=true,[0x0979]=true,[0x097A]=true,
- [0x0C95]=true,[0x0C96]=true,[0x0C97]=true,[0x0C98]=true,
- [0x0C99]=true,[0x0C9A]=true,[0x0C9B]=true,[0x0C9C]=true,
- [0x0C9D]=true,[0x0C9E]=true,[0x0C9F]=true,[0x0CA0]=true,
- [0x0CA1]=true,[0x0CA2]=true,[0x0CA3]=true,[0x0CA4]=true,
- [0x0CA5]=true,[0x0CA6]=true,[0x0CA7]=true,[0x0CA8]=true,
- [0x0CA9]=true,[0x0CAA]=true,[0x0CAB]=true,[0x0CAC]=true,
- [0x0CAD]=true,[0x0CAE]=true,[0x0CAF]=true,[0x0CB0]=true,
- [0x0CB1]=true,[0x0CB2]=true,[0x0CB3]=true,[0x0CB4]=true,
- [0x0CB5]=true,[0x0CB6]=true,[0x0CB7]=true,[0x0CB8]=true,
- [0x0CB9]=true,
- [0x0CDE]=true,
- [0x0D15]=true,[0x0D16]=true,[0x0D17]=true,[0x0D18]=true,
- [0x0D19]=true,[0x0D1A]=true,[0x0D1B]=true,[0x0D1C]=true,
- [0x0D1D]=true,[0x0D1E]=true,[0x0D1F]=true,[0x0D20]=true,
- [0x0D21]=true,[0x0D22]=true,[0x0D23]=true,[0x0D24]=true,
- [0x0D25]=true,[0x0D26]=true,[0x0D27]=true,[0x0D28]=true,
- [0x0D29]=true,[0x0D2A]=true,[0x0D2B]=true,[0x0D2C]=true,
- [0x0D2D]=true,[0x0D2E]=true,[0x0D2F]=true,[0x0D30]=true,
- [0x0D31]=true,[0x0D32]=true,[0x0D33]=true,[0x0D34]=true,
- [0x0D35]=true,[0x0D36]=true,[0x0D37]=true,[0x0D38]=true,
- [0x0D39]=true,[0x0D3A]=true,
-}
-local independent_vowel={
- [0x0904]=true,[0x0905]=true,[0x0906]=true,[0x0907]=true,
- [0x0908]=true,[0x0909]=true,[0x090A]=true,[0x090B]=true,
- [0x090C]=true,[0x090D]=true,[0x090E]=true,[0x090F]=true,
- [0x0910]=true,[0x0911]=true,[0x0912]=true,[0x0913]=true,
- [0x0914]=true,[0x0960]=true,[0x0961]=true,[0x0972]=true,
- [0x0973]=true,[0x0974]=true,[0x0975]=true,[0x0976]=true,
- [0x0977]=true,
- [0x0C85]=true,[0x0C86]=true,[0x0C87]=true,[0x0C88]=true,
- [0x0C89]=true,[0x0C8A]=true,[0x0C8B]=true,[0x0C8C]=true,
- [0x0C8D]=true,[0x0C8E]=true,[0x0C8F]=true,[0x0C90]=true,
- [0x0C91]=true,[0x0C92]=true,[0x0C93]=true,[0x0C94]=true,
- [0x0D05]=true,[0x0D06]=true,[0x0D07]=true,[0x0D08]=true,
- [0x0D09]=true,[0x0D0A]=true,[0x0D0B]=true,[0x0D0C]=true,
- [0x0D0E]=true,[0x0D0F]=true,[0x0D10]=true,[0x0D12]=true,
- [0x0D13]=true,[0x0D14]=true,
-}
-local dependent_vowel={
- [0x093A]=true,[0x093B]=true,[0x093E]=true,[0x093F]=true,
- [0x0940]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
- [0x0944]=true,[0x0945]=true,[0x0946]=true,[0x0947]=true,
- [0x0948]=true,[0x0949]=true,[0x094A]=true,[0x094B]=true,
- [0x094C]=true,[0x094E]=true,[0x094F]=true,[0x0955]=true,
- [0x0956]=true,[0x0957]=true,[0x0962]=true,[0x0963]=true,
- [0x0CBE]=true,[0x0CBF]=true,[0x0CC0]=true,[0x0CC1]=true,
- [0x0CC2]=true,[0x0CC3]=true,[0x0CC4]=true,[0x0CC5]=true,
- [0x0CC6]=true,[0x0CC7]=true,[0x0CC8]=true,[0x0CC9]=true,
- [0x0CCA]=true,[0x0CCB]=true,[0x0CCC]=true,
- [0x0D3E]=true,[0x0D3F]=true,[0x0D40]=true,[0x0D41]=true,
- [0x0D42]=true,[0x0D43]=true,[0x0D44]=true,[0x0D46]=true,
- [0x0D47]=true,[0x0D48]=true,[0x0D4A]=true,[0x0D4B]=true,
- [0x0D4C]=true,[0x0D57]=true,
-}
-local vowel_modifier={
- [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x0903]=true,
- [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
- [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
- [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
- [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
- [0xA8F0]=true,[0xA8F1]=true,
- [0x0D02]=true,[0x0D03]=true,
-}
-local stress_tone_mark={
- [0x0951]=true,[0x0952]=true,[0x0953]=true,[0x0954]=true,
- [0x0CCD]=true,
- [0x0D4D]=true,
-}
-local nukta={
- [0x093C]=true,
- [0x0CBC]=true,
-}
-local halant={
- [0x094D]=true,
- [0x0CCD]=true,
- [0x0D4D]=true,
-}
-local ra={
- [0x0930]=true,
- [0x0CB0]=true,
- [0x0D30]=true,
-}
-local c_anudatta=0x0952
-local c_nbsp=0x00A0
-local c_zwnj=0x200C
-local c_zwj=0x200D
+ function processcharacters(head,font)
+ local processors=fontdata[font].shared.processes
+ for i=1,#processors do
+ head=processors[i](head,font,0)
+ end
+ return head
+ end
+end
+local indicgroups=characters and characters.indicgroups
+if not indicgroups and characters then
+ local indic={
+ c={},
+ i={},
+ d={},
+ m={},
+ s={},
+ o={},
+ }
+ local indicmarks={
+ l={},
+ t={},
+ b={},
+ r={},
+ s={},
+ }
+ local indicclasses={
+ nukta={},
+ halant={},
+ ra={},
+ anudatta={},
+ }
+ local indicorders={
+ bp={},
+ ap={},
+ bs={},
+ as={},
+ bh={},
+ ah={},
+ bm={},
+ am={},
+ }
+ for k,v in next,characters.data do
+ local i=v.indic
+ if i then
+ indic[i][k]=true
+ i=v.indicmark
+ if i then
+ if i=="s" then
+ local s=v.specials
+ indicmarks[i][k]={ s[2],s[3] }
+ else
+ indicmarks[i][k]=true
+ end
+ end
+ i=v.indicclass
+ if i then
+ indicclasses[i][k]=true
+ end
+ i=v.indicorder
+ if i then
+ indicorders[i][k]=true
+ end
+ end
+ end
+ indicgroups={
+ consonant=indic.c,
+ independent_vowel=indic.i,
+ dependent_vowel=indic.d,
+ vowel_modifier=indic.m,
+ stress_tone_mark=indic.s,
+ pre_mark=indicmarks.l,
+ above_mark=indicmarks.t,
+ below_mark=indicmarks.b,
+ post_mark=indicmarks.r,
+ twopart_mark=indicmarks.s,
+ nukta=indicclasses.nukta,
+ halant=indicclasses.halant,
+ ra=indicclasses.ra,
+ anudatta=indicclasses.anudatta,
+ before_postscript=indicorders.bp,
+ after_postscript=indicorders.ap,
+ before_half=indicorders.bh,
+ after_half=indicorders.ah,
+ before_subscript=indicorders.bs,
+ after_subscript=indicorders.as,
+ before_main=indicorders.bm,
+ after_main=indicorders.am,
+ }
+ indic=nil
+ indicmarks=nil
+ indicclasses=nil
+ indicorders=nil
+ characters.indicgroups=indicgroups
+end
+local consonant=indicgroups.consonant
+local independent_vowel=indicgroups.independent_vowel
+local dependent_vowel=indicgroups.dependent_vowel
+local vowel_modifier=indicgroups.vowel_modifier
+local stress_tone_mark=indicgroups.stress_tone_mark
+local pre_mark=indicgroups.pre_mark
+local above_mark=indicgroups.above_mark
+local below_mark=indicgroups.below_mark
+local post_mark=indicgroups.post_mark
+local twopart_mark=indicgroups.twopart_mark
+local nukta=indicgroups.nukta
+local halant=indicgroups.halant
+local ra=indicgroups.ra
+local anudatta=indicgroups.anudatta
+local before_postscript=indicgroups.before_postscript
+local after_postscript=indicgroups.after_postscript
+local before_half=indicgroups.before_half
+local after_half=indicgroups.after_half
+local before_subscript=indicgroups.before_subscript
+local after_subscript=indicgroups.after_subscript
+local before_main=indicgroups.before_main
+local after_main=indicgroups.after_main
+local mark_four=table.merged (
+ pre_mark,
+ above_mark,
+ below_mark,
+ post_mark
+)
+local mark_above_below_post=table.merged (
+ above_mark,
+ below_mark,
+ post_mark
+)
local zw_char={
- [0x200C]=true,
- [0x200D]=true,
-}
-local pre_mark={
- [0x093F]=true,[0x094E]=true,
- [0x0D46]=true,[0x0D47]=true,[0x0D48]=true,
-}
-local above_mark={
- [0x0900]=true,[0x0901]=true,[0x0902]=true,[0x093A]=true,
- [0x0945]=true,[0x0946]=true,[0x0947]=true,[0x0948]=true,
- [0x0951]=true,[0x0953]=true,[0x0954]=true,[0x0955]=true,
- [0xA8E0]=true,[0xA8E1]=true,[0xA8E2]=true,[0xA8E3]=true,
- [0xA8E4]=true,[0xA8E5]=true,[0xA8E6]=true,[0xA8E7]=true,
- [0xA8E8]=true,[0xA8E9]=true,[0xA8EA]=true,[0xA8EB]=true,
- [0xA8EC]=true,[0xA8ED]=true,[0xA8EE]=true,[0xA8EF]=true,
- [0xA8F0]=true,[0xA8F1]=true,
- [0x0D4E]=true,
-}
-local below_mark={
- [0x093C]=true,[0x0941]=true,[0x0942]=true,[0x0943]=true,
- [0x0944]=true,[0x094D]=true,[0x0952]=true,[0x0956]=true,
- [0x0957]=true,[0x0962]=true,[0x0963]=true,
-}
-local post_mark={
- [0x0903]=true,[0x093B]=true,[0x093E]=true,[0x0940]=true,
- [0x0949]=true,[0x094A]=true,[0x094B]=true,[0x094C]=true,
- [0x094F]=true,
-}
-local twopart_mark={
- [0x0D4A]={ 0x0D46,0x0D3E,},
- [0x0D4B]={ 0x0D47,0x0D3E,},
- [0x0D4C]={ 0x0D46,0x0D57,},
-}
-local mark_four={}
-for k,v in next,pre_mark do mark_four[k]=pre_mark end
-for k,v in next,above_mark do mark_four[k]=above_mark end
-for k,v in next,below_mark do mark_four[k]=below_mark end
-for k,v in next,post_mark do mark_four[k]=post_mark end
-local mark_above_below_post={}
-for k,v in next,above_mark do mark_above_below_post[k]=above_mark end
-for k,v in next,below_mark do mark_above_below_post[k]=below_mark end
-for k,v in next,post_mark do mark_above_below_post[k]=post_mark end
-local reorder_class={
- [0x0930]="before postscript",
- [0x093F]="before half",
- [0x0940]="after subscript",
- [0x0941]="after subscript",
- [0x0942]="after subscript",
- [0x0943]="after subscript",
- [0x0944]="after subscript",
- [0x0945]="after subscript",
- [0x0946]="after subscript",
- [0x0947]="after subscript",
- [0x0948]="after subscript",
- [0x0949]="after subscript",
- [0x094A]="after subscript",
- [0x094B]="after subscript",
- [0x094C]="after subscript",
- [0x0962]="after subscript",
- [0x0963]="after subscript",
- [0x093E]="after subscript",
- [0x0CB0]="after postscript",
- [0x0CBF]="before subscript",
- [0x0CC6]="before subscript",
- [0x0CCC]="before subscript",
- [0x0CBE]="before subscript",
- [0x0CE2]="before subscript",
- [0x0CE3]="before subscript",
- [0x0CC1]="before subscript",
- [0x0CC2]="before subscript",
- [0x0CC3]="after subscript",
- [0x0CC4]="after subscript",
- [0x0CD5]="after subscript",
- [0x0CD6]="after subscript",
+ [c_zwnj]=true,
+ [c_zwj ]=true,
}
local dflt_true={
dflt=true
}
-local dev2_defaults={
+local two_defaults={
dev2=dflt_true,
}
-local deva_defaults={
+local one_defaults={
dev2=dflt_true,
deva=dflt_true,
}
local false_flags={ false,false,false,false }
-local both_joiners_true={
- [0x200C]=true,
- [0x200D]=true,
-}
local sequence_reorder_matras={
- features={ dv01=dev2_defaults },
+ features={ dv01=two_defaults },
flags=false_flags,
name="dv01_reorder_matras",
order={ "dv01" },
@@ -21844,13 +29332,12 @@ local sequence_reorder_matras={
nofsteps=1,
steps={
{
- osdstep=true,
coverage=pre_mark,
}
}
}
local sequence_reorder_reph={
- features={ dv02=dev2_defaults },
+ features={ dv02=two_defaults },
flags=false_flags,
name="dv02_reorder_reph",
order={ "dv02" },
@@ -21858,13 +29345,12 @@ local sequence_reorder_reph={
nofsteps=1,
steps={
{
- osdstep=true,
coverage={},
}
}
}
local sequence_reorder_pre_base_reordering_consonants={
- features={ dv03=dev2_defaults },
+ features={ dv03=two_defaults },
flags=false_flags,
name="dv03_reorder_pre_base_reordering_consonants",
order={ "dv03" },
@@ -21872,54 +29358,80 @@ local sequence_reorder_pre_base_reordering_consonants={
nofsteps=1,
steps={
{
- osdstep=true,
coverage={},
}
}
}
local sequence_remove_joiners={
- features={ dv04=deva_defaults },
+ features={ dv04=one_defaults },
flags=false_flags,
name="dv04_remove_joiners",
order={ "dv04" },
type="devanagari_remove_joiners",
nofsteps=1,
steps={
- { osdstep=true,
- coverage=both_joiners_true,
+ {
+ coverage=zw_char,
},
}
}
local basic_shaping_forms={
- nukt=true,
akhn=true,
- rphf=true,
- pref=true,
- rkrf=true,
blwf=true,
+ cjct=true,
half=true,
+ nukt=true,
+ pref=true,
pstf=true,
+ rkrf=true,
+ rphf=true,
vatu=true,
- cjct=true,
}
local valid={
+ abvs=true,
akhn=true,
- rphf=true,
- pref=true,
- half=true,
blwf=true,
+ calt=true,
+ cjct=true,
+ half=true,
+ haln=true,
+ nukt=true,
+ pref=true,
+ pres=true,
pstf=true,
+ psts=true,
+ rkrf=true,
+ rphf=true,
+ vatu=true,
pres=true,
+ abvs=true,
blws=true,
psts=true,
+ haln=true,
+ calt=true,
}
+local scripts={}
+local scripts_one={ "deva","mlym","beng","gujr","guru","knda","orya","taml","telu" }
+local scripts_two={ "dev2","mlm2","bng2","gjr2","gur2","knd2","ory2","tml2","tel2" }
+local nofscripts=#scripts_one
+for i=1,nofscripts do
+ local one=scripts_one[i]
+ local two=scripts_two[i]
+ scripts[one]=true
+ scripts[two]=true
+ two_defaults[one]=dflt_true
+ one_defaults[one]=dflt_true
+ one_defaults[two]=dflt_true
+end
+local function valid_one(s) for i=1,nofscripts do if s[scripts_one[i]] then return true end end end
+local function valid_two(s) for i=1,nofscripts do if s[scripts_two[i]] then return true end end end
local function initializedevanagi(tfmdata)
local script,language=otf.scriptandlanguage(tfmdata,attr)
- if script=="deva" or script=="dev2" or script=="mlym" or script=="mlm2" then
+ if scripts[script] then
local resources=tfmdata.resources
local devanagari=resources.devanagari
if not devanagari then
- report_devanagari("adding devanagari features to font")
+ report("adding devanagari features to font")
local gsubfeatures=resources.features.gsub
local sequences=resources.sequences
local sharedfeatures=tfmdata.shared.features
@@ -21935,10 +29447,10 @@ local function initializedevanagi(tfmdata)
end
end
local insertindex=lastmatch+1
- gsubfeatures["dv01"]=dev2_defaults
- gsubfeatures["dv02"]=dev2_defaults
- gsubfeatures["dv03"]=dev2_defaults
- gsubfeatures["dv04"]=deva_defaults
+ gsubfeatures["dv01"]=two_defaults
+ gsubfeatures["dv02"]=two_defaults
+ gsubfeatures["dv03"]=two_defaults
+ gsubfeatures["dv04"]=one_defaults
local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants)
local reorder_reph=copy(sequence_reorder_reph)
local reorder_matras=copy(sequence_reorder_matras)
@@ -21986,32 +29498,29 @@ local function initializedevanagi(tfmdata)
end
end
end
- for kind,spec in next,features do
- if spec.dev2 and valid[kind] then
+ for kind,spec in next,features do
+ if valid[kind] and valid_two(spec)then
for i=1,nofsteps do
local step=steps[i]
local coverage=step.coverage
if coverage then
local reph=false
if kind=="rphf" then
- if true then
- for k,v in next,ra do
- local r=coverage[k]
- if r then
- local h=false
- for k,v in next,halant do
- local h=r[k]
- if h then
- reph=h.ligature or false
- break
- end
- end
- if reph then
+ for k,v in next,ra do
+ local r=coverage[k]
+ if r then
+ local h=false
+ for k,v in next,halant do
+ local h=r[k]
+ if h then
+ reph=h.ligature or false
break
end
end
+ if reph then
+ break
+ end
end
- else
end
end
seqsubset[#seqsubset+1]={ kind,coverage,reph }
@@ -22059,8 +29568,14 @@ local function initializedevanagi(tfmdata)
sharedfeatures["pstf"]=true
sharedfeatures["pref"]=true
sharedfeatures["dv03"]=true
- gsubfeatures ["dv03"]=dev2_defaults
+ gsubfeatures ["dv03"]=two_defaults
insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants)
+ elseif script=="taml" then
+ sharedfeatures["dv04"]=true
+sharedfeatures["pstf"]=true
+ elseif script=="tml2" then
+ else
+ report("todo: enable the right features for script %a",script)
end
end
end
@@ -22073,7 +29588,18 @@ registerotffeature {
node=initializedevanagi,
},
}
-local function deva_initialize(font,attr)
+local show_syntax_errors=false
+local function inject_syntax_error(head,current,char)
+ local signal=copy_node(current)
+ copyinjection(signal,current)
+ if pre_mark[char] then
+ setchar(signal,dotted_circle)
+ else
+ setchar(current,dotted_circle)
+ end
+ return insert_node_after(head,current,signal)
+end
+local function initialize_one(font,attr)
local tfmdata=fontdata[font]
local datasets=otf.dataset(tfmdata,font,attr)
local devanagaridata=datasets.devanagari
@@ -22101,8 +29627,8 @@ local function deva_initialize(font,attr)
end
return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache
end
-local function deva_reorder(head,start,stop,font,attr,nbspaces)
- local reph,vattu,blwfcache=deva_initialize(font,attr)
+local function reorder_one(head,start,stop,font,attr,nbspaces)
+ local reph,vattu,blwfcache=initialize_one(font,attr)
local current=start
local n=getnext(start)
local base=nil
@@ -22133,40 +29659,39 @@ local function deva_reorder(head,start,stop,font,attr,nbspaces)
lastcons=current
current=getnext(current)
if current~=stop then
- if nukta[getchar(current)] then
+ local char=getchar(current)
+ if nukta[char] then
current=getnext(current)
+ char=getchar(current)
end
- if getchar(current)==c_zwj then
- if current~=stop then
- local next=getnext(current)
- if next~=stop and halant[getchar(next)] then
- current=next
- next=getnext(current)
- local tmp=next and getnext(next) or nil
- local changestop=next==stop
- local tempcurrent=copy_node(next)
- copyinjection(tempcurrent,next)
- local nextcurrent=copy_node(current)
- copyinjection(nextcurrent,current)
- setlink(tempcurrent,nextcurrent)
- setprop(tempcurrent,a_state,s_blwf)
- tempcurrent=processcharacters(tempcurrent,font)
- setprop(tempcurrent,a_state,unsetvalue)
- if getchar(next)==getchar(tempcurrent) then
- flush_list(tempcurrent)
- local n=copy_node(current)
- copyinjection(n,current)
- setchar(current,dotted_circle)
- head=insert_node_after(head,current,n)
- else
- setchar(current,getchar(tempcurrent))
- local freenode=getnext(current)
- setlink(current,tmp)
- flush_node(freenode)
- flush_list(tempcurrent)
- if changestop then
- stop=current
- end
+ if char==c_zwj and current~=stop then
+ local next=getnext(current)
+ if next~=stop and halant[getchar(next)] then
+ current=next
+ next=getnext(current)
+ local tmp=next and getnext(next) or nil
+ local changestop=next==stop
+ local tempcurrent=copy_node(next)
+ copyinjection(tempcurrent,next)
+ local nextcurrent=copy_node(current)
+ copyinjection(nextcurrent,current)
+ setlink(tempcurrent,nextcurrent)
+ setprop(tempcurrent,a_state,s_blwf)
+ tempcurrent=processcharacters(tempcurrent,font)
+ setprop(tempcurrent,a_state,unsetvalue)
+ if getchar(next)==getchar(tempcurrent) then
+ flush_list(tempcurrent)
+ if show_syntax_errors then
+ head,current=inject_syntax_error(head,current,char)
+ end
+ else
+ setchar(current,getchar(tempcurrent))
+ local freenode=getnext(current)
+ setlink(current,tmp)
+ flush_node(freenode)
+ flush_list(tempcurrent)
+ if changestop then
+ stop=current
end
end
end
@@ -22439,9 +29964,11 @@ function handlers.devanagari_reorder_reph(head,start)
local startprev=nil
local startfont=getfont(start)
local startattr=getprop(start,a_syllabe)
+ ::step_1::
+ ::step_2::
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
+ if char and getprop(current,a_syllabe)==startattr then
if halant[char] and not getprop(current,a_state) then
local next=getnext(current)
if next then
@@ -22464,16 +29991,17 @@ function handlers.devanagari_reorder_reph(head,start)
break
end
end
+ ::step_3::
+ ::step_4::
if not startnext then
current=getnext(start)
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
+ if char and getprop(current,a_syllabe)==startattr then
if getprop(current,a_state)==s_pstf then
startnext=getnext(start)
head=remove_node(head,start)
- local prev=getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
start=startnext
startattr=getprop(start,a_syllabe)
@@ -22485,13 +30013,14 @@ function handlers.devanagari_reorder_reph(head,start)
end
end
end
+ ::step_5::
if not startnext then
current=getnext(start)
local c=nil
while current do
local char=ischar(current,startfont)
- if char and getprop(current,a_syllabe)==startattr then
- if not c and mark_above_below_post[char] and reorder_class[char]~="after subscript" then
+ if char and getprop(current,a_syllabe)==startattr then
+ if not c and mark_above_below_post[char] and not after_subscript[char] then
c=current
end
current=getnext(current)
@@ -22502,19 +30031,19 @@ function handlers.devanagari_reorder_reph(head,start)
if c then
startnext=getnext(start)
head=remove_node(head,start)
- local prev=getprev(c)
- setlink(prev,start)
+ setlink(getprev(c),start)
setlink(start,c)
start=startnext
startattr=getprop(start,a_syllabe)
end
end
+ ::step_6::
if not startnext then
current=start
local next=getnext(current)
while next do
local nextchar=ischar(next,startfont)
- if nextchar and getprop(next,a_syllabe)==startattr then
+ if nextchar and getprop(next,a_syllabe)==startattr then
current=next
next=getnext(current)
else
@@ -22524,8 +30053,7 @@ function handlers.devanagari_reorder_reph(head,start)
if start~=current then
startnext=getnext(start)
head=remove_node(head,start)
- local next=getnext(current)
- setlink(start,next)
+ setlink(start,getnext(current))
setlink(current,start)
start=startnext
end
@@ -22573,8 +30101,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start)
if not consonant[char] and getprop(current,a_state) then
startnext=getnext(start)
removenode(start,start)
- local prev=getprev(current)
- setlink(prev,start)
+ setlink(getprev(current),start)
setlink(start,current)
start=startnext
break
@@ -22608,12 +30135,12 @@ function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replaceme
setnext(prev)
end
if head==start then
- head=stop
+ head=stop
end
flush_list(start)
return head,stop,true
end
-local function dev2_initialize(font,attr)
+local function initialize_two(font,attr)
local devanagari=fontdata[font].resources.devanagari
if devanagari then
return devanagari.seqsubset or {},devanagari.reorderreph or {}
@@ -22621,8 +30148,8 @@ local function dev2_initialize(font,attr)
return {},{}
end
end
-local function dev2_reorder(head,start,stop,font,attr,nbspaces)
- local seqsubset,reorderreph=dev2_initialize(font,attr)
+local function reorder_two(head,start,stop,font,attr,nbspaces)
+ local seqsubset,reorderreph=initialize_two(font,attr)
local reph=false
local halfpos=nil
local basepos=nil
@@ -22647,8 +30174,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if found[n] then
local afternext=next~=stop and getnext(next)
if afternext and zw_char[getchar(afternext)] then
- current=next
- current=getnext(current)
+ current=afternext
elseif current==start then
setprop(current,a_state,s_rphf)
current=next
@@ -22774,7 +30300,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
next=getnext(current)
local tmp=getnext(next)
local changestop=next==stop
- setnext(next,nil)
+ setnext(next)
setprop(current,a_state,s_pref)
current=processcharacters(current,font)
setprop(current,a_state,s_blwf)
@@ -22784,10 +30310,9 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
setprop(current,a_state,unsetvalue)
if halant[getchar(current)] then
setnext(getnext(current),tmp)
- local nc=copy_node(current)
- copyinjection(nc,current)
- setchar(current,dotted_circle)
- head=insert_node_after(head,current,nc)
+ if show_syntax_errors then
+ head,current=inject_syntax_error(head,current,char)
+ end
else
setnext(current,tmp)
if changestop then
@@ -22867,8 +30392,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
end
start=current
end
- local prev=getprev(halfpos)
- setlink(prev,current)
+ setlink(getprev(halfpos),current)
setlink(current,halfpos)
halfpos=current
elseif above_mark[char] then
@@ -22898,8 +30422,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if current==stop then
stop=prev
end
- local next=getnext(target)
- setlink(current,next)
+ setlink(current,getnext(target))
setlink(target,current)
end
end
@@ -22924,8 +30447,7 @@ local function dev2_reorder(head,start,stop,font,attr,nbspaces)
if stop==next then
stop=current
end
- local prev=getprev(c)
- setlink(prev,next)
+ setlink(getprev(c),next)
local nextnext=getnext(next)
setnext(current,nextnext)
local nextnextnext=getnext(nextnext)
@@ -23159,7 +30681,7 @@ local function analyze_next_chars_two(c,font)
if not v then
return c
end
- if v==c_anudatta then
+ if anudatta[v] then
c=n
n=getnext(c)
if not n then
@@ -23254,31 +30776,20 @@ local function analyze_next_chars_two(c,font)
return c
end
end
-local function inject_syntax_error(head,current,mark)
- local signal=copy_node(current)
- copyinjection(signal,current)
- if mark==pre_mark then
- setchar(signal,dotted_circle)
- else
- setchar(current,dotted_circle)
- end
- return insert_node_after(head,current,signal)
-end
-function methods.deva(head,font,attr)
- head=tonut(head)
+local function method_one(head,font,attr)
local current=head
local start=true
local done=false
local nbspaces=0
while current do
- local char=ischar(current,font)
+ local char=ischar(current,font)
if char then
done=true
local syllablestart=current
local syllableend=nil
local c=current
local n=getnext(c)
- local first=char
+ local first=char
if n and ra[first] then
local second=ischar(n,font)
if second and halant[second] then
@@ -23306,10 +30817,10 @@ function methods.deva(head,font,attr)
end
end
if standalone then
- local syllableend=analyze_next_chars_one(c,font,2)
- current=getnext(syllableend)
+ local syllableend=analyze_next_chars_one(c,font,2)
+ current=getnext(syllableend)
if syllablestart~=syllableend then
- head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current=getnext(current)
end
else
@@ -23406,7 +30917,7 @@ function methods.deva(head,font,attr)
end
end
if syllablestart~=syllableend then
- head,current,nbspaces=deva_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces)
current=getnext(current)
end
elseif independent_vowel[char] then
@@ -23427,9 +30938,11 @@ function methods.deva(head,font,attr)
end
end
else
- local mark=mark_four[char]
- if mark then
- head,current=inject_syntax_error(head,current,mark)
+ if show_syntax_errors then
+ local mark=mark_four[char]
+ if mark then
+ head,current=inject_syntax_error(head,current,char)
+ end
end
current=getnext(current)
end
@@ -23442,11 +30955,9 @@ function methods.deva(head,font,attr)
if nbspaces>0 then
head=replace_all_nbsp(head)
end
- head=tonode(head)
return head,done
end
-function methods.dev2(head,font,attr)
- head=tonut(head)
+local function method_two(head,font,attr)
local current=head
local start=true
local done=false
@@ -23469,7 +30980,7 @@ function methods.dev2(head,font,attr)
local nextnextchar=ischar(n,font)
if nextnextchar then
c=n
- char=nextnextchar
+ char=nextnextchar
end
end
end
@@ -23508,14 +31019,14 @@ function methods.dev2(head,font,attr)
end
end
if syllableend and syllablestart~=syllableend then
- head,current,nbspaces=dev2_reorder(head,syllablestart,syllableend,font,attr,nbspaces)
+ head,current,nbspaces=reorder_two(head,syllablestart,syllableend,font,attr,nbspaces)
end
- if not syllableend then
+ if not syllableend and show_syntax_errors then
local char=ischar(current,font)
if char and not getprop(current,a_state) then
local mark=mark_four[char]
if mark then
- head,current=inject_syntax_error(head,current,mark)
+ head,current=inject_syntax_error(head,current,char)
end
end
end
@@ -23525,11 +31036,12 @@ function methods.dev2(head,font,attr)
if nbspaces>0 then
head=replace_all_nbsp(head)
end
- head=tonode(head)
return head,done
end
-methods.mlym=methods.deva
-methods.mlm2=methods.dev2
+for i=1,nofscripts do
+ methods[scripts_one[i]]=method_one
+ methods[scripts_two[i]]=method_two
+end
end -- closure
@@ -23537,127 +31049,144 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-ocl']={
version=1.001,
- comment="companion to font-otf.lua (context)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local tostring,next,format=tostring,next,string.format
+local tostring,tonumber,next=tostring,tonumber,next
local round,max=math.round,math.round
+local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash
+local setmetatableindex=table.setmetatableindex
local formatters=string.formatters
local tounicode=fonts.mappings.tounicode
+local helpers=fonts.helpers
+local charcommand=helpers.commands.char
+local rightcommand=helpers.commands.right
+local leftcommand=helpers.commands.left
+local downcommand=helpers.commands.down
local otf=fonts.handlers.otf
-local f_color=formatters["pdf:direct:%f %f %f rg"]
-local f_gray=formatters["pdf:direct:%f g"]
-local s_black="pdf:direct:0 g"
+local f_color=formatters["%.3f %.3f %.3f rg"]
+local f_gray=formatters["%.3f g"]
if context then
- local startactualtext=nil
- local stopactualtext=nil
- function otf.getactualtext(s)
- if not startactualtext then
- startactualtext=backends.codeinjections.startunicodetoactualtextdirect
- stopactualtext=backends.codeinjections.stopunicodetoactualtextdirect
- end
- return startactualtext(s),stopactualtext()
- end
+
+--removed
+
else
local tounicode=fonts.mappings.tounicode16
function otf.getactualtext(s)
return
- "/Span << /ActualText <feff"..n.."> >> BDC",
+ "/Span << /ActualText <feff"..s.."> >> BDC",
"EMC"
end
end
local sharedpalettes={}
+local hash=setmetatableindex(function(t,k)
+ local v={ "pdf","direct",k }
+ t[k]=v
+ return v
+end)
if context then
- local graytorgb=attributes.colors.graytorgb
- local cmyktorgb=attributes.colors.cmyktorgb
+
+--removed
+
+else
function otf.registerpalette(name,values)
sharedpalettes[name]=values
for i=1,#values do
local v=values[i]
- local r,g,b
- local s=v.s
- if s then
- r,g,b=graytorgb(s)
- else
- local c,m,y,k=v.c,v.m,v.y,v.k
- if c or m or y or k then
- r,g,b=cmyktorgb(c or 0,m or 0,y or 0,k or 0)
- else
- r,g,b=v.r,v.g,v.b
- end
- end
- values[i]={
- max(r and round(r*255) or 0,255),
- max(g and round(g*255) or 0,255),
- max(b and round(b*255) or 0,255)
- }
+ values[i]=hash[f_color(
+ max(round((v.r or 0)*255),255)/255,
+ max(round((v.g or 0)*255),255)/255,
+ max(round((v.b or 0)*255),255)/255
+ )]
end
end
-else
- function otf.registerpalette(name,values)
- sharedpalettes[name]=values
- for i=1,#values do
- local v=values[i]
- values[i]={
- max(round((v.r or 0)*255),255),
- max(round((v.g or 0)*255),255),
- max(round((v.b or 0)*255),255)
- }
+end
+local function convert(t,k)
+ local v={}
+ for i=1,#k do
+ local p=k[i]
+ local r,g,b=p[1],p[2],p[3]
+ if r==g and g==b then
+ v[i]=hash[f_gray(r/255)]
+ else
+ v[i]=hash[f_color(r/255,g/255,b/255)]
end
end
+ t[k]=v
+ return v
+end
+local start={ "pdf","mode","font" }
+local push={ "pdf","page","q" }
+local pop={ "pdf","page","Q" }
+if not LUATEXFUNCTIONALITY or LUATEXFUNCTIONALITY<6472 then
+ start={ "nop" }
end
-local function initializecolr(tfmdata,kind,value)
+local function initialize(tfmdata,kind,value)
if value then
- local palettes=tfmdata.resources.colorpalettes
+ local resources=tfmdata.resources
+ local palettes=resources.colorpalettes
if palettes then
- local palette=sharedpalettes[value] or palettes[tonumber(value) or 1] or palettes[1] or {}
- local classes=#palette
+ local converted=resources.converted
+ if not converted then
+ converted=setmetatableindex(convert)
+ resources.converted=converted
+ end
+ local colorvalues=sharedpalettes[value] or converted[palettes[tonumber(value) or 1] or palettes[1]] or {}
+ local classes=#colorvalues
if classes==0 then
return
end
local characters=tfmdata.characters
local descriptions=tfmdata.descriptions
local properties=tfmdata.properties
- local colorvalues={}
properties.virtualized=true
tfmdata.fonts={
{ id=0 }
}
- for i=1,classes do
- local p=palette[i]
- local r,g,b=p[1],p[2],p[3]
- if r==g and g==b then
- colorvalues[i]={ "special",f_gray(r/255) }
- else
- colorvalues[i]={ "special",f_color(r/255,g/255,b/255) }
- end
- end
local getactualtext=otf.getactualtext
+ local default=colorvalues[#colorvalues]
+ local b,e=getactualtext(tounicode(0xFFFD))
+ local actualb={ "pdf","page",b }
+ local actuale={ "pdf","page",e }
for unicode,character in next,characters do
local description=descriptions[unicode]
if description then
local colorlist=description.colors
if colorlist then
- local b,e=getactualtext(tounicode(characters[unicode].unicode or 0xFFFD))
+ local u=description.unicode or characters[unicode].unicode
local w=character.width or 0
local s=#colorlist
+ local goback=w~=0 and leftcommand[w] or nil
local t={
- { "special","pdf:page:q" },
- { "special","pdf:raw:"..b }
+ start,
+ not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) }
}
- local n=#t
+ local n=2
+ local l=nil
+ local f=false
for i=1,s do
local entry=colorlist[i]
- n=n+1 t[n]=colorvalues[entry.class] or s_black
- n=n+1 t[n]={ "char",entry.slot }
- if s>1 and i<s and w~=0 then
- n=n+1 t[n]={ "right",-w }
+ local v=colorvalues[entry.class] or default
+ if v and l~=v then
+ if f then
+ n=n+1 t[n]=pop
+ end
+ n=n+1 t[n]=push
+ f=true
+ n=n+1 t[n]=v
+ l=v
+ end
+ n=n+1 t[n]=charcommand[entry.slot]
+ if s>1 and i<s and goback then
+ n=n+1 t[n]=goback
end
end
- n=n+1 t[n]={ "special","pdf:page:"..e }
- n=n+1 t[n]={ "special","pdf:raw:Q" }
+ if f then
+ n=n+1 t[n]=pop
+ end
+ n=n+1 t[n]=actuale
character.commands=t
end
end
@@ -23669,48 +31198,101 @@ fonts.handlers.otf.features.register {
name="colr",
description="color glyphs",
manipulators={
- base=initializecolr,
- node=initializecolr,
+ base=initialize,
+ node=initialize,
}
}
-local otfsvg=otf.svg or {}
-otf.svg=otfsvg
-otf.svgenabled=true
do
local nofstreams=0
- local f_name=formatters[ [[svg-glyph-%05i]] ]
+ local f_name=formatters[ [[pdf-glyph-%05i]] ]
local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ]
+ local hashed={}
local cache={}
- function otfsvg.storepdfdata(pdf)
- nofstreams=nofstreams+1
- local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams))
- cache[n]=o
- return nil,f_used(n),nil
+ if epdf then
+ local openpdf=epdf.openMemStream
+ function otf.storepdfdata(pdf)
+ local done=hashed[pdf]
+ if not done then
+ nofstreams=nofstreams+1
+ local o,n=openpdf(pdf,#pdf,f_name(nofstreams))
+ cache[n]=o
+ done=f_used(n)
+ hashed[pdf]=done
+ end
+ return nil,done,nil
+ end
+ else
+ local openpdf=pdfe.new
+ function otf.storepdfdata(pdf)
+ local done=hashed[pdf]
+ if not done then
+ nofstreams=nofstreams+1
+ local f=f_name(nofstreams)
+ local n=openpdf(pdf,#pdf,f)
+ done=f_used(n)
+ hashed[pdf]=done
+ end
+ return nil,done,nil
+ end
end
- if context then
- local storepdfdata=otfsvg.storepdfdata
- local initialized=false
- function otfsvg.storepdfdata(pdf)
- if not initialized then
- if resolvers.setmemstream then
- local f_setstream=formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ]
- local f_getstream=formatters[ [[memstream:///svg-glyph-%05i]] ]
- local f_nilstream=formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ]
- storepdfdata=function(pdf)
- nofstreams=nofstreams+1
- return
- f_setstream(nofstreams,pdf),
- f_getstream(nofstreams),
- f_nilstream(nofstreams)
- end
- otfsvg.storepdfdata=storepdfdata
+end
+local function pdftovirtual(tfmdata,pdfshapes,kind)
+ if not tfmdata or not pdfshapes or not kind then
+ return
+ end
+ local characters=tfmdata.characters
+ local properties=tfmdata.properties
+ local parameters=tfmdata.parameters
+ local hfactor=parameters.hfactor
+ properties.virtualized=true
+ tfmdata.fonts={
+ { id=0 }
+ }
+ local getactualtext=otf.getactualtext
+ local storepdfdata=otf.storepdfdata
+ local b,e=getactualtext(tounicode(0xFFFD))
+ local actualb={ "pdf","page",b }
+ local actuale={ "pdf","page",e }
+ for unicode,character in sortedhash(characters) do
+ local index=character.index
+ if index then
+ local pdf=pdfshapes[index]
+ local typ=type(pdf)
+ local data=nil
+ local dx=nil
+ local dy=nil
+ if typ=="table" then
+ data=pdf.data
+ dx=pdf.dx or 0
+ dy=pdf.dy or 0
+ elseif typ=="string" then
+ data=pdf
+ dx=0
+ dy=0
+ end
+ if data then
+ local setcode,name,nilcode=storepdfdata(data)
+ if name then
+ local bt=unicode and getactualtext(unicode)
+ local wd=character.width or 0
+ local ht=character.height or 0
+ local dp=character.depth or 0
+ character.commands={
+ not unicode and actualb or { "pdf","page",(getactualtext(unicode)) },
+ downcommand[dp+dy*hfactor],
+ rightcommand[dx*hfactor],
+ { "image",{ filename=name,width=wd,height=ht,depth=dp } },
+ actuale,
+ }
+ character[kind]=true
end
- initialized=true
end
- return storepdfdata(pdf)
end
end
end
+local otfsvg=otf.svg or {}
+otf.svg=otfsvg
+otf.svgenabled=true
do
local report_svg=logs.reporter("fonts","svg conversion")
local loaddata=io.loaddata
@@ -23730,52 +31312,68 @@ do
return entry.data
end
end
+ local runner=sandbox and sandbox.registerrunner {
+ name="otfsvg",
+ program="inkscape",
+ method="pipeto",
+ template="--shell > temp-otf-svg-shape.log",
+ reporter=report_svg,
+ }
+ if not runner then
+ runner=function()
+ return io.open("inkscape --shell > temp-otf-svg-shape.log","w")
+ end
+ end
function otfsvg.topdf(svgshapes)
- local inkscape=io.popen("inkscape --shell > temp-otf-svg-shape.log","w")
local pdfshapes={}
- local nofshapes=#svgshapes
- local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
- local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
- local f_convert=formatters["%s --export-pdf=%s\n"]
- local filterglyph=otfsvg.filterglyph
- report_svg("processing %i svg containers",nofshapes)
- statistics.starttiming()
- for i=1,nofshapes do
- local entry=svgshapes[i]
- for index=entry.first,entry.last do
- local data=filterglyph(entry,index)
- if data and data~="" then
- local svgfile=f_svgfile(index)
- local pdffile=f_pdffile(index)
- savedata(svgfile,data)
- inkscape:write(f_convert(svgfile,pdffile))
- pdfshapes[index]=true
- end
- end
- end
- inkscape:write("quit\n")
- inkscape:close()
- report_svg("processing %i pdf results",nofshapes)
- for index in next,pdfshapes do
- local svgfile=f_svgfile(index)
- local pdffile=f_pdffile(index)
- pdfshapes[index]=loaddata(pdffile)
- remove(svgfile)
- remove(pdffile)
- end
- statistics.stoptiming()
- if statistics.elapsedseconds then
- report_svg("svg conversion time %s",statistics.elapsedseconds())
+ local inkscape=runner()
+ if inkscape then
+ local nofshapes=#svgshapes
+ local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"]
+ local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"]
+ local f_convert=formatters["%s --export-pdf=%s\n"]
+ local filterglyph=otfsvg.filterglyph
+ local nofdone=0
+ report_svg("processing %i svg containers",nofshapes)
+ statistics.starttiming()
+ for i=1,nofshapes do
+ local entry=svgshapes[i]
+ for index=entry.first,entry.last do
+ local data=filterglyph(entry,index)
+ if data and data~="" then
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
+ savedata(svgfile,data)
+ inkscape:write(f_convert(svgfile,pdffile))
+ pdfshapes[index]=true
+ nofdone=nofdone+1
+ if nofdone%100==0 then
+ report_svg("%i shapes processed",nofdone)
+ end
+ end
+ end
+ end
+ inkscape:write("quit\n")
+ inkscape:close()
+ report_svg("processing %i pdf results",nofshapes)
+ for index in next,pdfshapes do
+ local svgfile=f_svgfile(index)
+ local pdffile=f_pdffile(index)
+ pdfshapes[index]=loaddata(pdffile)
+ remove(svgfile)
+ remove(pdffile)
+ end
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_svg("svg conversion time %s",statistics.elapsedseconds() or "-")
+ end
end
return pdfshapes
end
end
local function initializesvg(tfmdata,kind,value)
if value and otf.svgenabled then
- local characters=tfmdata.characters
- local descriptions=tfmdata.descriptions
- local properties=tfmdata.properties
- local svg=properties.svg
+ local svg=tfmdata.properties.svg
local hash=svg and svg.hash
local timestamp=svg and svg.timestamp
if not hash then
@@ -23792,40 +31390,7 @@ local function initializesvg(tfmdata,kind,value)
timestamp=timestamp,
})
end
- if not pdfshapes or not next(pdfshapes) then
- return
- end
- properties.virtualized=true
- tfmdata.fonts={
- { id=0 }
- }
- local getactualtext=otf.getactualtext
- local storepdfdata=otfsvg.storepdfdata
- local nop={ "nop" }
- for unicode,character in next,characters do
- local index=character.index
- if index then
- local pdf=pdfshapes[index]
- if pdf then
- local setcode,name,nilcode=storepdfdata(pdf)
- if name then
- local bt,et=getactualtext(unicode)
- local wd=character.width or 0
- local ht=character.height or 0
- local dp=character.depth or 0
- character.commands={
- { "special","pdf:direct:"..bt },
- { "down",dp },
- setcode and { "lua",setcode } or nop,
- { "image",{ filename=name,width=wd,height=ht,depth=dp } },
- nilcode and { "lua",nilcode } or nop,
- { "special","pdf:direct:"..et },
- }
- character.svg=true
- end
- end
- end
- end
+ pdftovirtual(tfmdata,pdfshapes,"svg")
end
end
fonts.handlers.otf.features.register {
@@ -23836,6 +31401,91 @@ fonts.handlers.otf.features.register {
node=initializesvg,
}
}
+local otfsbix=otf.sbix or {}
+otf.sbix=otfsbix
+otf.sbixenabled=true
+do
+ local report_sbix=logs.reporter("fonts","sbix conversion")
+ local loaddata=io.loaddata
+ local savedata=io.savedata
+ local remove=os.remove
+ local runner=sandbox and sandbox.registerrunner {
+ name="otfsbix",
+ program="gm",
+ template="convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log",
+ }
+ if not runner then
+ runner=function()
+ return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log")
+ end
+ end
+ function otfsbix.topdf(sbixshapes)
+ local pdfshapes={}
+ local sbixfile="temp-otf-sbix-shape.sbix"
+ local pdffile="temp-otf-sbix-shape.pdf"
+ local nofdone=0
+ local indices=sortedkeys(sbixshapes)
+ local nofindices=#indices
+ report_sbix("processing %i sbix containers",nofindices)
+ statistics.starttiming()
+ for i=1,nofindices do
+ local index=indices[i]
+ local entry=sbixshapes[index]
+ local data=entry.data
+ local x=entry.x
+ local y=entry.y
+ savedata(sbixfile,data)
+ runner()
+ pdfshapes[index]={
+ x=x~=0 and x or nil,
+ y=y~=0 and y or nil,
+ data=loaddata(pdffile),
+ }
+ nofdone=nofdone+1
+ if nofdone%100==0 then
+ report_sbix("%i shapes processed",nofdone)
+ end
+ end
+ report_sbix("processing %i pdf results",nofindices)
+ remove(sbixfile)
+ remove(pdffile)
+ statistics.stoptiming()
+ if statistics.elapsedseconds then
+ report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-")
+ end
+ return pdfshapes
+ end
+end
+local function initializesbix(tfmdata,kind,value)
+ if value and otf.sbixenabled then
+ local sbix=tfmdata.properties.sbix
+ local hash=sbix and sbix.hash
+ local timestamp=sbix and sbix.timestamp
+ if not hash then
+ return
+ end
+ local pdffile=containers.read(otf.pdfcache,hash)
+ local pdfshapes=pdffile and pdffile.pdfshapes
+ if not pdfshapes or pdffile.timestamp~=timestamp then
+ local sbixfile=containers.read(otf.sbixcache,hash)
+ local sbixshapes=sbixfile and sbixfile.sbixshapes
+ pdfshapes=sbixshapes and otfsbix.topdf(sbixshapes) or {}
+ containers.write(otf.pdfcache,hash,{
+ pdfshapes=pdfshapes,
+ timestamp=timestamp,
+ })
+ end
+ pdftovirtual(tfmdata,pdfshapes,"sbix")
+ end
+end
+fonts.handlers.otf.features.register {
+ name="sbix",
+ description="sbix glyphs",
+ manipulators={
+ base=initializesbix,
+ node=initializesbix,
+ }
+}
end -- closure
@@ -23843,21 +31493,25 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-otc']={
version=1.001,
- comment="companion to font-otf.lua (context)",
+ comment="companion to font-ini.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
-local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkeys,table.tohash
+local insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash
local type,next=type,next
local lpegmatch=lpeg.match
local utfbyte,utflen=utf.byte,utf.len
+local sortedhash=table.sortedhash
local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end)
local report_otf=logs.reporter("fonts","otf loading")
local fonts=fonts
local otf=fonts.handlers.otf
local registerotffeature=otf.features.register
local setmetatableindex=table.setmetatableindex
+local checkmerge=fonts.helpers.checkmerge
+local checkflags=fonts.helpers.checkflags
+local checksteps=fonts.helpers.checksteps
local normalized={
substitution="substitution",
single="substitution",
@@ -23866,6 +31520,7 @@ local normalized={
multiple="multiple",
kern="kern",
pair="pair",
+ single="single",
chainsubstitution="chainsubstitution",
chainposition="chainposition",
}
@@ -23876,6 +31531,7 @@ local types={
multiple="gsub_multiple",
kern="gpos_pair",
pair="gpos_pair",
+ single="gpos_single",
chainsubstitution="gsub_contextchain",
chainposition="gpos_contextchain",
}
@@ -24007,13 +31663,15 @@ local function addfeature(data,feature,specifications)
local coveractions=coverup.actions
local stepkey=coverup.stepkey
local register=coverup.register
- local function prepare_substitution(list,featuretype)
+ local function prepare_substitution(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip=skip+1
+ else
if type(replacement)=="table" then
replacement=replacement[1]
end
@@ -24024,25 +31682,23 @@ local function addfeature(data,feature,specifications)
else
skip=skip+1
end
- else
- skip=skip+1
end
end
return coverage
end
- local function prepare_alternate(list,featuretype)
+ local function prepare_alternate(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip=skip+1
elseif type(replacement)=="table" then
local r={}
for i=1,#replacement do
local u=tounicode(replacement[i])
- r[i]=descriptions[u] and u or unicode
+ r[i]=(nocheck or descriptions[u]) and u or unicode
end
cover(coverage,unicode,r)
done=done+1
@@ -24058,19 +31714,19 @@ local function addfeature(data,feature,specifications)
end
return coverage
end
- local function prepare_multiple(list,featuretype)
+ local function prepare_multiple(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if not description then
+ if not nocheck and not description then
skip=skip+1
elseif type(replacement)=="table" then
local r,n={},0
for i=1,#replacement do
local u=tounicode(replacement[i])
- if descriptions[u] then
+ if nocheck or descriptions[u] then
n=n+1
r[n]=u
end
@@ -24093,13 +31749,15 @@ local function addfeature(data,feature,specifications)
end
return coverage
end
- local function prepare_ligature(list,featuretype)
+ local function prepare_ligature(list,featuretype,nocheck)
local coverage={}
local cover=coveractions[featuretype]
for code,ligature in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
- if description then
+ if not nocheck and not description then
+ skip=skip+1
+ else
if type(ligature)=="string" then
ligature={ lpegmatch(splitter,ligature) }
end
@@ -24107,7 +31765,7 @@ local function addfeature(data,feature,specifications)
for i=1,#ligature do
local l=ligature[i]
local u=tounicode(l)
- if descriptions[u] then
+ if nocheck or descriptions[u] then
ligature[i]=u
else
present=false
@@ -24120,15 +31778,18 @@ local function addfeature(data,feature,specifications)
else
skip=skip+1
end
- else
- skip=skip+1
end
end
return coverage
end
+ local function resetspacekerns()
+ data.properties.hasspacekerns=true
+ data.resources .spacekerns=nil
+ end
local function prepare_kern(list,featuretype)
local coverage={}
local cover=coveractions[featuretype]
+ local isspace=false
for code,replacement in next,list do
local unicode=tounicode(code)
local description=descriptions[unicode]
@@ -24138,11 +31799,17 @@ local function addfeature(data,feature,specifications)
local u=tounicode(k)
if u then
r[u]=v
+ if u==32 then
+ isspace=true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done=done+1
+ if unicode==32 then
+ isspace=true
+ end
else
skip=skip+1
end
@@ -24150,6 +31817,9 @@ local function addfeature(data,feature,specifications)
skip=skip+1
end
end
+ if isspace then
+ resetspacekerns()
+ end
return coverage
end
local function prepare_pair(list,featuretype)
@@ -24165,11 +31835,17 @@ local function addfeature(data,feature,specifications)
local u=tounicode(k)
if u then
r[u]=v
+ if u==32 then
+ isspace=true
+ end
end
end
if next(r) then
cover(coverage,unicode,r)
done=done+1
+ if unicode==32 then
+ isspace=true
+ end
else
skip=skip+1
end
@@ -24177,19 +31853,21 @@ local function addfeature(data,feature,specifications)
skip=skip+1
end
end
+ if isspace then
+ resetspacekerns()
+ end
else
report_otf("unknown cover type %a",featuretype)
end
return coverage
end
+ local prepare_single=prepare_pair
local function prepare_chain(list,featuretype,sublookups)
local rules=list.rules
local coverage={}
if rules then
local rulehash={}
local rulesize=0
- local sequence={}
- local nofsequences=0
local lookuptype=types[featuretype]
for nofrules=1,#rules do
local rule=rules[nofrules]
@@ -24220,14 +31898,29 @@ local function addfeature(data,feature,specifications)
local lookups=rule.lookups or false
local subtype=nil
if lookups and sublookups then
- for k,v in next,lookups do
- local lookup=sublookups[v]
- if lookup then
- lookups[k]=lookup
- if not subtype then
- subtype=lookup.type
+ for k,v in sortedhash(lookups) do
+ local t=type(v)
+ if t=="table" then
+ for i=1,#v do
+ local vi=v[i]
+ if type(vi)~="table" then
+ v[i]={ vi }
+ end
+ end
+ elseif t=="number" then
+ local lookup=sublookups[v]
+ if lookup then
+ lookups[k]={ lookup }
+ if not subtype then
+ subtype=lookup.type
+ end
+ elseif v==0 then
+ lookups[k]={ { type="gsub_remove" } }
+ else
+ lookups[k]=false
end
else
+ lookups[k]=false
end
end
end
@@ -24256,14 +31949,16 @@ local function addfeature(data,feature,specifications)
replacements,
subtype,
}
- for unic in next,sequence[start] do
+ for unic in sortedhash(sequence[start]) do
local cu=coverage[unic]
if not cu then
coverage[unic]=rulehash
end
end
+ sequence.n=nofsequences
end
end
+ rulehash.n=rulesize
end
return coverage
end
@@ -24301,7 +31996,7 @@ local function addfeature(data,feature,specifications)
local s=sequences[i]
local f=s.features
if f then
- for k in next,f do
+ for k in sortedhash(f) do
if k==position then
index=i
break
@@ -24349,12 +32044,15 @@ local function addfeature(data,feature,specifications)
local askedsteps=specification.steps or specification.subtables or { specification.data } or {}
local featuretype=normalized[specification.type or "substitution"] or "substitution"
local featureflags=specification.flags or noflags
+ local nocheck=specification.nocheck
+ local futuresteps=specification.futuresteps
local featureorder=specification.order or { feature }
local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0
local nofsteps=0
local steps={}
local sublookups=specification.lookups
local category=nil
+ checkflags(specification,resources)
if sublookups then
local s={}
for i=1,#sublookups do
@@ -24369,28 +32067,34 @@ local function addfeature(data,feature,specifications)
local coverage=nil
local format=nil
if featuretype=="substitution" then
- coverage=prepare_substitution(list,featuretype)
+ coverage=prepare_substitution(list,featuretype,nocheck)
elseif featuretype=="ligature" then
- coverage=prepare_ligature(list,featuretype)
+ coverage=prepare_ligature(list,featuretype,nocheck)
elseif featuretype=="alternate" then
- coverage=prepare_alternate(list,featuretype)
+ coverage=prepare_alternate(list,featuretype,nocheck)
elseif featuretype=="multiple" then
- coverage=prepare_multiple(list,featuretype)
- elseif featuretype=="kern" then
- format="kern"
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
+ format=featuretype
coverage=prepare_kern(list,featuretype)
elseif featuretype=="pair" then
format="pair"
coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ format="single"
+ coverage=prepare_single(list,featuretype)
end
if coverage and next(coverage) then
nofsteps=nofsteps+1
steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources)
end
end
+ checkmerge(specification)
+ checksteps(specification)
s[i]={
[stepkey]=steps,
nofsteps=nofsteps,
+ flags=featureflags,
type=types[featuretype],
}
end
@@ -24402,24 +32106,28 @@ local function addfeature(data,feature,specifications)
local format=nil
if featuretype=="substitution" then
category="gsub"
- coverage=prepare_substitution(list,featuretype)
+ coverage=prepare_substitution(list,featuretype,nocheck)
elseif featuretype=="ligature" then
category="gsub"
- coverage=prepare_ligature(list,featuretype)
+ coverage=prepare_ligature(list,featuretype,nocheck)
elseif featuretype=="alternate" then
category="gsub"
- coverage=prepare_alternate(list,featuretype)
+ coverage=prepare_alternate(list,featuretype,nocheck)
elseif featuretype=="multiple" then
category="gsub"
- coverage=prepare_multiple(list,featuretype)
- elseif featuretype=="kern" then
+ coverage=prepare_multiple(list,featuretype,nocheck)
+ elseif featuretype=="kern" or featuretype=="move" then
category="gpos"
- format="kern"
+ format=featuretype
coverage=prepare_kern(list,featuretype)
elseif featuretype=="pair" then
category="gpos"
format="pair"
coverage=prepare_pair(list,featuretype)
+ elseif featuretype=="single" then
+ category="gpos"
+ format="single"
+ coverage=prepare_single(list,featuretype)
elseif featuretype=="chainsubstitution" then
category="gsub"
coverage=prepare_chain(list,featuretype,sublookups)
@@ -24455,6 +32163,9 @@ local function addfeature(data,feature,specifications)
nofsteps=nofsteps,
type=steptype,
}
+ checkflags(sequence,resources)
+ checkmerge(sequence)
+ checksteps(sequence)
local first,last=getrange(sequences,category)
inject(specification,sequences,sequence,first,last,category,feature)
local features=fontfeatures[category]
@@ -24498,10 +32209,13 @@ function otf.addfeature(name,specification)
specification,name=validspecification(specification,name)
if name and specification then
local slot=knownfeatures[name]
- if slot then
- else
+ if not slot then
slot=#extrafeatures+1
knownfeatures[name]=slot
+ elseif specification.overload==false then
+ slot=#extrafeatures+1
+ knownfeatures[name]=slot
+ else
end
specification.name=name
extrafeatures[slot]=specification
@@ -24515,98 +32229,6 @@ local function enhance(data,filename,raw)
end
otf.enhancers.enhance=enhance
otf.enhancers.register("check extra features",enhance)
-local tlig={
- [0x2013]={ 0x002D,0x002D },
- [0x2014]={ 0x002D,0x002D,0x002D },
-}
-local tlig_specification={
- type="ligature",
- features=everywhere,
- data=tlig,
- order={ "tlig" },
- flags=noflags,
- prepend=true,
-}
-otf.addfeature("tlig",tlig_specification)
-registerotffeature {
- name='tlig',
- description='tex ligatures',
-}
-local trep={
- [0x0027]=0x2019,
-}
-local trep_specification={
- type="substitution",
- features=everywhere,
- data=trep,
- order={ "trep" },
- flags=noflags,
- prepend=true,
-}
-otf.addfeature("trep",trep_specification)
-registerotffeature {
- name='trep',
- description='tex replacements',
-}
-local anum_arabic={
- [0x0030]=0x0660,
- [0x0031]=0x0661,
- [0x0032]=0x0662,
- [0x0033]=0x0663,
- [0x0034]=0x0664,
- [0x0035]=0x0665,
- [0x0036]=0x0666,
- [0x0037]=0x0667,
- [0x0038]=0x0668,
- [0x0039]=0x0669,
-}
-local anum_persian={
- [0x0030]=0x06F0,
- [0x0031]=0x06F1,
- [0x0032]=0x06F2,
- [0x0033]=0x06F3,
- [0x0034]=0x06F4,
- [0x0035]=0x06F5,
- [0x0036]=0x06F6,
- [0x0037]=0x06F7,
- [0x0038]=0x06F8,
- [0x0039]=0x06F9,
-}
-local function valid(data)
- local features=data.resources.features
- if features then
- for k,v in next,features do
- for k,v in next,v do
- if v.arab then
- return true
- end
- end
- end
- end
-end
-local anum_specification={
- {
- type="substitution",
- features={ arab={ urd=true,dflt=true } },
- order={ "anum" },
- data=anum_arabic,
- flags=noflags,
- valid=valid,
- },
- {
- type="substitution",
- features={ arab={ urd=true } },
- order={ "anum" },
- data=anum_persian,
- flags=noflags,
- valid=valid,
- },
-}
-otf.addfeature("anum",anum_specification)
-registerotffeature {
- name='anum',
- description='arabic digits',
-}
end -- closure
@@ -24636,7 +32258,7 @@ local afm=handlers.afm or {}
handlers.afm=afm
local readers=afm.readers or {}
afm.readers=readers
-afm.version=1.512
+afm.version=1.513
local get_indexes,get_shapes
do
local decrypt
@@ -24660,7 +32282,7 @@ do
local dup=P("dup")
local put=P("put")
local array=P("array")
- local name=P("/")*C((R("az")+R("AZ")+R("09")+S("-_."))^1)
+ local name=P("/")*C((R("az","AZ","09")+S("-_."))^1)
local digits=R("09")^1
local cardinal=digits/tonumber
local spaces=P(" ")^1
@@ -24671,30 +32293,38 @@ do
m=size
return position+1
end
- local setroutine=function(str,position,index,size)
+ local setroutine=function(str,position,index,size,filename)
local forward=position+tonumber(size)
- local stream=sub(str,position+1,forward)
- routines[index]=decrypt(stream,4330,4)
+ local stream=decrypt(sub(str,position+1,forward),4330,4)
+ routines[index]={ byte(stream,1,#stream) }
return forward
end
- local setvector=function(str,position,name,size)
+ local setvector=function(str,position,name,size,filename)
local forward=position+tonumber(size)
if n>=m then
return #str
elseif forward<#str then
+ if n==0 and name~=".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename)
+ n=n+1
+ end
vector[n]=name
- n=n+1
+ n=n+1
return forward
else
return #str
end
end
- local setshapes=function(str,position,name,size)
+ local setshapes=function(str,position,name,size,filename)
local forward=position+tonumber(size)
local stream=sub(str,position+1,forward)
if n>m then
return #str
elseif forward<#str then
+ if n==0 and name~=".notdef" then
+ report_pfb("reserving .notdef at index 0 in %a",filename)
+ n=n+1
+ end
vector[n]=name
n=n+1
chars [n]=decrypt(stream,4330,4)
@@ -24707,11 +32337,11 @@ do
local p_np=spacing*(P("NP")+P("|"))
local p_nd=spacing*(P("ND")+P("|"))
local p_filterroutines=
- (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd,setroutine)*p_np+P(1))^1
+ (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd*Carg(1),setroutine)*p_np+P(1))^1
local p_filtershapes=
- (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd,setshapes)*p_nd+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*p_rd*Carg(1),setshapes)*p_nd+P(1))^1
local p_filternames=Ct (
- (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,setvector)+P(1))^1
+ (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal*Carg(1),setvector)+P(1))^1
)
local p_filterencoding=(1-encoding)^0*encoding*spaces*digits*spaces*array*(1-dup)^0*Cf(
Ct("")*Cg(spacing*dup*spaces*cardinal*spaces*name*spaces*put)^1
@@ -24722,7 +32352,7 @@ do
report_pfb("no data in %a",filename)
return
end
- if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then
+ if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then
report_pfb("no font in %a",filename)
return
end
@@ -24737,8 +32367,8 @@ do
local glyphs={}
routines,vector,chars={},{},{}
if shapestoo then
- lpegmatch(p_filterroutines,binary)
- lpegmatch(p_filtershapes,binary)
+ lpegmatch(p_filterroutines,binary,1,filename)
+ lpegmatch(p_filtershapes,binary,1,filename)
local data={
dictionaries={
{
@@ -24748,9 +32378,9 @@ do
}
},
}
- fonts.handlers.otf.readers.parsecharstrings(data,glyphs,true,true)
+ fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,true)
else
- lpegmatch(p_filternames,binary)
+ lpegmatch(p_filternames,binary,1,filename)
end
names=vector
routines,vector,chars=nil,nil,nil
@@ -24766,7 +32396,7 @@ do
if trace_loading then
report_afm("getting index data from %a",pfbname)
end
- for index=1,#vector do
+ for index=0,#vector do
local name=vector[index]
local char=characters[name]
if char then
@@ -24774,6 +32404,10 @@ do
report_afm("glyph %a has index %a",name,index)
end
char.index=index
+ else
+ if trace_indexing then
+ report_afm("glyph %a has index %a but no data",name,index)
+ end
end
end
end
@@ -24879,7 +32513,6 @@ local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName
+(fontdata*C("AXISHEIGHT")*number*rest)/set_1
)
local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
-local fullparser=(P("StartFontMetrics")*fontdata*name/start )*(p_charmetrics+p_kernpairs+p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local infoparser=(P("StartFontMetrics")*fontdata*name/start )*(p_parameters+(1-P("EndFontMetrics")) )^0*(P("EndFontMetrics")/stop )
local function read(filename,parser)
local afmblob=io.loaddata(filename)
@@ -24918,16 +32551,15 @@ function readers.loadfont(afmname,pfbname)
local data=read(resolvers.findfile(afmname),fullparser)
if data then
if not pfbname or pfbname=="" then
- pfbname=file.replacesuffix(file.nameonly(afmname),"pfb")
- pfbname=resolvers.findfile(pfbname)
+ pfbname=resolvers.findfile(file.replacesuffix(file.nameonly(afmname),"pfb"))
end
if pfbname and pfbname~="" then
data.resources.filename=resolvers.unresolve(pfbname)
get_indexes(data,pfbname)
- elseif trace_loading then
+ return data
+ else
report_afm("no pfb file for %a",afmname)
end
- return data
end
end
function readers.loadshapes(filename)
@@ -24966,12 +32598,11 @@ if not modules then modules={} end modules ['font-one']={
}
local fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers
local next,type,tonumber,rawget=next,type,tonumber,rawget
-local match,gmatch,lower,gsub,strip,find=string.match,string.gmatch,string.lower,string.gsub,string.strip,string.find
-local char,byte,sub=string.char,string.byte,string.sub
+local match,gsub=string.match,string.gsub
local abs=math.abs
-local bxor,rshift=bit32.bxor,bit32.rshift
local P,S,R,Cmt,C,Ct,Cs,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg
local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local sortedhash=table.sortedhash
local trace_features=false trackers.register("afm.features",function(v) trace_features=v end)
local trace_indexing=false trackers.register("afm.indexing",function(v) trace_indexing=v end)
local trace_loading=false trackers.register("afm.loading",function(v) trace_loading=v end)
@@ -24980,6 +32611,7 @@ local report_afm=logs.reporter("fonts","afm loading")
local setmetatableindex=table.setmetatableindex
local derivetable=table.derive
local findbinfile=resolvers.findbinfile
+local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000
local definers=fonts.definers
local readers=fonts.readers
local constructors=fonts.constructors
@@ -24992,7 +32624,7 @@ local afmfeatures=constructors.features.afm
local registerafmfeature=afmfeatures.register
local afmenhancers=constructors.enhancers.afm
local registerafmenhancer=afmenhancers.register
-afm.version=1.512
+afm.version=1.513
afm.cache=containers.define("fonts","one",afm.version,true)
afm.autoprefixed=true
afm.helpdata={}
@@ -25005,7 +32637,7 @@ function afm.load(filename)
local name=file.removesuffix(file.basename(filename))
local data=containers.read(afm.cache,name)
local attr=lfs.attributes(filename)
- local size,time=attr.size or 0,attr.modification or 0
+ local size,time=attr and attr.size or 0,attr and attr.modification or 0
local pfbfile=file.replacesuffix(name,"pfb")
local pfbname=resolvers.findfile(pfbfile,"pfb") or ""
if pfbname=="" then
@@ -25050,9 +32682,9 @@ local function enhance_unify_names(data,filename)
local unicodevector=fonts.encodings.agl.unicodes
local unicodes={}
local names={}
- local private=constructors.privateoffset
+ local private=data.private or privateoffset
local descriptions=data.descriptions
- for name,blob in next,data.characters do
+ for name,blob in sortedhash(data.characters) do
local code=unicodevector[name]
if not code then
code=lpegmatch(uparser,name)
@@ -25089,12 +32721,12 @@ local function enhance_unify_names(data,filename)
end
end
data.characters=nil
+ data.private=private
local resources=data.resources
local filename=resources.filename or file.removesuffix(file.basename(filename))
resources.filename=resolvers.unresolve(filename)
resources.unicodes=unicodes
resources.marks={}
- resources.private=private
end
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
@@ -25448,6 +33080,7 @@ local function copytotfm(data)
properties.fullname=fullname
properties.psname=fullname
properties.name=filename or fullname or fontname
+ properties.private=properties.private or data.private or privateoffset
if next(characters) then
return {
characters=characters,
@@ -25659,7 +33292,7 @@ do -- begin closure to overcome local limits and interference
if not modules then modules={} end modules ['font-afk']={
version=1.001,
- comment="companion to font-afm.lua",
+ comment="companion to font-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
@@ -25844,6 +33477,7 @@ local findbinfile=resolvers.findbinfile
local setmetatableindex=table.setmetatableindex
local fonts=fonts
local handlers=fonts.handlers
+local helpers=fonts.helpers
local readers=fonts.readers
local constructors=fonts.constructors
local encodings=fonts.encodings
@@ -25857,6 +33491,7 @@ local tfmfeatures=constructors.features.tfm
local registertfmfeature=tfmfeatures.register
local tfmenhancers=constructors.enhancers.tfm
local registertfmenhancer=tfmenhancers.register
+local charcommand=helpers.commands.char
constructors.resolvevirtualtoo=false
fonts.formats.tfm="type1"
fonts.formats.ofm="type1"
@@ -25950,6 +33585,7 @@ local function read_from_tfm(specification)
parameters.quad=parameters.quad or parameters[6] or 0
parameters.extra_space=parameters.extra_space or parameters[7] or 0
constructors.enhanceparameters(parameters)
+ properties.private=properties.private or tfmdata.private or privateoffset
if newtfmdata then
elseif constructors.resolvevirtualtoo then
fonts.loggers.register(tfmdata,file.suffix(filename),specification)
@@ -26096,7 +33732,7 @@ do
local originals=tfmdata.characters
local indices={}
local parentfont={ "font",1 }
- local private=fonts.constructors.privateoffset
+ local private=tfmdata or fonts.constructors.privateoffset
local reported=encdone[tfmfile][encfile]
local backmap=vector and table.swapped(vector)
local done={}
@@ -26119,7 +33755,7 @@ do
if backmap then
original.index=backmap[name]
else
- original.commands={ parentfont,{ "char",index } }
+ original.commands={ parentfont,charcommand[index] }
original.oindex=index
end
done[name]=true
@@ -26163,6 +33799,7 @@ do
tfmdata.tounicode=1
tfmdata.embedding="subset"
tfmdata.usedbitmap=bitmap and virtualid
+ tfmdata.private=private
return tfmdata
end
end
@@ -26187,7 +33824,8 @@ end
]]
local flushstreamobject=lpdf and lpdf.flushstreamobject
local setfontattributes=pdf.setfontattributes
- if not flushstreamobject then
+ if flushstreamobject then
+ else
flushstreamobject=function(data)
return pdf.obj {
immediate=true,
@@ -26386,13 +34024,13 @@ if not modules then modules={} end modules ['font-def']={
local lower,gsub=string.lower,string.gsub
local tostring,next=tostring,next
local lpegmatch=lpeg.match
-local suffixonly,removesuffix=file.suffix,file.removesuffix
+local suffixonly,removesuffix,basename=file.suffix,file.removesuffix,file.basename
local formatters=string.formatters
+local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys
local allocate=utilities.storage.allocate
local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end)
trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading")
-trackers.register("fonts.all","fonts.*","otf.*","afm.*","tfm.*")
local report_defining=logs.reporter("fonts","defining")
local fonts=fonts
local fontdata=fonts.hashes.identifiers
@@ -26410,41 +34048,6 @@ local lastdefined=nil
local loadedfonts=constructors.loadedfonts
local designsizes=constructors.designsizes
local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end
-local splitter,splitspecifiers=nil,""
-local P,C,S,Cc=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc
-local left=P("(")
-local right=P(")")
-local colon=P(":")
-local space=P(" ")
-definers.defaultlookup="file"
-local prefixpattern=P(false)
-local function addspecifier(symbol)
- splitspecifiers=splitspecifiers..symbol
- local method=S(splitspecifiers)
- local lookup=C(prefixpattern)*colon
- local sub=left*C(P(1-left-right-method)^1)*right
- local specification=C(method)*C(P(1)^1)
- local name=C((1-sub-specification)^1)
- splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc("")))
-end
-local function addlookup(str,default)
- prefixpattern=prefixpattern+P(str)
-end
-definers.addlookup=addlookup
-addlookup("file")
-addlookup("name")
-addlookup("spec")
-local function getspecification(str)
- return lpegmatch(splitter,str or "")
-end
-definers.getspecification=getspecification
-function definers.registersplit(symbol,action,verbosename)
- addspecifier(symbol)
- variants[symbol]=action
- if verbosename then
- variants[verbosename]=action
- end
-end
local function makespecification(specification,lookup,name,sub,method,detail,size)
size=size or 655360
if not lookup or lookup=="" then
@@ -26469,9 +34072,10 @@ local function makespecification(specification,lookup,name,sub,method,detail,siz
return t
end
definers.makespecification=makespecification
-function definers.analyze(specification,size)
- local lookup,name,sub,method,detail=getspecification(specification or "")
- return makespecification(specification,lookup,name,sub,method,detail,size)
+if context then
+
+--removed
+
end
definers.resolvers=definers.resolvers or {}
local resolvers=definers.resolvers
@@ -26489,11 +34093,28 @@ end
function resolvers.name(specification)
local resolve=fonts.names.resolve
if resolve then
- local resolved,sub,subindex=resolve(specification.name,specification.sub,specification)
+ local resolved,sub,subindex,instance=resolve(specification.name,specification.sub,specification)
if resolved then
specification.resolved=resolved
specification.sub=sub
specification.subindex=subindex
+ if instance then
+ specification.instance=instance
+ local features=specification.features
+ if not features then
+ features={}
+ specification.features=features
+ end
+ local normal=features.normal
+ if not normal then
+ normal={}
+ features.normal=normal
+ end
+ normal.instance=instance
+ if not callbacks.supported.glyph_stream_provider then
+ normal.variableshapes=true
+ end
+ end
local suffix=lower(suffixonly(resolved))
if fonts.formats[suffix] then
specification.forced=suffix
@@ -26571,6 +34192,60 @@ local function checkembedding(tfmdata)
end
tfmdata.embedding=embedding
end
+local function checkfeatures(tfmdata)
+ local resources=tfmdata.resources
+ local shared=tfmdata.shared
+ if resources and shared then
+ local features=resources.features
+ local usedfeatures=shared.features
+ if features and usedfeatures then
+ local usedlanguage=usedfeatures.language or "dflt"
+ local usedscript=usedfeatures.script or "dflt"
+ local function check(what)
+ if what then
+ local foundlanguages={}
+ for feature,scripts in next,what do
+ if usedscript=="auto" or scripts["*"] then
+ elseif not scripts[usedscript] then
+ else
+ for script,languages in next,scripts do
+ if languages["*"] then
+ elseif not languages[usedlanguage] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,usedlanguage)
+ end
+ end
+ end
+ for script,languages in next,scripts do
+ for language in next,languages do
+ foundlanguages[language]=true
+ end
+ end
+ end
+ if false then
+ foundlanguages["*"]=nil
+ foundlanguages=sortedkeys(foundlanguages)
+ for feature,scripts in sortedhash(what) do
+ for script,languages in next,scripts do
+ if not languages["*"] then
+ for i=1,#foundlanguages do
+ local language=foundlanguages[i]
+ if not languages[language] then
+ report_defining("font %!font:name!, feature %a, script %a, no language %a",
+ tfmdata,feature,script,language)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ check(features.gsub)
+ check(features.gpos)
+ end
+ end
+end
function definers.loadfont(specification)
local hash=constructors.hashinstance(specification)
local tfmdata=loadedfonts[hash]
@@ -26604,6 +34279,7 @@ function definers.loadfont(specification)
checkembedding(tfmdata)
loadedfonts[hash]=tfmdata
designsizes[specification.hash]=tfmdata.parameters.designsize
+ checkfeatures(tfmdata)
end
end
if not tfmdata then
@@ -26611,8 +34287,6 @@ function definers.loadfont(specification)
end
return tfmdata
end
-function constructors.checkvirtualids()
-end
function constructors.readanddefine(name,size)
local specification=definers.analyze(name,size)
local method=specification.method
@@ -26626,7 +34300,6 @@ function constructors.readanddefine(name,size)
local tfmdata=definers.loadfont(specification)
if tfmdata then
tfmdata.properties.hash=hash
- constructors.checkvirtualids(tfmdata)
id=font.define(tfmdata)
definers.register(tfmdata,id)
else
@@ -26695,8 +34368,8 @@ function definers.read(specification,size,id)
local properties=tfmdata.properties or {}
local parameters=tfmdata.parameters or {}
report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a",
- properties.format or "unknown",id,properties.name,parameters.size,properties.encodingbytes,
- properties.encodingname,properties.fullname,file.basename(properties.filename))
+ properties.format or "unknown",id or "-",properties.name,parameters.size,properties.encodingbytes,
+ properties.encodingname,properties.fullname,basename(properties.filename))
end
statistics.stoptiming(fonts)
return tfmdata
@@ -26718,15 +34391,15 @@ if not modules then modules={} end modules ['luatex-fonts-def']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
local fonts=fonts
fonts.constructors.namemode="specification"
function fonts.definers.getspecification(str)
return "",str,"",":",str
end
-local list={}
+local list={}
local function issome () list.lookup='name' end
local function isfile () list.lookup='file' end
local function isname () list.lookup='name' end
@@ -26736,27 +34409,30 @@ local function iscrap (s) list.crap=string.lower(s) end
local function iskey (k,v) list[k]=v end
local function istrue (s) list[s]=true end
local function isfalse(s) list[s]=false end
-local P,S,R,C=lpeg.P,lpeg.S,lpeg.R,lpeg.C
+local P,S,R,C,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs
local spaces=P(" ")^0
-local namespec=(1-S("/:("))^0
+local namespec=Cs((P("{")/"")*(1-S("}"))^0*(P("}")/"")+(1-S("/:("))^0)
local crapspec=spaces*P("/")*(((1-P(":"))^0)/iscrap)*spaces
local filename_1=P("file:")/isfile*(namespec/thename)
-local filename_2=P("[")*P(true)/isname*(((1-P("]"))^0)/thename)*P("]")
+local filename_2=P("[")*P(true)/isfile*(((1-P("]"))^0)/thename)*P("]")
local fontname_1=P("name:")/isname*(namespec/thename)
local fontname_2=P(true)/issome*(namespec/thename)
-local sometext=(R("az","AZ","09")+S("+-.{}"))^1
+local sometext=R("az","AZ","09")^1
+local somekey=R("az","AZ","09")^1
+local somevalue=(P("{")/"")*(1-P("}"))^0*(P("}")/"")+(1-S(";"))^1
local truevalue=P("+")*spaces*(sometext/istrue)
local falsevalue=P("-")*spaces*(sometext/isfalse)
-local keyvalue=(C(sometext)*spaces*P("=")*spaces*C(sometext))/iskey
+local keyvalue=(C(somekey)*spaces*P("=")*spaces*C(somevalue))/iskey
local somevalue=sometext/istrue
local subvalue=P("(")*(C(P(1-S("()"))^1)/issub)*P(")")
local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces
local options=P(":")*spaces*(P(";")^0*option)^0
local pattern=(filename_1+filename_2+fontname_1+fontname_2)*subvalue^0*crapspec^0*options^0
-local function colonized(specification)
+function fonts.definers.analyze(str,size)
+ local specification=fonts.definers.makespecification(str,nil,nil,nil,":",nil,size)
list={}
- lpeg.match(pattern,specification.specification)
- list.crap=nil
+ lpeg.match(pattern,str)
+ list.crap=nil
if list.name then
specification.name=list.name
list.name=nil
@@ -26770,10 +34446,9 @@ local function colonized(specification)
list.sub=nil
end
specification.features.normal=fonts.handlers.otf.features.normalize(list)
+ list=nil
return specification
end
-fonts.definers.registersplit(":",colonized,"cryptic")
-fonts.definers.registersplit("",colonized,"more cryptic")
function fonts.definers.applypostprocessors(tfmdata)
local postprocessors=tfmdata.postprocessors
if postprocessors then
@@ -26800,72 +34475,37 @@ if not modules then modules={} end modules ['luatex-fonts-ext']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
+local byte=string.byte
local fonts=fonts
-local otffeatures=fonts.constructors.features.otf
-local function initializeitlc(tfmdata,value)
- if value then
- local parameters=tfmdata.parameters
- local italicangle=parameters.italicangle
- if italicangle and italicangle~=0 then
- local properties=tfmdata.properties
- local factor=tonumber(value) or 1
- properties.hasitalics=true
- properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
- end
- end
-end
-otffeatures.register {
- name="itlc",
- description="italic correction",
- initializers={
- base=initializeitlc,
- node=initializeitlc,
- }
-}
-local function initializeslant(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>1 then
- value=1
- elseif value<-1 then
- value=-1
- end
- tfmdata.parameters.slantfactor=value
-end
-otffeatures.register {
- name="slant",
- description="slant glyphs",
- initializers={
- base=initializeslant,
- node=initializeslant,
- }
-}
-local function initializeextend(tfmdata,value)
- value=tonumber(value)
- if not value then
- value=0
- elseif value>10 then
- value=10
- elseif value<-10 then
- value=-10
- end
- tfmdata.parameters.extendfactor=value
-end
-otffeatures.register {
- name="extend",
- description="scale glyphs horizontally",
- initializers={
- base=initializeextend,
- node=initializeextend,
- }
-}
+local handlers=fonts.handlers
+local otf=handlers.otf
+local afm=handlers.afm
+local registerotffeature=otf.features.register
+local registerafmfeature=afm.features.register
+function fonts.loggers.onetimemessage() end
fonts.protrusions=fonts.protrusions or {}
fonts.protrusions.setups=fonts.protrusions.setups or {}
local setups=fonts.protrusions.setups
+setups['default']={
+ factor=1,
+ left=1,
+ right=1,
+ [0x002C]={ 0,1 },
+ [0x002E]={ 0,1 },
+ [0x003A]={ 0,1 },
+ [0x003B]={ 0,1 },
+ [0x002D]={ 0,1 },
+ [0x2013]={ 0,0.50 },
+ [0x2014]={ 0,0.33 },
+ [0x3001]={ 0,1 },
+ [0x3002]={ 0,1 },
+ [0x060C]={ 0,1 },
+ [0x061B]={ 0,1 },
+ [0x06D4]={ 0,1 },
+}
local function initializeprotrusion(tfmdata,value)
if value then
local setup=setups[value]
@@ -26886,7 +34526,7 @@ local function initializeprotrusion(tfmdata,value)
end
end
end
-otffeatures.register {
+local specification={
name="protrusion",
description="shift characters into the left and or right margin",
initializers={
@@ -26894,9 +34534,26 @@ otffeatures.register {
node=initializeprotrusion,
}
}
+registerotffeature(specification)
+registerafmfeature(specification)
fonts.expansions=fonts.expansions or {}
fonts.expansions.setups=fonts.expansions.setups or {}
local setups=fonts.expansions.setups
+setups['default']={
+ stretch=2,
+ shrink=2,
+ step=.5,
+ factor=1,
+ [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
+ [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
+ [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
+ [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
+ [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
+ [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
+ [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
+ [byte('w')]=0.7,[byte('z')]=0.7,
+ [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
+}
local function initializeexpansion(tfmdata,value)
if value then
local setup=setups[value]
@@ -26919,7 +34576,7 @@ local function initializeexpansion(tfmdata,value)
end
end
end
-otffeatures.register {
+local specification={
name="expansion",
description="apply hz optimization",
initializers={
@@ -26927,40 +34584,15 @@ otffeatures.register {
node=initializeexpansion,
}
}
-function fonts.loggers.onetimemessage() end
-local byte=string.byte
-fonts.expansions.setups['default']={
- stretch=2,shrink=2,step=.5,factor=1,
- [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7,
- [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7,
- [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7,
- [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7,
- [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7,
- [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7,
- [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7,
- [byte('w')]=0.7,[byte('z')]=0.7,
- [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7,
-}
-fonts.protrusions.setups['default']={
- factor=1,left=1,right=1,
- [0x002C]={ 0,1 },
- [0x002E]={ 0,1 },
- [0x003A]={ 0,1 },
- [0x003B]={ 0,1 },
- [0x002D]={ 0,1 },
- [0x2013]={ 0,0.50 },
- [0x2014]={ 0,0.33 },
- [0x3001]={ 0,1 },
- [0x3002]={ 0,1 },
- [0x060C]={ 0,1 },
- [0x061B]={ 0,1 },
- [0x06D4]={ 0,1 },
-}
-fonts.handlers.otf.features.normalize=function(t)
- if t.rand then
- t.rand="random"
+registerotffeature(specification)
+registerafmfeature(specification)
+if not otf.features.normalize then
+ otf.features.normalize=function(t)
+ if t.rand then
+ t.rand="random"
+ end
+ return t
end
- return t
end
function fonts.helpers.nametoslot(name)
local t=type(name)
@@ -26990,7 +34622,7 @@ local function specialreencode(tfmdata,value)
return string.format("reencoded:%s",value)
end
end
-local function reencode(tfmdata,value)
+local function initialize(tfmdata,value)
tfmdata.postprocessors=tfmdata.postprocessors or {}
table.insert(tfmdata.postprocessors,
function(tfmdata)
@@ -26998,33 +34630,2776 @@ local function reencode(tfmdata,value)
end
)
end
-otffeatures.register {
+registerotffeature {
name="reencode",
description="reencode characters",
manipulators={
- base=reencode,
- node=reencode,
+ base=initialize,
+ node=initialize,
}
}
-local function ignore(tfmdata,key,value)
+local function initialize(tfmdata,key,value)
if value then
tfmdata.mathparameters=nil
end
end
-otffeatures.register {
+registerotffeature {
name="ignoremathconstants",
description="ignore math constants table",
initializers={
- base=ignore,
- node=ignore,
+ base=initialize,
+ node=initialize,
+ }
+}
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['font-imp-tex']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next=next
+local fonts=fonts
+local otf=fonts.handlers.otf
+local registerotffeature=otf.features.register
+local addotffeature=otf.addfeature
+local specification={
+ type="ligature",
+ order={ "tlig" },
+ prepend=true,
+ data={
+ [0x2013]={ 0x002D,0x002D },
+ [0x2014]={ 0x002D,0x002D,0x002D },
+ },
+}
+addotffeature("tlig",specification)
+registerotffeature {
+ name="tlig",
+ description="tex ligatures",
+}
+local specification={
+ type="substitution",
+ order={ "trep" },
+ prepend=true,
+ data={
+ [0x0027]=0x2019,
+ },
+}
+addotffeature("trep",specification)
+registerotffeature {
+ name="trep",
+ description="tex replacements",
+}
+local anum_arabic={
+ [0x0030]=0x0660,
+ [0x0031]=0x0661,
+ [0x0032]=0x0662,
+ [0x0033]=0x0663,
+ [0x0034]=0x0664,
+ [0x0035]=0x0665,
+ [0x0036]=0x0666,
+ [0x0037]=0x0667,
+ [0x0038]=0x0668,
+ [0x0039]=0x0669,
+}
+local anum_persian={
+ [0x0030]=0x06F0,
+ [0x0031]=0x06F1,
+ [0x0032]=0x06F2,
+ [0x0033]=0x06F3,
+ [0x0034]=0x06F4,
+ [0x0035]=0x06F5,
+ [0x0036]=0x06F6,
+ [0x0037]=0x06F7,
+ [0x0038]=0x06F8,
+ [0x0039]=0x06F9,
+}
+local function valid(data)
+ local features=data.resources.features
+ if features then
+ for k,v in next,features do
+ for k,v in next,v do
+ if v.arab then
+ return true
+ end
+ end
+ end
+ end
+end
+local specification={
+ {
+ type="substitution",
+ features={ arab={ urd=true,dflt=true } },
+ order={ "anum" },
+ data=anum_arabic,
+ valid=valid,
+ },
+ {
+ type="substitution",
+ features={ arab={ urd=true } },
+ order={ "anum" },
+ data=anum_persian,
+ valid=valid,
+ },
+}
+addotffeature("anum",specification)
+registerotffeature {
+ name="anum",
+ description="arabic digits",
+}
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['font-imp-ligatures']={
+ version=1.001,
+ comment="companion to font-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local lpegmatch=lpeg.match
+local utfsplit=utf.split
+local settings_to_array=utilities.parsers.settings_to_array
+local fonts=fonts
+local otf=fonts.handlers.otf
+local registerotffeature=otf.features.register
+local addotffeature=otf.addfeature
+local lookups={}
+local protect={}
+local revert={}
+local zwjchar=0x200C
+local zwj={ zwjchar }
+addotffeature {
+ name="blockligatures",
+ type="chainsubstitution",
+ nocheck=true,
+ prepend=true,
+ future=true,
+ lookups={
+ {
+ type="multiple",
+ data=lookups,
+ },
+ },
+ data={
+ rules=protect,
+ }
+}
+addotffeature {
+ name="blockligatures",
+ type="chainsubstitution",
+ nocheck=true,
+ append=true,
+ overload=false,
+ lookups={
+ {
+ type="ligature",
+ data=lookups,
+ },
+ },
+ data={
+ rules=revert,
+ }
+}
+registerotffeature {
+ name='blockligatures',
+ description='block certain ligatures',
+}
+local splitter=lpeg.splitat(":")
+local function blockligatures(str)
+ local t=settings_to_array(str)
+ for i=1,#t do
+ local ti=t[i]
+ local before,current,after=lpegmatch(splitter,ti)
+ if current and after then
+ if before then
+ before=utfsplit(before)
+ for i=1,#before do
+ before[i]={ before[i] }
+ end
+ end
+ if current then
+ current=utfsplit(current)
+ end
+ if after then
+ after=utfsplit(after)
+ for i=1,#after do
+ after[i]={ after[i] }
+ end
+ end
+ else
+ before=nil
+ current=utfsplit(ti)
+ after=nil
+ end
+ if #current>1 then
+ local one=current[1]
+ local two=current[2]
+ lookups[one]={ one,zwjchar }
+ local one={ one }
+ local two={ two }
+ local new=#protect+1
+ protect[new]={
+ before=before,
+ current={ one,two },
+ after=after,
+ lookups={ 1 },
+ }
+ revert[new]={
+ current={ one,zwj },
+ after={ two },
+ lookups={ 1 },
+ }
+ end
+ end
+end
+otf.helpers.blockligatures=blockligatures
+if context then
+
+--removed
+
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['font-imp-italics']={
+ version=1.001,
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next=next
+local fonts=fonts
+local handlers=fonts.handlers
+local registerotffeature=handlers.otf.features.register
+local registerafmfeature=handlers.afm.features.register
+local function initialize(tfmdata,key,value)
+ for unicode,character in next,tfmdata.characters do
+ local olditalic=character.italic
+ if olditalic and olditalic~=0 then
+ character.width=character.width+olditalic
+ character.italic=0
+ end
+ end
+end
+local specification={
+ name="italicwidths",
+ description="add italic to width",
+ manipulators={
+ base=initialize,
+ node=initialize,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initialize(tfmdata,value)
+ if value then
+ local parameters=tfmdata.parameters
+ local italicangle=parameters.italicangle
+ if italicangle and italicangle~=0 then
+ local properties=tfmdata.properties
+ local factor=tonumber(value) or 1
+ properties.hasitalics=true
+ properties.autoitalicamount=factor*(parameters.uwidth or 40)/2
+ end
+ end
+end
+local specification={
+ name="itlc",
+ description="italic correction",
+ initializers={
+ base=initialize,
+ node=initialize,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+if context then
+
+--removed
+
+end
+if context then
+ local letter=characters.is_letter
+ local always=true
+ local function collapseitalics(tfmdata,key,value)
+ local threshold=value==true and 100 or tonumber(value)
+ if threshold and threshold>0 then
+ if threshold>100 then
+ threshold=100
+ end
+ for unicode,data in next,tfmdata.characters do
+ if always or letter[unicode] or letter[data.unicode] then
+ local italic=data.italic
+ if italic and italic~=0 then
+ local width=data.width
+ if width and width~=0 then
+ local delta=threshold*italic/100
+ data.width=width+delta
+ data.italic=italic-delta
+ end
+ end
+ end
+ end
+ end
+ end
+ local dimensions_specification={
+ name="collapseitalics",
+ description="collapse italics",
+ manipulators={
+ base=collapseitalics,
+ node=collapseitalics,
+ }
+ }
+ registerotffeature(dimensions_specification)
+ registerafmfeature(dimensions_specification)
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['font-imp-effects']={
+ version=1.001,
+ comment="companion to font-ini.mkiv and hand-ini.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local next,type,tonumber=next,type,tonumber
+local is_boolean=string.is_boolean
+local fonts=fonts
+local handlers=fonts.handlers
+local registerotffeature=handlers.otf.features.register
+local registerafmfeature=handlers.afm.features.register
+local settings_to_hash=utilities.parsers.settings_to_hash_colon_too
+local helpers=fonts.helpers
+local prependcommands=helpers.prependcommands
+local charcommand=helpers.commands.char
+local leftcommand=helpers.commands.left
+local rightcommand=helpers.commands.right
+local upcommand=helpers.commands.up
+local downcommand=helpers.commands.down
+local dummycommand=helpers.commands.dummy
+local report_effect=logs.reporter("fonts","effect")
+local report_slant=logs.reporter("fonts","slant")
+local report_extend=logs.reporter("fonts","extend")
+local report_squeeze=logs.reporter("fonts","squeeze")
+local trace=false
+trackers.register("fonts.effect",function(v) trace=v end)
+trackers.register("fonts.slant",function(v) trace=v end)
+trackers.register("fonts.extend",function(v) trace=v end)
+trackers.register("fonts.squeeze",function(v) trace=v end)
+local function initializeslant(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>1 then
+ value=1
+ elseif value<-1 then
+ value=-1
+ end
+ if trace then
+ report_slant("applying %0.3f",value)
+ end
+ tfmdata.parameters.slantfactor=value
+end
+local specification={
+ name="slant",
+ description="slant glyphs",
+ initializers={
+ base=initializeslant,
+ node=initializeslant,
}
}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializeextend(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>10 then
+ value=10
+ elseif value<-10 then
+ value=-10
+ end
+ if trace then
+ report_extend("applying %0.3f",value)
+ end
+ tfmdata.parameters.extendfactor=value
+end
+local specification={
+ name="extend",
+ description="scale glyphs horizontally",
+ initializers={
+ base=initializeextend,
+ node=initializeextend,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializesqueeze(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ elseif value>10 then
+ value=10
+ elseif value<-10 then
+ value=-10
+ end
+ if trace then
+ report_squeeze("applying %0.3f",value)
+ end
+ tfmdata.parameters.squeezefactor=value
+end
+local specification={
+ name="squeeze",
+ description="scale glyphs vertically",
+ initializers={
+ base=initializesqueeze,
+ node=initializesqueeze,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local effects={
+ inner=0,
+ normal=0,
+ outer=1,
+ outline=1,
+ both=2,
+ hidden=3,
+}
+local function initializeeffect(tfmdata,value)
+ local spec
+ if type(value)=="number" then
+ spec={ width=value }
+ else
+ spec=settings_to_hash(value)
+ end
+ local effect=spec.effect or "both"
+ local width=tonumber(spec.width) or 0
+ local mode=effects[effect]
+ if not mode then
+ report_effect("invalid effect %a",effect)
+ elseif width==0 and mode==0 then
+ report_effect("invalid width %a for effect %a",width,effect)
+ else
+ local parameters=tfmdata.parameters
+ local properties=tfmdata.properties
+ parameters.mode=mode
+ parameters.width=width*1000
+ if is_boolean(spec.auto)==true then
+ local squeeze=1-width/20
+ local average=(1-squeeze)*width*100
+ spec.squeeze=squeeze
+ spec.extend=1+width/2
+ spec.wdelta=average
+ spec.hdelta=average/2
+ spec.ddelta=average/2
+ spec.vshift=average/2
+ end
+ local factor=tonumber(spec.factor) or 0
+ local hfactor=tonumber(spec.hfactor) or factor
+ local vfactor=tonumber(spec.vfactor) or factor
+ local delta=tonumber(spec.delta) or 1
+ local wdelta=tonumber(spec.wdelta) or delta
+ local hdelta=tonumber(spec.hdelta) or delta
+ local ddelta=tonumber(spec.ddelta) or hdelta
+ local vshift=tonumber(spec.vshift) or 0
+ local slant=spec.slant
+ local extend=spec.extend
+ local squeeze=spec.squeeze
+ if slant then
+ initializeslant(tfmdata,slant)
+ end
+ if extend then
+ initializeextend(tfmdata,extend)
+ end
+ if squeeze then
+ initializesqueeze(tfmdata,squeeze)
+ end
+ properties.effect={
+ effect=effect,
+ width=width,
+ factor=factor,
+ hfactor=hfactor,
+ vfactor=vfactor,
+ wdelta=wdelta,
+ hdelta=hdelta,
+ ddelta=ddelta,
+ vshift=vshift,
+ slant=tfmdata.parameters.slantfactor,
+ extend=tfmdata.parameters.extendfactor,
+ squeeze=tfmdata.parameters.squeezefactor,
+ }
+ end
+end
+local rules={
+ "RadicalRuleThickness",
+ "OverbarRuleThickness",
+ "FractionRuleThickness",
+ "UnderbarRuleThickness",
+}
+local function setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ if delta~=0 then
+ for i=1,#rules do
+ local name=rules[i]
+ local value=mathparameters[name]
+ if value then
+ mathparameters[name]=(squeeze or 1)*(value+dx)
+ end
+ end
+ end
+end
+local function setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+ local function wdpatch(char)
+ if wsnap~=0 then
+ char.width=char.width+wdelta/2
+ end
+ end
+ local function htpatch(char)
+ if hsnap~=0 then
+ local height=char.height
+ if height then
+ char.height=char.height+2*dy
+ end
+ end
+ end
+ local character=characters[0x221A]
+ if character and character.next then
+ local char=character
+ local next=character.next
+ wdpatch(char)
+ htpatch(char)
+ while next do
+ char=characters[next]
+ wdpatch(char)
+ htpatch(char)
+ next=char.next
+ end
+ if char then
+ local v=char.vert_variants
+ if v then
+ local top=v[#v]
+ if top then
+ local char=characters[top.glyph]
+ htpatch(char)
+ end
+ end
+ end
+ end
+end
+local function manipulateeffect(tfmdata)
+ local effect=tfmdata.properties.effect
+ if effect then
+ local characters=tfmdata.characters
+ local parameters=tfmdata.parameters
+ local mathparameters=tfmdata.mathparameters
+ local multiplier=effect.width*100
+ local factor=parameters.factor
+ local hfactor=parameters.hfactor
+ local vfactor=parameters.vfactor
+ local wdelta=effect.wdelta*hfactor*multiplier
+ local hdelta=effect.hdelta*vfactor*multiplier
+ local ddelta=effect.ddelta*vfactor*multiplier
+ local vshift=effect.vshift*vfactor*multiplier
+ local squeeze=effect.squeeze
+ local hshift=wdelta/2
+ local dx=multiplier*vfactor
+ local dy=vshift
+ local factor=(1+effect.factor)*factor
+ local hfactor=(1+effect.hfactor)*hfactor
+ local vfactor=(1+effect.vfactor)*vfactor
+ local vshift=vshift~=0 and upcommand[vshift] or false
+ for unicode,character in next,characters do
+ local oldwidth=character.width
+ local oldheight=character.height
+ local olddepth=character.depth
+ if oldwidth and oldwidth>0 then
+ character.width=oldwidth+wdelta
+ local commands=character.commands
+ local hshift=rightcommand[hshift]
+ if vshift then
+ if commands then
+ prependcommands (commands,
+ hshift,
+ vshift
+ )
+ else
+ character.commands={
+ hshift,
+ vshift,
+ charcommand[unicode]
+ }
+ end
+ else
+ if commands then
+ prependcommands (commands,
+ hshift
+ )
+ else
+ character.commands={
+ hshift,
+ charcommand[unicode]
+ }
+ end
+ end
+ end
+ if oldheight and oldheight>0 then
+ character.height=oldheight+hdelta
+ end
+ if olddepth and olddepth>0 then
+ character.depth=olddepth+ddelta
+ end
+ end
+ if mathparameters then
+ setmathparameters(tfmdata,characters,mathparameters,dx,dy,squeeze)
+ setmathcharacters(tfmdata,characters,mathparameters,dx,dy,squeeze,wdelta,hdelta,ddelta)
+ end
+ parameters.factor=factor
+ parameters.hfactor=hfactor
+ parameters.vfactor=vfactor
+ if trace then
+ report_effect("applying")
+ report_effect(" effect : %s",effect.effect)
+ report_effect(" width : %s => %s",effect.width,multiplier)
+ report_effect(" factor : %s => %s",effect.factor,factor )
+ report_effect(" hfactor : %s => %s",effect.hfactor,hfactor)
+ report_effect(" vfactor : %s => %s",effect.vfactor,vfactor)
+ report_effect(" wdelta : %s => %s",effect.wdelta,wdelta)
+ report_effect(" hdelta : %s => %s",effect.hdelta,hdelta)
+ report_effect(" ddelta : %s => %s",effect.ddelta,ddelta)
+ end
+ end
+end
+local specification={
+ name="effect",
+ description="apply effects to glyphs",
+ initializers={
+ base=initializeeffect,
+ node=initializeeffect,
+ },
+ manipulators={
+ base=manipulateeffect,
+ node=manipulateeffect,
+ },
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+local function initializeoutline(tfmdata,value)
+ value=tonumber(value)
+ if not value then
+ value=0
+ else
+ value=tonumber(value) or 0
+ end
+ local parameters=tfmdata.parameters
+ local properties=tfmdata.properties
+ parameters.mode=effects.outline
+ parameters.width=value*1000
+ properties.effect={
+ effect=effect,
+ width=width,
+ }
+end
+local specification={
+ name="outline",
+ description="outline glyphs",
+ initializers={
+ base=initializeoutline,
+ node=initializeoutline,
+ }
+}
+registerotffeature(specification)
+registerafmfeature(specification)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+
+fonts.handlers.otf.addfeature {
+ ["dataset"]={
+ {
+ ["data"]={
+ ["À"]={ "A","̀" },
+ ["Á"]={ "A","́" },
+ ["Â"]={ "A","̂" },
+ ["Ã"]={ "A","̃" },
+ ["Ä"]={ "A","̈" },
+ ["Å"]={ "A","̊" },
+ ["Ç"]={ "C","̧" },
+ ["È"]={ "E","̀" },
+ ["É"]={ "E","́" },
+ ["Ê"]={ "E","̂" },
+ ["Ë"]={ "E","̈" },
+ ["Ì"]={ "I","̀" },
+ ["Í"]={ "I","́" },
+ ["Î"]={ "I","̂" },
+ ["Ï"]={ "I","̈" },
+ ["Ñ"]={ "N","̃" },
+ ["Ò"]={ "O","̀" },
+ ["Ó"]={ "O","́" },
+ ["Ô"]={ "O","̂" },
+ ["Õ"]={ "O","̃" },
+ ["Ö"]={ "O","̈" },
+ ["Ù"]={ "U","̀" },
+ ["Ú"]={ "U","́" },
+ ["Û"]={ "U","̂" },
+ ["Ü"]={ "U","̈" },
+ ["Ý"]={ "Y","́" },
+ ["à"]={ "a","̀" },
+ ["á"]={ "a","́" },
+ ["â"]={ "a","̂" },
+ ["ã"]={ "a","̃" },
+ ["ä"]={ "a","̈" },
+ ["å"]={ "a","̊" },
+ ["ç"]={ "c","̧" },
+ ["è"]={ "e","̀" },
+ ["é"]={ "e","́" },
+ ["ê"]={ "e","̂" },
+ ["ë"]={ "e","̈" },
+ ["ì"]={ "i","̀" },
+ ["í"]={ "i","́" },
+ ["î"]={ "i","̂" },
+ ["ï"]={ "i","̈" },
+ ["ñ"]={ "n","̃" },
+ ["ò"]={ "o","̀" },
+ ["ó"]={ "o","́" },
+ ["ô"]={ "o","̂" },
+ ["õ"]={ "o","̃" },
+ ["ö"]={ "o","̈" },
+ ["ù"]={ "u","̀" },
+ ["ú"]={ "u","́" },
+ ["û"]={ "u","̂" },
+ ["ü"]={ "u","̈" },
+ ["ý"]={ "y","́" },
+ ["ÿ"]={ "y","̈" },
+ ["Ā"]={ "A","̄" },
+ ["ā"]={ "a","̄" },
+ ["Ă"]={ "A","̆" },
+ ["ă"]={ "a","̆" },
+ ["Ą"]={ "A","̨" },
+ ["ą"]={ "a","̨" },
+ ["Ć"]={ "C","́" },
+ ["ć"]={ "c","́" },
+ ["Ĉ"]={ "C","̂" },
+ ["ĉ"]={ "c","̂" },
+ ["Ċ"]={ "C","̇" },
+ ["ċ"]={ "c","̇" },
+ ["Č"]={ "C","̌" },
+ ["č"]={ "c","̌" },
+ ["Ď"]={ "D","̌" },
+ ["ď"]={ "d","̌" },
+ ["Ē"]={ "E","̄" },
+ ["ē"]={ "e","̄" },
+ ["Ĕ"]={ "E","̆" },
+ ["ĕ"]={ "e","̆" },
+ ["Ė"]={ "E","̇" },
+ ["ė"]={ "e","̇" },
+ ["Ę"]={ "E","̨" },
+ ["ę"]={ "e","̨" },
+ ["Ě"]={ "E","̌" },
+ ["ě"]={ "e","̌" },
+ ["Ĝ"]={ "G","̂" },
+ ["ĝ"]={ "g","̂" },
+ ["Ğ"]={ "G","̆" },
+ ["ğ"]={ "g","̆" },
+ ["Ġ"]={ "G","̇" },
+ ["ġ"]={ "g","̇" },
+ ["Ģ"]={ "G","̧" },
+ ["ģ"]={ "g","̧" },
+ ["Ĥ"]={ "H","̂" },
+ ["ĥ"]={ "h","̂" },
+ ["Ĩ"]={ "I","̃" },
+ ["ĩ"]={ "i","̃" },
+ ["Ī"]={ "I","̄" },
+ ["ī"]={ "i","̄" },
+ ["Ĭ"]={ "I","̆" },
+ ["ĭ"]={ "i","̆" },
+ ["Į"]={ "I","̨" },
+ ["į"]={ "i","̨" },
+ ["İ"]={ "I","̇" },
+ ["Ĵ"]={ "J","̂" },
+ ["ĵ"]={ "j","̂" },
+ ["Ķ"]={ "K","̧" },
+ ["ķ"]={ "k","̧" },
+ ["Ĺ"]={ "L","́" },
+ ["ĺ"]={ "l","́" },
+ ["Ļ"]={ "L","̧" },
+ ["ļ"]={ "l","̧" },
+ ["Ľ"]={ "L","̌" },
+ ["ľ"]={ "l","̌" },
+ ["Ń"]={ "N","́" },
+ ["ń"]={ "n","́" },
+ ["Ņ"]={ "N","̧" },
+ ["ņ"]={ "n","̧" },
+ ["Ň"]={ "N","̌" },
+ ["ň"]={ "n","̌" },
+ ["Ō"]={ "O","̄" },
+ ["ō"]={ "o","̄" },
+ ["Ŏ"]={ "O","̆" },
+ ["ŏ"]={ "o","̆" },
+ ["Ő"]={ "O","̋" },
+ ["ő"]={ "o","̋" },
+ ["Ŕ"]={ "R","́" },
+ ["ŕ"]={ "r","́" },
+ ["Ŗ"]={ "R","̧" },
+ ["ŗ"]={ "r","̧" },
+ ["Ř"]={ "R","̌" },
+ ["ř"]={ "r","̌" },
+ ["Ś"]={ "S","́" },
+ ["ś"]={ "s","́" },
+ ["Ŝ"]={ "S","̂" },
+ ["ŝ"]={ "s","̂" },
+ ["Ş"]={ "S","̧" },
+ ["ş"]={ "s","̧" },
+ ["Š"]={ "S","̌" },
+ ["š"]={ "s","̌" },
+ ["Ţ"]={ "T","̧" },
+ ["ţ"]={ "t","̧" },
+ ["Ť"]={ "T","̌" },
+ ["ť"]={ "t","̌" },
+ ["Ũ"]={ "U","̃" },
+ ["ũ"]={ "u","̃" },
+ ["Ū"]={ "U","̄" },
+ ["ū"]={ "u","̄" },
+ ["Ŭ"]={ "U","̆" },
+ ["ŭ"]={ "u","̆" },
+ ["Ů"]={ "U","̊" },
+ ["ů"]={ "u","̊" },
+ ["Ű"]={ "U","̋" },
+ ["ű"]={ "u","̋" },
+ ["Ų"]={ "U","̨" },
+ ["ų"]={ "u","̨" },
+ ["Ŵ"]={ "W","̂" },
+ ["ŵ"]={ "w","̂" },
+ ["Ŷ"]={ "Y","̂" },
+ ["ŷ"]={ "y","̂" },
+ ["Ÿ"]={ "Y","̈" },
+ ["Ź"]={ "Z","́" },
+ ["ź"]={ "z","́" },
+ ["Ż"]={ "Z","̇" },
+ ["ż"]={ "z","̇" },
+ ["Ž"]={ "Z","̌" },
+ ["ž"]={ "z","̌" },
+ ["Ơ"]={ "O","̛" },
+ ["ơ"]={ "o","̛" },
+ ["Ư"]={ "U","̛" },
+ ["ư"]={ "u","̛" },
+ ["Ǎ"]={ "A","̌" },
+ ["ǎ"]={ "a","̌" },
+ ["Ǐ"]={ "I","̌" },
+ ["ǐ"]={ "i","̌" },
+ ["Ǒ"]={ "O","̌" },
+ ["ǒ"]={ "o","̌" },
+ ["Ǔ"]={ "U","̌" },
+ ["ǔ"]={ "u","̌" },
+ ["Ǖ"]={ "Ü","̄" },
+ ["ǖ"]={ "ü","̄" },
+ ["Ǘ"]={ "Ü","́" },
+ ["ǘ"]={ "ü","́" },
+ ["Ǚ"]={ "Ü","̌" },
+ ["ǚ"]={ "ü","̌" },
+ ["Ǜ"]={ "Ü","̀" },
+ ["ǜ"]={ "ü","̀" },
+ ["Ǟ"]={ "Ä","̄" },
+ ["ǟ"]={ "ä","̄" },
+ ["Ǡ"]={ "Ȧ","̄" },
+ ["ǡ"]={ "ȧ","̄" },
+ ["Ǣ"]={ "Æ","̄" },
+ ["ǣ"]={ "æ","̄" },
+ ["Ǧ"]={ "G","̌" },
+ ["ǧ"]={ "g","̌" },
+ ["Ǩ"]={ "K","̌" },
+ ["ǩ"]={ "k","̌" },
+ ["Ǫ"]={ "O","̨" },
+ ["ǫ"]={ "o","̨" },
+ ["Ǭ"]={ "Ǫ","̄" },
+ ["ǭ"]={ "ǫ","̄" },
+ ["Ǯ"]={ "Ʒ","̌" },
+ ["ǯ"]={ "ʒ","̌" },
+ ["ǰ"]={ "j","̌" },
+ ["Ǵ"]={ "G","́" },
+ ["ǵ"]={ "g","́" },
+ ["Ǹ"]={ "N","̀" },
+ ["ǹ"]={ "n","̀" },
+ ["Ǻ"]={ "Å","́" },
+ ["ǻ"]={ "å","́" },
+ ["Ǽ"]={ "Æ","́" },
+ ["ǽ"]={ "æ","́" },
+ ["Ǿ"]={ "Ø","́" },
+ ["ǿ"]={ "ø","́" },
+ ["Ȁ"]={ "A","̏" },
+ ["ȁ"]={ "a","̏" },
+ ["Ȃ"]={ "A","̑" },
+ ["ȃ"]={ "a","̑" },
+ ["Ȅ"]={ "E","̏" },
+ ["ȅ"]={ "e","̏" },
+ ["Ȇ"]={ "E","̑" },
+ ["ȇ"]={ "e","̑" },
+ ["Ȉ"]={ "I","̏" },
+ ["ȉ"]={ "i","̏" },
+ ["Ȋ"]={ "I","̑" },
+ ["ȋ"]={ "i","̑" },
+ ["Ȍ"]={ "O","̏" },
+ ["ȍ"]={ "o","̏" },
+ ["Ȏ"]={ "O","̑" },
+ ["ȏ"]={ "o","̑" },
+ ["Ȑ"]={ "R","̏" },
+ ["ȑ"]={ "r","̏" },
+ ["Ȓ"]={ "R","̑" },
+ ["ȓ"]={ "r","̑" },
+ ["Ȕ"]={ "U","̏" },
+ ["ȕ"]={ "u","̏" },
+ ["Ȗ"]={ "U","̑" },
+ ["ȗ"]={ "u","̑" },
+ ["Ș"]={ "S","̦" },
+ ["ș"]={ "s","̦" },
+ ["Ț"]={ "T","̦" },
+ ["ț"]={ "t","̦" },
+ ["Ȟ"]={ "H","̌" },
+ ["ȟ"]={ "h","̌" },
+ ["Ȧ"]={ "A","̇" },
+ ["ȧ"]={ "a","̇" },
+ ["Ȩ"]={ "E","̧" },
+ ["ȩ"]={ "e","̧" },
+ ["Ȫ"]={ "Ö","̄" },
+ ["ȫ"]={ "ö","̄" },
+ ["Ȭ"]={ "Õ","̄" },
+ ["ȭ"]={ "õ","̄" },
+ ["Ȯ"]={ "O","̇" },
+ ["ȯ"]={ "o","̇" },
+ ["Ȱ"]={ "Ȯ","̄" },
+ ["ȱ"]={ "ȯ","̄" },
+ ["Ȳ"]={ "Y","̄" },
+ ["ȳ"]={ "y","̄" },
+ ["̈́"]={ "̈","́" },
+ ["΅"]={ "¨","́" },
+ ["Ά"]={ "Α","́" },
+ ["Έ"]={ "Ε","́" },
+ ["Ή"]={ "Η","́" },
+ ["Ί"]={ "Ι","́" },
+ ["Ό"]={ "Ο","́" },
+ ["Ύ"]={ "Υ","́" },
+ ["Ώ"]={ "Ω","́" },
+ ["ΐ"]={ "ϊ","́" },
+ ["Ϊ"]={ "Ι","̈" },
+ ["Ϋ"]={ "Υ","̈" },
+ ["ά"]={ "α","́" },
+ ["έ"]={ "ε","́" },
+ ["ή"]={ "η","́" },
+ ["ί"]={ "ι","́" },
+ ["ΰ"]={ "ϋ","́" },
+ ["ϊ"]={ "ι","̈" },
+ ["ϋ"]={ "υ","̈" },
+ ["ό"]={ "ο","́" },
+ ["ύ"]={ "υ","́" },
+ ["ώ"]={ "ω","́" },
+ ["ϓ"]={ "ϒ","́" },
+ ["ϔ"]={ "ϒ","̈" },
+ ["Ѐ"]={ "Е","̀" },
+ ["Ё"]={ "Е","̈" },
+ ["Ѓ"]={ "Г","́" },
+ ["Ї"]={ "І","̈" },
+ ["Ќ"]={ "К","́" },
+ ["Ѝ"]={ "И","̀" },
+ ["Ў"]={ "У","̆" },
+ ["Й"]={ "И","̆" },
+ ["й"]={ "и","̆" },
+ ["ѐ"]={ "е","̀" },
+ ["ё"]={ "е","̈" },
+ ["ѓ"]={ "г","́" },
+ ["ї"]={ "і","̈" },
+ ["ќ"]={ "к","́" },
+ ["ѝ"]={ "и","̀" },
+ ["ў"]={ "у","̆" },
+ ["Ѷ"]={ "Ѵ","̏" },
+ ["ѷ"]={ "ѵ","̏" },
+ ["Ӂ"]={ "Ж","̆" },
+ ["ӂ"]={ "ж","̆" },
+ ["Ӑ"]={ "А","̆" },
+ ["ӑ"]={ "а","̆" },
+ ["Ӓ"]={ "А","̈" },
+ ["ӓ"]={ "а","̈" },
+ ["Ӗ"]={ "Е","̆" },
+ ["ӗ"]={ "е","̆" },
+ ["Ӛ"]={ "Ә","̈" },
+ ["ӛ"]={ "ә","̈" },
+ ["Ӝ"]={ "Ж","̈" },
+ ["ӝ"]={ "ж","̈" },
+ ["Ӟ"]={ "З","̈" },
+ ["ӟ"]={ "з","̈" },
+ ["Ӣ"]={ "И","̄" },
+ ["ӣ"]={ "и","̄" },
+ ["Ӥ"]={ "И","̈" },
+ ["ӥ"]={ "и","̈" },
+ ["Ӧ"]={ "О","̈" },
+ ["ӧ"]={ "о","̈" },
+ ["Ӫ"]={ "Ө","̈" },
+ ["ӫ"]={ "ө","̈" },
+ ["Ӭ"]={ "Э","̈" },
+ ["ӭ"]={ "э","̈" },
+ ["Ӯ"]={ "У","̄" },
+ ["ӯ"]={ "у","̄" },
+ ["Ӱ"]={ "У","̈" },
+ ["ӱ"]={ "у","̈" },
+ ["Ӳ"]={ "У","̋" },
+ ["ӳ"]={ "у","̋" },
+ ["Ӵ"]={ "Ч","̈" },
+ ["ӵ"]={ "ч","̈" },
+ ["Ӹ"]={ "Ы","̈" },
+ ["ӹ"]={ "ы","̈" },
+ ["آ"]={ "ا","ٓ" },
+ ["أ"]={ "ا","ٔ" },
+ ["ؤ"]={ "و","ٔ" },
+ ["إ"]={ "ا","ٕ" },
+ ["ئ"]={ "ي","ٔ" },
+ ["ۀ"]={ "ە","ٔ" },
+ ["ۂ"]={ "ہ","ٔ" },
+ ["ۓ"]={ "ے","ٔ" },
+ ["ऩ"]={ "न","़" },
+ ["ऱ"]={ "र","़" },
+ ["ऴ"]={ "ळ","़" },
+ ["क़"]={ "क","़" },
+ ["ख़"]={ "ख","़" },
+ ["ग़"]={ "ग","़" },
+ ["ज़"]={ "ज","़" },
+ ["ड़"]={ "ड","़" },
+ ["ढ़"]={ "ढ","़" },
+ ["फ़"]={ "फ","़" },
+ ["य़"]={ "य","़" },
+ ["ো"]={ "ে","া" },
+ ["ৌ"]={ "ে","ৗ" },
+ ["ড়"]={ "ড","়" },
+ ["ঢ়"]={ "ঢ","়" },
+ ["য়"]={ "য","়" },
+ ["ਲ਼"]={ "ਲ","਼" },
+ ["ਸ਼"]={ "ਸ","਼" },
+ ["ਖ਼"]={ "ਖ","਼" },
+ ["ਗ਼"]={ "ਗ","਼" },
+ ["ਜ਼"]={ "ਜ","਼" },
+ ["ਫ਼"]={ "ਫ","਼" },
+ ["ୈ"]={ "େ","ୖ" },
+ ["ୋ"]={ "େ","ା" },
+ ["ୌ"]={ "େ","ୗ" },
+ ["ଡ଼"]={ "ଡ","଼" },
+ ["ଢ଼"]={ "ଢ","଼" },
+ ["ஔ"]={ "ஒ","ௗ" },
+ ["ொ"]={ "ெ","ா" },
+ ["ோ"]={ "ே","ா" },
+ ["ௌ"]={ "ெ","ௗ" },
+ ["ై"]={ "ె","ౖ" },
+ ["ೀ"]={ "ಿ","ೕ" },
+ ["ೇ"]={ "ೆ","ೕ" },
+ ["ೈ"]={ "ೆ","ೖ" },
+ ["ೊ"]={ "ೆ","ೂ" },
+ ["ೋ"]={ "ೊ","ೕ" },
+ ["ൊ"]={ "െ","ാ" },
+ ["ോ"]={ "േ","ാ" },
+ ["ൌ"]={ "െ","ൗ" },
+ ["ේ"]={ "ෙ","්" },
+ ["ො"]={ "ෙ","ා" },
+ ["ෝ"]={ "ො","්" },
+ ["ෞ"]={ "ෙ","ෟ" },
+ ["གྷ"]={ "ག","ྷ" },
+ ["ཌྷ"]={ "ཌ","ྷ" },
+ ["དྷ"]={ "ད","ྷ" },
+ ["བྷ"]={ "བ","ྷ" },
+ ["ཛྷ"]={ "ཛ","ྷ" },
+ ["ཀྵ"]={ "ཀ","ྵ" },
+ ["ཱི"]={ "ཱ","ི" },
+ ["ཱུ"]={ "ཱ","ུ" },
+ ["ྲྀ"]={ "ྲ","ྀ" },
+ ["ླྀ"]={ "ླ","ྀ" },
+ ["ཱྀ"]={ "ཱ","ྀ" },
+ ["ྒྷ"]={ "ྒ","ྷ" },
+ ["ྜྷ"]={ "ྜ","ྷ" },
+ ["ྡྷ"]={ "ྡ","ྷ" },
+ ["ྦྷ"]={ "ྦ","ྷ" },
+ ["ྫྷ"]={ "ྫ","ྷ" },
+ ["ྐྵ"]={ "ྐ","ྵ" },
+ ["ဦ"]={ "ဥ","ီ" },
+ ["ᬆ"]={ "ᬅ","ᬵ" },
+ ["ᬈ"]={ "ᬇ","ᬵ" },
+ ["ᬊ"]={ "ᬉ","ᬵ" },
+ ["ᬌ"]={ "ᬋ","ᬵ" },
+ ["ᬎ"]={ "ᬍ","ᬵ" },
+ ["ᬒ"]={ "ᬑ","ᬵ" },
+ ["ᬻ"]={ "ᬺ","ᬵ" },
+ ["ᬽ"]={ "ᬼ","ᬵ" },
+ ["ᭀ"]={ "ᬾ","ᬵ" },
+ ["ᭁ"]={ "ᬿ","ᬵ" },
+ ["ᭃ"]={ "ᭂ","ᬵ" },
+ ["Ḁ"]={ "A","̥" },
+ ["ḁ"]={ "a","̥" },
+ ["Ḃ"]={ "B","̇" },
+ ["ḃ"]={ "b","̇" },
+ ["Ḅ"]={ "B","̣" },
+ ["ḅ"]={ "b","̣" },
+ ["Ḇ"]={ "B","̱" },
+ ["ḇ"]={ "b","̱" },
+ ["Ḉ"]={ "Ç","́" },
+ ["ḉ"]={ "ç","́" },
+ ["Ḋ"]={ "D","̇" },
+ ["ḋ"]={ "d","̇" },
+ ["Ḍ"]={ "D","̣" },
+ ["ḍ"]={ "d","̣" },
+ ["Ḏ"]={ "D","̱" },
+ ["ḏ"]={ "d","̱" },
+ ["Ḑ"]={ "D","̧" },
+ ["ḑ"]={ "d","̧" },
+ ["Ḓ"]={ "D","̭" },
+ ["ḓ"]={ "d","̭" },
+ ["Ḕ"]={ "Ē","̀" },
+ ["ḕ"]={ "ē","̀" },
+ ["Ḗ"]={ "Ē","́" },
+ ["ḗ"]={ "ē","́" },
+ ["Ḙ"]={ "E","̭" },
+ ["ḙ"]={ "e","̭" },
+ ["Ḛ"]={ "E","̰" },
+ ["ḛ"]={ "e","̰" },
+ ["Ḝ"]={ "Ȩ","̆" },
+ ["ḝ"]={ "ȩ","̆" },
+ ["Ḟ"]={ "F","̇" },
+ ["ḟ"]={ "f","̇" },
+ ["Ḡ"]={ "G","̄" },
+ ["ḡ"]={ "g","̄" },
+ ["Ḣ"]={ "H","̇" },
+ ["ḣ"]={ "h","̇" },
+ ["Ḥ"]={ "H","̣" },
+ ["ḥ"]={ "h","̣" },
+ ["Ḧ"]={ "H","̈" },
+ ["ḧ"]={ "h","̈" },
+ ["Ḩ"]={ "H","̧" },
+ ["ḩ"]={ "h","̧" },
+ ["Ḫ"]={ "H","̮" },
+ ["ḫ"]={ "h","̮" },
+ ["Ḭ"]={ "I","̰" },
+ ["ḭ"]={ "i","̰" },
+ ["Ḯ"]={ "Ï","́" },
+ ["ḯ"]={ "ï","́" },
+ ["Ḱ"]={ "K","́" },
+ ["ḱ"]={ "k","́" },
+ ["Ḳ"]={ "K","̣" },
+ ["ḳ"]={ "k","̣" },
+ ["Ḵ"]={ "K","̱" },
+ ["ḵ"]={ "k","̱" },
+ ["Ḷ"]={ "L","̣" },
+ ["ḷ"]={ "l","̣" },
+ ["Ḹ"]={ "Ḷ","̄" },
+ ["ḹ"]={ "ḷ","̄" },
+ ["Ḻ"]={ "L","̱" },
+ ["ḻ"]={ "l","̱" },
+ ["Ḽ"]={ "L","̭" },
+ ["ḽ"]={ "l","̭" },
+ ["Ḿ"]={ "M","́" },
+ ["ḿ"]={ "m","́" },
+ ["Ṁ"]={ "M","̇" },
+ ["ṁ"]={ "m","̇" },
+ ["Ṃ"]={ "M","̣" },
+ ["ṃ"]={ "m","̣" },
+ ["Ṅ"]={ "N","̇" },
+ ["ṅ"]={ "n","̇" },
+ ["Ṇ"]={ "N","̣" },
+ ["ṇ"]={ "n","̣" },
+ ["Ṉ"]={ "N","̱" },
+ ["ṉ"]={ "n","̱" },
+ ["Ṋ"]={ "N","̭" },
+ ["ṋ"]={ "n","̭" },
+ ["Ṍ"]={ "Õ","́" },
+ ["ṍ"]={ "õ","́" },
+ ["Ṏ"]={ "Õ","̈" },
+ ["ṏ"]={ "õ","̈" },
+ ["Ṑ"]={ "Ō","̀" },
+ ["ṑ"]={ "ō","̀" },
+ ["Ṓ"]={ "Ō","́" },
+ ["ṓ"]={ "ō","́" },
+ ["Ṕ"]={ "P","́" },
+ ["ṕ"]={ "p","́" },
+ ["Ṗ"]={ "P","̇" },
+ ["ṗ"]={ "p","̇" },
+ ["Ṙ"]={ "R","̇" },
+ ["ṙ"]={ "r","̇" },
+ ["Ṛ"]={ "R","̣" },
+ ["ṛ"]={ "r","̣" },
+ ["Ṝ"]={ "Ṛ","̄" },
+ ["ṝ"]={ "ṛ","̄" },
+ ["Ṟ"]={ "R","̱" },
+ ["ṟ"]={ "r","̱" },
+ ["Ṡ"]={ "S","̇" },
+ ["ṡ"]={ "s","̇" },
+ ["Ṣ"]={ "S","̣" },
+ ["ṣ"]={ "s","̣" },
+ ["Ṥ"]={ "Ś","̇" },
+ ["ṥ"]={ "ś","̇" },
+ ["Ṧ"]={ "Š","̇" },
+ ["ṧ"]={ "š","̇" },
+ ["Ṩ"]={ "Ṣ","̇" },
+ ["ṩ"]={ "ṣ","̇" },
+ ["Ṫ"]={ "T","̇" },
+ ["ṫ"]={ "t","̇" },
+ ["Ṭ"]={ "T","̣" },
+ ["ṭ"]={ "t","̣" },
+ ["Ṯ"]={ "T","̱" },
+ ["ṯ"]={ "t","̱" },
+ ["Ṱ"]={ "T","̭" },
+ ["ṱ"]={ "t","̭" },
+ ["Ṳ"]={ "U","̤" },
+ ["ṳ"]={ "u","̤" },
+ ["Ṵ"]={ "U","̰" },
+ ["ṵ"]={ "u","̰" },
+ ["Ṷ"]={ "U","̭" },
+ ["ṷ"]={ "u","̭" },
+ ["Ṹ"]={ "Ũ","́" },
+ ["ṹ"]={ "ũ","́" },
+ ["Ṻ"]={ "Ū","̈" },
+ ["ṻ"]={ "ū","̈" },
+ ["Ṽ"]={ "V","̃" },
+ ["ṽ"]={ "v","̃" },
+ ["Ṿ"]={ "V","̣" },
+ ["ṿ"]={ "v","̣" },
+ ["Ẁ"]={ "W","̀" },
+ ["ẁ"]={ "w","̀" },
+ ["Ẃ"]={ "W","́" },
+ ["ẃ"]={ "w","́" },
+ ["Ẅ"]={ "W","̈" },
+ ["ẅ"]={ "w","̈" },
+ ["Ẇ"]={ "W","̇" },
+ ["ẇ"]={ "w","̇" },
+ ["Ẉ"]={ "W","̣" },
+ ["ẉ"]={ "w","̣" },
+ ["Ẋ"]={ "X","̇" },
+ ["ẋ"]={ "x","̇" },
+ ["Ẍ"]={ "X","̈" },
+ ["ẍ"]={ "x","̈" },
+ ["Ẏ"]={ "Y","̇" },
+ ["ẏ"]={ "y","̇" },
+ ["Ẑ"]={ "Z","̂" },
+ ["ẑ"]={ "z","̂" },
+ ["Ẓ"]={ "Z","̣" },
+ ["ẓ"]={ "z","̣" },
+ ["Ẕ"]={ "Z","̱" },
+ ["ẕ"]={ "z","̱" },
+ ["ẖ"]={ "h","̱" },
+ ["ẗ"]={ "t","̈" },
+ ["ẘ"]={ "w","̊" },
+ ["ẙ"]={ "y","̊" },
+ ["ẛ"]={ "ſ","̇" },
+ ["Ạ"]={ "A","̣" },
+ ["ạ"]={ "a","̣" },
+ ["Ả"]={ "A","̉" },
+ ["ả"]={ "a","̉" },
+ ["Ấ"]={ "Â","́" },
+ ["ấ"]={ "â","́" },
+ ["Ầ"]={ "Â","̀" },
+ ["ầ"]={ "â","̀" },
+ ["Ẩ"]={ "Â","̉" },
+ ["ẩ"]={ "â","̉" },
+ ["Ẫ"]={ "Â","̃" },
+ ["ẫ"]={ "â","̃" },
+ ["Ậ"]={ "Ạ","̂" },
+ ["ậ"]={ "ạ","̂" },
+ ["Ắ"]={ "Ă","́" },
+ ["ắ"]={ "ă","́" },
+ ["Ằ"]={ "Ă","̀" },
+ ["ằ"]={ "ă","̀" },
+ ["Ẳ"]={ "Ă","̉" },
+ ["ẳ"]={ "ă","̉" },
+ ["Ẵ"]={ "Ă","̃" },
+ ["ẵ"]={ "ă","̃" },
+ ["Ặ"]={ "Ạ","̆" },
+ ["ặ"]={ "ạ","̆" },
+ ["Ẹ"]={ "E","̣" },
+ ["ẹ"]={ "e","̣" },
+ ["Ẻ"]={ "E","̉" },
+ ["ẻ"]={ "e","̉" },
+ ["Ẽ"]={ "E","̃" },
+ ["ẽ"]={ "e","̃" },
+ ["Ế"]={ "Ê","́" },
+ ["ế"]={ "ê","́" },
+ ["Ề"]={ "Ê","̀" },
+ ["ề"]={ "ê","̀" },
+ ["Ể"]={ "Ê","̉" },
+ ["ể"]={ "ê","̉" },
+ ["Ễ"]={ "Ê","̃" },
+ ["ễ"]={ "ê","̃" },
+ ["Ệ"]={ "Ẹ","̂" },
+ ["ệ"]={ "ẹ","̂" },
+ ["Ỉ"]={ "I","̉" },
+ ["ỉ"]={ "i","̉" },
+ ["Ị"]={ "I","̣" },
+ ["ị"]={ "i","̣" },
+ ["Ọ"]={ "O","̣" },
+ ["ọ"]={ "o","̣" },
+ ["Ỏ"]={ "O","̉" },
+ ["ỏ"]={ "o","̉" },
+ ["Ố"]={ "Ô","́" },
+ ["ố"]={ "ô","́" },
+ ["Ồ"]={ "Ô","̀" },
+ ["ồ"]={ "ô","̀" },
+ ["Ổ"]={ "Ô","̉" },
+ ["ổ"]={ "ô","̉" },
+ ["Ỗ"]={ "Ô","̃" },
+ ["ỗ"]={ "ô","̃" },
+ ["Ộ"]={ "Ọ","̂" },
+ ["ộ"]={ "ọ","̂" },
+ ["Ớ"]={ "Ơ","́" },
+ ["ớ"]={ "ơ","́" },
+ ["Ờ"]={ "Ơ","̀" },
+ ["ờ"]={ "ơ","̀" },
+ ["Ở"]={ "Ơ","̉" },
+ ["ở"]={ "ơ","̉" },
+ ["Ỡ"]={ "Ơ","̃" },
+ ["ỡ"]={ "ơ","̃" },
+ ["Ợ"]={ "Ơ","̣" },
+ ["ợ"]={ "ơ","̣" },
+ ["Ụ"]={ "U","̣" },
+ ["ụ"]={ "u","̣" },
+ ["Ủ"]={ "U","̉" },
+ ["ủ"]={ "u","̉" },
+ ["Ứ"]={ "Ư","́" },
+ ["ứ"]={ "ư","́" },
+ ["Ừ"]={ "Ư","̀" },
+ ["ừ"]={ "ư","̀" },
+ ["Ử"]={ "Ư","̉" },
+ ["ử"]={ "ư","̉" },
+ ["Ữ"]={ "Ư","̃" },
+ ["ữ"]={ "ư","̃" },
+ ["Ự"]={ "Ư","̣" },
+ ["ự"]={ "ư","̣" },
+ ["Ỳ"]={ "Y","̀" },
+ ["ỳ"]={ "y","̀" },
+ ["Ỵ"]={ "Y","̣" },
+ ["ỵ"]={ "y","̣" },
+ ["Ỷ"]={ "Y","̉" },
+ ["ỷ"]={ "y","̉" },
+ ["Ỹ"]={ "Y","̃" },
+ ["ỹ"]={ "y","̃" },
+ ["ἀ"]={ "α","̓" },
+ ["ἁ"]={ "α","̔" },
+ ["ἂ"]={ "ἀ","̀" },
+ ["ἃ"]={ "ἁ","̀" },
+ ["ἄ"]={ "ἀ","́" },
+ ["ἅ"]={ "ἁ","́" },
+ ["ἆ"]={ "ἀ","͂" },
+ ["ἇ"]={ "ἁ","͂" },
+ ["Ἀ"]={ "Α","̓" },
+ ["Ἁ"]={ "Α","̔" },
+ ["Ἂ"]={ "Ἀ","̀" },
+ ["Ἃ"]={ "Ἁ","̀" },
+ ["Ἄ"]={ "Ἀ","́" },
+ ["Ἅ"]={ "Ἁ","́" },
+ ["Ἆ"]={ "Ἀ","͂" },
+ ["Ἇ"]={ "Ἁ","͂" },
+ ["ἐ"]={ "ε","̓" },
+ ["ἑ"]={ "ε","̔" },
+ ["ἒ"]={ "ἐ","̀" },
+ ["ἓ"]={ "ἑ","̀" },
+ ["ἔ"]={ "ἐ","́" },
+ ["ἕ"]={ "ἑ","́" },
+ ["Ἐ"]={ "Ε","̓" },
+ ["Ἑ"]={ "Ε","̔" },
+ ["Ἒ"]={ "Ἐ","̀" },
+ ["Ἓ"]={ "Ἑ","̀" },
+ ["Ἔ"]={ "Ἐ","́" },
+ ["Ἕ"]={ "Ἑ","́" },
+ ["ἠ"]={ "η","̓" },
+ ["ἡ"]={ "η","̔" },
+ ["ἢ"]={ "ἠ","̀" },
+ ["ἣ"]={ "ἡ","̀" },
+ ["ἤ"]={ "ἠ","́" },
+ ["ἥ"]={ "ἡ","́" },
+ ["ἦ"]={ "ἠ","͂" },
+ ["ἧ"]={ "ἡ","͂" },
+ ["Ἠ"]={ "Η","̓" },
+ ["Ἡ"]={ "Η","̔" },
+ ["Ἢ"]={ "Ἠ","̀" },
+ ["Ἣ"]={ "Ἡ","̀" },
+ ["Ἤ"]={ "Ἠ","́" },
+ ["Ἥ"]={ "Ἡ","́" },
+ ["Ἦ"]={ "Ἠ","͂" },
+ ["Ἧ"]={ "Ἡ","͂" },
+ ["ἰ"]={ "ι","̓" },
+ ["ἱ"]={ "ι","̔" },
+ ["ἲ"]={ "ἰ","̀" },
+ ["ἳ"]={ "ἱ","̀" },
+ ["ἴ"]={ "ἰ","́" },
+ ["ἵ"]={ "ἱ","́" },
+ ["ἶ"]={ "ἰ","͂" },
+ ["ἷ"]={ "ἱ","͂" },
+ ["Ἰ"]={ "Ι","̓" },
+ ["Ἱ"]={ "Ι","̔" },
+ ["Ἲ"]={ "Ἰ","̀" },
+ ["Ἳ"]={ "Ἱ","̀" },
+ ["Ἴ"]={ "Ἰ","́" },
+ ["Ἵ"]={ "Ἱ","́" },
+ ["Ἶ"]={ "Ἰ","͂" },
+ ["Ἷ"]={ "Ἱ","͂" },
+ ["ὀ"]={ "ο","̓" },
+ ["ὁ"]={ "ο","̔" },
+ ["ὂ"]={ "ὀ","̀" },
+ ["ὃ"]={ "ὁ","̀" },
+ ["ὄ"]={ "ὀ","́" },
+ ["ὅ"]={ "ὁ","́" },
+ ["Ὀ"]={ "Ο","̓" },
+ ["Ὁ"]={ "Ο","̔" },
+ ["Ὂ"]={ "Ὀ","̀" },
+ ["Ὃ"]={ "Ὁ","̀" },
+ ["Ὄ"]={ "Ὀ","́" },
+ ["Ὅ"]={ "Ὁ","́" },
+ ["ὐ"]={ "υ","̓" },
+ ["ὑ"]={ "υ","̔" },
+ ["ὒ"]={ "ὐ","̀" },
+ ["ὓ"]={ "ὑ","̀" },
+ ["ὔ"]={ "ὐ","́" },
+ ["ὕ"]={ "ὑ","́" },
+ ["ὖ"]={ "ὐ","͂" },
+ ["ὗ"]={ "ὑ","͂" },
+ ["Ὑ"]={ "Υ","̔" },
+ ["Ὓ"]={ "Ὑ","̀" },
+ ["Ὕ"]={ "Ὑ","́" },
+ ["Ὗ"]={ "Ὑ","͂" },
+ ["ὠ"]={ "ω","̓" },
+ ["ὡ"]={ "ω","̔" },
+ ["ὢ"]={ "ὠ","̀" },
+ ["ὣ"]={ "ὡ","̀" },
+ ["ὤ"]={ "ὠ","́" },
+ ["ὥ"]={ "ὡ","́" },
+ ["ὦ"]={ "ὠ","͂" },
+ ["ὧ"]={ "ὡ","͂" },
+ ["Ὠ"]={ "Ω","̓" },
+ ["Ὡ"]={ "Ω","̔" },
+ ["Ὢ"]={ "Ὠ","̀" },
+ ["Ὣ"]={ "Ὡ","̀" },
+ ["Ὤ"]={ "Ὠ","́" },
+ ["Ὥ"]={ "Ὡ","́" },
+ ["Ὦ"]={ "Ὠ","͂" },
+ ["Ὧ"]={ "Ὡ","͂" },
+ ["ὰ"]={ "α","̀" },
+ ["ὲ"]={ "ε","̀" },
+ ["ὴ"]={ "η","̀" },
+ ["ὶ"]={ "ι","̀" },
+ ["ὸ"]={ "ο","̀" },
+ ["ὺ"]={ "υ","̀" },
+ ["ὼ"]={ "ω","̀" },
+ ["ᾀ"]={ "ἀ","ͅ" },
+ ["ᾁ"]={ "ἁ","ͅ" },
+ ["ᾂ"]={ "ἂ","ͅ" },
+ ["ᾃ"]={ "ἃ","ͅ" },
+ ["ᾄ"]={ "ἄ","ͅ" },
+ ["ᾅ"]={ "ἅ","ͅ" },
+ ["ᾆ"]={ "ἆ","ͅ" },
+ ["ᾇ"]={ "ἇ","ͅ" },
+ ["ᾈ"]={ "Ἀ","ͅ" },
+ ["ᾉ"]={ "Ἁ","ͅ" },
+ ["ᾊ"]={ "Ἂ","ͅ" },
+ ["ᾋ"]={ "Ἃ","ͅ" },
+ ["ᾌ"]={ "Ἄ","ͅ" },
+ ["ᾍ"]={ "Ἅ","ͅ" },
+ ["ᾎ"]={ "Ἆ","ͅ" },
+ ["ᾏ"]={ "Ἇ","ͅ" },
+ ["ᾐ"]={ "ἠ","ͅ" },
+ ["ᾑ"]={ "ἡ","ͅ" },
+ ["ᾒ"]={ "ἢ","ͅ" },
+ ["ᾓ"]={ "ἣ","ͅ" },
+ ["ᾔ"]={ "ἤ","ͅ" },
+ ["ᾕ"]={ "ἥ","ͅ" },
+ ["ᾖ"]={ "ἦ","ͅ" },
+ ["ᾗ"]={ "ἧ","ͅ" },
+ ["ᾘ"]={ "Ἠ","ͅ" },
+ ["ᾙ"]={ "Ἡ","ͅ" },
+ ["ᾚ"]={ "Ἢ","ͅ" },
+ ["ᾛ"]={ "Ἣ","ͅ" },
+ ["ᾜ"]={ "Ἤ","ͅ" },
+ ["ᾝ"]={ "Ἥ","ͅ" },
+ ["ᾞ"]={ "Ἦ","ͅ" },
+ ["ᾟ"]={ "Ἧ","ͅ" },
+ ["ᾠ"]={ "ὠ","ͅ" },
+ ["ᾡ"]={ "ὡ","ͅ" },
+ ["ᾢ"]={ "ὢ","ͅ" },
+ ["ᾣ"]={ "ὣ","ͅ" },
+ ["ᾤ"]={ "ὤ","ͅ" },
+ ["ᾥ"]={ "ὥ","ͅ" },
+ ["ᾦ"]={ "ὦ","ͅ" },
+ ["ᾧ"]={ "ὧ","ͅ" },
+ ["ᾨ"]={ "Ὠ","ͅ" },
+ ["ᾩ"]={ "Ὡ","ͅ" },
+ ["ᾪ"]={ "Ὢ","ͅ" },
+ ["ᾫ"]={ "Ὣ","ͅ" },
+ ["ᾬ"]={ "Ὤ","ͅ" },
+ ["ᾭ"]={ "Ὥ","ͅ" },
+ ["ᾮ"]={ "Ὦ","ͅ" },
+ ["ᾯ"]={ "Ὧ","ͅ" },
+ ["ᾰ"]={ "α","̆" },
+ ["ᾱ"]={ "α","̄" },
+ ["ᾲ"]={ "ὰ","ͅ" },
+ ["ᾳ"]={ "α","ͅ" },
+ ["ᾴ"]={ "ά","ͅ" },
+ ["ᾶ"]={ "α","͂" },
+ ["ᾷ"]={ "ᾶ","ͅ" },
+ ["Ᾰ"]={ "Α","̆" },
+ ["Ᾱ"]={ "Α","̄" },
+ ["Ὰ"]={ "Α","̀" },
+ ["ᾼ"]={ "Α","ͅ" },
+ ["῁"]={ "¨","͂" },
+ ["ῂ"]={ "ὴ","ͅ" },
+ ["ῃ"]={ "η","ͅ" },
+ ["ῄ"]={ "ή","ͅ" },
+ ["ῆ"]={ "η","͂" },
+ ["ῇ"]={ "ῆ","ͅ" },
+ ["Ὲ"]={ "Ε","̀" },
+ ["Ὴ"]={ "Η","̀" },
+ ["ῌ"]={ "Η","ͅ" },
+ ["῍"]={ "᾿","̀" },
+ ["῎"]={ "᾿","́" },
+ ["῏"]={ "᾿","͂" },
+ ["ῐ"]={ "ι","̆" },
+ ["ῑ"]={ "ι","̄" },
+ ["ῒ"]={ "ϊ","̀" },
+ ["ῖ"]={ "ι","͂" },
+ ["ῗ"]={ "ϊ","͂" },
+ ["Ῐ"]={ "Ι","̆" },
+ ["Ῑ"]={ "Ι","̄" },
+ ["Ὶ"]={ "Ι","̀" },
+ ["῝"]={ "῾","̀" },
+ ["῞"]={ "῾","́" },
+ ["῟"]={ "῾","͂" },
+ ["ῠ"]={ "υ","̆" },
+ ["ῡ"]={ "υ","̄" },
+ ["ῢ"]={ "ϋ","̀" },
+ ["ῤ"]={ "ρ","̓" },
+ ["ῥ"]={ "ρ","̔" },
+ ["ῦ"]={ "υ","͂" },
+ ["ῧ"]={ "ϋ","͂" },
+ ["Ῠ"]={ "Υ","̆" },
+ ["Ῡ"]={ "Υ","̄" },
+ ["Ὺ"]={ "Υ","̀" },
+ ["Ῥ"]={ "Ρ","̔" },
+ ["῭"]={ "¨","̀" },
+ ["ῲ"]={ "ὼ","ͅ" },
+ ["ῳ"]={ "ω","ͅ" },
+ ["ῴ"]={ "ώ","ͅ" },
+ ["ῶ"]={ "ω","͂" },
+ ["ῷ"]={ "ῶ","ͅ" },
+ ["Ὸ"]={ "Ο","̀" },
+ ["Ὼ"]={ "Ω","̀" },
+ ["ῼ"]={ "Ω","ͅ" },
+ ["↚"]={ "←","̸" },
+ ["↛"]={ "→","̸" },
+ ["↮"]={ "↔","̸" },
+ ["⇍"]={ "⇐","̸" },
+ ["⇎"]={ "⇔","̸" },
+ ["⇏"]={ "⇒","̸" },
+ ["∄"]={ "∃","̸" },
+ ["∉"]={ "∈","̸" },
+ ["∌"]={ "∋","̸" },
+ ["∤"]={ "∣","̸" },
+ ["∦"]={ "∥","̸" },
+ ["≁"]={ "∼","̸" },
+ ["≄"]={ "≃","̸" },
+ ["≇"]={ "≅","̸" },
+ ["≉"]={ "≈","̸" },
+ ["≠"]={ "=","̸" },
+ ["≢"]={ "≡","̸" },
+ ["≭"]={ "≍","̸" },
+ ["≮"]={ "<","̸" },
+ ["≯"]={ ">","̸" },
+ ["≰"]={ "≤","̸" },
+ ["≱"]={ "≥","̸" },
+ ["≴"]={ "≲","̸" },
+ ["≵"]={ "≳","̸" },
+ ["≸"]={ "≶","̸" },
+ ["≹"]={ "≷","̸" },
+ ["⊀"]={ "≺","̸" },
+ ["⊁"]={ "≻","̸" },
+ ["⊄"]={ "⊂","̸" },
+ ["⊅"]={ "⊃","̸" },
+ ["⊈"]={ "⊆","̸" },
+ ["⊉"]={ "⊇","̸" },
+ ["⊬"]={ "⊢","̸" },
+ ["⊭"]={ "⊨","̸" },
+ ["⊮"]={ "⊩","̸" },
+ ["⊯"]={ "⊫","̸" },
+ ["⋠"]={ "≼","̸" },
+ ["⋡"]={ "≽","̸" },
+ ["⋢"]={ "⊑","̸" },
+ ["⋣"]={ "⊒","̸" },
+ ["⋪"]={ "⊲","̸" },
+ ["⋫"]={ "⊳","̸" },
+ ["⋬"]={ "⊴","̸" },
+ ["⋭"]={ "⊵","̸" },
+ ["⫝̸"]={ "⫝","̸" },
+ ["が"]={ "か","゙" },
+ ["ぎ"]={ "き","゙" },
+ ["ぐ"]={ "く","゙" },
+ ["げ"]={ "け","゙" },
+ ["ご"]={ "こ","゙" },
+ ["ざ"]={ "さ","゙" },
+ ["じ"]={ "し","゙" },
+ ["ず"]={ "す","゙" },
+ ["ぜ"]={ "せ","゙" },
+ ["ぞ"]={ "そ","゙" },
+ ["だ"]={ "た","゙" },
+ ["ぢ"]={ "ち","゙" },
+ ["づ"]={ "つ","゙" },
+ ["で"]={ "て","゙" },
+ ["ど"]={ "と","゙" },
+ ["ば"]={ "は","゙" },
+ ["ぱ"]={ "は","゚" },
+ ["び"]={ "ひ","゙" },
+ ["ぴ"]={ "ひ","゚" },
+ ["ぶ"]={ "ふ","゙" },
+ ["ぷ"]={ "ふ","゚" },
+ ["べ"]={ "へ","゙" },
+ ["ぺ"]={ "へ","゚" },
+ ["ぼ"]={ "ほ","゙" },
+ ["ぽ"]={ "ほ","゚" },
+ ["ゔ"]={ "う","゙" },
+ ["ゞ"]={ "ゝ","゙" },
+ ["ガ"]={ "カ","゙" },
+ ["ギ"]={ "キ","゙" },
+ ["グ"]={ "ク","゙" },
+ ["ゲ"]={ "ケ","゙" },
+ ["ゴ"]={ "コ","゙" },
+ ["ザ"]={ "サ","゙" },
+ ["ジ"]={ "シ","゙" },
+ ["ズ"]={ "ス","゙" },
+ ["ゼ"]={ "セ","゙" },
+ ["ゾ"]={ "ソ","゙" },
+ ["ダ"]={ "タ","゙" },
+ ["ヂ"]={ "チ","゙" },
+ ["ヅ"]={ "ツ","゙" },
+ ["デ"]={ "テ","゙" },
+ ["ド"]={ "ト","゙" },
+ ["バ"]={ "ハ","゙" },
+ ["パ"]={ "ハ","゚" },
+ ["ビ"]={ "ヒ","゙" },
+ ["ピ"]={ "ヒ","゚" },
+ ["ブ"]={ "フ","゙" },
+ ["プ"]={ "フ","゚" },
+ ["ベ"]={ "ヘ","゙" },
+ ["ペ"]={ "ヘ","゚" },
+ ["ボ"]={ "ホ","゙" },
+ ["ポ"]={ "ホ","゚" },
+ ["ヴ"]={ "ウ","゙" },
+ ["ヷ"]={ "ワ","゙" },
+ ["ヸ"]={ "ヰ","゙" },
+ ["ヹ"]={ "ヱ","゙" },
+ ["ヺ"]={ "ヲ","゙" },
+ ["ヾ"]={ "ヽ","゙" },
+ ["יִ"]={ "י","ִ" },
+ ["ײַ"]={ "ײ","ַ" },
+ ["שׁ"]={ "ש","ׁ" },
+ ["שׂ"]={ "ש","ׂ" },
+ ["שּׁ"]={ "שּ","ׁ" },
+ ["שּׂ"]={ "שּ","ׂ" },
+ ["אַ"]={ "א","ַ" },
+ ["אָ"]={ "א","ָ" },
+ ["אּ"]={ "א","ּ" },
+ ["בּ"]={ "ב","ּ" },
+ ["גּ"]={ "ג","ּ" },
+ ["דּ"]={ "ד","ּ" },
+ ["הּ"]={ "ה","ּ" },
+ ["וּ"]={ "ו","ּ" },
+ ["זּ"]={ "ז","ּ" },
+ ["טּ"]={ "ט","ּ" },
+ ["יּ"]={ "י","ּ" },
+ ["ךּ"]={ "ך","ּ" },
+ ["כּ"]={ "כ","ּ" },
+ ["לּ"]={ "ל","ּ" },
+ ["מּ"]={ "מ","ּ" },
+ ["נּ"]={ "נ","ּ" },
+ ["סּ"]={ "ס","ּ" },
+ ["ףּ"]={ "ף","ּ" },
+ ["פּ"]={ "פ","ּ" },
+ ["צּ"]={ "צ","ּ" },
+ ["קּ"]={ "ק","ּ" },
+ ["רּ"]={ "ר","ּ" },
+ ["שּ"]={ "ש","ּ" },
+ ["תּ"]={ "ת","ּ" },
+ ["וֹ"]={ "ו","ֹ" },
+ ["בֿ"]={ "ב","ֿ" },
+ ["כֿ"]={ "כ","ֿ" },
+ ["פֿ"]={ "פ","ֿ" },
+ ["𑂚"]={ "𑂙","𑂺" },
+ ["𑂜"]={ "𑂛","𑂺" },
+ ["𑂫"]={ "𑂥","𑂺" },
+ ["𑄮"]={ "𑄱","𑄧" },
+ ["𑄯"]={ "𑄲","𑄧" },
+ ["𑍋"]={ "𑍇","𑌾" },
+ ["𑍌"]={ "𑍇","𑍗" },
+ ["𑒻"]={ "𑒹","𑒺" },
+ ["𑒼"]={ "𑒹","𑒰" },
+ ["𑒾"]={ "𑒹","𑒽" },
+ ["𑖺"]={ "𑖸","𑖯" },
+ ["𑖻"]={ "𑖹","𑖯" },
+ ["𝅗𝅥"]={ "𝅗","𝅥" },
+ ["𝅘𝅥"]={ "𝅘","𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
+ ["𝆹𝅥"]={ "𝆹","𝅥" },
+ ["𝆺𝅥"]={ "𝆺","𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
+ },
+ },
+ {
+ ["data"]={
+ ["À"]={ "A","̀" },
+ ["Á"]={ "A","́" },
+ ["Â"]={ "A","̂" },
+ ["Ã"]={ "A","̃" },
+ ["Ä"]={ "A","̈" },
+ ["Å"]={ "A","̊" },
+ ["Ç"]={ "C","̧" },
+ ["È"]={ "E","̀" },
+ ["É"]={ "E","́" },
+ ["Ê"]={ "E","̂" },
+ ["Ë"]={ "E","̈" },
+ ["Ì"]={ "I","̀" },
+ ["Í"]={ "I","́" },
+ ["Î"]={ "I","̂" },
+ ["Ï"]={ "I","̈" },
+ ["Ñ"]={ "N","̃" },
+ ["Ò"]={ "O","̀" },
+ ["Ó"]={ "O","́" },
+ ["Ô"]={ "O","̂" },
+ ["Õ"]={ "O","̃" },
+ ["Ö"]={ "O","̈" },
+ ["Ù"]={ "U","̀" },
+ ["Ú"]={ "U","́" },
+ ["Û"]={ "U","̂" },
+ ["Ü"]={ "U","̈" },
+ ["Ý"]={ "Y","́" },
+ ["à"]={ "a","̀" },
+ ["á"]={ "a","́" },
+ ["â"]={ "a","̂" },
+ ["ã"]={ "a","̃" },
+ ["ä"]={ "a","̈" },
+ ["å"]={ "a","̊" },
+ ["ç"]={ "c","̧" },
+ ["è"]={ "e","̀" },
+ ["é"]={ "e","́" },
+ ["ê"]={ "e","̂" },
+ ["ë"]={ "e","̈" },
+ ["ì"]={ "i","̀" },
+ ["í"]={ "i","́" },
+ ["î"]={ "i","̂" },
+ ["ï"]={ "i","̈" },
+ ["ñ"]={ "n","̃" },
+ ["ò"]={ "o","̀" },
+ ["ó"]={ "o","́" },
+ ["ô"]={ "o","̂" },
+ ["õ"]={ "o","̃" },
+ ["ö"]={ "o","̈" },
+ ["ù"]={ "u","̀" },
+ ["ú"]={ "u","́" },
+ ["û"]={ "u","̂" },
+ ["ü"]={ "u","̈" },
+ ["ý"]={ "y","́" },
+ ["ÿ"]={ "y","̈" },
+ ["Ā"]={ "A","̄" },
+ ["ā"]={ "a","̄" },
+ ["Ă"]={ "A","̆" },
+ ["ă"]={ "a","̆" },
+ ["Ą"]={ "A","̨" },
+ ["ą"]={ "a","̨" },
+ ["Ć"]={ "C","́" },
+ ["ć"]={ "c","́" },
+ ["Ĉ"]={ "C","̂" },
+ ["ĉ"]={ "c","̂" },
+ ["Ċ"]={ "C","̇" },
+ ["ċ"]={ "c","̇" },
+ ["Č"]={ "C","̌" },
+ ["č"]={ "c","̌" },
+ ["Ď"]={ "D","̌" },
+ ["ď"]={ "d","̌" },
+ ["Ē"]={ "E","̄" },
+ ["ē"]={ "e","̄" },
+ ["Ĕ"]={ "E","̆" },
+ ["ĕ"]={ "e","̆" },
+ ["Ė"]={ "E","̇" },
+ ["ė"]={ "e","̇" },
+ ["Ę"]={ "E","̨" },
+ ["ę"]={ "e","̨" },
+ ["Ě"]={ "E","̌" },
+ ["ě"]={ "e","̌" },
+ ["Ĝ"]={ "G","̂" },
+ ["ĝ"]={ "g","̂" },
+ ["Ğ"]={ "G","̆" },
+ ["ğ"]={ "g","̆" },
+ ["Ġ"]={ "G","̇" },
+ ["ġ"]={ "g","̇" },
+ ["Ģ"]={ "G","̧" },
+ ["ģ"]={ "g","̧" },
+ ["Ĥ"]={ "H","̂" },
+ ["ĥ"]={ "h","̂" },
+ ["Ĩ"]={ "I","̃" },
+ ["ĩ"]={ "i","̃" },
+ ["Ī"]={ "I","̄" },
+ ["ī"]={ "i","̄" },
+ ["Ĭ"]={ "I","̆" },
+ ["ĭ"]={ "i","̆" },
+ ["Į"]={ "I","̨" },
+ ["į"]={ "i","̨" },
+ ["İ"]={ "I","̇" },
+ ["Ĵ"]={ "J","̂" },
+ ["ĵ"]={ "j","̂" },
+ ["Ķ"]={ "K","̧" },
+ ["ķ"]={ "k","̧" },
+ ["Ĺ"]={ "L","́" },
+ ["ĺ"]={ "l","́" },
+ ["Ļ"]={ "L","̧" },
+ ["ļ"]={ "l","̧" },
+ ["Ľ"]={ "L","̌" },
+ ["ľ"]={ "l","̌" },
+ ["Ń"]={ "N","́" },
+ ["ń"]={ "n","́" },
+ ["Ņ"]={ "N","̧" },
+ ["ņ"]={ "n","̧" },
+ ["Ň"]={ "N","̌" },
+ ["ň"]={ "n","̌" },
+ ["Ō"]={ "O","̄" },
+ ["ō"]={ "o","̄" },
+ ["Ŏ"]={ "O","̆" },
+ ["ŏ"]={ "o","̆" },
+ ["Ő"]={ "O","̋" },
+ ["ő"]={ "o","̋" },
+ ["Ŕ"]={ "R","́" },
+ ["ŕ"]={ "r","́" },
+ ["Ŗ"]={ "R","̧" },
+ ["ŗ"]={ "r","̧" },
+ ["Ř"]={ "R","̌" },
+ ["ř"]={ "r","̌" },
+ ["Ś"]={ "S","́" },
+ ["ś"]={ "s","́" },
+ ["Ŝ"]={ "S","̂" },
+ ["ŝ"]={ "s","̂" },
+ ["Ş"]={ "S","̧" },
+ ["ş"]={ "s","̧" },
+ ["Š"]={ "S","̌" },
+ ["š"]={ "s","̌" },
+ ["Ţ"]={ "T","̧" },
+ ["ţ"]={ "t","̧" },
+ ["Ť"]={ "T","̌" },
+ ["ť"]={ "t","̌" },
+ ["Ũ"]={ "U","̃" },
+ ["ũ"]={ "u","̃" },
+ ["Ū"]={ "U","̄" },
+ ["ū"]={ "u","̄" },
+ ["Ŭ"]={ "U","̆" },
+ ["ŭ"]={ "u","̆" },
+ ["Ů"]={ "U","̊" },
+ ["ů"]={ "u","̊" },
+ ["Ű"]={ "U","̋" },
+ ["ű"]={ "u","̋" },
+ ["Ų"]={ "U","̨" },
+ ["ų"]={ "u","̨" },
+ ["Ŵ"]={ "W","̂" },
+ ["ŵ"]={ "w","̂" },
+ ["Ŷ"]={ "Y","̂" },
+ ["ŷ"]={ "y","̂" },
+ ["Ÿ"]={ "Y","̈" },
+ ["Ź"]={ "Z","́" },
+ ["ź"]={ "z","́" },
+ ["Ż"]={ "Z","̇" },
+ ["ż"]={ "z","̇" },
+ ["Ž"]={ "Z","̌" },
+ ["ž"]={ "z","̌" },
+ ["Ơ"]={ "O","̛" },
+ ["ơ"]={ "o","̛" },
+ ["Ư"]={ "U","̛" },
+ ["ư"]={ "u","̛" },
+ ["Ǎ"]={ "A","̌" },
+ ["ǎ"]={ "a","̌" },
+ ["Ǐ"]={ "I","̌" },
+ ["ǐ"]={ "i","̌" },
+ ["Ǒ"]={ "O","̌" },
+ ["ǒ"]={ "o","̌" },
+ ["Ǔ"]={ "U","̌" },
+ ["ǔ"]={ "u","̌" },
+ ["Ǖ"]={ "Ü","̄" },
+ ["ǖ"]={ "ü","̄" },
+ ["Ǘ"]={ "Ü","́" },
+ ["ǘ"]={ "ü","́" },
+ ["Ǚ"]={ "Ü","̌" },
+ ["ǚ"]={ "ü","̌" },
+ ["Ǜ"]={ "Ü","̀" },
+ ["ǜ"]={ "ü","̀" },
+ ["Ǟ"]={ "Ä","̄" },
+ ["ǟ"]={ "ä","̄" },
+ ["Ǡ"]={ "Ȧ","̄" },
+ ["ǡ"]={ "ȧ","̄" },
+ ["Ǣ"]={ "Æ","̄" },
+ ["ǣ"]={ "æ","̄" },
+ ["Ǧ"]={ "G","̌" },
+ ["ǧ"]={ "g","̌" },
+ ["Ǩ"]={ "K","̌" },
+ ["ǩ"]={ "k","̌" },
+ ["Ǫ"]={ "O","̨" },
+ ["ǫ"]={ "o","̨" },
+ ["Ǭ"]={ "Ǫ","̄" },
+ ["ǭ"]={ "ǫ","̄" },
+ ["Ǯ"]={ "Ʒ","̌" },
+ ["ǯ"]={ "ʒ","̌" },
+ ["ǰ"]={ "j","̌" },
+ ["Ǵ"]={ "G","́" },
+ ["ǵ"]={ "g","́" },
+ ["Ǹ"]={ "N","̀" },
+ ["ǹ"]={ "n","̀" },
+ ["Ǻ"]={ "Å","́" },
+ ["ǻ"]={ "å","́" },
+ ["Ǽ"]={ "Æ","́" },
+ ["ǽ"]={ "æ","́" },
+ ["Ǿ"]={ "Ø","́" },
+ ["ǿ"]={ "ø","́" },
+ ["Ȁ"]={ "A","̏" },
+ ["ȁ"]={ "a","̏" },
+ ["Ȃ"]={ "A","̑" },
+ ["ȃ"]={ "a","̑" },
+ ["Ȅ"]={ "E","̏" },
+ ["ȅ"]={ "e","̏" },
+ ["Ȇ"]={ "E","̑" },
+ ["ȇ"]={ "e","̑" },
+ ["Ȉ"]={ "I","̏" },
+ ["ȉ"]={ "i","̏" },
+ ["Ȋ"]={ "I","̑" },
+ ["ȋ"]={ "i","̑" },
+ ["Ȍ"]={ "O","̏" },
+ ["ȍ"]={ "o","̏" },
+ ["Ȏ"]={ "O","̑" },
+ ["ȏ"]={ "o","̑" },
+ ["Ȑ"]={ "R","̏" },
+ ["ȑ"]={ "r","̏" },
+ ["Ȓ"]={ "R","̑" },
+ ["ȓ"]={ "r","̑" },
+ ["Ȕ"]={ "U","̏" },
+ ["ȕ"]={ "u","̏" },
+ ["Ȗ"]={ "U","̑" },
+ ["ȗ"]={ "u","̑" },
+ ["Ș"]={ "S","̦" },
+ ["ș"]={ "s","̦" },
+ ["Ț"]={ "T","̦" },
+ ["ț"]={ "t","̦" },
+ ["Ȟ"]={ "H","̌" },
+ ["ȟ"]={ "h","̌" },
+ ["Ȧ"]={ "A","̇" },
+ ["ȧ"]={ "a","̇" },
+ ["Ȩ"]={ "E","̧" },
+ ["ȩ"]={ "e","̧" },
+ ["Ȫ"]={ "Ö","̄" },
+ ["ȫ"]={ "ö","̄" },
+ ["Ȭ"]={ "Õ","̄" },
+ ["ȭ"]={ "õ","̄" },
+ ["Ȯ"]={ "O","̇" },
+ ["ȯ"]={ "o","̇" },
+ ["Ȱ"]={ "Ȯ","̄" },
+ ["ȱ"]={ "ȯ","̄" },
+ ["Ȳ"]={ "Y","̄" },
+ ["ȳ"]={ "y","̄" },
+ ["̈́"]={ "̈","́" },
+ ["΅"]={ "¨","́" },
+ ["Ά"]={ "Α","́" },
+ ["Έ"]={ "Ε","́" },
+ ["Ή"]={ "Η","́" },
+ ["Ί"]={ "Ι","́" },
+ ["Ό"]={ "Ο","́" },
+ ["Ύ"]={ "Υ","́" },
+ ["Ώ"]={ "Ω","́" },
+ ["ΐ"]={ "ϊ","́" },
+ ["Ϊ"]={ "Ι","̈" },
+ ["Ϋ"]={ "Υ","̈" },
+ ["ά"]={ "α","́" },
+ ["έ"]={ "ε","́" },
+ ["ή"]={ "η","́" },
+ ["ί"]={ "ι","́" },
+ ["ΰ"]={ "ϋ","́" },
+ ["ϊ"]={ "ι","̈" },
+ ["ϋ"]={ "υ","̈" },
+ ["ό"]={ "ο","́" },
+ ["ύ"]={ "υ","́" },
+ ["ώ"]={ "ω","́" },
+ ["ϓ"]={ "ϒ","́" },
+ ["ϔ"]={ "ϒ","̈" },
+ ["Ѐ"]={ "Е","̀" },
+ ["Ё"]={ "Е","̈" },
+ ["Ѓ"]={ "Г","́" },
+ ["Ї"]={ "І","̈" },
+ ["Ќ"]={ "К","́" },
+ ["Ѝ"]={ "И","̀" },
+ ["Ў"]={ "У","̆" },
+ ["Й"]={ "И","̆" },
+ ["й"]={ "и","̆" },
+ ["ѐ"]={ "е","̀" },
+ ["ё"]={ "е","̈" },
+ ["ѓ"]={ "г","́" },
+ ["ї"]={ "і","̈" },
+ ["ќ"]={ "к","́" },
+ ["ѝ"]={ "и","̀" },
+ ["ў"]={ "у","̆" },
+ ["Ѷ"]={ "Ѵ","̏" },
+ ["ѷ"]={ "ѵ","̏" },
+ ["Ӂ"]={ "Ж","̆" },
+ ["ӂ"]={ "ж","̆" },
+ ["Ӑ"]={ "А","̆" },
+ ["ӑ"]={ "а","̆" },
+ ["Ӓ"]={ "А","̈" },
+ ["ӓ"]={ "а","̈" },
+ ["Ӗ"]={ "Е","̆" },
+ ["ӗ"]={ "е","̆" },
+ ["Ӛ"]={ "Ә","̈" },
+ ["ӛ"]={ "ә","̈" },
+ ["Ӝ"]={ "Ж","̈" },
+ ["ӝ"]={ "ж","̈" },
+ ["Ӟ"]={ "З","̈" },
+ ["ӟ"]={ "з","̈" },
+ ["Ӣ"]={ "И","̄" },
+ ["ӣ"]={ "и","̄" },
+ ["Ӥ"]={ "И","̈" },
+ ["ӥ"]={ "и","̈" },
+ ["Ӧ"]={ "О","̈" },
+ ["ӧ"]={ "о","̈" },
+ ["Ӫ"]={ "Ө","̈" },
+ ["ӫ"]={ "ө","̈" },
+ ["Ӭ"]={ "Э","̈" },
+ ["ӭ"]={ "э","̈" },
+ ["Ӯ"]={ "У","̄" },
+ ["ӯ"]={ "у","̄" },
+ ["Ӱ"]={ "У","̈" },
+ ["ӱ"]={ "у","̈" },
+ ["Ӳ"]={ "У","̋" },
+ ["ӳ"]={ "у","̋" },
+ ["Ӵ"]={ "Ч","̈" },
+ ["ӵ"]={ "ч","̈" },
+ ["Ӹ"]={ "Ы","̈" },
+ ["ӹ"]={ "ы","̈" },
+ ["آ"]={ "ا","ٓ" },
+ ["أ"]={ "ا","ٔ" },
+ ["ؤ"]={ "و","ٔ" },
+ ["إ"]={ "ا","ٕ" },
+ ["ئ"]={ "ي","ٔ" },
+ ["ۀ"]={ "ە","ٔ" },
+ ["ۂ"]={ "ہ","ٔ" },
+ ["ۓ"]={ "ے","ٔ" },
+ ["ऩ"]={ "न","़" },
+ ["ऱ"]={ "र","़" },
+ ["ऴ"]={ "ळ","़" },
+ ["क़"]={ "क","़" },
+ ["ख़"]={ "ख","़" },
+ ["ग़"]={ "ग","़" },
+ ["ज़"]={ "ज","़" },
+ ["ड़"]={ "ड","़" },
+ ["ढ़"]={ "ढ","़" },
+ ["फ़"]={ "फ","़" },
+ ["य़"]={ "य","़" },
+ ["ো"]={ "ে","া" },
+ ["ৌ"]={ "ে","ৗ" },
+ ["ড়"]={ "ড","়" },
+ ["ঢ়"]={ "ঢ","়" },
+ ["য়"]={ "য","়" },
+ ["ਲ਼"]={ "ਲ","਼" },
+ ["ਸ਼"]={ "ਸ","਼" },
+ ["ਖ਼"]={ "ਖ","਼" },
+ ["ਗ਼"]={ "ਗ","਼" },
+ ["ਜ਼"]={ "ਜ","਼" },
+ ["ਫ਼"]={ "ਫ","਼" },
+ ["ୈ"]={ "େ","ୖ" },
+ ["ୋ"]={ "େ","ା" },
+ ["ୌ"]={ "େ","ୗ" },
+ ["ଡ଼"]={ "ଡ","଼" },
+ ["ଢ଼"]={ "ଢ","଼" },
+ ["ஔ"]={ "ஒ","ௗ" },
+ ["ொ"]={ "ெ","ா" },
+ ["ோ"]={ "ே","ா" },
+ ["ௌ"]={ "ெ","ௗ" },
+ ["ై"]={ "ె","ౖ" },
+ ["ೀ"]={ "ಿ","ೕ" },
+ ["ೇ"]={ "ೆ","ೕ" },
+ ["ೈ"]={ "ೆ","ೖ" },
+ ["ೊ"]={ "ೆ","ೂ" },
+ ["ೋ"]={ "ೊ","ೕ" },
+ ["ൊ"]={ "െ","ാ" },
+ ["ോ"]={ "േ","ാ" },
+ ["ൌ"]={ "െ","ൗ" },
+ ["ේ"]={ "ෙ","්" },
+ ["ො"]={ "ෙ","ා" },
+ ["ෝ"]={ "ො","්" },
+ ["ෞ"]={ "ෙ","ෟ" },
+ ["གྷ"]={ "ག","ྷ" },
+ ["ཌྷ"]={ "ཌ","ྷ" },
+ ["དྷ"]={ "ད","ྷ" },
+ ["བྷ"]={ "བ","ྷ" },
+ ["ཛྷ"]={ "ཛ","ྷ" },
+ ["ཀྵ"]={ "ཀ","ྵ" },
+ ["ཱི"]={ "ཱ","ི" },
+ ["ཱུ"]={ "ཱ","ུ" },
+ ["ྲྀ"]={ "ྲ","ྀ" },
+ ["ླྀ"]={ "ླ","ྀ" },
+ ["ཱྀ"]={ "ཱ","ྀ" },
+ ["ྒྷ"]={ "ྒ","ྷ" },
+ ["ྜྷ"]={ "ྜ","ྷ" },
+ ["ྡྷ"]={ "ྡ","ྷ" },
+ ["ྦྷ"]={ "ྦ","ྷ" },
+ ["ྫྷ"]={ "ྫ","ྷ" },
+ ["ྐྵ"]={ "ྐ","ྵ" },
+ ["ဦ"]={ "ဥ","ီ" },
+ ["ᬆ"]={ "ᬅ","ᬵ" },
+ ["ᬈ"]={ "ᬇ","ᬵ" },
+ ["ᬊ"]={ "ᬉ","ᬵ" },
+ ["ᬌ"]={ "ᬋ","ᬵ" },
+ ["ᬎ"]={ "ᬍ","ᬵ" },
+ ["ᬒ"]={ "ᬑ","ᬵ" },
+ ["ᬻ"]={ "ᬺ","ᬵ" },
+ ["ᬽ"]={ "ᬼ","ᬵ" },
+ ["ᭀ"]={ "ᬾ","ᬵ" },
+ ["ᭁ"]={ "ᬿ","ᬵ" },
+ ["ᭃ"]={ "ᭂ","ᬵ" },
+ ["Ḁ"]={ "A","̥" },
+ ["ḁ"]={ "a","̥" },
+ ["Ḃ"]={ "B","̇" },
+ ["ḃ"]={ "b","̇" },
+ ["Ḅ"]={ "B","̣" },
+ ["ḅ"]={ "b","̣" },
+ ["Ḇ"]={ "B","̱" },
+ ["ḇ"]={ "b","̱" },
+ ["Ḉ"]={ "Ç","́" },
+ ["ḉ"]={ "ç","́" },
+ ["Ḋ"]={ "D","̇" },
+ ["ḋ"]={ "d","̇" },
+ ["Ḍ"]={ "D","̣" },
+ ["ḍ"]={ "d","̣" },
+ ["Ḏ"]={ "D","̱" },
+ ["ḏ"]={ "d","̱" },
+ ["Ḑ"]={ "D","̧" },
+ ["ḑ"]={ "d","̧" },
+ ["Ḓ"]={ "D","̭" },
+ ["ḓ"]={ "d","̭" },
+ ["Ḕ"]={ "Ē","̀" },
+ ["ḕ"]={ "ē","̀" },
+ ["Ḗ"]={ "Ē","́" },
+ ["ḗ"]={ "ē","́" },
+ ["Ḙ"]={ "E","̭" },
+ ["ḙ"]={ "e","̭" },
+ ["Ḛ"]={ "E","̰" },
+ ["ḛ"]={ "e","̰" },
+ ["Ḝ"]={ "Ȩ","̆" },
+ ["ḝ"]={ "ȩ","̆" },
+ ["Ḟ"]={ "F","̇" },
+ ["ḟ"]={ "f","̇" },
+ ["Ḡ"]={ "G","̄" },
+ ["ḡ"]={ "g","̄" },
+ ["Ḣ"]={ "H","̇" },
+ ["ḣ"]={ "h","̇" },
+ ["Ḥ"]={ "H","̣" },
+ ["ḥ"]={ "h","̣" },
+ ["Ḧ"]={ "H","̈" },
+ ["ḧ"]={ "h","̈" },
+ ["Ḩ"]={ "H","̧" },
+ ["ḩ"]={ "h","̧" },
+ ["Ḫ"]={ "H","̮" },
+ ["ḫ"]={ "h","̮" },
+ ["Ḭ"]={ "I","̰" },
+ ["ḭ"]={ "i","̰" },
+ ["Ḯ"]={ "Ï","́" },
+ ["ḯ"]={ "ï","́" },
+ ["Ḱ"]={ "K","́" },
+ ["ḱ"]={ "k","́" },
+ ["Ḳ"]={ "K","̣" },
+ ["ḳ"]={ "k","̣" },
+ ["Ḵ"]={ "K","̱" },
+ ["ḵ"]={ "k","̱" },
+ ["Ḷ"]={ "L","̣" },
+ ["ḷ"]={ "l","̣" },
+ ["Ḹ"]={ "Ḷ","̄" },
+ ["ḹ"]={ "ḷ","̄" },
+ ["Ḻ"]={ "L","̱" },
+ ["ḻ"]={ "l","̱" },
+ ["Ḽ"]={ "L","̭" },
+ ["ḽ"]={ "l","̭" },
+ ["Ḿ"]={ "M","́" },
+ ["ḿ"]={ "m","́" },
+ ["Ṁ"]={ "M","̇" },
+ ["ṁ"]={ "m","̇" },
+ ["Ṃ"]={ "M","̣" },
+ ["ṃ"]={ "m","̣" },
+ ["Ṅ"]={ "N","̇" },
+ ["ṅ"]={ "n","̇" },
+ ["Ṇ"]={ "N","̣" },
+ ["ṇ"]={ "n","̣" },
+ ["Ṉ"]={ "N","̱" },
+ ["ṉ"]={ "n","̱" },
+ ["Ṋ"]={ "N","̭" },
+ ["ṋ"]={ "n","̭" },
+ ["Ṍ"]={ "Õ","́" },
+ ["ṍ"]={ "õ","́" },
+ ["Ṏ"]={ "Õ","̈" },
+ ["ṏ"]={ "õ","̈" },
+ ["Ṑ"]={ "Ō","̀" },
+ ["ṑ"]={ "ō","̀" },
+ ["Ṓ"]={ "Ō","́" },
+ ["ṓ"]={ "ō","́" },
+ ["Ṕ"]={ "P","́" },
+ ["ṕ"]={ "p","́" },
+ ["Ṗ"]={ "P","̇" },
+ ["ṗ"]={ "p","̇" },
+ ["Ṙ"]={ "R","̇" },
+ ["ṙ"]={ "r","̇" },
+ ["Ṛ"]={ "R","̣" },
+ ["ṛ"]={ "r","̣" },
+ ["Ṝ"]={ "Ṛ","̄" },
+ ["ṝ"]={ "ṛ","̄" },
+ ["Ṟ"]={ "R","̱" },
+ ["ṟ"]={ "r","̱" },
+ ["Ṡ"]={ "S","̇" },
+ ["ṡ"]={ "s","̇" },
+ ["Ṣ"]={ "S","̣" },
+ ["ṣ"]={ "s","̣" },
+ ["Ṥ"]={ "Ś","̇" },
+ ["ṥ"]={ "ś","̇" },
+ ["Ṧ"]={ "Š","̇" },
+ ["ṧ"]={ "š","̇" },
+ ["Ṩ"]={ "Ṣ","̇" },
+ ["ṩ"]={ "ṣ","̇" },
+ ["Ṫ"]={ "T","̇" },
+ ["ṫ"]={ "t","̇" },
+ ["Ṭ"]={ "T","̣" },
+ ["ṭ"]={ "t","̣" },
+ ["Ṯ"]={ "T","̱" },
+ ["ṯ"]={ "t","̱" },
+ ["Ṱ"]={ "T","̭" },
+ ["ṱ"]={ "t","̭" },
+ ["Ṳ"]={ "U","̤" },
+ ["ṳ"]={ "u","̤" },
+ ["Ṵ"]={ "U","̰" },
+ ["ṵ"]={ "u","̰" },
+ ["Ṷ"]={ "U","̭" },
+ ["ṷ"]={ "u","̭" },
+ ["Ṹ"]={ "Ũ","́" },
+ ["ṹ"]={ "ũ","́" },
+ ["Ṻ"]={ "Ū","̈" },
+ ["ṻ"]={ "ū","̈" },
+ ["Ṽ"]={ "V","̃" },
+ ["ṽ"]={ "v","̃" },
+ ["Ṿ"]={ "V","̣" },
+ ["ṿ"]={ "v","̣" },
+ ["Ẁ"]={ "W","̀" },
+ ["ẁ"]={ "w","̀" },
+ ["Ẃ"]={ "W","́" },
+ ["ẃ"]={ "w","́" },
+ ["Ẅ"]={ "W","̈" },
+ ["ẅ"]={ "w","̈" },
+ ["Ẇ"]={ "W","̇" },
+ ["ẇ"]={ "w","̇" },
+ ["Ẉ"]={ "W","̣" },
+ ["ẉ"]={ "w","̣" },
+ ["Ẋ"]={ "X","̇" },
+ ["ẋ"]={ "x","̇" },
+ ["Ẍ"]={ "X","̈" },
+ ["ẍ"]={ "x","̈" },
+ ["Ẏ"]={ "Y","̇" },
+ ["ẏ"]={ "y","̇" },
+ ["Ẑ"]={ "Z","̂" },
+ ["ẑ"]={ "z","̂" },
+ ["Ẓ"]={ "Z","̣" },
+ ["ẓ"]={ "z","̣" },
+ ["Ẕ"]={ "Z","̱" },
+ ["ẕ"]={ "z","̱" },
+ ["ẖ"]={ "h","̱" },
+ ["ẗ"]={ "t","̈" },
+ ["ẘ"]={ "w","̊" },
+ ["ẙ"]={ "y","̊" },
+ ["ẛ"]={ "ſ","̇" },
+ ["Ạ"]={ "A","̣" },
+ ["ạ"]={ "a","̣" },
+ ["Ả"]={ "A","̉" },
+ ["ả"]={ "a","̉" },
+ ["Ấ"]={ "Â","́" },
+ ["ấ"]={ "â","́" },
+ ["Ầ"]={ "Â","̀" },
+ ["ầ"]={ "â","̀" },
+ ["Ẩ"]={ "Â","̉" },
+ ["ẩ"]={ "â","̉" },
+ ["Ẫ"]={ "Â","̃" },
+ ["ẫ"]={ "â","̃" },
+ ["Ậ"]={ "Ạ","̂" },
+ ["ậ"]={ "ạ","̂" },
+ ["Ắ"]={ "Ă","́" },
+ ["ắ"]={ "ă","́" },
+ ["Ằ"]={ "Ă","̀" },
+ ["ằ"]={ "ă","̀" },
+ ["Ẳ"]={ "Ă","̉" },
+ ["ẳ"]={ "ă","̉" },
+ ["Ẵ"]={ "Ă","̃" },
+ ["ẵ"]={ "ă","̃" },
+ ["Ặ"]={ "Ạ","̆" },
+ ["ặ"]={ "ạ","̆" },
+ ["Ẹ"]={ "E","̣" },
+ ["ẹ"]={ "e","̣" },
+ ["Ẻ"]={ "E","̉" },
+ ["ẻ"]={ "e","̉" },
+ ["Ẽ"]={ "E","̃" },
+ ["ẽ"]={ "e","̃" },
+ ["Ế"]={ "Ê","́" },
+ ["ế"]={ "ê","́" },
+ ["Ề"]={ "Ê","̀" },
+ ["ề"]={ "ê","̀" },
+ ["Ể"]={ "Ê","̉" },
+ ["ể"]={ "ê","̉" },
+ ["Ễ"]={ "Ê","̃" },
+ ["ễ"]={ "ê","̃" },
+ ["Ệ"]={ "Ẹ","̂" },
+ ["ệ"]={ "ẹ","̂" },
+ ["Ỉ"]={ "I","̉" },
+ ["ỉ"]={ "i","̉" },
+ ["Ị"]={ "I","̣" },
+ ["ị"]={ "i","̣" },
+ ["Ọ"]={ "O","̣" },
+ ["ọ"]={ "o","̣" },
+ ["Ỏ"]={ "O","̉" },
+ ["ỏ"]={ "o","̉" },
+ ["Ố"]={ "Ô","́" },
+ ["ố"]={ "ô","́" },
+ ["Ồ"]={ "Ô","̀" },
+ ["ồ"]={ "ô","̀" },
+ ["Ổ"]={ "Ô","̉" },
+ ["ổ"]={ "ô","̉" },
+ ["Ỗ"]={ "Ô","̃" },
+ ["ỗ"]={ "ô","̃" },
+ ["Ộ"]={ "Ọ","̂" },
+ ["ộ"]={ "ọ","̂" },
+ ["Ớ"]={ "Ơ","́" },
+ ["ớ"]={ "ơ","́" },
+ ["Ờ"]={ "Ơ","̀" },
+ ["ờ"]={ "ơ","̀" },
+ ["Ở"]={ "Ơ","̉" },
+ ["ở"]={ "ơ","̉" },
+ ["Ỡ"]={ "Ơ","̃" },
+ ["ỡ"]={ "ơ","̃" },
+ ["Ợ"]={ "Ơ","̣" },
+ ["ợ"]={ "ơ","̣" },
+ ["Ụ"]={ "U","̣" },
+ ["ụ"]={ "u","̣" },
+ ["Ủ"]={ "U","̉" },
+ ["ủ"]={ "u","̉" },
+ ["Ứ"]={ "Ư","́" },
+ ["ứ"]={ "ư","́" },
+ ["Ừ"]={ "Ư","̀" },
+ ["ừ"]={ "ư","̀" },
+ ["Ử"]={ "Ư","̉" },
+ ["ử"]={ "ư","̉" },
+ ["Ữ"]={ "Ư","̃" },
+ ["ữ"]={ "ư","̃" },
+ ["Ự"]={ "Ư","̣" },
+ ["ự"]={ "ư","̣" },
+ ["Ỳ"]={ "Y","̀" },
+ ["ỳ"]={ "y","̀" },
+ ["Ỵ"]={ "Y","̣" },
+ ["ỵ"]={ "y","̣" },
+ ["Ỷ"]={ "Y","̉" },
+ ["ỷ"]={ "y","̉" },
+ ["Ỹ"]={ "Y","̃" },
+ ["ỹ"]={ "y","̃" },
+ ["ἀ"]={ "α","̓" },
+ ["ἁ"]={ "α","̔" },
+ ["ἂ"]={ "ἀ","̀" },
+ ["ἃ"]={ "ἁ","̀" },
+ ["ἄ"]={ "ἀ","́" },
+ ["ἅ"]={ "ἁ","́" },
+ ["ἆ"]={ "ἀ","͂" },
+ ["ἇ"]={ "ἁ","͂" },
+ ["Ἀ"]={ "Α","̓" },
+ ["Ἁ"]={ "Α","̔" },
+ ["Ἂ"]={ "Ἀ","̀" },
+ ["Ἃ"]={ "Ἁ","̀" },
+ ["Ἄ"]={ "Ἀ","́" },
+ ["Ἅ"]={ "Ἁ","́" },
+ ["Ἆ"]={ "Ἀ","͂" },
+ ["Ἇ"]={ "Ἁ","͂" },
+ ["ἐ"]={ "ε","̓" },
+ ["ἑ"]={ "ε","̔" },
+ ["ἒ"]={ "ἐ","̀" },
+ ["ἓ"]={ "ἑ","̀" },
+ ["ἔ"]={ "ἐ","́" },
+ ["ἕ"]={ "ἑ","́" },
+ ["Ἐ"]={ "Ε","̓" },
+ ["Ἑ"]={ "Ε","̔" },
+ ["Ἒ"]={ "Ἐ","̀" },
+ ["Ἓ"]={ "Ἑ","̀" },
+ ["Ἔ"]={ "Ἐ","́" },
+ ["Ἕ"]={ "Ἑ","́" },
+ ["ἠ"]={ "η","̓" },
+ ["ἡ"]={ "η","̔" },
+ ["ἢ"]={ "ἠ","̀" },
+ ["ἣ"]={ "ἡ","̀" },
+ ["ἤ"]={ "ἠ","́" },
+ ["ἥ"]={ "ἡ","́" },
+ ["ἦ"]={ "ἠ","͂" },
+ ["ἧ"]={ "ἡ","͂" },
+ ["Ἠ"]={ "Η","̓" },
+ ["Ἡ"]={ "Η","̔" },
+ ["Ἢ"]={ "Ἠ","̀" },
+ ["Ἣ"]={ "Ἡ","̀" },
+ ["Ἤ"]={ "Ἠ","́" },
+ ["Ἥ"]={ "Ἡ","́" },
+ ["Ἦ"]={ "Ἠ","͂" },
+ ["Ἧ"]={ "Ἡ","͂" },
+ ["ἰ"]={ "ι","̓" },
+ ["ἱ"]={ "ι","̔" },
+ ["ἲ"]={ "ἰ","̀" },
+ ["ἳ"]={ "ἱ","̀" },
+ ["ἴ"]={ "ἰ","́" },
+ ["ἵ"]={ "ἱ","́" },
+ ["ἶ"]={ "ἰ","͂" },
+ ["ἷ"]={ "ἱ","͂" },
+ ["Ἰ"]={ "Ι","̓" },
+ ["Ἱ"]={ "Ι","̔" },
+ ["Ἲ"]={ "Ἰ","̀" },
+ ["Ἳ"]={ "Ἱ","̀" },
+ ["Ἴ"]={ "Ἰ","́" },
+ ["Ἵ"]={ "Ἱ","́" },
+ ["Ἶ"]={ "Ἰ","͂" },
+ ["Ἷ"]={ "Ἱ","͂" },
+ ["ὀ"]={ "ο","̓" },
+ ["ὁ"]={ "ο","̔" },
+ ["ὂ"]={ "ὀ","̀" },
+ ["ὃ"]={ "ὁ","̀" },
+ ["ὄ"]={ "ὀ","́" },
+ ["ὅ"]={ "ὁ","́" },
+ ["Ὀ"]={ "Ο","̓" },
+ ["Ὁ"]={ "Ο","̔" },
+ ["Ὂ"]={ "Ὀ","̀" },
+ ["Ὃ"]={ "Ὁ","̀" },
+ ["Ὄ"]={ "Ὀ","́" },
+ ["Ὅ"]={ "Ὁ","́" },
+ ["ὐ"]={ "υ","̓" },
+ ["ὑ"]={ "υ","̔" },
+ ["ὒ"]={ "ὐ","̀" },
+ ["ὓ"]={ "ὑ","̀" },
+ ["ὔ"]={ "ὐ","́" },
+ ["ὕ"]={ "ὑ","́" },
+ ["ὖ"]={ "ὐ","͂" },
+ ["ὗ"]={ "ὑ","͂" },
+ ["Ὑ"]={ "Υ","̔" },
+ ["Ὓ"]={ "Ὑ","̀" },
+ ["Ὕ"]={ "Ὑ","́" },
+ ["Ὗ"]={ "Ὑ","͂" },
+ ["ὠ"]={ "ω","̓" },
+ ["ὡ"]={ "ω","̔" },
+ ["ὢ"]={ "ὠ","̀" },
+ ["ὣ"]={ "ὡ","̀" },
+ ["ὤ"]={ "ὠ","́" },
+ ["ὥ"]={ "ὡ","́" },
+ ["ὦ"]={ "ὠ","͂" },
+ ["ὧ"]={ "ὡ","͂" },
+ ["Ὠ"]={ "Ω","̓" },
+ ["Ὡ"]={ "Ω","̔" },
+ ["Ὢ"]={ "Ὠ","̀" },
+ ["Ὣ"]={ "Ὡ","̀" },
+ ["Ὤ"]={ "Ὠ","́" },
+ ["Ὥ"]={ "Ὡ","́" },
+ ["Ὦ"]={ "Ὠ","͂" },
+ ["Ὧ"]={ "Ὡ","͂" },
+ ["ὰ"]={ "α","̀" },
+ ["ὲ"]={ "ε","̀" },
+ ["ὴ"]={ "η","̀" },
+ ["ὶ"]={ "ι","̀" },
+ ["ὸ"]={ "ο","̀" },
+ ["ὺ"]={ "υ","̀" },
+ ["ὼ"]={ "ω","̀" },
+ ["ᾀ"]={ "ἀ","ͅ" },
+ ["ᾁ"]={ "ἁ","ͅ" },
+ ["ᾂ"]={ "ἂ","ͅ" },
+ ["ᾃ"]={ "ἃ","ͅ" },
+ ["ᾄ"]={ "ἄ","ͅ" },
+ ["ᾅ"]={ "ἅ","ͅ" },
+ ["ᾆ"]={ "ἆ","ͅ" },
+ ["ᾇ"]={ "ἇ","ͅ" },
+ ["ᾈ"]={ "Ἀ","ͅ" },
+ ["ᾉ"]={ "Ἁ","ͅ" },
+ ["ᾊ"]={ "Ἂ","ͅ" },
+ ["ᾋ"]={ "Ἃ","ͅ" },
+ ["ᾌ"]={ "Ἄ","ͅ" },
+ ["ᾍ"]={ "Ἅ","ͅ" },
+ ["ᾎ"]={ "Ἆ","ͅ" },
+ ["ᾏ"]={ "Ἇ","ͅ" },
+ ["ᾐ"]={ "ἠ","ͅ" },
+ ["ᾑ"]={ "ἡ","ͅ" },
+ ["ᾒ"]={ "ἢ","ͅ" },
+ ["ᾓ"]={ "ἣ","ͅ" },
+ ["ᾔ"]={ "ἤ","ͅ" },
+ ["ᾕ"]={ "ἥ","ͅ" },
+ ["ᾖ"]={ "ἦ","ͅ" },
+ ["ᾗ"]={ "ἧ","ͅ" },
+ ["ᾘ"]={ "Ἠ","ͅ" },
+ ["ᾙ"]={ "Ἡ","ͅ" },
+ ["ᾚ"]={ "Ἢ","ͅ" },
+ ["ᾛ"]={ "Ἣ","ͅ" },
+ ["ᾜ"]={ "Ἤ","ͅ" },
+ ["ᾝ"]={ "Ἥ","ͅ" },
+ ["ᾞ"]={ "Ἦ","ͅ" },
+ ["ᾟ"]={ "Ἧ","ͅ" },
+ ["ᾠ"]={ "ὠ","ͅ" },
+ ["ᾡ"]={ "ὡ","ͅ" },
+ ["ᾢ"]={ "ὢ","ͅ" },
+ ["ᾣ"]={ "ὣ","ͅ" },
+ ["ᾤ"]={ "ὤ","ͅ" },
+ ["ᾥ"]={ "ὥ","ͅ" },
+ ["ᾦ"]={ "ὦ","ͅ" },
+ ["ᾧ"]={ "ὧ","ͅ" },
+ ["ᾨ"]={ "Ὠ","ͅ" },
+ ["ᾩ"]={ "Ὡ","ͅ" },
+ ["ᾪ"]={ "Ὢ","ͅ" },
+ ["ᾫ"]={ "Ὣ","ͅ" },
+ ["ᾬ"]={ "Ὤ","ͅ" },
+ ["ᾭ"]={ "Ὥ","ͅ" },
+ ["ᾮ"]={ "Ὦ","ͅ" },
+ ["ᾯ"]={ "Ὧ","ͅ" },
+ ["ᾰ"]={ "α","̆" },
+ ["ᾱ"]={ "α","̄" },
+ ["ᾲ"]={ "ὰ","ͅ" },
+ ["ᾳ"]={ "α","ͅ" },
+ ["ᾴ"]={ "ά","ͅ" },
+ ["ᾶ"]={ "α","͂" },
+ ["ᾷ"]={ "ᾶ","ͅ" },
+ ["Ᾰ"]={ "Α","̆" },
+ ["Ᾱ"]={ "Α","̄" },
+ ["Ὰ"]={ "Α","̀" },
+ ["ᾼ"]={ "Α","ͅ" },
+ ["῁"]={ "¨","͂" },
+ ["ῂ"]={ "ὴ","ͅ" },
+ ["ῃ"]={ "η","ͅ" },
+ ["ῄ"]={ "ή","ͅ" },
+ ["ῆ"]={ "η","͂" },
+ ["ῇ"]={ "ῆ","ͅ" },
+ ["Ὲ"]={ "Ε","̀" },
+ ["Ὴ"]={ "Η","̀" },
+ ["ῌ"]={ "Η","ͅ" },
+ ["῍"]={ "᾿","̀" },
+ ["῎"]={ "᾿","́" },
+ ["῏"]={ "᾿","͂" },
+ ["ῐ"]={ "ι","̆" },
+ ["ῑ"]={ "ι","̄" },
+ ["ῒ"]={ "ϊ","̀" },
+ ["ῖ"]={ "ι","͂" },
+ ["ῗ"]={ "ϊ","͂" },
+ ["Ῐ"]={ "Ι","̆" },
+ ["Ῑ"]={ "Ι","̄" },
+ ["Ὶ"]={ "Ι","̀" },
+ ["῝"]={ "῾","̀" },
+ ["῞"]={ "῾","́" },
+ ["῟"]={ "῾","͂" },
+ ["ῠ"]={ "υ","̆" },
+ ["ῡ"]={ "υ","̄" },
+ ["ῢ"]={ "ϋ","̀" },
+ ["ῤ"]={ "ρ","̓" },
+ ["ῥ"]={ "ρ","̔" },
+ ["ῦ"]={ "υ","͂" },
+ ["ῧ"]={ "ϋ","͂" },
+ ["Ῠ"]={ "Υ","̆" },
+ ["Ῡ"]={ "Υ","̄" },
+ ["Ὺ"]={ "Υ","̀" },
+ ["Ῥ"]={ "Ρ","̔" },
+ ["῭"]={ "¨","̀" },
+ ["ῲ"]={ "ὼ","ͅ" },
+ ["ῳ"]={ "ω","ͅ" },
+ ["ῴ"]={ "ώ","ͅ" },
+ ["ῶ"]={ "ω","͂" },
+ ["ῷ"]={ "ῶ","ͅ" },
+ ["Ὸ"]={ "Ο","̀" },
+ ["Ὼ"]={ "Ω","̀" },
+ ["ῼ"]={ "Ω","ͅ" },
+ ["↚"]={ "←","̸" },
+ ["↛"]={ "→","̸" },
+ ["↮"]={ "↔","̸" },
+ ["⇍"]={ "⇐","̸" },
+ ["⇎"]={ "⇔","̸" },
+ ["⇏"]={ "⇒","̸" },
+ ["∄"]={ "∃","̸" },
+ ["∉"]={ "∈","̸" },
+ ["∌"]={ "∋","̸" },
+ ["∤"]={ "∣","̸" },
+ ["∦"]={ "∥","̸" },
+ ["≁"]={ "∼","̸" },
+ ["≄"]={ "≃","̸" },
+ ["≇"]={ "≅","̸" },
+ ["≉"]={ "≈","̸" },
+ ["≠"]={ "=","̸" },
+ ["≢"]={ "≡","̸" },
+ ["≭"]={ "≍","̸" },
+ ["≮"]={ "<","̸" },
+ ["≯"]={ ">","̸" },
+ ["≰"]={ "≤","̸" },
+ ["≱"]={ "≥","̸" },
+ ["≴"]={ "≲","̸" },
+ ["≵"]={ "≳","̸" },
+ ["≸"]={ "≶","̸" },
+ ["≹"]={ "≷","̸" },
+ ["⊀"]={ "≺","̸" },
+ ["⊁"]={ "≻","̸" },
+ ["⊄"]={ "⊂","̸" },
+ ["⊅"]={ "⊃","̸" },
+ ["⊈"]={ "⊆","̸" },
+ ["⊉"]={ "⊇","̸" },
+ ["⊬"]={ "⊢","̸" },
+ ["⊭"]={ "⊨","̸" },
+ ["⊮"]={ "⊩","̸" },
+ ["⊯"]={ "⊫","̸" },
+ ["⋠"]={ "≼","̸" },
+ ["⋡"]={ "≽","̸" },
+ ["⋢"]={ "⊑","̸" },
+ ["⋣"]={ "⊒","̸" },
+ ["⋪"]={ "⊲","̸" },
+ ["⋫"]={ "⊳","̸" },
+ ["⋬"]={ "⊴","̸" },
+ ["⋭"]={ "⊵","̸" },
+ ["⫝̸"]={ "⫝","̸" },
+ ["が"]={ "か","゙" },
+ ["ぎ"]={ "き","゙" },
+ ["ぐ"]={ "く","゙" },
+ ["げ"]={ "け","゙" },
+ ["ご"]={ "こ","゙" },
+ ["ざ"]={ "さ","゙" },
+ ["じ"]={ "し","゙" },
+ ["ず"]={ "す","゙" },
+ ["ぜ"]={ "せ","゙" },
+ ["ぞ"]={ "そ","゙" },
+ ["だ"]={ "た","゙" },
+ ["ぢ"]={ "ち","゙" },
+ ["づ"]={ "つ","゙" },
+ ["で"]={ "て","゙" },
+ ["ど"]={ "と","゙" },
+ ["ば"]={ "は","゙" },
+ ["ぱ"]={ "は","゚" },
+ ["び"]={ "ひ","゙" },
+ ["ぴ"]={ "ひ","゚" },
+ ["ぶ"]={ "ふ","゙" },
+ ["ぷ"]={ "ふ","゚" },
+ ["べ"]={ "へ","゙" },
+ ["ぺ"]={ "へ","゚" },
+ ["ぼ"]={ "ほ","゙" },
+ ["ぽ"]={ "ほ","゚" },
+ ["ゔ"]={ "う","゙" },
+ ["ゞ"]={ "ゝ","゙" },
+ ["ガ"]={ "カ","゙" },
+ ["ギ"]={ "キ","゙" },
+ ["グ"]={ "ク","゙" },
+ ["ゲ"]={ "ケ","゙" },
+ ["ゴ"]={ "コ","゙" },
+ ["ザ"]={ "サ","゙" },
+ ["ジ"]={ "シ","゙" },
+ ["ズ"]={ "ス","゙" },
+ ["ゼ"]={ "セ","゙" },
+ ["ゾ"]={ "ソ","゙" },
+ ["ダ"]={ "タ","゙" },
+ ["ヂ"]={ "チ","゙" },
+ ["ヅ"]={ "ツ","゙" },
+ ["デ"]={ "テ","゙" },
+ ["ド"]={ "ト","゙" },
+ ["バ"]={ "ハ","゙" },
+ ["パ"]={ "ハ","゚" },
+ ["ビ"]={ "ヒ","゙" },
+ ["ピ"]={ "ヒ","゚" },
+ ["ブ"]={ "フ","゙" },
+ ["プ"]={ "フ","゚" },
+ ["ベ"]={ "ヘ","゙" },
+ ["ペ"]={ "ヘ","゚" },
+ ["ボ"]={ "ホ","゙" },
+ ["ポ"]={ "ホ","゚" },
+ ["ヴ"]={ "ウ","゙" },
+ ["ヷ"]={ "ワ","゙" },
+ ["ヸ"]={ "ヰ","゙" },
+ ["ヹ"]={ "ヱ","゙" },
+ ["ヺ"]={ "ヲ","゙" },
+ ["ヾ"]={ "ヽ","゙" },
+ ["יִ"]={ "י","ִ" },
+ ["ײַ"]={ "ײ","ַ" },
+ ["שׁ"]={ "ש","ׁ" },
+ ["שׂ"]={ "ש","ׂ" },
+ ["שּׁ"]={ "שּ","ׁ" },
+ ["שּׂ"]={ "שּ","ׂ" },
+ ["אַ"]={ "א","ַ" },
+ ["אָ"]={ "א","ָ" },
+ ["אּ"]={ "א","ּ" },
+ ["בּ"]={ "ב","ּ" },
+ ["גּ"]={ "ג","ּ" },
+ ["דּ"]={ "ד","ּ" },
+ ["הּ"]={ "ה","ּ" },
+ ["וּ"]={ "ו","ּ" },
+ ["זּ"]={ "ז","ּ" },
+ ["טּ"]={ "ט","ּ" },
+ ["יּ"]={ "י","ּ" },
+ ["ךּ"]={ "ך","ּ" },
+ ["כּ"]={ "כ","ּ" },
+ ["לּ"]={ "ל","ּ" },
+ ["מּ"]={ "מ","ּ" },
+ ["נּ"]={ "נ","ּ" },
+ ["סּ"]={ "ס","ּ" },
+ ["ףּ"]={ "ף","ּ" },
+ ["פּ"]={ "פ","ּ" },
+ ["צּ"]={ "צ","ּ" },
+ ["קּ"]={ "ק","ּ" },
+ ["רּ"]={ "ר","ּ" },
+ ["שּ"]={ "ש","ּ" },
+ ["תּ"]={ "ת","ּ" },
+ ["וֹ"]={ "ו","ֹ" },
+ ["בֿ"]={ "ב","ֿ" },
+ ["כֿ"]={ "כ","ֿ" },
+ ["פֿ"]={ "פ","ֿ" },
+ ["𑂚"]={ "𑂙","𑂺" },
+ ["𑂜"]={ "𑂛","𑂺" },
+ ["𑂫"]={ "𑂥","𑂺" },
+ ["𑄮"]={ "𑄱","𑄧" },
+ ["𑄯"]={ "𑄲","𑄧" },
+ ["𑍋"]={ "𑍇","𑌾" },
+ ["𑍌"]={ "𑍇","𑍗" },
+ ["𑒻"]={ "𑒹","𑒺" },
+ ["𑒼"]={ "𑒹","𑒰" },
+ ["𑒾"]={ "𑒹","𑒽" },
+ ["𑖺"]={ "𑖸","𑖯" },
+ ["𑖻"]={ "𑖹","𑖯" },
+ ["𝅗𝅥"]={ "𝅗","𝅥" },
+ ["𝅘𝅥"]={ "𝅘","𝅥" },
+ ["𝅘𝅥𝅮"]={ "𝅘𝅥","𝅮" },
+ ["𝅘𝅥𝅯"]={ "𝅘𝅥","𝅯" },
+ ["𝅘𝅥𝅰"]={ "𝅘𝅥","𝅰" },
+ ["𝅘𝅥𝅱"]={ "𝅘𝅥","𝅱" },
+ ["𝅘𝅥𝅲"]={ "𝅘𝅥","𝅲" },
+ ["𝆹𝅥"]={ "𝆹","𝅥" },
+ ["𝆺𝅥"]={ "𝆺","𝅥" },
+ ["𝆹𝅥𝅮"]={ "𝆹𝅥","𝅮" },
+ ["𝆺𝅥𝅮"]={ "𝆺𝅥","𝅮" },
+ ["𝆹𝅥𝅯"]={ "𝆹𝅥","𝅯" },
+ ["𝆺𝅥𝅯"]={ "𝆺𝅥","𝅯" },
+ },
+ },
+ },
+ ["name"]="collapse",
+ ["prepend"]=true,
+ ["type"]="ligature",
+}
end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['font-gbn']={
+if not modules then modules={} end modules ['luatex-fonts-gbn']={
version=1.001,
comment="companion to luatex-*.tex",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -27032,9 +37407,10 @@ if not modules then modules={} end modules ['font-gbn']={
license="see context related readme files"
}
if context then
- texio.write_nl("fatal error: this module is not for context")
- os.exit()
+--removed
+
end
+local next=next
local fonts=fonts
local nodes=nodes
local nuts=nodes.nuts
@@ -27056,11 +37432,11 @@ local setlink=nuts.setlink
local setprev=nuts.setprev
local n_ligaturing=node.ligaturing
local n_kerning=node.kerning
-local ligaturing=nuts.ligaturing
-local kerning=nuts.kerning
+local d_ligaturing=nuts.ligaturing
+local d_kerning=nuts.kerning
local basemodepass=true
-local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning=nil end
-local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning=nil end
+local function l_warning() logs.report("fonts","don't call 'node.ligaturing' directly") l_warning=nil end
+local function k_warning() logs.report("fonts","don't call 'node.kerning' directly") k_warning=nil end
function node.ligaturing(...)
if basemodepass and l_warning then
l_warning()
@@ -27073,20 +37449,32 @@ function node.kerning(...)
end
return n_kerning(...)
end
+function nuts.ligaturing(...)
+ if basemodepass and l_warning then
+ l_warning()
+ end
+ return d_ligaturing(...)
+end
+function nuts.kerning(...)
+ if basemodepass and k_warning then
+ k_warning()
+ end
+ return d_kerning(...)
+end
function nodes.handlers.setbasemodepass(v)
basemodepass=v
end
-function nodes.handlers.nodepass(head)
+local function nodepass(head,groupcode,size,packtype,direction)
local fontdata=fonts.hashes.identifiers
if fontdata then
- local nuthead=tonut(head)
local usedfonts={}
local basefonts={}
local prevfont=nil
local basefont=nil
local variants=nil
local redundant=nil
- for n in traverse_id(glyph_code,nuthead) do
+ local nofused=0
+ for n in traverse_id(glyph_code,head) do
local font=getfont(n)
if font~=prevfont then
if basefont then
@@ -27102,6 +37490,7 @@ function nodes.handlers.nodepass(head)
local processors=shared.processes
if processors and #processors>0 then
usedfonts[font]=processors
+ nofused=nofused+1
elseif basemodepass then
basefont={ n,nil }
basefonts[#basefonts+1]=basefont
@@ -27122,7 +37511,7 @@ function nodes.handlers.nodepass(head)
end
if variants then
local char=getchar(n)
- if char>=0xFE00 and (char<=0xFE0F or (char>=0xE0100 and char<=0xE01EF)) then
+ if (char>=0xFE00 and char<=0xFE0F) or (char>=0xE0100 and char<=0xE01EF) then
local hash=variants[char]
if hash then
local p=getprev(n)
@@ -27146,8 +37535,8 @@ function nodes.handlers.nodepass(head)
for i=1,#redundant do
local r=redundant[i]
local p,n=getboth(r)
- if r==nuthead then
- nuthead=n
+ if r==head then
+ head=n
setprev(n)
else
setlink(p,n)
@@ -27166,7 +37555,7 @@ function nodes.handlers.nodepass(head)
flush_node(r)
end
end
- for d in traverse_id(disc_code,nuthead) do
+ for d in traverse_id(disc_code,head) do
local _,_,r=getdisc(d)
if r then
for n in traverse_id(glyph_code,r) do
@@ -27182,6 +37571,7 @@ function nodes.handlers.nodepass(head)
local processors=shared.processes
if processors and #processors>0 then
usedfonts[font]=processors
+ nofused=nofused+1
end
end
end
@@ -27193,7 +37583,7 @@ function nodes.handlers.nodepass(head)
if next(usedfonts) then
for font,processors in next,usedfonts do
for i=1,#processors do
- head=processors[i](head,font,0) or head
+ head=processors[i](head,font,0,direction,nofused) or head
end
end
end
@@ -27203,16 +37593,16 @@ function nodes.handlers.nodepass(head)
local start=range[1]
local stop=range[2]
if start then
- local front=nuthead==start
+ local front=head==start
local prev,next
if stop then
next=getnext(stop)
- start,stop=ligaturing(start,stop)
- start,stop=kerning(start,stop)
+ start,stop=d_ligaturing(start,stop)
+ start,stop=d_kerning(start,stop)
else
prev=getprev(start)
- start=ligaturing(start)
- start=kerning(start)
+ start=d_ligaturing(start)
+ start=d_kerning(start)
end
if prev then
setlink(prev,start)
@@ -27220,40 +37610,57 @@ function nodes.handlers.nodepass(head)
if next then
setlink(stop,next)
end
- if front and nuthead~=start then
- head=tonode(start)
+ if front and head~=start then
+ head=start
end
end
end
end
- return head,true
- else
- return head,false
+ end
+ return head
+end
+local function basepass(head)
+ if basemodepass then
+ head=d_ligaturing(head)
+ head=d_kerning(head)
+ end
+ return head
+end
+local protectpass=node.direct.protect_glyphs
+local injectpass=nodes.injections.handler
+function nodes.handlers.nodepass(head,...)
+ if head then
+ return tonode(nodepass(tonut(head),...))
end
end
function nodes.handlers.basepass(head)
- if not basemodepass then
- head=n_ligaturing(head)
- head=n_kerning(head)
+ if head then
+ return tonode(basepass(tonut(head)))
end
- return head,true
end
-local nodepass=nodes.handlers.nodepass
-local basepass=nodes.handlers.basepass
-local injectpass=nodes.injections.handler
-local protectpass=nodes.handlers.protectglyphs
-function nodes.simple_font_handler(head)
+function nodes.handlers.injectpass(head)
if head then
- head=nodepass(head)
+ return tonode(injectpass(tonut(head)))
+ end
+end
+function nodes.handlers.protectpass(head)
+ if head then
+ protectpass(tonut(head))
+ return head
+ end
+end
+function nodes.simple_font_handler(head,groupcode,size,packtype,direction)
+ if head then
+ head=tonut(head)
+ head=nodepass(head,groupcode,size,packtype,direction)
head=injectpass(head)
if not basemodepass then
head=basepass(head)
end
protectpass(head)
- return head,true
- else
- return head,false
+ head=tonode(head)
end
+ return head
end
end -- closure
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.lua
deleted file mode 100644
index 00d7c5a4efe..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.lua
+++ /dev/null
@@ -1,743 +0,0 @@
-
-
--- local gm = require("swiglib.gmwand.core") -- local gm = swiglib("gmwand.core")
---
--- gm.InitializeMagick(".")
---
--- local magick_wand = gm.NewMagickWand()
--- local drawing_wand = gm.NewDrawingWand()
---
--- gm.MagickSetSize(magick_wand,800,600)
--- gm.MagickReadImage(magick_wand,"xc:red")
---
--- gm.DrawPushGraphicContext(drawing_wand)
---
--- gm.DrawSetFillColor(drawing_wand,gm.NewPixelWand())
---
--- -- gm.DrawSetFont(drawing_wand, kpse.findfile("DejaVuSerifBold.ttf"))
--- -- gm.DrawSetFontSize(drawing_wand, 96)
--- -- gm.DrawAnnotation(drawing_wand,300,200, "LuaTeX")
---
--- gm.DrawPopGraphicContext(drawing_wand)
--- gm.MagickDrawImage(magick_wand,drawing_wand)
---
--- gm.MagickWriteImages(magick_wand,"./luatex-swiglib-test.jpg",1)
---
--- gm.DestroyDrawingWand(drawing_wand)
--- gm.DestroyMagickWand(magick_wand)
-
-local swighelpers = require("swiglib.helpers.core")
-local sqlite = require("swiglib.sqlite.core")
-
--- s.sqlite3_create_function_v2_lua_callback(function() end)
-
-
-local t = [[
- CREATE TABLE IF NOT EXISTS loggers (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `time` int(11) NOT NULL,
- `type` int(11) NOT NULL,
- `action` varchar(15) NOT NULL,
- `data` longtext,
- PRIMARY KEY (`id`),
- UNIQUE KEY `id_unique_key` (`id`)
- )
- DEFAULT CHARSET = utf8 ;
-]]
-
-local t = [[
-CREATE TABLE IF NOT EXISTS loggers (
- `id` INTEGER PRIMARY KEY AUTOINCREMENT,
- `time` int(11) NOT NULL,
- `type` int(11) NOT NULL,
- `action` varchar(15) NOT NULL,
- `data` longtext
- );
-]]
-
-local function execute(name,query)
- local db = sqlite.new_sqlite3_p_array(1)
- local okay = sqlite.sqlite3_open(name,db)
- local dbh = sqlite.sqlite3_p_array_getitem(db,0)
- if okay ~= sqlite.SQLITE_OK then
- return false, sqlite.sqlite3_errmsg(dbh)
- end
- local result = { }
- local callback = function(data,nofcolumns,values,fields)
- local r = { }
- for i=0,nofcolumns-1 do
- local field = sqlite.char_p_array_getitem(fields,i)
- local value = sqlite.char_p_array_getitem(values,i)
- r[field] = value
- end
- result[#result+1] = r
- return sqlite.SQLITE_OK
- end
- local data = nil
- local message = nil
- local okay = sqlite.sqlite3_exec_lua_callback(dbh,query,callback,data,message)
- if okay ~= sqlite.SQLITE_OK then
- return false, sqlite.sqlite3_errmsg(dbh)
- end
- sqlite.sqlite3_close(dbh)
- sqlite.delete_sqlite3_p_array(db)
- return result
-end
-
-execute("foo.db",t)
--- execute("test.db",t)
-
-local template =[[
- INSERT INTO loggers (
- `time`,
- `type`,
- `action`,
- `data`
- ) VALUES (
- %s,
- %s,
- '%s',
- '%s'
- ) ;
-]]
-
--- for i=1,100 do
--- local t = string.format(template,os.time(),1,"oeps " .. i,"more")
--- execute("foo.db",t)
--- end
-
-
-local r = execute("foo.db","select * from loggers;")
-inspect(r)
-
-
--- inspect(table.sortedkeys(sqlite))
--- inspect(table.sortedkeys(swighelpers))
-
-
-
-t={
- "FULLY_WITHIN",
- "NOT_WITHIN",
- "PARTLY_WITHIN",
- "SQLITE3_TEXT",
- "SQLITE_ABORT",
- "SQLITE_ABORT_ROLLBACK",
- "SQLITE_ACCESS_EXISTS",
- "SQLITE_ACCESS_READ",
- "SQLITE_ACCESS_READWRITE",
- "SQLITE_ALTER_TABLE",
- "SQLITE_ANALYZE",
- "SQLITE_ANY",
- "SQLITE_ATTACH",
- "SQLITE_AUTH",
- "SQLITE_AUTH_USER",
- "SQLITE_BLOB",
- "SQLITE_BUSY",
- "SQLITE_BUSY_RECOVERY",
- "SQLITE_BUSY_SNAPSHOT",
- "SQLITE_CANTOPEN",
- "SQLITE_CANTOPEN_CONVPATH",
- "SQLITE_CANTOPEN_FULLPATH",
- "SQLITE_CANTOPEN_ISDIR",
- "SQLITE_CANTOPEN_NOTEMPDIR",
- "SQLITE_CHECKPOINT_FULL",
- "SQLITE_CHECKPOINT_PASSIVE",
- "SQLITE_CHECKPOINT_RESTART",
- "SQLITE_CONFIG_COVERING_INDEX_SCAN",
- "SQLITE_CONFIG_GETMALLOC",
- "SQLITE_CONFIG_GETMUTEX",
- "SQLITE_CONFIG_GETPCACHE",
- "SQLITE_CONFIG_GETPCACHE2",
- "SQLITE_CONFIG_HEAP",
- "SQLITE_CONFIG_LOG",
- "SQLITE_CONFIG_LOOKASIDE",
- "SQLITE_CONFIG_MALLOC",
- "SQLITE_CONFIG_MEMSTATUS",
- "SQLITE_CONFIG_MMAP_SIZE",
- "SQLITE_CONFIG_MULTITHREAD",
- "SQLITE_CONFIG_MUTEX",
- "SQLITE_CONFIG_PAGECACHE",
- "SQLITE_CONFIG_PCACHE",
- "SQLITE_CONFIG_PCACHE2",
- "SQLITE_CONFIG_SCRATCH",
- "SQLITE_CONFIG_SERIALIZED",
- "SQLITE_CONFIG_SINGLETHREAD",
- "SQLITE_CONFIG_SQLLOG",
- "SQLITE_CONFIG_URI",
- "SQLITE_CONFIG_WIN32_HEAPSIZE",
- "SQLITE_CONSTRAINT",
- "SQLITE_CONSTRAINT_CHECK",
- "SQLITE_CONSTRAINT_COMMITHOOK",
- "SQLITE_CONSTRAINT_FOREIGNKEY",
- "SQLITE_CONSTRAINT_FUNCTION",
- "SQLITE_CONSTRAINT_NOTNULL",
- "SQLITE_CONSTRAINT_PRIMARYKEY",
- "SQLITE_CONSTRAINT_ROWID",
- "SQLITE_CONSTRAINT_TRIGGER",
- "SQLITE_CONSTRAINT_UNIQUE",
- "SQLITE_CONSTRAINT_VTAB",
- "SQLITE_COPY",
- "SQLITE_CORRUPT",
- "SQLITE_CORRUPT_VTAB",
- "SQLITE_CREATE_INDEX",
- "SQLITE_CREATE_TABLE",
- "SQLITE_CREATE_TEMP_INDEX",
- "SQLITE_CREATE_TEMP_TABLE",
- "SQLITE_CREATE_TEMP_TRIGGER",
- "SQLITE_CREATE_TEMP_VIEW",
- "SQLITE_CREATE_TRIGGER",
- "SQLITE_CREATE_VIEW",
- "SQLITE_CREATE_VTABLE",
- "SQLITE_DBCONFIG_ENABLE_FKEY",
- "SQLITE_DBCONFIG_ENABLE_TRIGGER",
- "SQLITE_DBCONFIG_LOOKASIDE",
- "SQLITE_DBSTATUS_CACHE_HIT",
- "SQLITE_DBSTATUS_CACHE_MISS",
- "SQLITE_DBSTATUS_CACHE_USED",
- "SQLITE_DBSTATUS_CACHE_WRITE",
- "SQLITE_DBSTATUS_DEFERRED_FKS",
- "SQLITE_DBSTATUS_LOOKASIDE_HIT",
- "SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL",
- "SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE",
- "SQLITE_DBSTATUS_LOOKASIDE_USED",
- "SQLITE_DBSTATUS_MAX",
- "SQLITE_DBSTATUS_SCHEMA_USED",
- "SQLITE_DBSTATUS_STMT_USED",
- "SQLITE_DELETE",
- "SQLITE_DENY",
- "SQLITE_DETACH",
- "SQLITE_DETERMINISTIC",
- "SQLITE_DONE",
- "SQLITE_DROP_INDEX",
- "SQLITE_DROP_TABLE",
- "SQLITE_DROP_TEMP_INDEX",
- "SQLITE_DROP_TEMP_TABLE",
- "SQLITE_DROP_TEMP_TRIGGER",
- "SQLITE_DROP_TEMP_VIEW",
- "SQLITE_DROP_TRIGGER",
- "SQLITE_DROP_VIEW",
- "SQLITE_DROP_VTABLE",
- "SQLITE_EMPTY",
- "SQLITE_ERROR",
- "SQLITE_FAIL",
- "SQLITE_FCNTL_BUSYHANDLER",
- "SQLITE_FCNTL_CHUNK_SIZE",
- "SQLITE_FCNTL_COMMIT_PHASETWO",
- "SQLITE_FCNTL_FILE_POINTER",
- "SQLITE_FCNTL_HAS_MOVED",
- "SQLITE_FCNTL_LOCKSTATE",
- "SQLITE_FCNTL_MMAP_SIZE",
- "SQLITE_FCNTL_OVERWRITE",
- "SQLITE_FCNTL_PERSIST_WAL",
- "SQLITE_FCNTL_POWERSAFE_OVERWRITE",
- "SQLITE_FCNTL_PRAGMA",
- "SQLITE_FCNTL_SIZE_HINT",
- "SQLITE_FCNTL_SYNC",
- "SQLITE_FCNTL_SYNC_OMITTED",
- "SQLITE_FCNTL_TEMPFILENAME",
- "SQLITE_FCNTL_TRACE",
- "SQLITE_FCNTL_VFSNAME",
- "SQLITE_FCNTL_WIN32_AV_RETRY",
- "SQLITE_FCNTL_WIN32_SET_HANDLE",
- "SQLITE_FLOAT",
- "SQLITE_FORMAT",
- "SQLITE_FULL",
- "SQLITE_FUNCTION",
- "SQLITE_GET_LOCKPROXYFILE",
- "SQLITE_IGNORE",
- "SQLITE_INDEX_CONSTRAINT_EQ",
- "SQLITE_INDEX_CONSTRAINT_GE",
- "SQLITE_INDEX_CONSTRAINT_GT",
- "SQLITE_INDEX_CONSTRAINT_LE",
- "SQLITE_INDEX_CONSTRAINT_LT",
- "SQLITE_INDEX_CONSTRAINT_MATCH",
- "SQLITE_INSERT",
- "SQLITE_INTEGER",
- "SQLITE_INTERNAL",
- "SQLITE_INTERRUPT",
- "SQLITE_IOCAP_ATOMIC",
- "SQLITE_IOCAP_ATOMIC16K",
- "SQLITE_IOCAP_ATOMIC1K",
- "SQLITE_IOCAP_ATOMIC2K",
- "SQLITE_IOCAP_ATOMIC32K",
- "SQLITE_IOCAP_ATOMIC4K",
- "SQLITE_IOCAP_ATOMIC512",
- "SQLITE_IOCAP_ATOMIC64K",
- "SQLITE_IOCAP_ATOMIC8K",
- "SQLITE_IOCAP_IMMUTABLE",
- "SQLITE_IOCAP_POWERSAFE_OVERWRITE",
- "SQLITE_IOCAP_SAFE_APPEND",
- "SQLITE_IOCAP_SEQUENTIAL",
- "SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN",
- "SQLITE_IOERR",
- "SQLITE_IOERR_ACCESS",
- "SQLITE_IOERR_BLOCKED",
- "SQLITE_IOERR_CHECKRESERVEDLOCK",
- "SQLITE_IOERR_CLOSE",
- "SQLITE_IOERR_CONVPATH",
- "SQLITE_IOERR_DELETE",
- "SQLITE_IOERR_DELETE_NOENT",
- "SQLITE_IOERR_DIR_CLOSE",
- "SQLITE_IOERR_DIR_FSYNC",
- "SQLITE_IOERR_FSTAT",
- "SQLITE_IOERR_FSYNC",
- "SQLITE_IOERR_GETTEMPPATH",
- "SQLITE_IOERR_LOCK",
- "SQLITE_IOERR_MMAP",
- "SQLITE_IOERR_NOMEM",
- "SQLITE_IOERR_RDLOCK",
- "SQLITE_IOERR_READ",
- "SQLITE_IOERR_SEEK",
- "SQLITE_IOERR_SHMLOCK",
- "SQLITE_IOERR_SHMMAP",
- "SQLITE_IOERR_SHMOPEN",
- "SQLITE_IOERR_SHMSIZE",
- "SQLITE_IOERR_SHORT_READ",
- "SQLITE_IOERR_TRUNCATE",
- "SQLITE_IOERR_UNLOCK",
- "SQLITE_IOERR_WRITE",
- "SQLITE_LAST_ERRNO",
- "SQLITE_LIMIT_ATTACHED",
- "SQLITE_LIMIT_COLUMN",
- "SQLITE_LIMIT_COMPOUND_SELECT",
- "SQLITE_LIMIT_EXPR_DEPTH",
- "SQLITE_LIMIT_FUNCTION_ARG",
- "SQLITE_LIMIT_LENGTH",
- "SQLITE_LIMIT_LIKE_PATTERN_LENGTH",
- "SQLITE_LIMIT_SQL_LENGTH",
- "SQLITE_LIMIT_TRIGGER_DEPTH",
- "SQLITE_LIMIT_VARIABLE_NUMBER",
- "SQLITE_LIMIT_VDBE_OP",
- "SQLITE_LIMIT_WORKER_THREADS",
- "SQLITE_LOCKED",
- "SQLITE_LOCKED_SHAREDCACHE",
- "SQLITE_LOCK_EXCLUSIVE",
- "SQLITE_LOCK_NONE",
- "SQLITE_LOCK_PENDING",
- "SQLITE_LOCK_RESERVED",
- "SQLITE_LOCK_SHARED",
- "SQLITE_MISMATCH",
- "SQLITE_MISUSE",
- "SQLITE_MUTEX_FAST",
- "SQLITE_MUTEX_RECURSIVE",
- "SQLITE_MUTEX_STATIC_APP1",
- "SQLITE_MUTEX_STATIC_APP2",
- "SQLITE_MUTEX_STATIC_APP3",
- "SQLITE_MUTEX_STATIC_LRU",
- "SQLITE_MUTEX_STATIC_LRU2",
- "SQLITE_MUTEX_STATIC_MASTER",
- "SQLITE_MUTEX_STATIC_MEM",
- "SQLITE_MUTEX_STATIC_MEM2",
- "SQLITE_MUTEX_STATIC_OPEN",
- "SQLITE_MUTEX_STATIC_PMEM",
- "SQLITE_MUTEX_STATIC_PRNG",
- "SQLITE_NOLFS",
- "SQLITE_NOMEM",
- "SQLITE_NOTADB",
- "SQLITE_NOTFOUND",
- "SQLITE_NOTICE",
- "SQLITE_NOTICE_RECOVER_ROLLBACK",
- "SQLITE_NOTICE_RECOVER_WAL",
- "SQLITE_NULL",
- "SQLITE_OK",
- "SQLITE_OPEN_AUTOPROXY",
- "SQLITE_OPEN_CREATE",
- "SQLITE_OPEN_DELETEONCLOSE",
- "SQLITE_OPEN_EXCLUSIVE",
- "SQLITE_OPEN_FULLMUTEX",
- "SQLITE_OPEN_MAIN_DB",
- "SQLITE_OPEN_MAIN_JOURNAL",
- "SQLITE_OPEN_MASTER_JOURNAL",
- "SQLITE_OPEN_MEMORY",
- "SQLITE_OPEN_NOMUTEX",
- "SQLITE_OPEN_PRIVATECACHE",
- "SQLITE_OPEN_READONLY",
- "SQLITE_OPEN_READWRITE",
- "SQLITE_OPEN_SHAREDCACHE",
- "SQLITE_OPEN_SUBJOURNAL",
- "SQLITE_OPEN_TEMP_DB",
- "SQLITE_OPEN_TEMP_JOURNAL",
- "SQLITE_OPEN_TRANSIENT_DB",
- "SQLITE_OPEN_URI",
- "SQLITE_OPEN_WAL",
- "SQLITE_PERM",
- "SQLITE_PRAGMA",
- "SQLITE_PROTOCOL",
- "SQLITE_RANGE",
- "SQLITE_READ",
- "SQLITE_READONLY",
- "SQLITE_READONLY_CANTLOCK",
- "SQLITE_READONLY_DBMOVED",
- "SQLITE_READONLY_RECOVERY",
- "SQLITE_READONLY_ROLLBACK",
- "SQLITE_RECURSIVE",
- "SQLITE_REINDEX",
- "SQLITE_REPLACE",
- "SQLITE_ROLLBACK",
- "SQLITE_ROW",
- "SQLITE_SAVEPOINT",
- "SQLITE_SCHEMA",
- "SQLITE_SELECT",
- "SQLITE_SET_LOCKPROXYFILE",
- "SQLITE_SHM_EXCLUSIVE",
- "SQLITE_SHM_LOCK",
- "SQLITE_SHM_NLOCK",
- "SQLITE_SHM_SHARED",
- "SQLITE_SHM_UNLOCK",
- "SQLITE_SOURCE_ID",
- "SQLITE_STATUS_MALLOC_COUNT",
- "SQLITE_STATUS_MALLOC_SIZE",
- "SQLITE_STATUS_MEMORY_USED",
- "SQLITE_STATUS_PAGECACHE_OVERFLOW",
- "SQLITE_STATUS_PAGECACHE_SIZE",
- "SQLITE_STATUS_PAGECACHE_USED",
- "SQLITE_STATUS_PARSER_STACK",
- "SQLITE_STATUS_SCRATCH_OVERFLOW",
- "SQLITE_STATUS_SCRATCH_SIZE",
- "SQLITE_STATUS_SCRATCH_USED",
- "SQLITE_STMTSTATUS_AUTOINDEX",
- "SQLITE_STMTSTATUS_FULLSCAN_STEP",
- "SQLITE_STMTSTATUS_SORT",
- "SQLITE_STMTSTATUS_VM_STEP",
- "SQLITE_SYNC_DATAONLY",
- "SQLITE_SYNC_FULL",
- "SQLITE_SYNC_NORMAL",
- "SQLITE_TESTCTRL_ALWAYS",
- "SQLITE_TESTCTRL_ASSERT",
- "SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS",
- "SQLITE_TESTCTRL_BITVEC_TEST",
- "SQLITE_TESTCTRL_BYTEORDER",
- "SQLITE_TESTCTRL_EXPLAIN_STMT",
- "SQLITE_TESTCTRL_FAULT_INSTALL",
- "SQLITE_TESTCTRL_FIRST",
- "SQLITE_TESTCTRL_ISINIT",
- "SQLITE_TESTCTRL_ISKEYWORD",
- "SQLITE_TESTCTRL_LAST",
- "SQLITE_TESTCTRL_LOCALTIME_FAULT",
- "SQLITE_TESTCTRL_NEVER_CORRUPT",
- "SQLITE_TESTCTRL_OPTIMIZATIONS",
- "SQLITE_TESTCTRL_PENDING_BYTE",
- "SQLITE_TESTCTRL_PRNG_RESET",
- "SQLITE_TESTCTRL_PRNG_RESTORE",
- "SQLITE_TESTCTRL_PRNG_SAVE",
- "SQLITE_TESTCTRL_RESERVE",
- "SQLITE_TESTCTRL_SCRATCHMALLOC",
- "SQLITE_TESTCTRL_SORTER_MMAP",
- "SQLITE_TESTCTRL_VDBE_COVERAGE",
- "SQLITE_TEXT",
- "SQLITE_TOOBIG",
- "SQLITE_TRANSACTION",
- "SQLITE_UPDATE",
- "SQLITE_UTF16",
- "SQLITE_UTF16BE",
- "SQLITE_UTF16LE",
- "SQLITE_UTF16_ALIGNED",
- "SQLITE_UTF8",
- "SQLITE_VERSION",
- "SQLITE_VERSION_NUMBER",
- "SQLITE_VTAB_CONSTRAINT_SUPPORT",
- "SQLITE_WARNING",
- "SQLITE_WARNING_AUTOINDEX",
- "call_callback_sqlite3_create_collation_v2_1",
- "call_callback_sqlite3_create_collation_v2_2",
- "call_callback_sqlite3_create_function16_1",
- "call_callback_sqlite3_create_function16_2",
- "call_callback_sqlite3_create_function16_3",
- "call_callback_sqlite3_create_function_1",
- "call_callback_sqlite3_create_function_2",
- "call_callback_sqlite3_create_function_3",
- "call_callback_sqlite3_create_function_v2_1",
- "call_callback_sqlite3_create_function_v2_2",
- "call_callback_sqlite3_create_function_v2_3",
- "call_callback_sqlite3_create_function_v2_4",
- "call_callback_sqlite3_rtree_query_callback_1",
- "call_callback_sqlite3_rtree_query_callback_2",
- "char_p_array_getitem",
- "char_p_array_setitem",
- "delete_char_p_array",
- "delete_sqlite3_p_array",
- "delete_sqlite3_rtree_dbl_array",
- "delete_sqlite3_stmt_p_array",
- "delete_sqlite3_value_p_array",
- "delete_sqlite3_vtab_cursor_p_array",
- "delete_sqlite3_vtab_p_array",
- "delete_void_p_array",
- "new_char_p_array",
- "new_sqlite3_p_array",
- "new_sqlite3_rtree_dbl_array",
- "new_sqlite3_stmt_p_array",
- "new_sqlite3_value_p_array",
- "new_sqlite3_vtab_cursor_p_array",
- "new_sqlite3_vtab_p_array",
- "new_void_p_array",
- "sqlite3_aggregate_context",
- "sqlite3_aggregate_count",
- "sqlite3_auto_extension",
- "sqlite3_auto_extension_lua_callback",
- "sqlite3_backup_finish",
- "sqlite3_backup_init",
- "sqlite3_backup_pagecount",
- "sqlite3_backup_remaining",
- "sqlite3_backup_step",
- "sqlite3_bind_blob",
- "sqlite3_bind_blob64",
- "sqlite3_bind_blob64_lua_callback",
- "sqlite3_bind_blob_lua_callback",
- "sqlite3_bind_double",
- "sqlite3_bind_int",
- "sqlite3_bind_int64",
- "sqlite3_bind_null",
- "sqlite3_bind_parameter_count",
- "sqlite3_bind_parameter_index",
- "sqlite3_bind_parameter_name",
- "sqlite3_bind_text",
- "sqlite3_bind_text16",
- "sqlite3_bind_text16_lua_callback",
- "sqlite3_bind_text64",
- "sqlite3_bind_text64_lua_callback",
- "sqlite3_bind_text_lua_callback",
- "sqlite3_bind_value",
- "sqlite3_bind_zeroblob",
- "sqlite3_blob_bytes",
- "sqlite3_blob_close",
- "sqlite3_blob_open",
- "sqlite3_blob_read",
- "sqlite3_blob_reopen",
- "sqlite3_blob_write",
- "sqlite3_busy_handler",
- "sqlite3_busy_handler_lua_callback",
- "sqlite3_busy_timeout",
- "sqlite3_cancel_auto_extension",
- "sqlite3_cancel_auto_extension_lua_callback",
- "sqlite3_changes",
- "sqlite3_clear_bindings",
- "sqlite3_close",
- "sqlite3_close_v2",
- "sqlite3_collation_needed",
- "sqlite3_collation_needed16",
- "sqlite3_collation_needed16_lua_callback",
- "sqlite3_collation_needed_lua_callback",
- "sqlite3_column_blob",
- "sqlite3_column_bytes",
- "sqlite3_column_bytes16",
- "sqlite3_column_count",
- "sqlite3_column_decltype",
- "sqlite3_column_decltype16",
- "sqlite3_column_double",
- "sqlite3_column_int",
- "sqlite3_column_int64",
- "sqlite3_column_name",
- "sqlite3_column_name16",
- "sqlite3_column_text",
- "sqlite3_column_text16",
- "sqlite3_column_type",
- "sqlite3_column_value",
- "sqlite3_commit_hook",
- "sqlite3_commit_hook_lua_callback",
- "sqlite3_compileoption_get",
- "sqlite3_compileoption_used",
- "sqlite3_complete",
- "sqlite3_complete16",
- "sqlite3_config",
- "sqlite3_context_db_handle",
- "sqlite3_create_collation",
- "sqlite3_create_collation16",
- "sqlite3_create_collation16_lua_callback",
- "sqlite3_create_collation_lua_callback",
- "sqlite3_create_collation_v2",
- "sqlite3_create_collation_v2_lua_callback",
- "sqlite3_create_function",
- "sqlite3_create_function16",
- "sqlite3_create_function16_lua_callback",
- "sqlite3_create_function_lua_callback",
- "sqlite3_create_function_v2",
- "sqlite3_create_function_v2_lua_callback",
- "sqlite3_create_module",
- "sqlite3_create_module_v2",
- "sqlite3_create_module_v2_lua_callback",
- "sqlite3_data_count",
- "sqlite3_db_config",
- "sqlite3_db_filename",
- "sqlite3_db_handle",
- "sqlite3_db_mutex",
- "sqlite3_db_readonly",
- "sqlite3_db_release_memory",
- "sqlite3_db_status",
- "sqlite3_declare_vtab",
- "sqlite3_enable_load_extension",
- "sqlite3_enable_shared_cache",
- "sqlite3_errcode",
- "sqlite3_errmsg",
- "sqlite3_errmsg16",
- "sqlite3_errstr",
- "sqlite3_exec",
- "sqlite3_exec_lua_callback",
- "sqlite3_expired",
- "sqlite3_extended_errcode",
- "sqlite3_extended_result_codes",
- "sqlite3_file",
- "sqlite3_file_control",
- "sqlite3_finalize",
- "sqlite3_free",
- "sqlite3_free_table",
- "sqlite3_get_autocommit",
- "sqlite3_get_auxdata",
- "sqlite3_get_table",
- "sqlite3_global_recover",
- "sqlite3_index_info",
- "sqlite3_index_info_aConstraint",
- "sqlite3_index_info_aConstraintUsage",
- "sqlite3_index_info_aOrderBy",
- "sqlite3_initialize",
- "sqlite3_interrupt",
- "sqlite3_io_methods",
- "sqlite3_last_insert_rowid",
- "sqlite3_libversion",
- "sqlite3_libversion_number",
- "sqlite3_limit",
- "sqlite3_load_extension",
- "sqlite3_log",
- "sqlite3_malloc",
- "sqlite3_malloc64",
- "sqlite3_mem_methods",
- "sqlite3_memory_alarm",
- "sqlite3_memory_highwater",
- "sqlite3_memory_used",
- "sqlite3_module",
- "sqlite3_mprintf",
- "sqlite3_msize",
- "sqlite3_mutex_alloc",
- "sqlite3_mutex_enter",
- "sqlite3_mutex_free",
- "sqlite3_mutex_leave",
- "sqlite3_mutex_methods",
- "sqlite3_mutex_try",
- "sqlite3_next_stmt",
- "sqlite3_open",
- "sqlite3_open16",
- "sqlite3_open_v2",
- "sqlite3_os_end",
- "sqlite3_os_init",
- "sqlite3_overload_function",
- "sqlite3_p_array_getitem",
- "sqlite3_p_array_setitem",
- "sqlite3_pcache_methods",
- "sqlite3_pcache_methods2",
- "sqlite3_pcache_page",
- "sqlite3_prepare",
- "sqlite3_prepare16",
- "sqlite3_prepare16_v2",
- "sqlite3_prepare_v2",
- "sqlite3_profile",
- "sqlite3_progress_handler",
- "sqlite3_progress_handler_lua_callback",
- "sqlite3_randomness",
- "sqlite3_realloc",
- "sqlite3_realloc64",
- "sqlite3_release_memory",
- "sqlite3_reset",
- "sqlite3_reset_auto_extension",
- "sqlite3_result_blob",
- "sqlite3_result_blob64",
- "sqlite3_result_blob64_lua_callback",
- "sqlite3_result_blob_lua_callback",
- "sqlite3_result_double",
- "sqlite3_result_error",
- "sqlite3_result_error16",
- "sqlite3_result_error_code",
- "sqlite3_result_error_nomem",
- "sqlite3_result_error_toobig",
- "sqlite3_result_int",
- "sqlite3_result_int64",
- "sqlite3_result_null",
- "sqlite3_result_text",
- "sqlite3_result_text16",
- "sqlite3_result_text16_lua_callback",
- "sqlite3_result_text16be",
- "sqlite3_result_text16be_lua_callback",
- "sqlite3_result_text16le",
- "sqlite3_result_text16le_lua_callback",
- "sqlite3_result_text64",
- "sqlite3_result_text64_lua_callback",
- "sqlite3_result_text_lua_callback",
- "sqlite3_result_value",
- "sqlite3_result_zeroblob",
- "sqlite3_rollback_hook",
- "sqlite3_rollback_hook_lua_callback",
- "sqlite3_rtree_dbl_array_getitem",
- "sqlite3_rtree_dbl_array_setitem",
- "sqlite3_rtree_geometry",
- "sqlite3_rtree_geometry_callback",
- "sqlite3_rtree_geometry_callback_lua_callback",
- "sqlite3_rtree_query_callback",
- "sqlite3_rtree_query_callback_lua_callback",
- "sqlite3_rtree_query_info",
- "sqlite3_set_authorizer",
- "sqlite3_set_authorizer_lua_callback",
- "sqlite3_set_auxdata",
- "sqlite3_set_auxdata_lua_callback",
- "sqlite3_shutdown",
- "sqlite3_sleep",
- "sqlite3_snprintf",
- "sqlite3_soft_heap_limit",
- "sqlite3_soft_heap_limit64",
- "sqlite3_sourceid",
- "sqlite3_sql",
- "sqlite3_status",
- "sqlite3_step",
- "sqlite3_stmt_busy",
- "sqlite3_stmt_p_array_getitem",
- "sqlite3_stmt_p_array_setitem",
- "sqlite3_stmt_readonly",
- "sqlite3_stmt_status",
- "sqlite3_strglob",
- "sqlite3_stricmp",
- "sqlite3_strnicmp",
- "sqlite3_test_control",
- "sqlite3_thread_cleanup",
- "sqlite3_threadsafe",
- "sqlite3_total_changes",
- "sqlite3_trace",
- "sqlite3_trace_lua_callback",
- "sqlite3_transfer_bindings",
- "sqlite3_update_hook",
- "sqlite3_update_hook_lua_callback",
- "sqlite3_uri_boolean",
- "sqlite3_uri_int64",
- "sqlite3_uri_parameter",
- "sqlite3_user_data",
- "sqlite3_value_blob",
- "sqlite3_value_bytes",
- "sqlite3_value_bytes16",
- "sqlite3_value_double",
- "sqlite3_value_int",
- "sqlite3_value_int64",
- "sqlite3_value_numeric_type",
- "sqlite3_value_p_array_getitem",
- "sqlite3_value_p_array_setitem",
- "sqlite3_value_text",
- "sqlite3_value_text16",
- "sqlite3_value_text16be",
- "sqlite3_value_text16le",
- "sqlite3_value_type",
- "sqlite3_vfs",
- "sqlite3_vfs_find",
- "sqlite3_vfs_register",
- "sqlite3_vfs_unregister",
- "sqlite3_vtab",
- "sqlite3_vtab_config",
- "sqlite3_vtab_cursor",
- "sqlite3_vtab_cursor_p_array_getitem",
- "sqlite3_vtab_cursor_p_array_setitem",
- "sqlite3_vtab_on_conflict",
- "sqlite3_vtab_p_array_getitem",
- "sqlite3_vtab_p_array_setitem",
- "sqlite3_wal_autocheckpoint",
- "sqlite3_wal_checkpoint",
- "sqlite3_wal_checkpoint_v2",
- "sqlite3_wal_hook",
- "sqlite3_wal_hook_lua_callback",
- "void_p_array_getitem",
- "void_p_array_setitem",
-}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.tex
deleted file mode 100644
index d26bb6ffbb3..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib-test.tex
+++ /dev/null
@@ -1,11 +0,0 @@
-% luatex --fmt=luatex=plain luatex-swiglib-test.tex
-
-\input luatex-swiglib.tex
-
-\directlua {
- dofile("luatex-swiglib-test.lua")
-}
-
-\pdfximage {luatex-swiglib-test.jpg} \pdfrefximage\pdflastximage
-
-\end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.lua
deleted file mode 100644
index 3108dd43fb8..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.lua
+++ /dev/null
@@ -1,63 +0,0 @@
-if not modules then modules = { } end modules ['luatex-swiglib'] = {
- version = 1.001,
- comment = "companion to luatex-swiglib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local savedrequire = require
-
-local libsuffix = os.type == "windows" and ".dll" or ".so"
-local pathsplit = "([^" .. io.pathseparator .. "]+)"
-
-function requireswiglib(required,version)
- local library = package.loaded[required]
- if library then
- return library
- else
- local name = string.gsub(required,"%.","/") .. libsuffix
- local list = kpse.show_path("clua")
- for root in string.gmatch(list,pathsplit) do
- local full = false
- if type(version) == "string" and version ~= "" then
- full = root .. "/" .. version .. "/" .. name
- full = lfs.isfile(full) and full
- end
- if not full then
- full = root .. "/" .. name
- full = lfs.isfile(full) and full
- end
- if full then
- local path, base = string.match(full,"^(.-)([^\\/]+)" .. libsuffix .."$")
- local savedlibrary = package.loaded[base]
- package.loaded[base] = nil
- local savedpath = lfs.currentdir()
- lfs.chdir(path)
- library = package.loadlib(full,"luaopen_" .. base)
- if type(library) == "function" then
- library = library()
- texio.write("<swiglib: '",required,"' is loaded>")
- end
- lfs.chdir(savedpath)
- package.loaded[base] = savedlibrary
- package.loaded[required] = library
- return library
- end
- end
- texio.write("<swiglib: '",name,"'is not found on '",list,"'")
- end
- texio.write("<swiglib: '",required,"' is not found>")
-end
-
-function require(name)
- if string.find(name,"^swiglib%.") then
- return requireswiglib(name)
- else
- return savedrequire(name)
- end
-end
-
-function swiglib(name,version)
- return requireswiglib("swiglib." .. name,version)
-end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.tex
deleted file mode 100644
index 7c437751587..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-swiglib.tex
+++ /dev/null
@@ -1,20 +0,0 @@
-%D \module
-%D [ file=luatex-swiglib,
-%D version=2013.03.30,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Generic \SWIGLIB\ Font Handler,
-%D author=Hans Hagen,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D This is an experimental setup. Usage:
-%D
-%D \starttyping
-%D local gm = swiglib("gmwand.core")
-%D local gm = require("swiglib.gmwand.core")
-%D local sq = swiglib("mysql.core")
-%D local sq = swiglib("mysql.core","5.6")
-%D \stoptyping
-
-\directlua {
- dofile(kpse.find_file("luatex-swiglib.lua","tex"))
-}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-test.tex b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-test.tex
deleted file mode 100644
index 2aa4f22d975..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-test.tex
+++ /dev/null
@@ -1,173 +0,0 @@
-% texformat=luatex-plain
-
-%D \module
-%D [ file=luatex-test,
-%D version=2009.12.01,
-%D title=\LUATEX\ Support Macros,
-%D subtitle=Simple Test File,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
-
-%D See \type {luatex-plain.tex} (or on my machine \type {luatex.tex}
-%D for how to make a format.
-
-% You can generate a font database with:
-%
-% mtxrun --script fonts --reload --save
-%
-% The file luatex-fonts-names.lua has to be moved to a place
-% where kpse can find it.
-
-\pdfoutput=1
-
-\font\testa=file:lmroman10-regular at 12pt \testa \input tufte \par
-\font\testb=file:lmroman12-regular:+liga; at 24pt \testb effe flink fietsen \par
-\font\testc=file:lmroman12-regular:mode=node;+liga; at 24pt \testc effe flink fietsen \par
-\font\testd=name:lmroman10bold at 12pt \testd a bit bold \par
-
-\font\oeps=cmr10
-
-\font\oeps=[lmroman12-regular]:+liga at 30pt \oeps crap
-\font\oeps=[lmroman12-regular] at 40pt \oeps more crap
-
-\font\cidtest=adobesongstd-light
-
-\font\mathtest=cambria(math) {\mathtest 123}
-
-% \font\gothic=msgothic(ms-gothic) {\gothic whatever} % no longer in windows 10
-
-\bgroup
-
- \ifdefined\pdfprotrudechars \pdfprotrudechars \else \protrudechars \fi 2 \relax
- \ifdefined\pdfadjustspacing \pdfadjustspacing \else \adjustspacing \fi 2 \relax
-
- \font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par
- \font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par
- \font\testb=file:lmroman12-regular:+liga;protrusion=default at 12pt \testb \input tufte \par
-
-\egroup
-
-\setmplibformat{plain}
-
-\directlua {
- function MpTest()
- metapost.print("fullcircle scaled 3cm")
- end
-}
-
-\mplibcode
- beginfig(1) ;
- draw fullcircle
- scaled 10cm
- withcolor red
- withpen pencircle xscaled 4mm yscaled 2mm rotated 30 ;
- draw "test" infont defaultfont scaled 4 ;
- verbatimtex \sl etex;
- draw btex some more test etex scaled 2 ;
- currentpicture := currentpicture shifted (0,1cm) ;
- verbatimtex \bf etex;
- draw btex another test etex scaled 2 ;
- currentpicture := currentpicture shifted (0,1cm) ;
- draw btex another test etex scaled 2 ;
- draw
- runscript("MpTest()")
- withcolor green
- withpen pencircle xscaled 2mm yscaled 1mm rotated 20 ;
- endfig ;
-\endmplibcode
-
-\font\mine=file:luatex-fonts-demo-vf-1.lua at 12pt
-
-\mine \input tufte \par
-
-% \font\mine=file:luatex-fonts-demo-vf-2.lua at 12pt \mine [abab] \par
-% \font\mine=file:luatex-fonts-demo-vf-3.lua at 12pt \mine [abab] \par
-
-\font\test=dejavuserif:+kern at 10pt \test
-
-
-\bgroup \hsize 1mm \noindent Циолковский \par \egroup
-
-\loadpatterns{ru}
-
-\bgroup \hsize 1mm \noindent Циолковский \par \egroup
-
-a bit of math
-
-$\it e=mc^2 \bf e=mc^2 \Uchar"1D49D$
-
-$$\left( { {1} \over { {1} \over {x} } } \right) $$
-
-$$\sqrt {2} { { {1} \over { {1} \over {x} } } } $$
-
-\font\cows=file:koeieletters.afm at 50pt
-
-\cows Hello World!
-
-% math test
-
-\latinmodern
-
-\def\sqrt{\Uroot "0 "221A{}}
-
-\def\root#1\of{\Uroot "0 "221A{#1}}
-
-Inline $\sqrt{x}{1.2}$ math. % same for $\root n of x$
-
-$\root3\of x$
-
-$\sin{x}$
-
-\lucidabright
-
-\def\sqrt{\Uroot "0 "221A{}}
-
-\def\root#1\of{\Uroot "0 "221A{#1}}
-
-Inline $\sqrt{x}{1.2}$ math. % same for $\root n of x$
-
-$\root3\of x$
-
-$\sin{x}$
-
-\bgroup
-
- % drawback: no features (so use basemode)
-
- \font\crapa=lmroman12-regular:mode=base;liga=yes;kern=yes; at 12pt
- \font\crapb=lmsans12-regular:mode=base;liga=yes;kern=yes; at 30pt
- %\font\mine=file:luatex-fonts-demo-vf-4.lua:1=lmroman12-regular;2=lmsans12-regular{0x41-0x5A+0x30-0x39+0x21}; at 12pt
- \font\mine=file:luatex-fonts-demo-vf-4.lua:1=\fontid\crapa;2=\fontid\crapb{0x41-0x5A+0x30-0x39+0x21}; at 12pt
-
- \crapa Test\par
- \crapb Test\par
-
- \mine Zomaar een eindje fiets! En dan weer terug.
-
-\egroup
-
-% \font\amiri=file:amiri-regular.ttf:%
-% mode=node;analyze=yes;language=dflt;script=arab;ccmp=yes;%
-% init=yes;medi=yes;fina=yes;isol=yes;%
-% mark=yes;mkmk=yes;kern=yes;curs=yes;%
-% liga=yes;dlig=yes;rlig=yes;clig=yes;calt=yes %
-% at 32pt
-
-% \bgroup
-% \textdir TRT\amiri بِسْمِ اللَّـهِ الرَّ‌حْمَـٰنِ الرَّ‌حِيمِ
-% \egroup
-
-% assumes csr10.tfm csr10.pfb csr.enc to be present
-
-% \font\foo=file:luatex-plain-tfm.lua:tfm=csr10;enc=csr;pfb=csr10 at 12pt
-%
-% \foo áäčďěíĺľňóôŕřšťúýž ff ffi
-
-% \font\foo=file:csr10.tfm:reencode=csr
-% \font\foo=file:csr10.tfm:reencode=csr;bitmap=yes % use map file
-% \font\foo=file:csr10.tfm:reencode=auto
-%
-% \foo áäčďěíĺľňóôŕřšťúýž ff ffi \input tufte\par
-
-\end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua
index 0f9731a2656..d568a2e1fd0 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua
@@ -6,10 +6,8 @@ if not modules then modules = { } end modules ['util-fil'] = {
license = "see context related readme files"
}
-local byte = string.byte
-local char = string.char
-local extract = bit32 and bit32.extract
-local floor = math.floor
+local byte = string.byte
+local char = string.char
-- Here are a few helpers (the starting point were old ones I used for parsing
-- flac files). In Lua 5.3 we can probably do this better. Some code will move
@@ -35,7 +33,10 @@ function files.close(f)
end
function files.size(f)
- return f:seek("end")
+ local current = f:seek()
+ local size = f:seek("end")
+ f:seek("set",current)
+ return size
end
files.getsize = files.size
@@ -83,6 +84,12 @@ function files.readbytes(f,n)
return byte(f:read(n),1,n)
end
+function files.readbytetable(f,n)
+ -- return { byte(f:read(n),1,n) }
+ local s = f:read(n or 1)
+ return { byte(s,1,#s) } -- best use the real length
+end
+
function files.readchar(f)
return f:read(1)
end
@@ -93,22 +100,23 @@ end
function files.readinteger1(f) -- one byte
local n = byte(f:read(1))
- if n >= 0x80 then
- -- return n - 0xFF - 1
+ if n >= 0x80 then
return n - 0x100
else
return n
end
end
-files.readcardinal1 = files.readbyte -- one byte
-files.readcardinal = files.readcardinal1
-files.readinteger = files.readinteger1
+files.readcardinal1 = files.readbyte -- one byte
+files.readcardinal = files.readcardinal1
+files.readinteger = files.readinteger1
+files.readsignedbyte = files.readinteger1
function files.readcardinal2(f)
local a, b = byte(f:read(2),1,2)
return 0x100 * a + b
end
+
function files.readcardinal2le(f)
local b, a = byte(f:read(2),1,2)
return 0x100 * a + b
@@ -116,22 +124,19 @@ end
function files.readinteger2(f)
local a, b = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1
- return n - 0x10000
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
else
- return n
+ return 0x100 * a + b
end
end
+
function files.readinteger2le(f)
local b, a = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1
- return n - 0x10000
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
else
- return n
+ return 0x100 * a + b
end
end
@@ -139,6 +144,7 @@ function files.readcardinal3(f)
local a, b, c = byte(f:read(3),1,3)
return 0x10000 * a + 0x100 * b + c
end
+
function files.readcardinal3le(f)
local c, b, a = byte(f:read(3),1,3)
return 0x10000 * a + 0x100 * b + c
@@ -146,22 +152,19 @@ end
function files.readinteger3(f)
local a, b, c = byte(f:read(3),1,3)
- local n = 0x10000 * a + 0x100 * b + c
- if n >= 0x80000 then
- -- return n - 0xFFFFFF - 1
- return n - 0x1000000
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
else
- return n
+ return 0x10000 * a + 0x100 * b + c
end
end
+
function files.readinteger3le(f)
local c, b, a = byte(f:read(3),1,3)
- local n = 0x10000 * a + 0x100 * b + c
- if n >= 0x80000 then
- -- return n - 0xFFFFFF - 1
- return n - 0x1000000
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
else
- return n
+ return 0x10000 * a + 0x100 * b + c
end
end
@@ -169,6 +172,7 @@ function files.readcardinal4(f)
local a, b, c, d = byte(f:read(4),1,4)
return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
end
+
function files.readcardinal4le(f)
local d, c, b, a = byte(f:read(4),1,4)
return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
@@ -176,48 +180,75 @@ end
function files.readinteger4(f)
local a, b, c, d = byte(f:read(4),1,4)
- local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
- if n >= 0x8000000 then
- -- return n - 0xFFFFFFFF - 1
- return n - 0x100000000
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
else
- return n
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
end
end
+
function files.readinteger4le(f)
local d, c, b, a = byte(f:read(4),1,4)
- local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
- if n >= 0x8000000 then
- -- return n - 0xFFFFFFFF - 1
- return n - 0x100000000
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
else
- return n
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
end
end
+-- function files.readfixed2(f)
+-- local a, b = byte(f:read(2),1,2)
+-- if a >= 0x80 then
+-- return (0x100 * a + b - 0x10000)/256.0
+-- else
+-- return (0x100 * a + b)/256.0
+-- end
+-- end
+
+function files.readfixed2(f)
+ local a, b = byte(f:read(2),1,2)
+ if a >= 0x80 then
+ return (a - 0x100) + b/0x100
+ else
+ return (a ) + b/0x100
+ end
+end
+
+-- (real) (n>>16) + ((n&0xffff)/65536.0))
+
+-- function files.readfixed4(f)
+-- local a, b, c, d = byte(f:read(4),1,4)
+-- if a >= 0x80 then
+-- return (0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000)/65536.0
+-- else
+-- return (0x1000000 * a + 0x10000 * b + 0x100 * c + d)/65536.0
+-- end
+-- end
+
function files.readfixed4(f)
local a, b, c, d = byte(f:read(4),1,4)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
- return n - 0x10000 + (0x100 * c + d)/0xFFFF
+ if a >= 0x80 then
+ return (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000
else
- return n + (0x100 * c + d)/0xFFFF
+ return (0x100 * a + b ) + (0x100 * c + d)/0x10000
end
end
-if extract then
+-- (real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))
+
+if bit32 then
+
+ local extract = bit32.extract
+ local band = bit32.band
function files.read2dot14(f)
local a, b = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- local m = extract(n,0,30)
- if n > 0x7FFF then
- n = extract(n,30,2)
- return m/0x4000 - 4
+ if a >= 0x80 then
+ local n = -(0x100 * a + b)
+ return - (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
else
- n = extract(n,30,2)
- return n + m/0x4000
+ local n = 0x100 * a + b
+ return (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
end
end
@@ -233,20 +264,37 @@ end
-- writers (kind of slow)
-function files.writecardinal2(f,n)
- local a = char(n % 256)
- n = floor(n/256)
- local b = char(n % 256)
- f:write(b,a)
+if bit32 then
+
+ local rshift = bit32.rshift
+
+ function files.writecardinal2(f,n)
+ local a = char(n % 256)
+ n = rshift(n,8)
+ local b = char(n % 256)
+ f:write(b,a)
+ end
+
+else
+
+ local floor = math.floor
+
+ function files.writecardinal2(f,n)
+ local a = char(n % 256)
+ n = floor(n/256)
+ local b = char(n % 256)
+ f:write(b,a)
+ end
+
end
function files.writecardinal4(f,n)
local a = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local b = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local c = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local d = char(n % 256)
f:write(d,c,b,a)
end
@@ -259,3 +307,76 @@ function files.writebyte(f,b)
f:write(char(b))
end
+if fio and fio.readcardinal1 then
+
+ files.readcardinal1 = fio.readcardinal1
+ files.readcardinal2 = fio.readcardinal2
+ files.readcardinal3 = fio.readcardinal3
+ files.readcardinal4 = fio.readcardinal4
+ files.readinteger1 = fio.readinteger1
+ files.readinteger2 = fio.readinteger2
+ files.readinteger3 = fio.readinteger3
+ files.readinteger4 = fio.readinteger4
+ files.readfixed2 = fio.readfixed2
+ files.readfixed4 = fio.readfixed4
+ files.read2dot14 = fio.read2dot14
+ files.setposition = fio.setposition
+ files.getposition = fio.getposition
+
+ files.readbyte = files.readcardinal1
+ files.readsignedbyte = files.readinteger1
+ files.readcardinal = files.readcardinal1
+ files.readinteger = files.readinteger1
+
+ local skipposition = fio.skipposition
+ files.skipposition = skipposition
+
+ files.readbytes = fio.readbytes
+ files.readbytetable = fio.readbytetable
+
+ function files.skipshort(f,n)
+ skipposition(f,2*(n or 1))
+ end
+
+ function files.skiplong(f,n)
+ skipposition(f,4*(n or 1))
+ end
+
+end
+
+if fio and fio.readcardinaltable then
+
+ files.readcardinaltable = fio.readcardinaltable
+ files.readintegertable = fio.readintegertable
+
+else
+
+ local readcardinal1 = files.readcardinal1
+ local readcardinal2 = files.readcardinal2
+ local readcardinal3 = files.readcardinal3
+ local readcardinal4 = files.readcardinal4
+
+ function files.readcardinaltable(f,n,b)
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readcardinal1(f) end
+ elseif b == 2 then for i=1,n do t[i] = readcardinal2(f) end
+ elseif b == 3 then for i=1,n do t[i] = readcardinal3(f) end
+ elseif b == 4 then for i=1,n do t[i] = readcardinal4(f) end end
+ return t
+ end
+
+ local readinteger1 = files.readinteger1
+ local readinteger2 = files.readinteger2
+ local readinteger3 = files.readinteger3
+ local readinteger4 = files.readinteger4
+
+ function files.readintegertable(f,n,b)
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readinteger1(f) end
+ elseif b == 2 then for i=1,n do t[i] = readinteger2(f) end
+ elseif b == 3 then for i=1,n do t[i] = readinteger3(f) end
+ elseif b == 4 then for i=1,n do t[i] = readinteger4(f) end end
+ return t
+ end
+
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua
index fb510257a2f..f090bce55cc 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua
@@ -12,17 +12,20 @@ local strings = utilities.strings
local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
local load, dump = load, string.dump
-local tonumber, type, tostring = tonumber, type, tostring
+local tonumber, type, tostring, next, setmetatable = tonumber, type, tostring, next, setmetatable
+local unpack, concat = table.unpack, table.concat
local unpack, concat = table.unpack, table.concat
local 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
local patterns, lpegmatch = lpeg.patterns, lpeg.match
-local utfchar, utfbyte = utf.char, utf.byte
+local utfchar, utfbyte, utflen = utf.char, utf.byte, utf.len
+
----- loadstripped = utilities.lua.loadstripped
----- setmetatableindex = table.setmetatableindex
local loadstripped = nil
+local oldfashioned = LUAVERSION < 5.2
-if _LUAVERSION < 5.2 then
+if oldfashioned then
loadstripped = function(str,shortcuts)
return load(str)
@@ -44,21 +47,60 @@ end
if not number then number = { } end -- temp hack for luatex-fonts
-local stripper = patterns.stripzeros
+local stripzero = patterns.stripzero
+local stripzeros = patterns.stripzeros
local newline = patterns.newline
local endofstring = patterns.endofstring
+local anything = patterns.anything
local whitespace = patterns.whitespace
+local space = patterns.space
local spacer = patterns.spacer
local spaceortab = patterns.spaceortab
+local digit = patterns.digit
+local sign = patterns.sign
+local period = patterns.period
+
+-- local function points(n)
+-- n = tonumber(n)
+-- return (not n or n == 0) and "0pt" or lpegmatch(stripzeros,format("%.5fpt",n/65536))
+-- end
+
+-- local function basepoints(n)
+-- n = tonumber(n)
+-- return (not n or n == 0) and "0bp" or lpegmatch(stripzeros,format("%.5fbp", n*(7200/7227)/65536))
+-- end
+
+local ptf = 1 / 65536
+local bpf = (7200/7227) / 65536
local function points(n)
+ if n == 0 then
+ return "0pt"
+ end
n = tonumber(n)
- return (not n or n == 0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
+ if not n or n == 0 then
+ return "0pt"
+ end
+ n = n * ptf
+ if n % 1 == 0 then
+ return format("%ipt",n)
+ end
+ return lpegmatch(stripzeros,format("%.5fpt",n)) -- plural as we need to keep the pt
end
local function basepoints(n)
+ if n == 0 then
+ return "0pt"
+ end
n = tonumber(n)
- return (not n or n == 0) and "0bp" or lpegmatch(stripper,format("%.5fbp", n*(7200/7227)/65536))
+ if not n or n == 0 then
+ return "0pt"
+ end
+ n = n * bpf
+ if n % 1 == 0 then
+ return format("%ibp",n)
+ end
+ return lpegmatch(stripzeros,format("%.5fbp",n)) -- plural as we need to keep the pt
end
number.points = points
@@ -69,7 +111,6 @@ number.basepoints = basepoints
local rubish = spaceortab^0 * newline
local anyrubish = spaceortab + newline
-local anything = patterns.anything
local stripped = (spaceortab^1 / "") * newline
local leading = rubish^0 / ""
local trailing = (anyrubish^1 * endofstring) / ""
@@ -137,13 +178,26 @@ local pattern =
+ newline * Cp() / function(position)
extra, start = 0, position
end
- + patterns.anything
+ + anything
)^1)
function strings.tabtospace(str,tab)
+ -- no real gain in first checking if a \t is there
return lpegmatch(pattern,str,1,tab or 7)
end
+function string.utfpadding(s,n)
+ if not n or n == 0 then
+ return ""
+ end
+ local l = utflen(s)
+ if n > 0 then
+ return nspaces[n-l]
+ else
+ return nspaces[-n-l]
+ end
+end
+
-- local t = {
-- "1234567123456712345671234567",
-- "\tb\tc",
@@ -167,27 +221,31 @@ end
-- return str
-- end
-local space = spacer^0
-local nospace = space/""
-local endofline = nospace * newline
+local optionalspace = spacer^0
+local nospace = optionalspace/""
+local endofline = nospace * newline
-local stripend = (whitespace^1 * endofstring)/""
+local stripend = (whitespace^1 * endofstring)/""
-local normalline = (nospace * ((1-space*(newline+endofstring))^1) * nospace)
+local normalline = (nospace * ((1-optionalspace*(newline+endofstring))^1) * nospace)
-local stripempty = endofline^1/""
-local normalempty = endofline^1
-local singleempty = endofline * (endofline^0/"")
-local doubleempty = endofline * endofline^-1 * (endofline^0/"")
+local stripempty = endofline^1/""
+local normalempty = endofline^1
+local singleempty = endofline * (endofline^0/"")
+local doubleempty = endofline * endofline^-1 * (endofline^0/"")
+local stripstart = stripempty^0
-local stripstart = stripempty^0
+local intospace = whitespace^1/" "
+local noleading = whitespace^1/""
+local notrailing = noleading * endofstring
-local p_prune_normal = Cs ( stripstart * ( stripend + normalline + normalempty )^0 )
-local p_prune_collapse = Cs ( stripstart * ( stripend + normalline + doubleempty )^0 )
-local p_prune_noempty = Cs ( stripstart * ( stripend + normalline + singleempty )^0 )
-local p_retain_normal = Cs ( ( normalline + normalempty )^0 )
-local p_retain_collapse = Cs ( ( normalline + doubleempty )^0 )
-local p_retain_noempty = Cs ( ( normalline + singleempty )^0 )
+local p_prune_normal = Cs ( stripstart * ( stripend + normalline + normalempty )^0 )
+local p_prune_collapse = Cs ( stripstart * ( stripend + normalline + doubleempty )^0 )
+local p_prune_noempty = Cs ( stripstart * ( stripend + normalline + singleempty )^0 )
+local p_prune_intospace = Cs ( noleading * ( notrailing + intospace + 1 )^0 )
+local p_retain_normal = Cs ( ( normalline + normalempty )^0 )
+local p_retain_collapse = Cs ( ( normalline + doubleempty )^0 )
+local p_retain_noempty = Cs ( ( normalline + singleempty )^0 )
-- function striplines(str,prune,collapse,noempty)
-- if prune then
@@ -213,10 +271,11 @@ local striplinepatterns = {
["prune"] = p_prune_normal,
["prune and collapse"] = p_prune_collapse, -- default
["prune and no empty"] = p_prune_noempty,
+ ["prune and to space"] = p_prune_intospace,
["retain"] = p_retain_normal,
["retain and collapse"] = p_retain_collapse,
["retain and no empty"] = p_retain_noempty,
- ["collapse"] = patterns.collapser, -- how about: stripper fullstripper
+ ["collapse"] = patterns.collapser,
}
setmetatable(striplinepatterns,{ __index = function(t,k) return p_prune_collapse end })
@@ -227,6 +286,10 @@ function strings.striplines(str,how)
return str and lpegmatch(striplinepatterns[how],str) or str
end
+function strings.collapse(str) -- maybe also in strings
+ return str and lpegmatch(p_prune_intospace,str) or str
+end
+
-- also see: string.collapsespaces
strings.striplong = strings.striplines -- for old times sake
@@ -242,13 +305,14 @@ strings.striplong = strings.striplines -- for old times sake
-- " zus wim jet",
-- " ",
-- }, "\n")
-
+--
-- local str = table.concat( {
-- " aaaa",
-- " bb",
-- " cccccc",
+-- " ",
-- }, "\n")
-
+--
-- for k, v in table.sortedhash(utilities.strings.striplinepatterns) do
-- logs.report("stripper","method: %s, result: [[%s]]",k,utilities.strings.striplines(str,k))
-- end
@@ -280,41 +344,49 @@ end
--
-- More info can be found in cld-mkiv.pdf so here I stick to a simple list.
--
--- integer %...i number
--- integer %...d number
--- unsigned %...u number
--- character %...c number
--- hexadecimal %...x number
--- HEXADECIMAL %...X number
--- octal %...o number
--- string %...s string number
--- float %...f number
--- checked float %...F number
--- exponential %...e number
--- exponential %...E number
--- autofloat %...g number
--- autofloat %...G number
--- utf character %...c number
--- force tostring %...S any
--- force tostring %Q any
--- force tonumber %N number (strip leading zeros)
--- signed number %I number
--- rounded number %r number
--- 0xhexadecimal %...h character number
--- 0xHEXADECIMAL %...H character number
--- U+hexadecimal %...u character number
--- U+HEXADECIMAL %...U character number
--- points %p number (scaled points)
--- basepoints %b number (scaled points)
--- table concat %...t table
--- table concat %{.}t table
--- serialize %...T sequenced (no nested tables)
--- serialize %{.}T sequenced (no nested tables)
--- boolean (logic) %l boolean
--- BOOLEAN %L boolean
--- whitespace %...w
--- automatic %...a 'whatever' (string, table, ...)
--- automatic %...A "whatever" (string, table, ...)
+-- integer %...i number
+-- integer %...d number
+-- unsigned %...u number -- not used
+-- character %...c number
+-- hexadecimal %...x number
+-- HEXADECIMAL %...X number
+-- octal %...o number
+-- string %...s string number
+-- float %...f number
+-- checked float %...F number
+-- exponential %...e number
+-- exponential %...E number
+-- stripped e %...j number
+-- stripped E %...J number
+-- autofloat %...g number
+-- autofloat %...G number
+-- utf character %...c number
+-- force tostring %...S any
+-- force tostring %Q any
+-- force tonumber %N number (strip leading zeros)
+-- signed number %I number
+-- rounded number %r number
+-- 0xhexadecimal %...h character number
+-- 0xHEXADECIMAL %...H character number
+-- U+hexadecimal %...u character number
+-- U+HEXADECIMAL %...U character number
+-- points %p number (scaled points)
+-- basepoints %b number (scaled points)
+-- table concat %...t table
+-- table concat %{.}t table
+-- serialize %...T sequenced (no nested tables)
+-- serialize %{.}T sequenced (no nested tables)
+-- boolean (logic) %l boolean
+-- BOOLEAN %L boolean
+-- whitespace %...w number
+-- whitespace %...W (fixed)
+-- automatic %...a 'whatever' (string, table, ...)
+-- automatic %...A "whatever" (string, table, ...)
+-- zap %...z skip
+-- stripped %...N %...N
+-- comma/period real %...m
+-- period/comma real %...M
+-- formatted float %...k n.m
local n = 0
@@ -387,27 +459,45 @@ end
-- maybe to util-num
-local digit = patterns.digit
-local period = patterns.period
-local three = digit * digit * digit
+local two = digit * digit
+local three = two * digit
+local prefix = (Carg(1) * three)^1
local splitter = Cs (
- (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
- * (P(1)/"" * Carg(2)) * C(2)
+ (((1 - (three^1 * period))^1 + C(three)) * prefix + C((1-period)^1))
+ * (anything/"" * Carg(2)) * C(2)
+)
+
+local splitter3 = Cs (
+ three * prefix * endofstring +
+ two * prefix * endofstring +
+ digit * prefix * endofstring +
+ three +
+ two +
+ digit
)
patterns.formattednumber = splitter
function number.formatted(n,sep1,sep2)
- local s = type(s) == "string" and n or format("%0.2f",n)
- if sep1 == true then
- return lpegmatch(splitter,s,1,".",",")
- elseif sep1 == "." then
- return lpegmatch(splitter,s,1,sep1,sep2 or ",")
- elseif sep1 == "," then
- return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+ if sep1 == false then
+ if type(n) == "number" then
+ n = tostring(n)
+ end
+ return lpegmatch(splitter3,n,1,sep2 or ".")
else
- return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+ if type(n) == "number" then
+ n = format("%0.2f",n)
+ end
+ if sep1 == true then
+ return lpegmatch(splitter,n,1,".",",")
+ elseif sep1 == "." then
+ return lpegmatch(splitter,n,1,sep1,sep2 or ",")
+ elseif sep1 == "," then
+ return lpegmatch(splitter,n,1,sep1,sep2 or ".")
+ else
+ return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".")
+ end
end
end
@@ -420,17 +510,45 @@ end
-- print(number.formatted(1234567))
-- print(number.formatted(12345678))
-- print(number.formatted(12345678,true))
+-- print(number.formatted(1,false))
+-- print(number.formatted(12,false))
+-- print(number.formatted(123,false))
+-- print(number.formatted(1234,false))
+-- print(number.formatted(12345,false))
+-- print(number.formatted(123456,false))
+-- print(number.formatted(1234567,false))
+-- print(number.formatted(12345678,false))
-- print(number.formatted(1234.56,"!","?"))
+local p = Cs(
+ P("-")^0
+ * (P("0")^1/"")^0
+ * (1-period)^0
+ * (period * P("0")^1 * endofstring/"" + period^0)
+ * P(1-P("0")^1*endofstring)^0
+ )
+
+function number.compactfloat(n,fmt)
+ if n == 0 then
+ return "0"
+ elseif n == 1 then
+ return "1"
+ end
+ n = lpegmatch(p,format(fmt or "%0.3f",n))
+ if n == "." or n == "" or n == "-" then
+ return "0"
+ end
+ return n
+end
+
local zero = P("0")^1 / ""
local plus = P("+") / ""
local minus = P("-")
-local separator = S(".")
-local digit = R("09")
+local separator = period
local trailing = zero^1 * #S("eE")
-local exponent = (S("eE") * (plus + Cs((minus * zero^0 * P(-1))/"") + minus) * zero^0 * (P(-1) * Cc("0") + P(1)^1))
+local exponent = (S("eE") * (plus + Cs((minus * zero^0 * endofstring)/"") + minus) * zero^0 * (endofstring * Cc("0") + anything^1))
local pattern_a = Cs(minus^0 * digit^1 * (separator/"" * trailing + separator * (trailing + digit)^0) * exponent)
-local pattern_b = Cs((exponent + P(1))^0)
+local pattern_b = Cs((exponent + anything)^0)
function number.sparseexponent(f,n)
if not n then
@@ -449,6 +567,31 @@ function number.sparseexponent(f,n)
return tostring(n)
end
+local hf = { }
+local hs = { }
+
+setmetatable(hf, { __index = function(t,k)
+ local v = "%." .. k .. "f"
+ t[k] = v
+ return v
+end } )
+
+setmetatable(hs, { __index = function(t,k)
+ local v = "%" .. k .. "s"
+ t[k] = v
+ return v
+end } )
+
+function number.formattedfloat(n,b,a)
+ local s = format(hf[a],n)
+ local l = (b or 0) + (a or 0) + 1
+ if #s < l then
+ return format(hs[l],s)
+ else
+ return s
+ end
+end
+
local template = [[
%s
%s
@@ -457,7 +600,7 @@ return function(%s) return %s end
local preamble, environment = "", { }
-if _LUAVERSION < 5.2 then
+if oldfashioned then
preamble = [[
local lpeg=lpeg
@@ -473,12 +616,16 @@ local utfchar=utf.char
local utfbyte=utf.byte
local lpegmatch=lpeg.match
local nspaces=string.nspaces
+local utfpadding=string.utfpadding
local tracedchar=string.tracedchar
local autosingle=string.autosingle
local autodouble=string.autodouble
local sequenced=table.sequenced
local formattednumber=number.formatted
local sparseexponent=number.sparseexponent
+local formattedfloat=number.formattedfloat
+local stripzero=lpeg.patterns.stripzero
+local stripzeros=lpeg.patterns.stripzeros
]]
else
@@ -498,12 +645,16 @@ else
utfbyte = utf.byte,
lpegmatch = lpeg.match,
nspaces = string.nspaces,
+ utfpadding = string.utfpadding,
tracedchar = string.tracedchar,
autosingle = string.autosingle,
autodouble = string.autodouble,
sequenced = table.sequenced,
formattednumber = number.formatted,
sparseexponent = number.sparseexponent,
+ formattedfloat = number.formattedfloat,
+ stripzero = lpeg.patterns.stripzero,
+ stripzeros = lpeg.patterns.stripzeros,
}
end
@@ -520,7 +671,10 @@ setmetatable(arguments, { __index =
end
})
-local prefix_any = C((S("+- .") + R("09"))^0)
+local prefix_any = C((sign + space + period + digit)^0)
+local prefix_sub = (C((sign + digit)^0) + Cc(0))
+ * period
+ * (C((sign + digit)^0) + Cc(0))
local prefix_tab = P("{") * C((1-P("}"))^0) * P("}") + C((1-R("az","AZ","09","%%"))^0)
-- we've split all cases as then we can optimize them (let's omit the fuzzy u)
@@ -545,9 +699,36 @@ local format_S = function(f) -- can be optimized
end
end
+local format_right = function(f)
+ n = n + 1
+ f = tonumber(f)
+ if not f or f == 0 then
+ return format("(a%s or '')",n)
+ elseif f > 0 then
+ return format("utfpadding(a%s,%i)..a%s",n,f,n)
+ else
+ return format("a%s..utfpadding(a%s,%i)",n,n,f)
+ end
+end
+
+local format_left = function(f)
+ n = n + 1
+ f = tonumber(f)
+ if not f or f == 0 then
+ return format("(a%s or '')",n)
+ end
+ if f < 0 then
+ return format("utfpadding(a%s,%i)..a%s",n,-f,n)
+ else
+ return format("a%s..utfpadding(a%s,%i)",n,n,-f)
+ end
+end
+
local format_q = function()
n = n + 1
- return format("(a%s and format('%%q',a%s) or '')",n,n) -- goodie: nil check (maybe separate lpeg, not faster)
+ -- lua 5.3 has a different q than lua 5.2 (which does a tostring on numbers)
+ -- return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
+ return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
end
local format_Q = function() -- can be optimized
@@ -594,6 +775,11 @@ local format_F = function(f) -- beware, no cast to number
end
end
+local format_k = function(b,a) -- slow
+ n = n + 1
+ return format("formattedfloat(a%s,%i,%i)",n,b or 0, a or 0)
+end
+
local format_g = function(f)
n = n + 1
return format("format('%%%sg',a%s)",f,n)
@@ -732,9 +918,43 @@ local format_L = function()
return format("(a%s and 'TRUE' or 'FALSE')",n)
end
-local format_N = function() -- strips leading zeros
+local format_n = function() -- strips leading and trailing zeros and removes .0
+ n = n + 1
+ return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n)
+end
+
+-- local format_N = function() -- strips leading and trailing zeros (also accepts string)
+-- n = n + 1
+-- return format("tostring(tonumber(a%s) or a%s)",n,n)
+-- end
+
+-- local format_N = function(f) -- strips leading and trailing zeros
+-- n = n + 1
+-- -- stripzero (singular) as we only have a number
+-- if not f or f == "" then
+-- return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or ((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%.9f',a%s)))",n,n,n,n,n)
+-- else
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+-- end
+-- end
+
+-- local format_N = function(f) -- strips leading and trailing zeros
+-- n = n + 1
+-- -- stripzero (singular) as we only have a number
+-- if not f or f == "" then
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or ((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or lpegmatch(stripzero,format('%%.9f',a%s)))",n,n,n,n,n)
+-- else
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+-- end
+-- end
+
+local format_N = function(f) -- strips leading and trailing zeros
n = n + 1
- return format("tostring(tonumber(a%s) or a%s)",n,n)
+ -- stripzero (singular) as we only have a number
+ if not f or f == "" then
+ f = ".9"
+ end -- always a leading number !
+ return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
end
local format_a = function(f)
@@ -774,7 +994,11 @@ local format_m = function(f)
if not f or f == "" then
f = ","
end
- return format([[formattednumber(a%s,%q,".")]],n,f)
+ if f == "0" then
+ return format([[formattednumber(a%s,false)]],n)
+ else
+ return format([[formattednumber(a%s,%q,".")]],n,f)
+ end
end
local format_M = function(f)
@@ -782,7 +1006,11 @@ local format_M = function(f)
if not f or f == "" then
f = "."
end
- return format([[formattednumber(a%s,%q,",")]],n,f)
+ if f == "0" then
+ return format([[formattednumber(a%s,false)]],n)
+ else
+ return format([[formattednumber(a%s,%q,",")]],n,f)
+ end
end
--
@@ -794,6 +1022,22 @@ end
--
+-- local strip
+--
+-- local format_Z = function(f)
+-- n = n + 1
+-- if not f or f == "" then
+-- f = ".9"
+-- end
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or (strip and lpegmatch(stripzero,format('%%%sf',a%s))) or format('%%%sf',a%s))",n,n,f,n,f,n)
+-- end
+--
+-- function strings.stripformatterzeros()
+-- strip = true
+-- end
+
+--
+
local format_rest = function(s)
return format("%q",s) -- catches " and \n and such
end
@@ -854,7 +1098,9 @@ local builder = Cs { "start",
+ V("C")
+ V("S") -- new
+ V("Q") -- new
+ + V("n") -- new
+ V("N") -- new
+ + V("k") -- new
--
+ V("r")
+ V("h") + V("H") + V("u") + V("U")
@@ -870,11 +1116,14 @@ local builder = Cs { "start",
+ V("m") + V("M") -- new (formatted number)
+ V("z") -- new
--
+ + V(">") -- left padding
+ + V("<") -- right padding
+ --
-- + V("?") -- ignored, probably messed up %
)
+ V("*")
)
- * (P(-1) + Carg(1))
+ * (endofstring + Carg(1))
)^0,
--
["s"] = (prefix_any * P("s")) / format_s, -- %s => regular %s (string)
@@ -892,8 +1141,10 @@ local builder = Cs { "start",
["o"] = (prefix_any * P("o")) / format_o, -- %o => regular %o (octal)
--
["S"] = (prefix_any * P("S")) / format_S, -- %S => %s (tostring)
- ["Q"] = (prefix_any * P("Q")) / format_S, -- %Q => %q (tostring)
- ["N"] = (prefix_any * P("N")) / format_N, -- %N => tonumber (strips leading zeros)
+ ["Q"] = (prefix_any * P("Q")) / format_Q, -- %Q => %q (tostring)
+ ["n"] = (prefix_any * P("n")) / format_n, -- %n => tonumber (strips leading and trailing zeros, as well as .0, expects number)
+ ["N"] = (prefix_any * P("N")) / format_N, -- %N => tonumber (strips leading and trailing zeros, also takes string)
+ ["k"] = (prefix_sub * P("k")) / format_k, -- %k => like f but with n.m
["c"] = (prefix_any * P("c")) / format_c, -- %c => utf character (extension to regular)
["C"] = (prefix_any * P("C")) / format_C, -- %c => U+.... utf character
--
@@ -916,48 +1167,49 @@ local builder = Cs { "start",
["j"] = (prefix_any * P("j")) / format_j, -- %j => %e (float) stripped exponent (irrational)
["J"] = (prefix_any * P("J")) / format_J, -- %J => %E (float) stripped exponent (irrational)
--
- ["m"] = (prefix_tab * P("m")) / format_m, -- %m => xxx.xxx.xxx,xx (optional prefix instead of .)
- ["M"] = (prefix_tab * P("M")) / format_M, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
+ ["m"] = (prefix_any * P("m")) / format_m, -- %m => xxx.xxx.xxx,xx (optional prefix instead of .)
+ ["M"] = (prefix_any * P("M")) / format_M, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
--
- ["z"] = (prefix_any * P("z")) / format_z, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
+ ["z"] = (prefix_any * P("z")) / format_z, -- %z => skip n arguments
+ -- ["Z"] = (prefix_any * P("Z")) / format_Z, -- %Z => optionally strip zeros
--
["a"] = (prefix_any * P("a")) / format_a, -- %a => '...' (forces tostring)
["A"] = (prefix_any * P("A")) / format_A, -- %A => "..." (forces tostring)
--
+ ["<"] = (prefix_any * P("<")) / format_left,
+ [">"] = (prefix_any * P(">")) / format_right,
+ --
["*"] = Cs(((1-P("%"))^1 + P("%%")/"%%")^1) / format_rest, -- rest (including %%)
["?"] = Cs(((1-P("%"))^1 )^1) / format_rest, -- rest (including %%)
--
["!"] = Carg(2) * prefix_any * P("!") * C((1-P("!"))^1) * P("!") / format_extension,
}
--- we can be clever and only alias what is needed
-
--- local direct = Cs (
--- P("%")/""
--- * Cc([[local format = string.format return function(str) return format("%]])
--- * (S("+- .") + R("09"))^0
--- * S("sqidfgGeExXo")
--- * Cc([[",str) end]])
--- * P(-1)
--- )
-
-local direct = Cs (
- P("%")
- * (S("+- .") + R("09"))^0
- * S("sqidfgGeExXo")
- * P(-1) / [[local format = string.format return function(str) return format("%0",str) end]]
-)
+-- We can be clever and only alias what is needed:
+
+local xx = setmetatable({ }, { __index = function(t,k) local v = format("%02x",k) t[k] = v return v end })
+local XX = setmetatable({ }, { __index = function(t,k) local v = format("%02X",k) t[k] = v return v end })
+
+local preset = {
+ ["%02x"] = function(n) return xx[n] end,
+ ["%02X"] = function(n) return XX[n] end,
+}
+
+local direct =
+ P("%") * (sign + space + period + digit)^0 * S("sqidfgGeExXo") * endofstring
+ / [[local format = string.format return function(str) return format("%0",str) end]]
local function make(t,str)
- local f
- local p
+ local f = preset[str]
+ if f then
+ return f
+ end
local p = lpegmatch(direct,str)
if p then
- -- f = loadstripped(p)()
-- print("builder 1 >",p)
f = loadstripped(p)()
else
- n = 0
+ n = 0 -- used in patterns
-- p = lpegmatch(builder,str,1,"..",t._extensions_) -- after this we know n
p = lpegmatch(builder,str,1,t._connector_,t._extensions_) -- after this we know n
if n > 0 then
@@ -968,6 +1220,7 @@ local function make(t,str)
f = function() return str end
end
end
+ -- if jit then jit.on(f,true) end
t[str] = f
return f
end
@@ -1020,7 +1273,7 @@ strings.formatters = { }
-- _connector_ is an experiment
-if _LUAVERSION < 5.2 then
+if oldfashioned then
function strings.formatters.new(noconcat)
local t = { _type_ = "formatter", _connector_ = noconcat and "," or "..", _extensions_ = { }, _preamble_ = preamble, _environment_ = { } }
@@ -1072,19 +1325,15 @@ strings.formatters.add = add
-- registered in the default instance (should we fall back on this one?)
-patterns.xmlescape = Cs((P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;" + P('"')/"&quot;" + P(1))^0)
-patterns.texescape = Cs((C(S("#$%\\{}"))/"\\%1" + P(1))^0)
+patterns.xmlescape = Cs((P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;" + P('"')/"&quot;" + anything)^0)
+patterns.texescape = Cs((C(S("#$%\\{}"))/"\\%1" + anything)^0)
patterns.luaescape = Cs(((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0) -- maybe also \0
patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0 * Cc('"'))
-- escaping by lpeg is faster for strings without quotes, slower on a string with quotes, but
-- faster again when other q-escapables are found (the ones we don't need to escape)
--- add(formatters,"xml", [[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]])
--- add(formatters,"tex", [[lpegmatch(texescape,%s)]],[[local texescape = lpeg.patterns.texescape]])
--- add(formatters,"lua", [[lpegmatch(luaescape,%s)]],[[local luaescape = lpeg.patterns.luaescape]])
-
-if _LUAVERSION < 5.2 then
+if oldfashioned then
add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape")
add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape")
@@ -1133,7 +1382,6 @@ end
local dquote = patterns.dquote -- P('"')
local equote = patterns.escaped + dquote / '\\"' + 1
-local space = patterns.space
local cquote = Cc('"')
local pattern =
@@ -1149,3 +1397,21 @@ local pattern = Cs((newline / (os.newline or "\r") + 1)^0)
function string.replacenewlines(str)
return lpegmatch(pattern,str)
end
+
+--
+
+function strings.newcollector()
+ local result, r = { }, 0
+ return
+ function(fmt,str,...) -- write
+ r = r + 1
+ result[r] = str == nil and fmt or formatters[fmt](str,...)
+ end,
+ function(connector) -- flush
+ if result then
+ local str = concat(result,connector)
+ result, r = { }, 0
+ return str
+ end
+ end
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua
index 395f9b5b519..03027e760e3 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua
@@ -2,7 +2,7 @@
-----------------------------------------------------------------------
-- FILE: luaotfload-auxiliary.lua
-- DESCRIPTION: part of luaotfload
--- REQUIREMENTS: luaotfload 2.8
+-- REQUIREMENTS: luaotfload 2.9
-- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
-----------------------------------------------------------------------
--
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua
index 258a5aee649..552759811dd 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua
@@ -5475,6 +5475,10 @@ return {
category="po",
direction="l",
},
+ [0x560]={
+ category="ll",
+ direction="l",
+ },
[0x561]={
category="ll",
direction="l",
@@ -5631,6 +5635,10 @@ return {
category="ll",
direction="l",
},
+ [0x588]={
+ category="ll",
+ direction="l",
+ },
[0x589]={
category="po",
direction="l",
@@ -5979,6 +5987,10 @@ return {
category="lo",
direction="r",
},
+ [0x5EF]={
+ category="lo",
+ direction="r",
+ },
[0x5F0]={
category="lo",
direction="r",
@@ -7955,6 +7967,18 @@ return {
category="lm",
direction="r",
},
+ [0x7FD]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x7FE]={
+ category="sc",
+ direction="r",
+ },
+ [0x7FF]={
+ category="sc",
+ direction="r",
+ },
[0x800]={
category="lo",
direction="r",
@@ -8315,6 +8339,50 @@ return {
category="po",
direction="r",
},
+ [0x860]={
+ category="lo",
+ direction="al",
+ },
+ [0x861]={
+ category="lo",
+ direction="al",
+ },
+ [0x862]={
+ category="lo",
+ direction="al",
+ },
+ [0x863]={
+ category="lo",
+ direction="al",
+ },
+ [0x864]={
+ category="lo",
+ direction="al",
+ },
+ [0x865]={
+ category="lo",
+ direction="al",
+ },
+ [0x866]={
+ category="lo",
+ direction="al",
+ },
+ [0x867]={
+ category="lo",
+ direction="al",
+ },
+ [0x868]={
+ category="lo",
+ direction="al",
+ },
+ [0x869]={
+ category="lo",
+ direction="al",
+ },
+ [0x86A]={
+ category="lo",
+ direction="al",
+ },
[0x8A0]={
category="lo",
direction="al",
@@ -8431,6 +8499,10 @@ return {
category="lo",
direction="al",
},
+ [0x8D3]={
+ category="mn",
+ direction="nsm",
+ },
[0x8D4]={
category="mn",
direction="nsm",
@@ -9491,6 +9563,18 @@ return {
category="sc",
direction="et",
},
+ [0x9FC]={
+ category="lo",
+ direction="l",
+ },
+ [0x9FD]={
+ category="po",
+ direction="l",
+ },
+ [0x9FE]={
+ category="mn",
+ direction="nsm",
+ },
[0xA01]={
category="mn",
direction="nsm",
@@ -9807,6 +9891,10 @@ return {
category="mn",
direction="nsm",
},
+ [0xA76]={
+ category="po",
+ direction="l",
+ },
[0xA81]={
category="mn",
direction="nsm",
@@ -10147,6 +10235,30 @@ return {
category="lo",
direction="l",
},
+ [0xAFA]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xAFB]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xAFC]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xAFD]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xAFE]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xAFF]={
+ category="mn",
+ direction="nsm",
+ },
[0xB01]={
category="mn",
direction="nsm",
@@ -10811,6 +10923,10 @@ return {
category="mc",
direction="l",
},
+ [0xC04]={
+ category="mn",
+ direction="nsm",
+ },
[0xC05]={
category="lo",
direction="l",
@@ -11195,6 +11311,10 @@ return {
category="mc",
direction="l",
},
+ [0xC84]={
+ category="po",
+ direction="l",
+ },
[0xC85]={
category="lo",
direction="l",
@@ -11531,6 +11651,10 @@ return {
category="so",
direction="l",
},
+ [0xD00]={
+ category="mn",
+ direction="nsm",
+ },
[0xD01]={
category="mn",
direction="nsm",
@@ -11751,6 +11875,14 @@ return {
category="lo",
direction="l",
},
+ [0xD3B]={
+ category="mn",
+ direction="nsm",
+ },
+ [0xD3C]={
+ category="mn",
+ direction="nsm",
+ },
[0xD3D]={
category="lo",
direction="l",
@@ -21997,6 +22129,10 @@ return {
category="lo",
direction="l",
},
+ [0x1878]={
+ category="lo",
+ direction="l",
+ },
[0x1880]={
category="lo",
direction="l",
@@ -25497,6 +25633,190 @@ return {
category="ll",
direction="l",
},
+ [0x1C90]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C91]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C92]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C93]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C94]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C95]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C96]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C97]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C98]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C99]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9A]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9B]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9C]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9D]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9E]={
+ category="lu",
+ direction="l",
+ },
+ [0x1C9F]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA0]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA1]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA2]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA3]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA4]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA5]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA6]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA7]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA8]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CA9]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAA]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAB]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAC]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAD]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAE]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CAF]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB0]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB1]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB2]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB3]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB4]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB5]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB6]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB7]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB8]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CB9]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CBA]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CBD]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CBE]={
+ category="lu",
+ direction="l",
+ },
+ [0x1CBF]={
+ category="lu",
+ direction="l",
+ },
[0x1CC0]={
category="po",
direction="l",
@@ -25685,6 +26005,10 @@ return {
category="lo",
direction="l",
},
+ [0x1CF7]={
+ category="mc",
+ direction="l",
+ },
[0x1CF8]={
category="mn",
direction="nsm",
@@ -26677,6 +27001,22 @@ return {
category="mn",
direction="nsm",
},
+ [0x1DF6]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x1DF7]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x1DF8]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x1DF9]={
+ category="mn",
+ direction="nsm",
+ },
[0x1DFB]={
category="mn",
direction="nsm",
@@ -29403,6 +29743,10 @@ return {
category="sc",
direction="et",
},
+ [0x20BF]={
+ category="sc",
+ direction="et",
+ },
[0x20D0]={
category="mn",
direction="nsm",
@@ -30677,18 +31021,22 @@ return {
[0x221F]={
category="sm",
direction="on",
+ mirror=0x2BFE,
},
[0x2220]={
category="sm",
direction="on",
+ mirror=0x29A3,
},
[0x2221]={
category="sm",
direction="on",
+ mirror=0x299B,
},
[0x2222]={
category="sm",
direction="on",
+ mirror=0x29A0,
},
[0x2223]={
category="sm",
@@ -30697,6 +31045,7 @@ return {
[0x2224]={
category="sm",
direction="on",
+ mirror=0x2AEE,
},
[0x2225]={
category="sm",
@@ -30832,6 +31181,7 @@ return {
[0x2245]={
category="sm",
direction="on",
+ mirror=0x224C,
},
[0x2246]={
category="sm",
@@ -30860,6 +31210,7 @@ return {
[0x224C]={
category="sm",
direction="on",
+ mirror=0x2245,
},
[0x224D]={
category="sm",
@@ -31353,6 +31704,7 @@ return {
[0x22B8]={
category="sm",
direction="on",
+ mirror=0x27DC,
},
[0x22B9]={
category="sm",
@@ -32707,6 +33059,10 @@ return {
category="so",
direction="on",
},
+ [0x23FF]={
+ category="so",
+ direction="on",
+ },
[0x2400]={
category="so",
direction="on",
@@ -36502,6 +36858,7 @@ return {
[0x27DC]={
category="sm",
direction="on",
+ mirror=0x22B8,
},
[0x27DD]={
category="sm",
@@ -38330,6 +38687,7 @@ return {
[0x299B]={
category="sm",
direction="on",
+ mirror=0x2221,
},
[0x299C]={
category="sm",
@@ -38350,6 +38708,7 @@ return {
[0x29A0]={
category="sm",
direction="on",
+ mirror=0x2222,
},
[0x29A1]={
category="sm",
@@ -38362,14 +38721,17 @@ return {
[0x29A3]={
category="sm",
direction="on",
+ mirror=0x2220,
},
[0x29A4]={
category="sm",
direction="on",
+ mirror=0x29A5,
},
[0x29A5]={
category="sm",
direction="on",
+ mirror=0x29A4,
},
[0x29A6]={
category="sm",
@@ -38382,34 +38744,42 @@ return {
[0x29A8]={
category="sm",
direction="on",
+ mirror=0x29A9,
},
[0x29A9]={
category="sm",
direction="on",
+ mirror=0x29A8,
},
[0x29AA]={
category="sm",
direction="on",
+ mirror=0x29AB,
},
[0x29AB]={
category="sm",
direction="on",
+ mirror=0x29AA,
},
[0x29AC]={
category="sm",
direction="on",
+ mirror=0x29AD,
},
[0x29AD]={
category="sm",
direction="on",
+ mirror=0x29AC,
},
[0x29AE]={
category="sm",
direction="on",
+ mirror=0x29AF,
},
[0x29AF]={
category="sm",
direction="on",
+ mirror=0x29AE,
},
[0x29B0]={
category="sm",
@@ -38653,10 +39023,12 @@ return {
[0x29E8]={
category="sm",
direction="on",
+ mirror=0x29E9,
},
[0x29E9]={
category="sm",
direction="on",
+ mirror=0x29E8,
},
[0x29EA]={
category="sm",
@@ -39258,10 +39630,12 @@ return {
[0x2A7B]={
category="sm",
direction="on",
+ mirror=0x2A7C,
},
[0x2A7C]={
category="sm",
direction="on",
+ mirror=0x2A7B,
},
[0x2A7D]={
category="sm",
@@ -39306,26 +39680,32 @@ return {
[0x2A85]={
category="sm",
direction="on",
+ mirror=0x2A86,
},
[0x2A86]={
category="sm",
direction="on",
+ mirror=0x2A85,
},
[0x2A87]={
category="sm",
direction="on",
+ mirror=0x2A88,
},
[0x2A88]={
category="sm",
direction="on",
+ mirror=0x2A87,
},
[0x2A89]={
category="sm",
direction="on",
+ mirror=0x2A8A,
},
[0x2A8A]={
category="sm",
direction="on",
+ mirror=0x2A89,
},
[0x2A8B]={
category="sm",
@@ -39340,18 +39720,22 @@ return {
[0x2A8D]={
category="sm",
direction="on",
+ mirror=0x2A8E,
},
[0x2A8E]={
category="sm",
direction="on",
+ mirror=0x2A8D,
},
[0x2A8F]={
category="sm",
direction="on",
+ mirror=0x2A90,
},
[0x2A90]={
category="sm",
direction="on",
+ mirror=0x2A8F,
},
[0x2A91]={
category="sm",
@@ -39416,18 +39800,22 @@ return {
[0x2A9D]={
category="sm",
direction="on",
+ mirror=0x2A9E,
},
[0x2A9E]={
category="sm",
direction="on",
+ mirror=0x2A9D,
},
[0x2A9F]={
category="sm",
direction="on",
+ mirror=0x2AA0,
},
[0x2AA0]={
category="sm",
direction="on",
+ mirror=0x2A9F,
},
[0x2AA1]={
category="sm",
@@ -39508,10 +39896,12 @@ return {
[0x2AB1]={
category="sm",
direction="on",
+ mirror=0x2AB2,
},
[0x2AB2]={
category="sm",
direction="on",
+ mirror=0x2AB1,
},
[0x2AB3]={
category="sm",
@@ -39526,26 +39916,32 @@ return {
[0x2AB5]={
category="sm",
direction="on",
+ mirror=0x2AB6,
},
[0x2AB6]={
category="sm",
direction="on",
+ mirror=0x2AB5,
},
[0x2AB7]={
category="sm",
direction="on",
+ mirror=0x2AB8,
},
[0x2AB8]={
category="sm",
direction="on",
+ mirror=0x2AB7,
},
[0x2AB9]={
category="sm",
direction="on",
+ mirror=0x2ABA,
},
[0x2ABA]={
category="sm",
direction="on",
+ mirror=0x2AB9,
},
[0x2ABB]={
category="sm",
@@ -39610,26 +40006,32 @@ return {
[0x2AC7]={
category="sm",
direction="on",
+ mirror=0x2AC8,
},
[0x2AC8]={
category="sm",
direction="on",
+ mirror=0x2AC7,
},
[0x2AC9]={
category="sm",
direction="on",
+ mirror=0x2ACA,
},
[0x2ACA]={
category="sm",
direction="on",
+ mirror=0x2AC9,
},
[0x2ACB]={
category="sm",
direction="on",
+ mirror=0x2ACC,
},
[0x2ACC]={
category="sm",
direction="on",
+ mirror=0x2ACB,
},
[0x2ACD]={
category="sm",
@@ -39782,6 +40184,7 @@ return {
[0x2AEE]={
category="sm",
direction="on",
+ mirror=0x2224,
},
[0x2AEF]={
category="sm",
@@ -40583,6 +40986,18 @@ return {
category="so",
direction="on",
},
+ [0x2BBA]={
+ category="so",
+ direction="on",
+ },
+ [0x2BBB]={
+ category="so",
+ direction="on",
+ },
+ [0x2BBC]={
+ category="so",
+ direction="on",
+ },
[0x2BBD]={
category="so",
direction="on",
@@ -40663,6 +41078,110 @@ return {
category="so",
direction="on",
},
+ [0x2BD2]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD3]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD4]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD5]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD6]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD7]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD8]={
+ category="so",
+ direction="on",
+ },
+ [0x2BD9]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDA]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDB]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDC]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDD]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDE]={
+ category="so",
+ direction="on",
+ },
+ [0x2BDF]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE0]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE1]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE2]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE3]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE4]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE5]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE6]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE7]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE8]={
+ category="so",
+ direction="on",
+ },
+ [0x2BE9]={
+ category="so",
+ direction="on",
+ },
+ [0x2BEA]={
+ category="so",
+ direction="on",
+ },
+ [0x2BEB]={
+ category="so",
+ direction="on",
+ },
[0x2BEC]={
category="so",
direction="on",
@@ -40679,6 +41198,67 @@ return {
category="so",
direction="on",
},
+ [0x2BF0]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF1]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF2]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF3]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF4]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF5]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF6]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF7]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF8]={
+ category="so",
+ direction="on",
+ },
+ [0x2BF9]={
+ category="so",
+ direction="on",
+ },
+ [0x2BFA]={
+ category="so",
+ direction="on",
+ },
+ [0x2BFB]={
+ category="so",
+ direction="on",
+ },
+ [0x2BFC]={
+ category="so",
+ direction="on",
+ },
+ [0x2BFD]={
+ category="so",
+ direction="on",
+ },
+ [0x2BFE]={
+ category="so",
+ direction="on",
+ mirror=0x221F,
+ },
[0x2C00]={
category="lu",
direction="l",
@@ -42811,6 +43391,46 @@ return {
category="po",
direction="on",
},
+ [0x2E45]={
+ category="po",
+ direction="on",
+ },
+ [0x2E46]={
+ category="po",
+ direction="on",
+ },
+ [0x2E47]={
+ category="po",
+ direction="on",
+ },
+ [0x2E48]={
+ category="po",
+ direction="on",
+ },
+ [0x2E49]={
+ category="po",
+ direction="on",
+ },
+ [0x2E4A]={
+ category="po",
+ direction="on",
+ },
+ [0x2E4B]={
+ category="po",
+ direction="on",
+ },
+ [0x2E4C]={
+ category="po",
+ direction="on",
+ },
+ [0x2E4D]={
+ category="po",
+ direction="on",
+ },
+ [0x2E4E]={
+ category="po",
+ direction="on",
+ },
[0x2E80]={
category="so",
direction="on",
@@ -45369,6 +45989,14 @@ return {
category="lo",
direction="l",
},
+ [0x312E]={
+ category="lo",
+ direction="l",
+ },
+ [0x312F]={
+ category="lo",
+ direction="l",
+ },
[0x3131]={
category="lo",
direction="l",
@@ -56129,6 +56757,10 @@ return {
category="lu",
direction="l",
},
+ [0xA7AF]={
+ category="ll",
+ direction="l",
+ },
[0xA7B0]={
category="lu",
direction="l",
@@ -56161,6 +56793,14 @@ return {
category="ll",
direction="l",
},
+ [0xA7B8]={
+ category="lu",
+ direction="l",
+ },
+ [0xA7B9]={
+ category="ll",
+ direction="l",
+ },
[0xA7F7]={
category="lo",
direction="l",
@@ -57085,6 +57725,14 @@ return {
category="lo",
direction="l",
},
+ [0xA8FE]={
+ category="lo",
+ direction="l",
+ },
+ [0xA8FF]={
+ category="mn",
+ direction="nsm",
+ },
[0xA900]={
category="nd",
direction="l",
@@ -64641,6 +65289,7 @@ return {
category="so",
direction="on",
},
+ [0xFE00]={},
[0xFE10]={
category="po",
direction="on",
@@ -68693,6 +69342,18 @@ return {
category="no",
direction="l",
},
+ [0x1032D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1032E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1032F]={
+ category="lo",
+ direction="l",
+ },
[0x10330]={
category="lo",
direction="l",
@@ -73617,6 +74278,14 @@ return {
category="lo",
direction="r",
},
+ [0x10A34]={
+ category="lo",
+ direction="r",
+ },
+ [0x10A35]={
+ category="lo",
+ direction="r",
+ },
[0x10A38]={
category="mn",
direction="nsm",
@@ -73665,6 +74334,10 @@ return {
category="no",
direction="r",
},
+ [0x10A48]={
+ category="no",
+ direction="r",
+ },
[0x10A50]={
category="po",
direction="r",
@@ -75473,6 +76146,206 @@ return {
category="no",
direction="r",
},
+ [0x10D00]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D01]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D02]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D03]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D04]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D05]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D06]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D07]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D08]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D09]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0A]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0B]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0C]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0D]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0E]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D0F]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D10]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D11]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D12]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D13]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D14]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D15]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D16]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D17]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D18]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D19]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1A]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1B]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1C]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1D]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1E]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D1F]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D20]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D21]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D22]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D23]={
+ category="lo",
+ direction="al",
+ },
+ [0x10D24]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10D25]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10D26]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10D27]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10D30]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D31]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D32]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D33]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D34]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D35]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D36]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D37]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D38]={
+ category="nd",
+ direction="an",
+ },
+ [0x10D39]={
+ category="nd",
+ direction="an",
+ },
[0x10E60]={
category="no",
direction="an",
@@ -75597,6 +76470,334 @@ return {
category="no",
direction="an",
},
+ [0x10F00]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F01]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F02]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F03]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F04]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F05]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F06]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F07]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F08]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F09]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0A]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0B]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0C]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0D]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0E]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F0F]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F10]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F11]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F12]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F13]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F14]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F15]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F16]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F17]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F18]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F19]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F1A]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F1B]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F1C]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F1D]={
+ category="no",
+ direction="r",
+ },
+ [0x10F1E]={
+ category="no",
+ direction="r",
+ },
+ [0x10F1F]={
+ category="no",
+ direction="r",
+ },
+ [0x10F20]={
+ category="no",
+ direction="r",
+ },
+ [0x10F21]={
+ category="no",
+ direction="r",
+ },
+ [0x10F22]={
+ category="no",
+ direction="r",
+ },
+ [0x10F23]={
+ category="no",
+ direction="r",
+ },
+ [0x10F24]={
+ category="no",
+ direction="r",
+ },
+ [0x10F25]={
+ category="no",
+ direction="r",
+ },
+ [0x10F26]={
+ category="no",
+ direction="r",
+ },
+ [0x10F27]={
+ category="lo",
+ direction="r",
+ },
+ [0x10F30]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F31]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F32]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F33]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F34]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F35]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F36]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F37]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F38]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F39]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3A]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3B]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3C]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3D]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3E]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F3F]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F40]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F41]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F42]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F43]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F44]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F45]={
+ category="lo",
+ direction="al",
+ },
+ [0x10F46]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F47]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F48]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F49]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4B]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4C]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4D]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4E]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F4F]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F50]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x10F51]={
+ category="no",
+ direction="al",
+ },
+ [0x10F52]={
+ category="no",
+ direction="al",
+ },
+ [0x10F53]={
+ category="no",
+ direction="al",
+ },
+ [0x10F54]={
+ category="no",
+ direction="al",
+ },
+ [0x10F55]={
+ category="po",
+ direction="al",
+ },
+ [0x10F56]={
+ category="po",
+ direction="al",
+ },
+ [0x10F57]={
+ category="po",
+ direction="al",
+ },
+ [0x10F58]={
+ category="po",
+ direction="al",
+ },
+ [0x10F59]={
+ category="po",
+ direction="al",
+ },
[0x11000]={
category="mc",
direction="l",
@@ -76297,6 +77498,10 @@ return {
category="po",
direction="l",
},
+ [0x110CD]={
+ category="cf",
+ direction="l",
+ },
[0x110D0]={
category="lo",
direction="l",
@@ -76705,6 +77910,18 @@ return {
category="po",
direction="l",
},
+ [0x11144]={
+ category="lo",
+ direction="l",
+ },
+ [0x11145]={
+ category="mc",
+ direction="l",
+ },
+ [0x11146]={
+ category="mc",
+ direction="l",
+ },
[0x11150]={
category="lo",
direction="l",
@@ -77155,7 +78372,7 @@ return {
},
[0x111C9]={
category="po",
- direction="l",
+ direction="nsm",
},
[0x111CA]={
category="mn",
@@ -78193,6 +79410,10 @@ return {
category="lo",
direction="l",
},
+ [0x1133B]={
+ category="mn",
+ direction="nsm",
+ },
[0x1133C]={
category="mn",
direction="nsm",
@@ -78701,6 +79922,10 @@ return {
category="po",
direction="l",
},
+ [0x1145E]={
+ category="mn",
+ direction="nsm",
+ },
[0x11480]={
category="lo",
direction="l",
@@ -80133,6 +81358,10 @@ return {
category="lo",
direction="l",
},
+ [0x1171A]={
+ category="lo",
+ direction="l",
+ },
[0x1171D]={
category="mn",
direction="nsm",
@@ -80257,6 +81486,246 @@ return {
category="so",
direction="l",
},
+ [0x11800]={
+ category="lo",
+ direction="l",
+ },
+ [0x11801]={
+ category="lo",
+ direction="l",
+ },
+ [0x11802]={
+ category="lo",
+ direction="l",
+ },
+ [0x11803]={
+ category="lo",
+ direction="l",
+ },
+ [0x11804]={
+ category="lo",
+ direction="l",
+ },
+ [0x11805]={
+ category="lo",
+ direction="l",
+ },
+ [0x11806]={
+ category="lo",
+ direction="l",
+ },
+ [0x11807]={
+ category="lo",
+ direction="l",
+ },
+ [0x11808]={
+ category="lo",
+ direction="l",
+ },
+ [0x11809]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1180F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11810]={
+ category="lo",
+ direction="l",
+ },
+ [0x11811]={
+ category="lo",
+ direction="l",
+ },
+ [0x11812]={
+ category="lo",
+ direction="l",
+ },
+ [0x11813]={
+ category="lo",
+ direction="l",
+ },
+ [0x11814]={
+ category="lo",
+ direction="l",
+ },
+ [0x11815]={
+ category="lo",
+ direction="l",
+ },
+ [0x11816]={
+ category="lo",
+ direction="l",
+ },
+ [0x11817]={
+ category="lo",
+ direction="l",
+ },
+ [0x11818]={
+ category="lo",
+ direction="l",
+ },
+ [0x11819]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1181F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11820]={
+ category="lo",
+ direction="l",
+ },
+ [0x11821]={
+ category="lo",
+ direction="l",
+ },
+ [0x11822]={
+ category="lo",
+ direction="l",
+ },
+ [0x11823]={
+ category="lo",
+ direction="l",
+ },
+ [0x11824]={
+ category="lo",
+ direction="l",
+ },
+ [0x11825]={
+ category="lo",
+ direction="l",
+ },
+ [0x11826]={
+ category="lo",
+ direction="l",
+ },
+ [0x11827]={
+ category="lo",
+ direction="l",
+ },
+ [0x11828]={
+ category="lo",
+ direction="l",
+ },
+ [0x11829]={
+ category="lo",
+ direction="l",
+ },
+ [0x1182A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1182B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1182C]={
+ category="mc",
+ direction="l",
+ },
+ [0x1182D]={
+ category="mc",
+ direction="l",
+ },
+ [0x1182E]={
+ category="mc",
+ direction="l",
+ },
+ [0x1182F]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11830]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11831]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11832]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11833]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11834]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11835]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11836]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11837]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11838]={
+ category="mc",
+ direction="l",
+ },
+ [0x11839]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x1183A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x1183B]={
+ category="po",
+ direction="l",
+ },
[0x118A0]={
category="lu",
direction="l",
@@ -80593,6 +82062,618 @@ return {
category="lo",
direction="l",
},
+ [0x11A00]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A01]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A02]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A03]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A04]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A05]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A06]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A07]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A08]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A09]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A0A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A0B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A0C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A0D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A0E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A0F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A10]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A11]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A12]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A13]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A14]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A15]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A16]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A17]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A18]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A19]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A1F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A20]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A21]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A22]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A23]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A24]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A25]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A26]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A27]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A28]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A29]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A2F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A30]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A31]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A32]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A33]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A34]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A35]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A36]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A37]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A38]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A39]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A3A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A3B]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A3C]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A3D]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A3E]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A3F]={
+ category="po",
+ direction="l",
+ },
+ [0x11A40]={
+ category="po",
+ direction="l",
+ },
+ [0x11A41]={
+ category="po",
+ direction="l",
+ },
+ [0x11A42]={
+ category="po",
+ direction="l",
+ },
+ [0x11A43]={
+ category="po",
+ direction="l",
+ },
+ [0x11A44]={
+ category="po",
+ direction="l",
+ },
+ [0x11A45]={
+ category="po",
+ direction="l",
+ },
+ [0x11A46]={
+ category="po",
+ direction="l",
+ },
+ [0x11A47]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A50]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A51]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A52]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A53]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A54]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A55]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A56]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A57]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A58]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A59]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A5A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A5B]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A5C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A5D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A5E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A5F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A60]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A61]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A62]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A63]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A64]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A65]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A66]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A67]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A68]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A69]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A6F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A70]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A71]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A72]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A73]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A74]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A75]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A76]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A77]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A78]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A79]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A7F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A80]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A81]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A82]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A83]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A86]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A87]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A88]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A89]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A8A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A8B]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A8C]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A8D]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A8E]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A8F]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A90]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A91]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A92]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A93]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A94]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A95]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A96]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A97]={
+ category="mc",
+ direction="l",
+ },
+ [0x11A98]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A99]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11A9A]={
+ category="po",
+ direction="l",
+ },
+ [0x11A9B]={
+ category="po",
+ direction="l",
+ },
+ [0x11A9C]={
+ category="po",
+ direction="l",
+ },
+ [0x11A9D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11A9E]={
+ category="po",
+ direction="l",
+ },
+ [0x11A9F]={
+ category="po",
+ direction="l",
+ },
+ [0x11AA0]={
+ category="po",
+ direction="l",
+ },
+ [0x11AA1]={
+ category="po",
+ direction="l",
+ },
+ [0x11AA2]={
+ category="po",
+ direction="l",
+ },
[0x11AC0]={
category="lo",
direction="l",
@@ -81481,6 +83562,658 @@ return {
category="mn",
direction="nsm",
},
+ [0x11D00]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D01]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D02]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D03]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D04]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D05]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D06]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D08]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D09]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D0B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D0C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D0D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D0E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D0F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D10]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D11]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D12]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D13]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D14]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D15]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D16]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D17]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D18]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D19]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D1F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D20]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D21]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D22]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D23]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D24]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D25]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D26]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D27]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D28]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D29]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D2F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D30]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D31]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D32]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D33]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D34]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D35]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D36]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D3A]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D3C]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D3D]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D3F]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D40]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D41]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D42]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D43]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D44]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D45]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D46]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D47]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D50]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D51]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D52]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D53]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D54]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D55]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D56]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D57]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D58]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D59]={
+ category="nd",
+ direction="l",
+ },
+ [0x11D60]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D61]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D62]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D63]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D64]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D65]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D67]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D68]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D6F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D70]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D71]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D72]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D73]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D74]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D75]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D76]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D77]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D78]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D79]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7A]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7B]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7C]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7D]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7E]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D7F]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D80]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D81]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D82]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D83]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D84]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D85]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D86]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D87]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D88]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D89]={
+ category="lo",
+ direction="l",
+ },
+ [0x11D8A]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D8B]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D8C]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D8D]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D8E]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D90]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D91]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D93]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D94]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D95]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D96]={
+ category="mc",
+ direction="l",
+ },
+ [0x11D97]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11D98]={
+ category="lo",
+ direction="l",
+ },
+ [0x11DA0]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA1]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA2]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA3]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA4]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA5]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA6]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA7]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA8]={
+ category="nd",
+ direction="l",
+ },
+ [0x11DA9]={
+ category="nd",
+ direction="l",
+ },
+ [0x11EE0]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE1]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE2]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE3]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE4]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE5]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE6]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE7]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE8]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EE9]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EEA]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EEB]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EEC]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EED]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EEE]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EEF]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EF0]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EF1]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EF2]={
+ category="lo",
+ direction="l",
+ },
+ [0x11EF3]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11EF4]={
+ category="mn",
+ direction="nsm",
+ },
+ [0x11EF5]={
+ category="mc",
+ direction="l",
+ },
+ [0x11EF6]={
+ category="mc",
+ direction="l",
+ },
+ [0x11EF7]={
+ category="po",
+ direction="l",
+ },
+ [0x11EF8]={
+ category="po",
+ direction="l",
+ },
[0x12000]={
category="lo",
direction="l",
@@ -96133,6 +98866,370 @@ return {
category="lo",
direction="l",
},
+ [0x16E40]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E41]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E42]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E43]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E44]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E45]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E46]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E47]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E48]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E49]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4A]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4B]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4C]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4D]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4E]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E4F]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E50]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E51]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E52]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E53]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E54]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E55]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E56]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E57]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E58]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E59]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5A]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5B]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5C]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5D]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5E]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E5F]={
+ category="lu",
+ direction="l",
+ },
+ [0x16E60]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E61]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E62]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E63]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E64]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E65]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E66]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E67]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E68]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E69]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6A]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6B]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6C]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6D]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6E]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E6F]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E70]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E71]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E72]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E73]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E74]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E75]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E76]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E77]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E78]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E79]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7A]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7B]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7C]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7D]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7E]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E7F]={
+ category="ll",
+ direction="l",
+ },
+ [0x16E80]={
+ category="no",
+ direction="l",
+ },
+ [0x16E81]={
+ category="no",
+ direction="l",
+ },
+ [0x16E82]={
+ category="no",
+ direction="l",
+ },
+ [0x16E83]={
+ category="no",
+ direction="l",
+ },
+ [0x16E84]={
+ category="no",
+ direction="l",
+ },
+ [0x16E85]={
+ category="no",
+ direction="l",
+ },
+ [0x16E86]={
+ category="no",
+ direction="l",
+ },
+ [0x16E87]={
+ category="no",
+ direction="l",
+ },
+ [0x16E88]={
+ category="no",
+ direction="l",
+ },
+ [0x16E89]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8A]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8B]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8C]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8D]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8E]={
+ category="no",
+ direction="l",
+ },
+ [0x16E8F]={
+ category="no",
+ direction="l",
+ },
+ [0x16E90]={
+ category="no",
+ direction="l",
+ },
+ [0x16E91]={
+ category="no",
+ direction="l",
+ },
+ [0x16E92]={
+ category="no",
+ direction="l",
+ },
+ [0x16E93]={
+ category="no",
+ direction="l",
+ },
+ [0x16E94]={
+ category="no",
+ direction="l",
+ },
+ [0x16E95]={
+ category="no",
+ direction="l",
+ },
+ [0x16E96]={
+ category="no",
+ direction="l",
+ },
+ [0x16E97]={
+ category="po",
+ direction="l",
+ },
+ [0x16E98]={
+ category="po",
+ direction="l",
+ },
+ [0x16E99]={
+ category="po",
+ direction="l",
+ },
+ [0x16E9A]={
+ category="po",
+ direction="l",
+ },
[0x16F00]={
category="lo",
direction="l",
@@ -96669,6 +99766,10 @@ return {
category="lm",
direction="l",
},
+ [0x16FE1]={
+ category="lm",
+ direction="l",
+ },
[0x18800]={
category="lo",
direction="l",
@@ -99697,6 +102798,2730 @@ return {
category="lo",
direction="l",
},
+ [0x1B002]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B003]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B004]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B005]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B006]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B007]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B008]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B009]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B00F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B010]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B011]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B012]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B013]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B014]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B015]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B016]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B017]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B018]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B019]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B01F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B020]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B021]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B022]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B023]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B024]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B025]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B026]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B027]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B028]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B029]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B02F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B030]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B031]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B032]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B033]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B034]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B035]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B036]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B037]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B038]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B039]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B03F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B040]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B041]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B042]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B043]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B044]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B045]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B046]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B047]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B048]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B049]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B04F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B050]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B051]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B052]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B053]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B054]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B055]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B056]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B057]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B058]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B059]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B05F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B060]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B061]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B062]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B063]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B064]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B065]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B066]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B067]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B068]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B069]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B06F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B070]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B071]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B072]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B073]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B074]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B075]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B076]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B077]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B078]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B079]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B07F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B080]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B081]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B082]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B083]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B084]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B085]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B086]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B087]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B088]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B089]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B08F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B090]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B091]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B092]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B093]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B094]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B095]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B096]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B097]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B098]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B099]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B09F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0A9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0AF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0B9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0BF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0C9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0CF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0D9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0DF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0E9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0EA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0EB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0EC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0ED]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0EE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0EF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0F9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B0FF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B100]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B101]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B102]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B103]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B104]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B105]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B106]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B107]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B108]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B109]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B10F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B110]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B111]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B112]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B113]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B114]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B115]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B116]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B117]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B118]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B119]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B11A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B11B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B11C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B11D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B11E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B170]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B171]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B172]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B173]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B174]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B175]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B176]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B177]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B178]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B179]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B17F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B180]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B181]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B182]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B183]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B184]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B185]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B186]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B187]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B188]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B189]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B18F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B190]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B191]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B192]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B193]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B194]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B195]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B196]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B197]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B198]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B199]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B19F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1A9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1AF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1B9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1BF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1C9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1CF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1D9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1DF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1E9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1EA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1EB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1EC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1ED]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1EE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1EF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1F9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B1FF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B200]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B201]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B202]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B203]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B204]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B205]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B206]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B207]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B208]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B209]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B20F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B210]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B211]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B212]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B213]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B214]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B215]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B216]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B217]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B218]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B219]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B21F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B220]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B221]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B222]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B223]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B224]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B225]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B226]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B227]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B228]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B229]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B22F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B230]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B231]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B232]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B233]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B234]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B235]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B236]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B237]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B238]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B239]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B23F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B240]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B241]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B242]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B243]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B244]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B245]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B246]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B247]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B248]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B249]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B24F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B250]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B251]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B252]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B253]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B254]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B255]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B256]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B257]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B258]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B259]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B25F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B260]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B261]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B262]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B263]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B264]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B265]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B266]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B267]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B268]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B269]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B26F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B270]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B271]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B272]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B273]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B274]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B275]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B276]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B277]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B278]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B279]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B27F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B280]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B281]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B282]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B283]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B284]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B285]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B286]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B287]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B288]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B289]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B28F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B290]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B291]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B292]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B293]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B294]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B295]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B296]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B297]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B298]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B299]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29A]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29B]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29C]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29D]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29E]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B29F]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2A9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2AF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2B9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2BF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2C9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2CF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2D9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DD]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2DF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2E9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2EA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2EB]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2EC]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2ED]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2EE]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2EF]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F0]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F1]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F2]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F3]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F4]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F5]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F6]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F7]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F8]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2F9]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2FA]={
+ category="lo",
+ direction="l",
+ },
+ [0x1B2FB]={
+ category="lo",
+ direction="l",
+ },
[0x1BC00]={
category="lo",
direction="l",
@@ -102473,6 +108298,86 @@ return {
category="so",
direction="on",
},
+ [0x1D2E0]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E1]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E2]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E3]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E4]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E5]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E6]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E7]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E8]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2E9]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2EA]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2EB]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2EC]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2ED]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2EE]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2EF]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2F0]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2F1]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2F2]={
+ category="no",
+ direction="l",
+ },
+ [0x1D2F3]={
+ category="no",
+ direction="l",
+ },
[0x1D300]={
category="so",
direction="on",
@@ -102893,6 +108798,34 @@ return {
category="no",
direction="l",
},
+ [0x1D372]={
+ category="no",
+ direction="l",
+ },
+ [0x1D373]={
+ category="no",
+ direction="l",
+ },
+ [0x1D374]={
+ category="no",
+ direction="l",
+ },
+ [0x1D375]={
+ category="no",
+ direction="l",
+ },
+ [0x1D376]={
+ category="no",
+ direction="l",
+ },
+ [0x1D377]={
+ category="no",
+ direction="l",
+ },
+ [0x1D378]={
+ category="no",
+ direction="l",
+ },
[0x1D400]={
category="lu",
direction="l",
@@ -110917,6 +116850,278 @@ return {
category="po",
direction="r",
},
+ [0x1EC71]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC72]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC73]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC74]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC75]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC76]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC77]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC78]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC79]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7A]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7B]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7C]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7D]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7E]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC7F]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC80]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC81]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC82]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC83]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC84]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC85]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC86]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC87]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC88]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC89]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8A]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8B]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8C]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8D]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8E]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC8F]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC90]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC91]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC92]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC93]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC94]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC95]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC96]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC97]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC98]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC99]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9A]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9B]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9C]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9D]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9E]={
+ category="no",
+ direction="al",
+ },
+ [0x1EC9F]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA0]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA1]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA2]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA3]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA4]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA5]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA6]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA7]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA8]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECA9]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECAA]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECAB]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECAC]={
+ category="so",
+ direction="al",
+ },
+ [0x1ECAD]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECAE]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECAF]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECB0]={
+ category="sc",
+ direction="al",
+ },
+ [0x1ECB1]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECB2]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECB3]={
+ category="no",
+ direction="al",
+ },
+ [0x1ECB4]={
+ category="no",
+ direction="al",
+ },
[0x1EE00]={
category="lo",
direction="al",
@@ -112569,6 +118774,10 @@ return {
category="so",
direction="l",
},
+ [0x1F12F]={
+ category="so",
+ direction="on",
+ },
[0x1F130]={
category="so",
direction="l",
@@ -113389,6 +119598,30 @@ return {
category="so",
direction="l",
},
+ [0x1F260]={
+ category="so",
+ direction="on",
+ },
+ [0x1F261]={
+ category="so",
+ direction="on",
+ },
+ [0x1F262]={
+ category="so",
+ direction="on",
+ },
+ [0x1F263]={
+ category="so",
+ direction="on",
+ },
+ [0x1F264]={
+ category="so",
+ direction="on",
+ },
+ [0x1F265]={
+ category="so",
+ direction="on",
+ },
[0x1F300]={
category="so",
direction="on",
@@ -117305,6 +123538,14 @@ return {
category="so",
direction="on",
},
+ [0x1F6D3]={
+ category="so",
+ direction="on",
+ },
+ [0x1F6D4]={
+ category="so",
+ direction="on",
+ },
[0x1F6E0]={
category="so",
direction="on",
@@ -117385,6 +123626,18 @@ return {
category="so",
direction="on",
},
+ [0x1F6F7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F6F8]={
+ category="so",
+ direction="on",
+ },
+ [0x1F6F9]={
+ category="so",
+ direction="on",
+ },
[0x1F700]={
category="so",
direction="on",
@@ -118189,6 +124442,22 @@ return {
category="so",
direction="on",
},
+ [0x1F7D5]={
+ category="so",
+ direction="on",
+ },
+ [0x1F7D6]={
+ category="so",
+ direction="on",
+ },
+ [0x1F7D7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F7D8]={
+ category="so",
+ direction="on",
+ },
[0x1F800]={
category="so",
direction="on",
@@ -118781,6 +125050,54 @@ return {
category="so",
direction="on",
},
+ [0x1F900]={
+ category="so",
+ direction="on",
+ },
+ [0x1F901]={
+ category="so",
+ direction="on",
+ },
+ [0x1F902]={
+ category="so",
+ direction="on",
+ },
+ [0x1F903]={
+ category="so",
+ direction="on",
+ },
+ [0x1F904]={
+ category="so",
+ direction="on",
+ },
+ [0x1F905]={
+ category="so",
+ direction="on",
+ },
+ [0x1F906]={
+ category="so",
+ direction="on",
+ },
+ [0x1F907]={
+ category="so",
+ direction="on",
+ },
+ [0x1F908]={
+ category="so",
+ direction="on",
+ },
+ [0x1F909]={
+ category="so",
+ direction="on",
+ },
+ [0x1F90A]={
+ category="so",
+ direction="on",
+ },
+ [0x1F90B]={
+ category="so",
+ direction="on",
+ },
[0x1F910]={
category="so",
direction="on",
@@ -118841,6 +125158,10 @@ return {
category="so",
direction="on",
},
+ [0x1F91F]={
+ category="so",
+ direction="on",
+ },
[0x1F920]={
category="so",
direction="on",
@@ -118873,10 +125194,50 @@ return {
category="so",
direction="on",
},
+ [0x1F928]={
+ category="so",
+ direction="on",
+ },
+ [0x1F929]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92A]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92B]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92C]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92D]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92E]={
+ category="so",
+ direction="on",
+ },
+ [0x1F92F]={
+ category="so",
+ direction="on",
+ },
[0x1F930]={
category="so",
direction="on",
},
+ [0x1F931]={
+ category="so",
+ direction="on",
+ },
+ [0x1F932]={
+ category="so",
+ direction="on",
+ },
[0x1F933]={
category="so",
direction="on",
@@ -118973,6 +125334,22 @@ return {
category="so",
direction="on",
},
+ [0x1F94C]={
+ category="so",
+ direction="on",
+ },
+ [0x1F94D]={
+ category="so",
+ direction="on",
+ },
+ [0x1F94E]={
+ category="so",
+ direction="on",
+ },
+ [0x1F94F]={
+ category="so",
+ direction="on",
+ },
[0x1F950]={
category="so",
direction="on",
@@ -119033,6 +125410,114 @@ return {
category="so",
direction="on",
},
+ [0x1F95F]={
+ category="so",
+ direction="on",
+ },
+ [0x1F960]={
+ category="so",
+ direction="on",
+ },
+ [0x1F961]={
+ category="so",
+ direction="on",
+ },
+ [0x1F962]={
+ category="so",
+ direction="on",
+ },
+ [0x1F963]={
+ category="so",
+ direction="on",
+ },
+ [0x1F964]={
+ category="so",
+ direction="on",
+ },
+ [0x1F965]={
+ category="so",
+ direction="on",
+ },
+ [0x1F966]={
+ category="so",
+ direction="on",
+ },
+ [0x1F967]={
+ category="so",
+ direction="on",
+ },
+ [0x1F968]={
+ category="so",
+ direction="on",
+ },
+ [0x1F969]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96A]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96B]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96C]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96D]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96E]={
+ category="so",
+ direction="on",
+ },
+ [0x1F96F]={
+ category="so",
+ direction="on",
+ },
+ [0x1F970]={
+ category="so",
+ direction="on",
+ },
+ [0x1F973]={
+ category="so",
+ direction="on",
+ },
+ [0x1F974]={
+ category="so",
+ direction="on",
+ },
+ [0x1F975]={
+ category="so",
+ direction="on",
+ },
+ [0x1F976]={
+ category="so",
+ direction="on",
+ },
+ [0x1F97A]={
+ category="so",
+ direction="on",
+ },
+ [0x1F97C]={
+ category="so",
+ direction="on",
+ },
+ [0x1F97D]={
+ category="so",
+ direction="on",
+ },
+ [0x1F97E]={
+ category="so",
+ direction="on",
+ },
+ [0x1F97F]={
+ category="so",
+ direction="on",
+ },
[0x1F980]={
category="so",
direction="on",
@@ -119105,10 +125590,374 @@ return {
category="so",
direction="on",
},
+ [0x1F992]={
+ category="so",
+ direction="on",
+ },
+ [0x1F993]={
+ category="so",
+ direction="on",
+ },
+ [0x1F994]={
+ category="so",
+ direction="on",
+ },
+ [0x1F995]={
+ category="so",
+ direction="on",
+ },
+ [0x1F996]={
+ category="so",
+ direction="on",
+ },
+ [0x1F997]={
+ category="so",
+ direction="on",
+ },
+ [0x1F998]={
+ category="so",
+ direction="on",
+ },
+ [0x1F999]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99A]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99B]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99C]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99D]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99E]={
+ category="so",
+ direction="on",
+ },
+ [0x1F99F]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9A0]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9A1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9A2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B0]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B3]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B4]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B5]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B6]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B8]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9B9]={
+ category="so",
+ direction="on",
+ },
[0x1F9C0]={
category="so",
direction="on",
},
+ [0x1F9C1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9C2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D0]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D3]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D4]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D5]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D6]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D8]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9D9]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DA]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DB]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DC]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DD]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DE]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9DF]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E0]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E3]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E4]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E5]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E6]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E8]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9E9]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9EA]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9EB]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9EC]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9ED]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9EE]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9EF]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F0]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F1]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F2]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F3]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F4]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F5]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F6]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F7]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F8]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9F9]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FA]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FB]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FC]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FD]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FE]={
+ category="so",
+ direction="on",
+ },
+ [0x1F9FF]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA60]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA61]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA62]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA63]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA64]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA65]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA66]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA67]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA68]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA69]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA6A]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA6B]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA6C]={
+ category="so",
+ direction="on",
+ },
+ [0x1FA6D]={
+ category="so",
+ direction="on",
+ },
[0x2F800]={
category="lo",
direction="l",
@@ -121665,6 +128514,7 @@ return {
category="cf",
direction="bn",
},
+ [0xE0100]={},
characters={},
classifiers={
[0x600]=0x4,
@@ -121936,7 +128786,6 @@ return {
[0x70B]=0x6,
[0x70C]=0x6,
[0x70D]=0x6,
- [0x70F]=0x6,
[0x710]=0x3,
[0x711]=0x5,
[0x712]=0x2,
@@ -122106,6 +128955,9 @@ return {
[0x7F8]=0x6,
[0x7F9]=0x6,
[0x7FA]=0x2,
+ [0x7FD]=0x5,
+ [0x7FE]=0x6,
+ [0x7FF]=0x6,
[0x840]=0x3,
[0x841]=0x2,
[0x842]=0x2,
@@ -122131,6 +128983,17 @@ return {
[0x856]=0x4,
[0x857]=0x4,
[0x858]=0x4,
+ [0x860]=0x2,
+ [0x861]=0x4,
+ [0x862]=0x2,
+ [0x863]=0x2,
+ [0x864]=0x2,
+ [0x865]=0x2,
+ [0x866]=0x4,
+ [0x867]=0x3,
+ [0x868]=0x2,
+ [0x869]=0x3,
+ [0x86A]=0x3,
[0x8A0]=0x2,
[0x8A1]=0x2,
[0x8A2]=0x2,
@@ -122253,6 +129116,7 @@ return {
[0x1875]=0x2,
[0x1876]=0x2,
[0x1877]=0x2,
+ [0x1878]=0x2,
[0x1880]=0x4,
[0x1881]=0x4,
[0x1882]=0x4,
@@ -122419,6 +129283,70 @@ return {
[0x10BAD]=0x2,
[0x10BAE]=0x2,
[0x10BAF]=0x4,
+ [0x10D00]=0x1,
+ [0x10D01]=0x2,
+ [0x10D02]=0x2,
+ [0x10D03]=0x2,
+ [0x10D04]=0x2,
+ [0x10D05]=0x2,
+ [0x10D06]=0x2,
+ [0x10D07]=0x2,
+ [0x10D08]=0x2,
+ [0x10D09]=0x2,
+ [0x10D0A]=0x2,
+ [0x10D0B]=0x2,
+ [0x10D0C]=0x2,
+ [0x10D0D]=0x2,
+ [0x10D0E]=0x2,
+ [0x10D0F]=0x2,
+ [0x10D10]=0x2,
+ [0x10D11]=0x2,
+ [0x10D12]=0x2,
+ [0x10D13]=0x2,
+ [0x10D14]=0x2,
+ [0x10D15]=0x2,
+ [0x10D16]=0x2,
+ [0x10D17]=0x2,
+ [0x10D18]=0x2,
+ [0x10D19]=0x2,
+ [0x10D1A]=0x2,
+ [0x10D1B]=0x2,
+ [0x10D1C]=0x2,
+ [0x10D1D]=0x2,
+ [0x10D1E]=0x2,
+ [0x10D1F]=0x2,
+ [0x10D20]=0x2,
+ [0x10D21]=0x2,
+ [0x10D22]=0x3,
+ [0x10D23]=0x2,
+ [0x10F30]=0x2,
+ [0x10F31]=0x2,
+ [0x10F32]=0x2,
+ [0x10F33]=0x3,
+ [0x10F34]=0x2,
+ [0x10F35]=0x2,
+ [0x10F36]=0x2,
+ [0x10F37]=0x2,
+ [0x10F38]=0x2,
+ [0x10F39]=0x2,
+ [0x10F3A]=0x2,
+ [0x10F3B]=0x2,
+ [0x10F3C]=0x2,
+ [0x10F3D]=0x2,
+ [0x10F3E]=0x2,
+ [0x10F3F]=0x2,
+ [0x10F40]=0x2,
+ [0x10F41]=0x2,
+ [0x10F42]=0x2,
+ [0x10F43]=0x2,
+ [0x10F44]=0x2,
+ [0x10F45]=0x4,
+ [0x10F51]=0x2,
+ [0x10F52]=0x2,
+ [0x10F53]=0x2,
+ [0x10F54]=0x3,
+ [0x110BD]=0x4,
+ [0x110CD]=0x4,
[0x1E900]=0x2,
[0x1E901]=0x2,
[0x1E902]=0x2,
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua
index f2fdceb2c50..13b2e05157b 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua
@@ -1,5 +1,5 @@
if not modules then modules = { } end modules ['luaotfload-colors'] = {
- version = "2.8",
+ version = "2.9",
comment = "companion to luaotfload-main.lua (font color)",
author = "Khaled Hosny, Elie Roux, Philipp Gesang, Dohyun Kim, David Carlisle",
copyright = "Luaotfload Development Team",
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua
index 2f4589b10d0..d7604241c4d 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua
@@ -9,7 +9,7 @@
--
if not modules then modules = { } end modules ["luaotfload-configuration"] = {
- version = "2.8",
+ version = "2.9",
comment = "part of Luaotfload",
author = "Philipp Gesang, Dohyun Kim",
copyright = "Luaotfload Development Team",
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua
index 9c8c298636a..a195eaae724 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua
@@ -1,11 +1,13 @@
if not modules then modules = { } end modules ['luaotfload-database'] = {
- version = "2.8",
+ version = "2.9",
comment = "companion to luaotfload-main.lua",
- author = "Khaled Hosny, Elie Roux, Philipp Gesang",
+ author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
copyright = "Luaotfload Development Team",
license = "GNU GPL v2.0"
}
+
+
--[[doc--
With version 2.7 we killed of the Fontforge libraries in favor of
@@ -617,7 +619,11 @@ local style_category = {
i = "italic",
}
-local type1_metrics = { "tfm", "ofm", }
+-- MK Determine if casefold search is requested
+local casefold_search =
+ not ({['0'] = true, ['f'] = true, [''] = true})
+ [(kpse.var_value'texmf_casefold_search' or '1'):sub(1,1)]
+-- /MK
local lookup_filename = function (filename)
if not name_index then name_index = load_names () end
@@ -630,7 +636,10 @@ local lookup_filename = function (filename)
local barenames = baredata [location]
local idx
if basenames ~= nil then
+ -- MK Added fallback
idx = basenames [filename]
+ or casefold_search and basenames [stringlower(filename)]
+ -- /MK
if idx then
goto done
end
@@ -640,7 +649,10 @@ local lookup_filename = function (filename)
local format = format_precedence [j]
local filemap = barenames [format]
if filemap then
+ -- MK Added fallback
idx = barenames [format] [filename]
+ or casefold_search and barenames [format] [stringlower(filename)]
+ -- /MK
if idx then
break
end
@@ -668,6 +680,12 @@ local dummy_findfile = resolvers.findfile -- from basics-gen
--- string -> string * string * bool
local lookup_font_file
+
+-- MK Added mini scope to avoid variable limit
+do
+local type1_metrics = { "tfm", "ofm", }
+-- /MK
+
lookup_font_file = function (filename)
local found = lookup_filename (filename)
@@ -693,6 +711,9 @@ lookup_font_file = function (filename)
end
return filename, nil, false
end
+-- MK
+end
+-- /MK
--[[doc--
@@ -1208,12 +1229,18 @@ lookup_fullpath = function (fontname, ext) --- getfilename()
local basenames = basedata [location]
local idx
if basenames ~= nil then
+ -- MK Added fallback
idx = basenames [fontname]
+ or casefold_search and basenames [stringlower(fontname)]
+ -- /MK
end
if ext then
local barenames = baredata [location] [ext]
if not idx and barenames ~= nil then
+ -- MK Added fallback
idx = barenames [fontname]
+ or casefold_search and barenames [stringlower(fontname)]
+ -- /MK
end
end
if idx then
@@ -2567,6 +2594,7 @@ generate_filedata = function (mappings)
local inbase = base [location] --- no format since the suffix is known
+ -- MK Added lowercase versions for case-insensitive fallback
if inbase then
local present = inbase [basename]
if present then
@@ -2586,11 +2614,38 @@ generate_filedata = function (mappings)
end
else
+ local lowerbasename = stringlower (basename)
+ if basename ~= lowerbasename then
+ present = inbase [lowerbasename]
+ if present then
+ logreport ("both", 4, "db",
+ "Conflicting basename: %q already indexed \z
+ as %s.",
+ barename, mappings[present].basename)
+ conflicts.basenames = conflicts.basenames + 1
+
+ --- track conflicts per font
+ local conflictdata = entry.conflicts
+
+ if not conflictdata then
+ entry.conflicts = { basename = present }
+ else -- some conflicts already detected
+ conflictdata.basename = present
+ end
+
+ else
+ inbase [lowerbasename] = index
+ end
+ end
inbase [basename] = index
end
else
inbase = { basename = index }
base [location] = inbase
+ local lowerbasename = stringlower (basename)
+ if basename ~= lowerbasename then
+ inbase [lowerbasename] = index
+ end
end
--- 2) add to barename table
@@ -2614,14 +2669,40 @@ generate_filedata = function (mappings)
else -- some conflicts already detected
conflictdata.barename = present
end
-
else
+ local lowerbarename = stringlower (barename)
+ if barename ~= lowerbarename then
+ present = inbare [lowerbarename]
+ if present then
+ logreport ("both", 4, "db",
+ "Conflicting barename: %q already indexed \z
+ as %s.",
+ barename, mappings[present].basename)
+ conflicts.barenames = conflicts.barenames + 1
+
+ --- track conflicts per font
+ local conflictdata = entry.conflicts
+
+ if not conflictdata then
+ entry.conflicts = { barename = present }
+ else -- some conflicts already detected
+ conflictdata.barename = present
+ end
+ else
+ inbare [lowerbarename] = index
+ end
+ end
inbare [barename] = index
end
else
inbare = { [barename] = index }
bare [location] [format] = inbare
+ local lowerbarename = stringlower (barename)
+ if barename ~= lowerbarename then
+ inbare [lowerbarename] = index
+ end
end
+ -- /MK
--- 3) add to fullpath map
@@ -3680,7 +3761,10 @@ return {
fonts.definers = fonts.definers or { resolvers = { } }
names.blacklist = blacklist
- names.version = 5 --- increase monotonically
+ -- MK Changed to rebuild with case insensitive fallback.
+ -- Negative version to indicate generation by modified code.
+ names.version = -1 --- decrease monotonically
+ -- /MK
names.data = nil --- contains the loaded database
names.lookups = nil --- contains the lookup cache
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua
index f11f05b9b0e..c69cab3a720 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua
@@ -1,11 +1,12 @@
if not modules then modules = { } end modules ["features"] = {
- version = "2.8",
+ version = "2.9",
comment = "companion to luaotfload-main.lua",
- author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang",
+ author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
+
local type = type
local next = next
local tonumber = tonumber
@@ -1259,12 +1260,17 @@ if as_script == true then --- skip the remainder of the file
report ("log", 5, "features",
"Exiting early from luaotfload-features.lua.")
return
-else
- local registersplit = definers.registersplit
- registersplit (":", handle_request, "common")
- registersplit ("", handle_request, "xetex path style") -- catches \font\text=[names]
end
+-- MK: Added
+function fonts.definers.analyze (spec_string, size)
+ return handle_request {
+ size = size,
+ specification = spec_string,
+ }
+end
+-- /MK
+
-- We assume that the other otf stuff is loaded already; though there’s
-- another check below during the initialization phase.
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua
new file mode 100644
index 00000000000..3446b79aff9
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua
@@ -0,0 +1,417 @@
+-------------------------------------------------------------------------------
+-- FILE: luaotfload-filelist.lua
+-- DESCRIPTION: a table with the files of luaotfload
+-- VERSION: 2.9
+-- AUTHOR: Ulrike Fischer, <fischer@troubleshooting-tex.de>
+-- DATE: 2018-09-23
+-------------------------------------------------------------------------------
+
+
+
+--[[doc--
+
+luaotfload has tables with files list in many places: In the import scripts,
+in the init file, in the documentation. This makes maintenance difficult.
+This here is a try to get everything in one place. As the order how files are
+loaded during the merge matters the table is an array. Lists with other
+sorting should be created with functions. Ditto for subtables.
+
+Some redundancy can not be avoided for now if one want to avoid to have to change all sort of functions.
+
+## locations
+files can reside in up to three location (with perhaps different names)
+- context ctxdir
+- git gitdir
+- texmf texdir
+
+files don't need to exist in all locations but the direction of the flow is
+always from context over git to texmf:
+ context-> git -> texmf
+so the "stations" of a file and its source can be deduced by the dirs recorded in the entries
+
+
+## "kind"
+the first four entries are from the original mkimport code and are important for the imports.
+the others are new.
+
+ · *essential*: Files required at runtime.
+ · *merged*: Files merged into the fontloader package.
+ · *ignored*: Lua files not merged, but part of the format.
+ · *tex*: TeX code, i.e. format and examples.
+ · *lualibs*: Files imported, but also provided by the Lualibs package.
+ · *library*: native luaotfload-files of type library
+ · *core*: native core luaotfload files
+ · *generated*: generated luaotfload files
+ · *scripts*: scripts (mk-...)
+ · *docu*: documentation (should perhaps be more refined
+
+## names
+
+The "real" name of a file in a location can be build
+
+- in the context location: ctxpref + name + ext
+- in the git location: (gitpref or "fontloader-") + (ours or name ) + ext
+- in the tex location: (gitpref or "fontloader-") + (texname or ours or name ) + ext
+
+## fields
+ mkstatus: used to ignore some files in mkstatus
+
+
+## files which use the file names
+
+### mkimport
+
+ mkimports needs an
+ --> "import" table with two subtables:
+ --> fontloader, with the files to get from generic, cond: ctxtype = "ctxgene"
+ --> context, with the files to get from context, cond: ctxtype = "ctxbase"
+ entries are subtables with {name=, ours=, kind= }
+
+and a
+ --> "package" table with
+ --> optional (probably unused)
+ --> required = files of type kind_merged
+ entries are the values of name
+
+### mkstatus
+
+this script has been already changed to use luaotfload-filelist.lua
+
+### luaotfload-init.lua
+
+luaotfload-init.lua needs a table
+--> context_modules
+with the (ordered) entries
+
+{false, "name"} -- kind_lualibs
+{ctxdir,"ctxprefix+name"} -- kind_essential or kind_merged
+
+The same list should be used in local init_main = function ()
+but only without the prefix.
+it is unclear how fonts_syn should be handled!!!!
+
+### filegraph.tex
+has been already adapted
+
+### luaotfload-latex.tex/luaotfload-main.tex
+has been already adapted
+
+### build.lua
+???
+
+--doc]]--
+
+
+local kind_essential = 0
+local kind_merged = 1
+local kind_tex = 2
+local kind_ignored = 3
+local kind_lualibs = 4
+local kind_library = 5
+local kind_core = 6
+local kind_generated = 7
+local kind_script = 8
+local kind_docu = 9
+
+local kind_name = {
+ [0] = "essential",
+ [1] = "merged" ,
+ [2] = "tex" ,
+ [3] = "ignored" ,
+ [4] = "lualibs" ,
+ [5] = "library" ,
+ [6] = "core",
+ [7] = "generated",
+ [8] = "script",
+ [9] = "docu"
+}
+
+
+local ctxdirbas = "tex/context/base/mkiv/"
+local ctxdirgen = "tex/generic/context/luatex/"
+
+local gitdirimp = "src/fontloader/misc/" -- imp=imported
+local gitdirsrc = "src/"
+local gitdiress = "src/fontloader/runtime/"
+local gitdirgen = "src/fontloader/auto/"
+local gitdirdoc = "doc/"
+local gitdirscr = "scripts/"
+local gitdirmain = "./"
+
+-- these here a not really pathes
+local texdirtex = "tex"
+local texdirscr = "scripts"
+local texdirdoc = "doc"
+local texdirman = "man"
+
+luaotfload = luaotfload or {}
+luaotfload.filelist = luaotfload.filelist or {}
+
+luaotfload.filelist.data =
+ {
+ -- at first the source files from context
+ { name = "l-lua" , ours = "l-lua" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-lpeg" , ours = "l-lpeg" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-function" , ours = "l-function" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-string" , ours = "l-string" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-table" , ours = "l-table" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-io" , ours = "l-io" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-file" , ours = "l-file" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-boolean" , ours = "l-boolean" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-math" , ours = "l-math" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "l-unicode" , ours = "l-unicode" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+
+ { name = "util-str" , ours = "util-str" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "util-fil" , ours = "util-fil" , ext = ".lua", kind = kind_lualibs , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+
+ { name = "basics-gen" , ours = nil , ext = ".lua", kind = kind_essential , gitdir=gitdiress, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+-- files merged in the fontloader. Two files are ignored
+ { name = "data-con" , ours = "data-con" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "basics-nod" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "basics-chr" , ours = nil , ext = ".lua", kind = kind_ignored , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "font-ini" , ours = "font-ini" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "fonts-mis" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "font-con" , ours = "font-con" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "fonts-enc" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "font-cid" , ours = "font-cid" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-map" , ours = "font-map" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "fonts-syn" , ours = nil , ext = ".lua", kind = kind_ignored , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "font-vfc" , ours = "font-vfc" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-otr" , ours = "font-otr" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-oti" , ours = "font-oti" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ott" , ours = "font-ott" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-cff" , ours = "font-cff" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ttf" , ours = "font-ttf" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-dsp" , ours = "font-dsp" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-oup" , ours = "font-oup" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-otl" , ours = "font-otl" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-oto" , ours = "font-oto" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-otj" , ours = "font-otj" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ota" , ours = "font-ota" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ots" , ours = "font-ots" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-osd" , ours = "font-osd" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-ocl" , ours = "font-ocl" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-otc" , ours = "font-otc" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-onr" , ours = "font-onr" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-one" , ours = "font-one" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-afk" , ours = "font-afk" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-tfm" , ours = "font-tfm" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-lua" , ours = "font-lua" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-def" , ours = "font-def" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "fonts-def" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "fonts-ext" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "font-imp-tex" , ours = "font-imp-tex" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-imp-ligatures", ours = "font-imp-ligatures", ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-imp-italics" , ours = "font-imp-italics" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "font-imp-effects" , ours = "font-imp-effects" , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxbase" },
+ { name = "fonts-lig" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "fonts-gbn" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+-- end of files merged
+
+ { name = "fonts-merged" , ours = "reference" , ext = ".lua", kind = kind_essential , gitdir=gitdiress, texdir = texdirtex , ctxdir= ctxdirgen ,ctxtype = "ctxgene" , ctxpref = "luatex-" },
+
+
+
+-- this two files are useful as reference for the load order but should not be installed
+ { name = "fonts" , ours = "load-order-reference", ext = ".lua", kind = kind_ignored , gitdir=gitdirimp, ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+ { name = "fonts" , ours = "load-order-reference", ext = ".tex", kind = kind_tex , gitdir=gitdirimp, ctxdir= ctxdirgen, ctxtype = "ctxgene" , ctxpref = "luatex-" },
+
+-- the default fontloader. How to code the name??
+ { name = "YYYY-MM-DD" , ext = ".lua", kind = kind_generated , gitdir = gitdirgen, texdir = texdirtex,mkstatus="auto" },
+
+-- the luaotfload files
+ { name = "luaotfload" ,kind = kind_core, ext =".sty", gitdir=gitdirsrc, texdir=texdirtex, gitpref="",},
+ { name = "main" ,kind = kind_core, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "init" ,kind = kind_core, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "log" ,kind = kind_core, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "diagnostics" ,kind = kind_core, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+
+ { name = "tool" ,kind = kind_core, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "blacklist" ,kind = kind_core, ext =".cnf", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+
+ { name = "filelist" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "auxiliary" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "colors" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "configuration" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "database" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "features" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "letterspace" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "loaders" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "parsers" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+ { name = "resolvers" ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+
+ { name = "characters" ,kind = kind_generated, ext =".lua", gitdir=gitdirgen, texdir=texdirtex, gitpref = "luaotfload-", script="mkcharacter" },
+ { name = "glyphlist" ,kind = kind_generated, ext =".lua", gitdir=gitdirgen, texdir=texdirtex, gitpref = "luaotfload-", script="mkglyphlist" },
+ { name = "status" ,kind = kind_generated, ext =".lua", gitdir=gitdirgen, texdir=texdirtex, gitpref = "luaotfload-", script="mkstatus",mkstatus="ignore" },
+
+
+
+-- scripts
+ { name = "mkimport" ,kind = kind_script, gitdir = gitdirscr, gitpref = "", ext=""},
+ { name = "mkglyphlist" ,kind = kind_script, gitdir = gitdirscr, gitpref = "", ext=""},
+ { name = "mkcharacters" ,kind = kind_script, gitdir = gitdirscr, gitpref = "", ext=""},
+ { name = "mkstatus" ,kind = kind_script, gitdir = gitdirscr, gitpref = "", ext=""},
+ { name = "mktests" ,kind = kind_script, gitdir = gitdirscr, gitpref = "", ext=""},
+
+-- documentation (source dirs need perhaps coding ...) but don't overdo for now
+
+ { name = "latex" , kind= kind_docu, ext = ".tex", gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirdoc, typeset = true },
+ { name = "main" , kind= kind_docu, ext = ".tex", gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirdoc, typeset = false },
+ { name = "conf" , kind= kind_docu, ext = ".tex", gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirdoc, typeset = true , generated = true},
+ { name = "tool" , kind= kind_docu, ext = ".tex", gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirdoc, typeset = true , generated = true},
+ { name = "filegraph" , kind= kind_docu, ext = ".tex", gitpref ="", gitdir = gitdirdoc, texdir= texdirdoc, typeset = true , generated = true},
+ { name = "conf" , kind= kind_docu, ext = ".rst", gitpref = "luaotfload.", gitdir = gitdirdoc, texdir= texdirdoc },
+ { name = "conf" , kind= kind_docu, ext = ".5" , gitpref = "luaotfload.", gitdir = gitdirdoc, texdir= texdirman},
+ { name = "tool" , kind= kind_docu, ext = ".rst", gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirdoc},
+ { name = "tool" , kind= kind_docu, ext = ".1" , gitpref = "luaotfload-", gitdir = gitdirdoc, texdir= texdirman },
+ { name = "README" , kind= kind_docu, texname = "README", gitpref="", ext = ".md" , gitdir = gitdirdoc, texdir= texdirdoc},
+ { name = "COPYING" , kind= kind_docu, ext = "" , gitpref="", gitdir = gitdirmain, texdir= texdirdoc},
+ { name = "NEWS" , kind= kind_docu, ext = "" , gitpref="", gitdir = gitdirmain , texdir= texdirdoc},
+ { name = "README" , kind= kind_docu, gitpref="", ext = ".md" , gitdir = gitdirmain}, -- github readme
+
+}
+
+
+
+-- functions
+-- list of kind:
+--local kind_essential = 0
+--local kind_merged = 1
+--local kind_tex = 2
+--local kind_ignored = 3
+--local kind_lualibs = 4
+--local kind_library = 5
+--local kind_core = 6
+--local kind_generated = 7
+--local kind_script = 8
+--local kind_docu = 9
+
+
+-- some selections
+-- due to the history and setup of the other files, there are not always simple "kind" selections.
+-- ctx base files are splitted in two sets:
+-- 1. font & node
+function luaotfload.filelist.selectctxfontentries ( filetable )
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.ctxtype == "ctxbase" and v.kind==1 then
+ table.insert(result,v)
+ end
+ end
+ return result
+end
+
+-- 2. lualibs libraries
+function luaotfload.filelist.selectctxlibsentries ( filetable )
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.ctxtype == "ctxbase" and v.kind==4 then
+ table.insert(result,v)
+ end
+ end
+ return result
+end
+
+-- ctx generic files
+-- 1. ignored files are not in the list ...
+function luaotfload.filelist.selectctxgeneusedentries ( filetable )
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.ctxtype == "ctxgene" and v.kind==1 then
+ table.insert(result,v)
+ end
+ end
+ return result
+end
+
+-- 2. ignored files are in the list
+function luaotfload.filelist.selectctxgeneentries ( filetable )
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.ctxtype == "ctxgene" and (v.kind==1 or v.kind== 3) then
+ table.insert(result,v)
+ end
+ end
+ return result
+end
+
+-- luaotfload-files (lol) are splitted in essential (0), core (6), lib (5) and gene (7) and scr (scripts):
+-- luaoftload libraries
+
+function luaotfload.filelist.selectlolessentries (filetable)
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.kind == 0 then
+ table.insert (result,v)
+ end
+ end
+ return result
+end
+
+
+function luaotfload.filelist.selectlollibentries (filetable)
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.kind == 5 then
+ table.insert (result,v)
+ end
+ end
+ return result
+end
+
+-- luaoftload core
+
+function luaotfload.filelist.selectlolcoreentries (filetable)
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.kind == 6 then
+ table.insert (result,v)
+ end
+ end
+ return result
+end
+
+-- core and lib lua-files
+
+function luaotfload.filelist.selectlolsrcluaentries (filetable)
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if (v.kind == 5 or v.kind==6) and v.ext==".lua" then
+ table.insert (result,v)
+ end
+ end
+ return result
+end
+
+
+
+-- luaoftload generated
+
+function luaotfload.filelist.selectlolgeneentries (filetable)
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.kind == 7 then
+ table.insert (result,v)
+ end
+ end
+ return result
+end
+
+
+
+-- scripts
+function luaotfload.filelist.selectlolscrentries ( filetable )
+ local result = {}
+ for i,v in ipairs (filetable) do
+ if v.kind==8 then
+ table.insert(result,v)
+ end
+ end
+ return result
+end
+
+
+
+
+
+
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua
index ad18b321c5e..b50b5c2291d 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua
@@ -3,10 +3,12 @@
-- FILE: luaotfload-init.lua
-- DESCRIPTION: Luaotfload font loader initialization
-- REQUIREMENTS: luatex v.0.80 or later; packages lualibs
--- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>
+-- VERSION: 2.9 2018-09-24
+-- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>, Marcel Krüger
-----------------------------------------------------------------------
--
+
local setmetatable = setmetatable
local kpselookup = kpse.lookup
local lfsisdir = lfs.isdir
@@ -238,6 +240,7 @@ local context_modules = {
{ false, "l-file" },
{ false, "l-boolean" },
{ false, "l-math" },
+ { false, "l-unicode" }, -- NEW UF 19.09.2018
{ false, "util-str" },
{ false, "util-fil" },
@@ -246,13 +249,16 @@ local context_modules = {
{ ctx, "data-con" },
{ ltx, "luatex-basics-nod" },
{ ctx, "font-ini" },
+ { ltx, "luatex-fonts-mis" }, -- NEW UF 19.09.2018
{ ctx, "font-con" },
{ ltx, "luatex-fonts-enc" },
{ ctx, "font-cid" },
{ ctx, "font-map" },
- { ltx, "luatex-fonts-syn" },
+-- { ltx, "luatex-fonts-syn" }, -- ignore??
+ { ctx, "font-vfc" }, -- NEW UF 19.09.2018
{ ctx, "font-oti" },
{ ctx, "font-otr" },
+ { ctx, "font-ott" },
{ ctx, "font-cff" },
{ ctx, "font-ttf" },
{ ctx, "font-dsp" },
@@ -271,8 +277,15 @@ local context_modules = {
{ ctx, "font-tfm" },
{ ctx, "font-lua" },
{ ctx, "font-def" },
+ { ltx, "luatex-fonts-def" },
{ ltx, "luatex-fonts-ext" },
- { ctx, "font-gbn" },
+ { ctx, "font-imp-tex" },
+ { ctx, "font-imp-ligatures"},
+ { ctx, "font-imp-italics" },
+ { ctx, "font-imp-effects" },
+ { ltx, "luatex-fonts-lig" },
+ { ltx, "luatex-fonts-gbn" },
+
} --[[context_modules]]
@@ -527,13 +540,16 @@ local init_main = function ()
load_fontloader_module "data-con"
load_fontloader_module "basics-nod"
load_fontloader_module "font-ini"
+ load_fontloader_module "fonts-mis"
load_fontloader_module "font-con"
load_fontloader_module "fonts-enc"
load_fontloader_module "font-cid"
load_fontloader_module "font-map"
- load_fontloader_module "fonts-syn"
- load_fontloader_module "font-oti"
+-- load_fontloader_module "fonts-syn" -- ignore?
+ load_fontloader_module "font-vfc"
load_fontloader_module "font-otr"
+ load_fontloader_module "font-oti"
+ load_fontloader_module "font-ott"
load_fontloader_module "font-cff"
load_fontloader_module "font-ttf"
load_fontloader_module "font-dsp"
@@ -545,14 +561,21 @@ local init_main = function ()
load_fontloader_module "font-ots"
load_fontloader_module "font-osd"
load_fontloader_module "font-ocl"
+ load_fontloader_module "font-otc"
load_fontloader_module "font-onr"
load_fontloader_module "font-one"
load_fontloader_module "font-afk"
load_fontloader_module "font-tfm"
load_fontloader_module "font-lua"
load_fontloader_module "font-def"
+ load_fontloader_module "fonts-def"
load_fontloader_module "fonts-ext"
- load_fontloader_module "font-gbn"
+ load_fontloader_module "font-imp-tex"
+ load_fontloader_module "font-imp-ligatures"
+ load_fontloader_module "font-imp-italics"
+ load_fontloader_module "font-imp-effects"
+ load_fontloader_module "fonts-lig"
+ load_fontloader_module "fonts-gbn"
elseif fontloader == "context" then
logreport ("log", 0, "init",
@@ -648,14 +671,20 @@ local init_post_install_callbacks = function ()
--doc]]--
+ -- MK Pass current text direction to simple_font_handler
+ local handler = nodes.simple_font_handler
+ local callback = function(head, groupcode, _, _, direction)
+ return handler(head, groupcode, nil, nil, direction or tex.get'textdir')
+ end
luatexbase.add_to_callback("pre_linebreak_filter",
- nodes.simple_font_handler,
+ callback,
"luaotfload.node_processor",
1)
luatexbase.add_to_callback("hpack_filter",
- nodes.simple_font_handler,
+ callback,
"luaotfload.node_processor",
1)
+ -- /MK
end
local init_post_load_agl = function ()
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua
index fd64c90a4b8..104047ba8ba 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua
@@ -1,7 +1,7 @@
if not modules then modules = { } end modules ['letterspace'] = {
- version = "2.8",
+ version = "2.9",
comment = "companion to luaotfload-main.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang, Ulrike Fischer",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
@@ -70,7 +70,7 @@ local copy_node = nodedirect.copy
local new_node = nodedirect.new
local nodepool = nodedirect.pool
-local new_kern = nodepool.kern
+-- local new_kern = nodepool.kern -- UF removed 2017-07-14
local nodecodes = nodes.nodecodes
@@ -236,16 +236,21 @@ end
--- character kerning functionality
---=================================================================---
+-- UF changed 2017-07-14
+local nodedirectnew = node.direct.new
+
local kern_injector = function (fillup, kern)
- if fillup then
- local g = new_glue(kern)
- local s = getfield(g, "spec")
- setfield(s, "stretch", kern)
- setfield(s, "stretch_order", 1)
- return g
- end
- return new_kern(kern)
+ if fillup then
+ local g = nodedirectnew("glue")
+ setfield(g, "stretch", kern)
+ setfield(g, "stretch_order", 1)
+ return g
+ end
+ local g = nodedirectnew("kern")
+ setfield(g,"kern",kern)
+ return g
end
+-- /UF
local kernable_skip = function (n)
local st = getsubtype (n)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua
index ab38ffaac14..8ba3e1c474a 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua
@@ -1,5 +1,5 @@
if not modules then modules = { } end modules ["luaotfload-log"] = {
- version = "2.8",
+ version = "2.9",
comment = "companion to Luaotfload",
author = "Khaled Hosny, Elie Roux, Philipp Gesang",
copyright = "Luaotfload Development Team",
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua
index 14d531683a2..1ac0752c621 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua
@@ -2,7 +2,7 @@
-- FILE: luaotfload-main.lua
-- DESCRIPTION: Luaotfload entry point
-- REQUIREMENTS: luatex v.0.95.0 or later; package lualibs
--- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang
+-- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang, Ulrike Fischer, Marcel Krüger
-----------------------------------------------------------------------
--
@@ -11,7 +11,7 @@ config = config or { }
luaotfload = luaotfload or { }
local luaotfload = luaotfload
luaotfload.log = luaotfload.log or { }
-luaotfload.version = "2.8"
+luaotfload.version = "2.9"
luaotfload.loaders = { }
luaotfload.min_luatex_version = { 0, 95, 0 }
luaotfload.fontloader_package = "reference" --- default: from current Context
@@ -52,8 +52,8 @@ local authors = "\z
luaotfload.module = {
name = "luaotfload-main",
- version = 2.80001,
- date = "2017/01/29",
+ version = 2.90001,
+ date = "2018/09/24",
description = "OpenType layout system.",
author = authors,
copyright = authors,
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua
index b188bb0d28c..b6e7acab7a6 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua
@@ -3,10 +3,11 @@
-- FILE: luaotfload-parsers.lua
-- DESCRIPTION: various lpeg-based parsers used in Luaotfload
-- REQUIREMENTS: Luaotfload >= 2.8
--- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>
+-- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>, Marcel Krüger
-------------------------------------------------------------------------------
--
+
local traversal_maxdepth = 42 --- prevent stack overflows
local rawset = rawset
@@ -238,6 +239,7 @@ end
--- -> (string -> fun option -> string list)
--- -> tab * tab * tab
local read_fonts_conf_indeed
+-- MK Made basedir an explicit parameter to fix relative paths
read_fonts_conf_indeed = function (depth,
start,
home,
@@ -246,7 +248,8 @@ read_fonts_conf_indeed = function (depth,
acc,
done,
dirs_done,
- find_files)
+ find_files,
+ basedir)
logreport ("both", 4, "db",
"Fontconfig scanner processing path %s.",
@@ -303,7 +306,7 @@ read_fonts_conf_indeed = function (depth,
elseif --- if the path is relative, we make it absolute
not ( lfsisfile(path) or lfsisdir(path) )
then
- path = filejoin(filedirname(start), path)
+ path = filejoin(basedir, path)
end
if lfsisfile(path)
and kpsereadable_file(path)
@@ -321,17 +324,22 @@ read_fonts_conf_indeed = function (depth,
acc,
done,
dirs_done,
- find_files)
+ find_files,
+ basedir)
end
elseif lfsisdir(path) then --- arrow code ahead
- local config_files = find_files (path, conf_filter)
- for _, filename in next, config_files do
- if not done[filename] then
- if done[path] then
+ if done[path] then
+ logreport ("log", 3, "db",
+ "Skipping directory at %s, already included.", path)
+ else
+ done[path] = true
+ local config_files = find_files (path, conf_filter)
+ for _, filename in next, config_files do
+ if done[filename] then
logreport ("log", 3, "db",
- "Skipping file at %s, already included.", path)
+ "Skipping file at %s, already included.", filename)
else
- done[path] = true
+ done[filename] = true
acc = read_fonts_conf_indeed(depth + 1,
filename,
home,
@@ -340,7 +348,8 @@ read_fonts_conf_indeed = function (depth,
acc,
done,
dirs_done,
- find_files)
+ find_files,
+ basedir)
end
end
end
@@ -352,6 +361,7 @@ read_fonts_conf_indeed = function (depth,
--inspect(done)
return acc, done, dirs_done
end --- read_fonts_conf_indeed()
+-- /MK
--[[doc--
read_fonts_conf() sets up an accumulator and two sets
@@ -376,6 +386,7 @@ local read_fonts_conf = function (path_list, find_files)
local done = { } ---> set: files inspected
local dirs_done = { } ---> set: dirs in list
for i=1, #path_list do --- we keep the state between files
+ -- MK Pass the base directory
acc, done, dirs_done = read_fonts_conf_indeed(0,
path_list[i],
home,
@@ -384,7 +395,9 @@ local read_fonts_conf = function (path_list, find_files)
acc,
done,
dirs_done,
- find_files)
+ find_files,
+ filedirname(path_list[i]))
+ -- /MK
end
return acc
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua
index 5571e947cf0..cb3cdd57811 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua
@@ -1,85 +1,86 @@
return {
["hashes"]={
- { "fontloader-2017-02-11.lua", "c2db29b75e1838c08ff5867778f79cc3" },
- { "fontloader-util-fil.lua", "0573e91847e722ffe0fcdb465ba89e6b" },
- { "fontloader-util-str.lua", "513836cfea6a8027c1451a95bc74649f" },
- { "fontloader-swiglib-test.lua", "2f0b431faf53d3e19bfae22035bdc77e" },
- { "fontloader-swiglib.lua", "c20138e09bfd743dba7de1d5421be4af" },
- { "fontloader-preprocessor.lua", "f87963c22d5523218f1beee7e315bae5" },
- { "fontloader-mplib.lua", "55ad1c7febc72c6700b49692c2384738" },
- { "fontloader-math.lua", "f7eda9d5922e4aa7bb858ba9943fdacd" },
- { "fontloader-l-table.lua", "92978e5ea9ca13dae04fb606f5be4a1c" },
- { "fontloader-l-string.lua", "2ca01eeb225c09e73ff4f3a2d101827a" },
- { "fontloader-l-math.lua", "51275e81c652e3fbd7d02b1c383d3049" },
- { "fontloader-l-lua.lua", "5466b2db6d8cc3b9786a398bb4230ea1" },
- { "fontloader-l-lpeg.lua", "93b90b22d7d3600ddd9def9f3ad9a7bb" },
- { "fontloader-l-io.lua", "ee77e357f5965196f9559b8fcccc6e71" },
- { "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" },
- { "fontloader-l-file.lua", "32d9ba0a5cdd3509a3847bb050bfb800" },
+ { "fontloader-2018-09-24.lua", "9b44571b829ca5276deffe1d1a9c8673" },
+ { "fontloader-util-fil.lua", "258d23db3b135c06ceb87faecbe785b4" },
+ { "fontloader-util-str.lua", "98fd6915ad05564aed39dff72102b6db" },
+ { "fontloader-l-unicode.lua", "c8dd70435ced1bd05e257557a05b718b" },
+ { "fontloader-l-math.lua", "082add08e0bb79f39191ae9534a79849" },
{ "fontloader-l-boolean.lua", "abe28515dd33e8f6c416c09bca351cf8" },
- { "fontloader-languages.lua", "4e5bbdad336fa4969ac21a5242643a40" },
- { "fontloader-font-otc.lua", "85d63e257c748c624768aa7c8ec7f0bc" },
- { "fontloader-font-ocl.lua", "fbc00782e4efb24a7569f99cd1574ffb" },
- { "fontloader-font-osd.lua", "10ecd4b375680b011e7c6a25e5ad74f7" },
- { "fontloader-font-ots.lua", "7e1e55f9f728474372665e4a64a43f5a" },
- { "fontloader-font-ota.lua", "c281d18dfc89a8ca18af64f55e9fa92b" },
- { "fontloader-font-otj.lua", "5ea70db9f1990dc1459425853c79f663" },
- { "fontloader-font-oto.lua", "5fbdd899624d4eef639f81b580afe9aa" },
- { "fontloader-font-otl.lua", "2e7c8d9a331c46826211bd507f8e488a" },
- { "fontloader-font-oup.lua", "f7237130b648a4c2b477dabedc7f90e8" },
- { "fontloader-font-dsp.lua", "4a5266ada979d5c2d48867dc3ffaefea" },
- { "fontloader-font-ttf.lua", "e0893de6d0f3f421ee4386fa90429db8" },
- { "fontloader-font-cff.lua", "f3fc74e8629f7a2825c34a34550c790d" },
- { "fontloader-font-otr.lua", "2bd0085b78027f261218d63034f43474" },
- { "fontloader-font-tfm.lua", "3d813578dbf6c447e4b859c2bf0618f7" },
- { "fontloader-fonts-syn.lua", "6753dfb9a28aad35266284bb00072dca" },
+ { "fontloader-l-file.lua", "7496b10d145575310f3888ee0b22d04d" },
+ { "fontloader-l-io.lua", "acbb79a157e9d141379ed4708bef1c04" },
+ { "fontloader-l-table.lua", "d021aef90825ed5844f26395ee16916c" },
+ { "fontloader-l-string.lua", "ce0b99ddb7749540105b13450971ca7e" },
+ { "fontloader-l-function.lua", "a7e68a9703c35238729da41a474e951b" },
+ { "fontloader-l-lpeg.lua", "42ea6d8dd58797f4d9531c42fb3b6147" },
+ { "fontloader-l-lua.lua", "a5deb6c4d9f8b0ca85740880eef75063" },
+ { "fontloader-fonts-gbn.lua", "10ecdf01e7c926e5128ad8a9dff4d677" },
+ { "fontloader-fonts-lig.lua", "fbd251eea3810a43a8d5542319361d68" },
+ { "fontloader-fonts-ext.lua", "32013cbc5d5d336be8b1d1e5879d86c4" },
+ { "fontloader-fonts-def.lua", "f435e0875f203f343157baeff876ec9c" },
+ { "fontloader-fonts-enc.lua", "5ff4ca50493d7c4ecea0e15c203099f0" },
+ { "fontloader-fonts-mis.lua", "f8d0788d2554d71720dc543cf4ffafe1" },
+ { "fontloader-basics-nod.lua", "78f56219685f3145b9393c2b688aad94" },
+ { "fontloader-font-imp-effects.lua", "3327181ef3db6f44dd234ad66ccc3f38" },
+ { "fontloader-font-imp-italics.lua", "c2e6d6c4096a2c30d68fbffd3d7d58a7" },
+ { "fontloader-font-imp-ligatures.lua", "26ffcf089391445f7af59536c8814364" },
+ { "fontloader-font-imp-tex.lua", "ceb087ef6fa2f89aed7179f60ddf8f35" },
+ { "fontloader-font-def.lua", "8e2cb2552bf02246da2ac43334b91795" },
{ "fontloader-font-lua.lua", "1fbfdf7b689b2bdfd0e3bb9bf74ce136" },
- { "fontloader-fonts.lua", "96e568c9b2ffa8108fb95d886bb2b645" },
- { "fontloader-fonts-ext.lua", "aff3846f4c1f15de0a9f4fd7081e0c68" },
- { "fontloader-fonts-enc.lua", "a7ace7c1969cd64a5ca9888838f3edb6" },
- { "fontloader-fonts-demo-vf-1.lua", "7a4cb26eda4f1090d195114c10a33a75" },
- { "fontloader-font-def.lua", "49fa2b50d8d2a1bb70b08b72f858ecd0" },
- { "fontloader-font-gbn.lua", "850f31ba73ff8de96371d0aed2b2b4cb" },
- { "fontloader-font-oti.lua", "8f48c06a1d632febd7231ad5dfadfc53" },
- { "fontloader-font-map.lua", "8708bde7467785c4d3b7afdaf2f9333a" },
- { "fontloader-font-ini.lua", "10cb9a563a98e06ff79c35a8751e13dc" },
- { "fontloader-font-def.lua", "49fa2b50d8d2a1bb70b08b72f858ecd0" },
- { "fontloader-font-con.lua", "7575a7b4e6d04816072945e27d7d0b33" },
- { "fontloader-font-cid.lua", "52421d1fdaa07ec4b1d936c6ff5079be" },
- { "fontloader-font-one.lua", "6fbf6b9e219a944cd1ad5933d77cc488" },
- { "fontloader-font-onr.lua", "205c8bc640715aecf3538a33b842f450" },
- { "fontloader-font-afk.lua", "b36a76ceb835f41f8c05b471000ddc14" },
+ { "fontloader-font-tfm.lua", "c9797c1b4ccb8fdb7f041e19207109a2" },
+ { "fontloader-font-afk.lua", "9da14e0fb22129c053acc599d1312544" },
+ { "fontloader-font-one.lua", "52588c7c3aab714d95d03e91ee86e1ad" },
+ { "fontloader-font-onr.lua", "66a0c352b5c36b9974aab1b5026152f2" },
+ { "fontloader-font-otc.lua", "9dcd93d83bc61c90f0fb6161a1911a55" },
+ { "fontloader-font-ocl.lua", "49cf3230228aa7f2d19cd491f55f5395" },
+ { "fontloader-font-osd.lua", "d2b542031aa693bb423b6d3272820c9a" },
+ { "fontloader-font-ots.lua", "624f23e63b7430a51212c8824d09924f" },
+ { "fontloader-font-ota.lua", "d883cf661bb8c27bfa9b7cc66420c1ed" },
+ { "fontloader-font-otj.lua", "578448ae37a167319dbccd5af04738da" },
+ { "fontloader-font-oto.lua", "d78a6165b7ff6c21f4c3c4c3c0553648" },
+ { "fontloader-font-otl.lua", "fcc55ae6cff5fd55b5054f923c21cafa" },
+ { "fontloader-font-oup.lua", "020f2630f5a18d39e209f1cbf7a334ea" },
+ { "fontloader-font-dsp.lua", "9cade9beb226c61b4323729aca1f4a80" },
+ { "fontloader-font-ttf.lua", "ff587471f4297aa8ba0fa022609adc6e" },
+ { "fontloader-font-cff.lua", "eefa156275ba0ac91aa651a944d35978" },
+ { "fontloader-font-ott.lua", "a4dd9bc516bdb7669ee61d5207f899c6" },
+ { "fontloader-font-oti.lua", "309a75f9c14b77d87e94eba827dc4e71" },
+ { "fontloader-font-otr.lua", "4a1dae571a43d7cb8afce7e906df89c6" },
+ { "fontloader-font-vfc.lua", "237aff1862009b7850653c2098473bd4" },
+ { "fontloader-font-map.lua", "2c03dc61afabb5887ef18a88e6ec86bd" },
+ { "fontloader-font-cid.lua", "22b0367742fb253deef84ef7ccf5e8de" },
+ { "fontloader-font-con.lua", "3218bd21a24c2abb13b284085da8ced4" },
+ { "fontloader-font-ini.lua", "6f615d3bc72fb29f409ed2b8f6364c35" },
{ "fontloader-data-con.lua", "d8982c834ed9acc6193eee23067b9d5d" },
- { "fontloader-basics-nod.lua", "9288471b8395bfb683aba0ff3964d950" },
- { "fontloader-reference.lua", "12efa565c640e8583a8fde380dc0e1a0" },
- { "fontloader-basics-gen.lua", "b6c8f256b6c6d3350bf5bad2034857a0" },
- { "mktests", "918cb50be9ee8bd645ac1a27dc501e8c" },
- { "mkstatus", "d66d9237a9e18e64732f239e49e77633" },
- { "mkimport", "a90dbe00a99c7e77494b07fbe0e669af" },
- { "mkglyphlist", "b573c7a7645e5b84e776d7d0bb06c559" },
- { "mkcharacters", "1db01d8172c49c8a405897dc45340917" },
+ { "fontloader-reference.lua", "78d6781759aa7a701282370a9c02bbb5" },
+ { "fontloader-basics-gen.lua", "a1e8c7de52ec6a8afcce3b2105f0d355" },
+ { "mktests", "c7cff7025962922944376acc1ffa9c47" },
+ { "mkstatus", "66bd373bfc704d78084cfe95a6b9c192" },
+ { "mkcharacters", "42bb2bec362979ffdccce9be69acc5fb" },
+ { "mkglyphlist", "2ff6dcdec67b4853c6ad102a16fa8539" },
+ { "mkimport", "2540d1920712e0b3777d0dc0aec52729" },
{ "luaotfload-glyphlist.lua", "bcf89e1441be9f4ad29c0cf3a076bcea" },
- { "luaotfload-characters.lua", "99578c3eff8b68cae3da45a4a7cbfcf2" },
- { "luaotfload-tool.lua", "e6ca512e0620ccaac968ccc17239ee39" },
- { "luaotfload-resolvers.lua", "bcdde7940630c4b563f3884b64ae3c84" },
- { "luaotfload-parsers.lua", "0f40bde1938a5cb72b75fccbbaa43d75" },
- { "luaotfload-main.lua", "8411e662c9867c423dc0229b12eb174c" },
- { "luaotfload-log.lua", "cc79197903756cde068d3c197844be99" },
- { "luaotfload-loaders.lua", "26fef8c4436e02b03deab714716a0948" },
- { "luaotfload-letterspace.lua", "0f4bd9bc0365e96f099e68f4a8114d3e" },
- { "luaotfload-init.lua", "e5c4c96fc7e3bf150229013fb56e77b5" },
- { "luaotfload-features.lua", "dc9dcfb374577b47dafac01e19935050" },
- { "luaotfload-diagnostics.lua", "7b35c9f91e3e73fc5a61dbfe1f0e7ad9" },
- { "luaotfload-database.lua", "62fee5ba6afb4ee38aa1a2b183d59ff8" },
- { "luaotfload-configuration.lua", "64fa81f2f8fe6815f109873fb27f78aa" },
- { "luaotfload-colors.lua", "2582a42a68739087a72e5ea6440cf0d8" },
- { "luaotfload-auxiliary.lua", "a6c092c006660ee6e6fbdcddf104a99b" },
+ { "luaotfload-characters.lua", "910152da2c9ae773c539284ac6cb0a90" },
+ { "luaotfload-resolvers.lua", "6cd52af62c4726ba8fce657376de4579" },
+ { "luaotfload-parsers.lua", "c6e627e3b157fc4004f7c9e715c01822" },
+ { "luaotfload-loaders.lua", "a2bdea2fc644fbc31efec7377312b282" },
+ { "luaotfload-letterspace.lua", "078b211a668ac6943141442b84062354" },
+ { "luaotfload-features.lua", "14041df7943fb33d0d2493b14cf95706" },
+ { "luaotfload-database.lua", "f4ee22158855438aa8a29623552ed82c" },
+ { "luaotfload-configuration.lua", "12e69f5d83340c8fb810c590f16f60cf" },
+ { "luaotfload-colors.lua", "d494389674e7fe39678f4819c7bd0d00" },
+ { "luaotfload-auxiliary.lua", "6788b0f763d759933de8c1d493421210" },
+ { "luaotfload-filelist.lua", "dae5349af86ec3b471f9a57eb6b5631b" },
+ { "luaotfload-tool.lua", "e3cc9e50fb9fc5ce3428c0c8ac72bf25" },
+ { "luaotfload-diagnostics.lua", "1ff35d5ef3adf4e9d92ee3f979672b9c" },
+ { "luaotfload-log.lua", "7b9e8dd90047a06a8840d662f2b63739" },
+ { "luaotfload-init.lua", "63d9efafb1a9f659f7f2cce355022899" },
+ { "luaotfload-main.lua", "c4784393b85fb082a100ffaf100d5e74" },
},
["notes"]={
- ["committer"]="Philipp Gesang <phg@phi-gamma.net>",
- ["description"]="v2.8-fix-2",
- ["loader"]="fontloader-2017-02-11.lua",
- ["revision"]="ad480924393fffa2896156e1a32c22f5c61120dd",
- ["timestamp"]="2017-02-11 00:21:52 +0100",
+ ["committer"]="Ulrike Fischer <fischer@troubleshooting-tex.de>",
+ ["description"]="2.9",
+ ["loader"]="fontloader-2018-09-24.lua",
+ ["revision"]="f9f554b2305fba2bc075b84380321104161e230d",
+ ["timestamp"]="2018-09-25 16:34:44 +0200",
},
} \ No newline at end of file
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
index 45744d15053..312771474f0 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
@@ -1,4 +1,4 @@
-%% Copyright (C) 2009-2017
+%% Copyright (C) 2009-2018
%%
%% by Elie Roux <elie.roux@telecom-bretagne.eu>
%% and Khaled Hosny <khaledhosny@eglug.org>
@@ -8,7 +8,8 @@
%%
%% This file is part of Luaotfload.
%%
-%% Home: https://github.com/lualatex/luaotfload
+%% Home: https://github.com/lualatex/luaotfload
+%%Current home: https://github.com/u-fischer/luaotfload
%% Support: <lualatex-dev@tug.org>.
%%
%% Luaotfload is under the GPL v2.0 (exactly) license.
@@ -41,10 +42,9 @@
\ProvidesPackage{luaotfload}%
%% FIXME The date is meaningless, we need to find a way to
%% use the git revision instead.
- [2017/01/29 v2.8 OpenType layout system]
+ [2018/09/24 v2.9 OpenType layout system]
\fi
\directlua{
require('luaotfload-main')
local _void = luaotfload.main ()
}
-