diff options
author | Karl Berry <karl@freefriends.org> | 2019-05-22 21:17:44 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-05-22 21:17:44 +0000 |
commit | 31de23b1c0c3951f92b39f6456a725219639872e (patch) | |
tree | ad54074f26ea2b12205f3a515552528ae0d564b8 /Master/texmf-dist | |
parent | 33287ebde9b1ee5d46becf889a8e562394db014e (diff) |
luaotfload
git-svn-id: svn://tug.org/texlive/trunk@51190 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
56 files changed, 34777 insertions, 35294 deletions
diff --git a/Master/texmf-dist/doc/luatex/luaotfload/NEWS b/Master/texmf-dist/doc/luatex/luaotfload/NEWS index 7c8085ee562..fea00cad1ef 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/NEWS +++ b/Master/texmf-dist/doc/luatex/luaotfload/NEWS @@ -1,5 +1,12 @@ Change History -------------- +2019-05-18 luaotfload v2.97 + * fix issue #47 + * fix whatsits interfering with letterspacing (issue #53) + * fix luaotfload-tool switches version and find not working correctly (PR#59) + * fix luaotfload-tool support of ttc fonts (PR#58) + * sync with context files from 2019-05-18 (improves handling of large fonts, see e.g. issue #55 and PR#58) + 2019-01-28 luaotfload v2.96 * repaired broken letterspace (issue #38) * changed handling of spaces in letterspacing diff --git a/Master/texmf-dist/doc/luatex/luaotfload/README.md b/Master/texmf-dist/doc/luatex/luaotfload/README.md index 97164c8be48..684ea073010 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/README.md +++ b/Master/texmf-dist/doc/luatex/luaotfload/README.md @@ -1,8 +1,8 @@ # The Luaotfload Package -VERSION: 2.96 +VERSION: 2.97 -DATE: 2019-02-14 +DATE: 2019-05-18 ## Description diff --git a/Master/texmf-dist/doc/luatex/luaotfload/filegraph.pdf b/Master/texmf-dist/doc/luatex/luaotfload/filegraph.pdf Binary files differindex 400ca4408d7..6ee560951be 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/filegraph.pdf +++ b/Master/texmf-dist/doc/luatex/luaotfload/filegraph.pdf diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-conf.pdf b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-conf.pdf Binary files differindex 22342387768..c8e8f2badd2 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-conf.pdf +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-conf.pdf diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-latex.pdf b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-latex.pdf Binary files differindex 6b5628bbfdc..5060318ff40 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-latex.pdf +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-latex.pdf diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-main.tex b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-main.tex index f4a9bf06359..d178b409670 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-main.tex +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-main.tex @@ -32,7 +32,7 @@ \beginfrontmatter \setdocumenttitle {The \identifier{luaotfload} package} - \setdocumentdate {2019-02-14 v2.96} + \setdocumentdate {2019-05-18 v2.97} \setdocumentauthor {Elie Roux · Khaled Hosny · Philipp Gesang · Ulrike Fischer\\ Home: \hyperlink {https://github.com/lualatex/luaotfload}\\ New Home: \hyperlink {https://github.com/u-fischer/luaotfload}\\ @@ -55,6 +55,13 @@ \pdfbookmark[1]{\contentsname}{table} \typesetcontent +\beginsection {New in version 2.97 (by Ulrike Fischer)} +\begin{itemize} +\item the new generic fontloader improves the handling of large fonts (but some fonts still need a 64bit luatex version to create the font files). +\item A number of small bug (also in luaotfload-tool) have been corrected, see the NEWS file for details. + +\end{itemize} +\endsection \beginsection {New in version 2.96 (by Ulrike Fischer)} \begin{itemize} diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.pdf b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.pdf Binary files differindex 3289076c15d..5dae8860093 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.pdf +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.pdf diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.rst b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.rst index 440e8158608..67b5603c588 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.rst +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload-tool.rst @@ -6,9 +6,9 @@ generate and query the Luaotfload font names database ----------------------------------------------------------------------- -:Date: 2019-02-14 +:Date: 2019-05-18 :Copyright: GPL v2.0 -:Version: 2.96 +:Version: 2.97 :Manual section: 1 :Manual group: text processing diff --git a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload.conf.rst b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload.conf.rst index a03b4831508..ad4576305c1 100644 --- a/Master/texmf-dist/doc/luatex/luaotfload/luaotfload.conf.rst +++ b/Master/texmf-dist/doc/luatex/luaotfload/luaotfload.conf.rst @@ -6,9 +6,9 @@ Luaotfload configuration file ----------------------------------------------------------------------- -:Date: 2019-02-14 +:Date: 2019-05-18 :Copyright: GPL v2.0 -:Version: 2.96 +:Version: 2.97 :Manual section: 5 :Manual group: text processing diff --git a/Master/texmf-dist/doc/man/man1/luaotfload-tool.1 b/Master/texmf-dist/doc/man/man1/luaotfload-tool.1 index df30b840a57..5a7407beecf 100644 --- a/Master/texmf-dist/doc/man/man1/luaotfload-tool.1 +++ b/Master/texmf-dist/doc/man/man1/luaotfload-tool.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD-TOOL 1 "2019-02-14" "2.96" "text processing" +.TH LUAOTFLOAD-TOOL 1 "2019-05-18" "2.97" "text processing" .SH NAME luaotfload-tool \- generate and query the Luaotfload font names database . diff --git a/Master/texmf-dist/doc/man/man1/luaotfload-tool.man1.pdf b/Master/texmf-dist/doc/man/man1/luaotfload-tool.man1.pdf Binary files differindex 3a58eb2cd2a..0c24f0481b5 100644 --- a/Master/texmf-dist/doc/man/man1/luaotfload-tool.man1.pdf +++ b/Master/texmf-dist/doc/man/man1/luaotfload-tool.man1.pdf diff --git a/Master/texmf-dist/doc/man/man5/luaotfload.conf.5 b/Master/texmf-dist/doc/man/man5/luaotfload.conf.5 index 67b2e125867..925625fd678 100644 --- a/Master/texmf-dist/doc/man/man5/luaotfload.conf.5 +++ b/Master/texmf-dist/doc/man/man5/luaotfload.conf.5 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH LUAOTFLOAD.CONF 5 "2019-02-14" "2.96" "text processing" +.TH LUAOTFLOAD.CONF 5 "2019-05-18" "2.97" "text processing" .SH NAME luaotfload.conf \- Luaotfload configuration file . diff --git a/Master/texmf-dist/doc/man/man5/luaotfload.conf.man5.pdf b/Master/texmf-dist/doc/man/man5/luaotfload.conf.man5.pdf Binary files differindex 61af4259ad9..27eda7a97ae 100644 --- a/Master/texmf-dist/doc/man/man5/luaotfload.conf.man5.pdf +++ b/Master/texmf-dist/doc/man/man5/luaotfload.conf.man5.pdf diff --git a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua index a7bbf1114c8..039c282cda8 100755 --- a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua +++ b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua @@ -9,8 +9,8 @@ local ProvidesLuaModule = { name = "luaotfload-tool", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload-tool / database functionality", license = "GPL v2.0" } @@ -70,7 +70,7 @@ do local minimum = luaotfload.min_luatex_version local actual = { 0, 0, 0 } if stats then - local major = stats.luatex_version / 100 + local major = stats.luatex_version // 100 local minor = stats.luatex_version % 100 local revision = stats.luatex_revision --[[ : string ]] local revno = tonumber (revision) @@ -152,7 +152,7 @@ require "fontloader-basics-gen.lua" texio.write, texio.write_nl = backup.write, backup.write_nl utilities = backup.utilities -pdf = pdf or { } --- for font-tfm +pdf = pdf or { } --- for fonts-tfm require "fontloader-data-con" require "fontloader-font-ini" @@ -162,6 +162,7 @@ require "fontloader-font-cid" require "fontloader-font-map" require "fontloader-font-oti" require "fontloader-font-otr" +require "fontloader-font-ott" require "fontloader-font-cff" require "fontloader-font-ttf" require "fontloader-font-dsp" @@ -628,7 +629,7 @@ local display_feature_set = function (set) end local display_features_type = function (id, feat) - if next (feat) then + if feat and next (feat) then print_heading(id, 3) display_feature_set(feat) return true @@ -640,10 +641,19 @@ local display_features = function (features) texiowrite_nl "" print_heading("Features", 2) - if not display_features_type ("GSUB Features", features.gsub) - or not display_features_type ("GPOS Features", features.gpos) - then + local status = 0 + if not display_features_type ("GSUB Features", features.gsub) then + status = status + 1 + end + if not display_features_type ("GPOS Features", features.gpos) then + status = status + 2 + end + if status == 3 then texiowrite_nl("font defines neither gsub nor gpos features") + elseif status == 2 then + texiowrite_nl("font defines no gpos feature") + elseif status == 1 then + texiowrite_nl("font defines no gsub feature") end end @@ -1188,8 +1198,8 @@ actions.query = function (job) end elseif tmpspec.lookup == "file" then needle = tmpspec.name - subfont = tmpspec.sub end + subfont = tmpspec.sub if needle then foundname, _, success = fonts.names.lookup_font_file (tmpspec.name) diff --git a/Master/texmf-dist/source/luatex/luaotfload/fontloader-reference-load-order.lua b/Master/texmf-dist/source/luatex/luaotfload/fontloader-reference-load-order.lua index 69908dfccf7..85fe1ae9750 100644 --- a/Master/texmf-dist/source/luatex/luaotfload/fontloader-reference-load-order.lua +++ b/Master/texmf-dist/source/luatex/luaotfload/fontloader-reference-load-order.lua @@ -209,8 +209,8 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then -- A few slightly higher level support modules: - loadmodule("util-str.lua") - loadmodule("util-fil.lua") + loadmodule("util-str.lua") -- future versions can ship without this one + loadmodule("util-fil.lua") -- future versions can ship without this one -- The following modules contain code that is either not used at all -- outside context or will fail when enabled due to lack of other @@ -283,7 +283,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then -- And for traditional TeX fonts. - loadmodule('font-tfm.lua') + loadmodule('luatex-fonts-tfm.lua') -- Some common code. diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2019-02-14.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2019-02-14.lua deleted file mode 100644 index 8d675e10006..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2019-02-14.lua +++ /dev/null @@ -1,33244 +0,0 @@ ---[[info----------------------------------------------------------------------- - Luaotfload fontloader package - build 2019-02-22 23:32:55 -------------------------------------------------------------------------------- - - © 2019 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. - - Report bugs to github.com/u-fischer/luaotfload - - This file has been assembled from components taken from Context. See - the Luaotfload documentation for details: - - $ texdoc luaotfload - $ man 1 luaotfload-tool - $ man 5 luaotfload.conf - - Included files: - - · fontloader-data-con.lua - · fontloader-basics-nod.lua - · fontloader-basics-chr.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-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 - · fontloader-font-oup.lua - · fontloader-font-otl.lua - · fontloader-font-oto.lua - · fontloader-font-otj.lua - · fontloader-font-ota.lua - · fontloader-font-ots.lua - · fontloader-font-osd.lua - · fontloader-font-ocl.lua - · fontloader-font-otc.lua - · fontloader-font-onr.lua - · fontloader-font-one.lua - · fontloader-font-afk.lua - · fontloader-font-tfm.lua - · fontloader-font-lua.lua - · fontloader-font-def.lua - · fontloader-fonts-def.lua - · fontloader-fonts-ext.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-2019-02-22.lua scope for “data-con” 7ce546725b1550f655c78ac9d69419ca] --- - -if not modules then modules={} end modules ['data-con']={ - version=1.100, - 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" -} -local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) -containers=containers or {} -local containers=containers -containers.usecache=true -local report_containers=logs.reporter("resolvers","containers") -local allocated={} -local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end, - __storage__=true -} -function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s - end -end -function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) -end -function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end -end -function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) - if stored and stored.cache_version==container.version then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","load",container.subcategory,name) - end - else - stored=nil - end - storage[name]=stored - elseif stored then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) - end - end - return stored -end -function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","save",container.subcategory,name) - end - data.unique,data.shared=unique,shared - end - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","store",container.subcategory,name) - end - container.storage[name]=data - end - return data -end -function containers.content(container,name) - return container.storage[name] -end -function containers.cleanname(name) - return (gsub(lower(name),"[^%w\128-\255]+","-")) -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “data-con”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “basics-nod” c5185eab8319653452cc5957c787f4be] --- - -if not modules then modules={} end modules ['luatex-fonts-nod']={ - version=1.001, - comment="companion to luatex-fonts.lua", - 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 -if tex.attribute[0]~=0 then - texio.write_nl("log","!") - texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") - texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") - texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.") - texio.write_nl("log","!") - tex.attribute[0]=0 -end -attributes=attributes or {} -attributes.unsetvalue=-0x7FFFFFFF -local numbers,last={},127 -attributes.private=attributes.private or function(name) - local number=numbers[name] - if not number then - if last<255 then - last=last+1 - end - number=last - numbers[name]=number - end - return number -end -nodes={} -nodes.handlers={} -local nodecodes={} -local glyphcodes=node.subtypes("glyph") -local disccodes=node.subtypes("disc") -for k,v in next,node.types() do - v=string.gsub(v,"_","") - nodecodes[k]=v - nodecodes[v]=k -end -for k,v in next,glyphcodes do - glyphcodes[v]=k -end -for k,v in next,disccodes 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 traverse_id=node.traverse_id -nodes.handlers.protectglyphs=node.protect_glyphs -nodes.handlers.unprotectglyphs=node.unprotect_glyphs -function nodes.remove(head,current,free_too) - local t=current - head,current=remove_node(head,current) - if t then - if free_too then - flush_node(t) - t=nil - else - t.next,t.prev=nil,nil - end - end - return head,current,t -end -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end -local getfield=node.getfield -local setfield=node.setfield -nodes.getfield=getfield -nodes.setfield=setfield -nodes.getattr=getfield -nodes.setattr=setfield -nodes.tostring=node.tostring or tostring -nodes.copy=node.copy -nodes.copy_node=node.copy -nodes.copy_list=node.copy_list -nodes.delete=node.delete -nodes.dimensions=node.dimensions -nodes.end_of_math=node.end_of_math -nodes.flush_list=node.flush_list -nodes.flush_node=node.flush_node -nodes.flush=node.flush_node -nodes.free=node.free -nodes.insert_after=node.insert_after -nodes.insert_before=node.insert_before -nodes.hpack=node.hpack -nodes.new=node.new -nodes.tail=node.tail -nodes.traverse=node.traverse -nodes.traverse_id=node.traverse_id -nodes.slide=node.slide -nodes.vpack=node.vpack -nodes.first_glyph=node.first_glyph -nodes.has_glyph=node.has_glyph or node.first_glyph -nodes.current_attr=node.current_attr -nodes.has_field=node.has_field -nodes.last_node=node.last_node -nodes.usedlist=node.usedlist -nodes.protrusion_skippable=node.protrusion_skippable -nodes.write=node.write -nodes.has_attribute=node.has_attribute -nodes.set_attribute=node.set_attribute -nodes.unset_attribute=node.unset_attribute -nodes.protect_glyphs=node.protect_glyphs -nodes.unprotect_glyphs=node.unprotect_glyphs -nodes.mlist_to_hlist=node.mlist_to_hlist -local direct=node.direct -local nuts={} -nodes.nuts=nuts -local tonode=direct.tonode -local tonut=direct.todirect -nodes.tonode=tonode -nodes.tonut=tonut -nuts.tonode=tonode -nuts.tonut=tonut -nuts.getattr=direct.get_attribute -nuts.getboth=direct.getboth -nuts.getchar=direct.getchar -nuts.getcomponents=direct.getcomponents -nuts.getdirection=direct.getdirection -nuts.getdisc=direct.getdisc -nuts.getfield=direct.getfield -nuts.getfont=direct.getfont -nuts.getid=direct.getid -nuts.getkern=direct.getkern -nuts.getlist=direct.getlist -nuts.getnext=direct.getnext -nuts.getoffsets=direct.getoffsets -nuts.getprev=direct.getprev -nuts.getsubtype=direct.getsubtype -nuts.getwidth=direct.getwidth -nuts.setattr=direct.setfield -nuts.setboth=direct.setboth -nuts.setchar=direct.setchar -nuts.setcomponents=direct.setcomponents -nuts.setdir=direct.setdir -nuts.setdirection=direct.setdirection -nuts.setdisc=direct.setdisc -nuts.setfield=setfield -nuts.setkern=direct.setkern -nuts.setlink=direct.setlink -nuts.setlist=direct.setlist -nuts.setnext=direct.setnext -nuts.setoffsets=direct.setoffsets -nuts.setprev=direct.setprev -nuts.setsplit=direct.setsplit -nuts.setsubtype=direct.setsubtype -nuts.setwidth=direct.setwidth -nuts.is_char=direct.is_char -nuts.is_glyph=direct.is_glyph -nuts.ischar=direct.is_char -nuts.isglyph=direct.is_glyph -nuts.copy=direct.copy -nuts.copy_list=direct.copy_list -nuts.copy_node=direct.copy -nuts.delete=direct.delete -nuts.end_of_math=direct.end_of_math -nuts.flush=direct.flush -nuts.flush_list=direct.flush_list -nuts.flush_node=direct.flush_node -nuts.free=direct.free -nuts.insert_after=direct.insert_after -nuts.insert_before=direct.insert_before -nuts.is_node=direct.is_node -nuts.kerning=direct.kerning -nuts.ligaturing=direct.ligaturing -nuts.new=direct.new -nuts.remove=direct.remove -nuts.tail=direct.tail -nuts.traverse=direct.traverse -nuts.traverse_char=direct.traverse_char -nuts.traverse_glyph=direct.traverse_glyph -nuts.traverse_id=direct.traverse_id -if not nuts.getdirection then - local getdir=direct.getdir - function nuts.getdirection(n) - local d=getdir(n) - if d=="TLT" then return 0 - elseif d=="TRT" then return 1 - elseif d=="+TLT" then return 0,false - elseif d=="+TRT" then return 1,false - elseif d=="-TLT" then return 0,true - elseif d=="-TRT" then return 1,true - else return 0 - end - end -end -local propertydata=direct.get_properties_table() -nodes.properties={ data=propertydata } -if direct.set_properties_mode then - direct.set_properties_mode(true,true) - function direct.set_properties_mode() end -end -nuts.getprop=function(n,k) - local p=propertydata[n] - if p then - return p[k] - end -end -nuts.setprop=function(n,k,v) - if v then - local p=propertydata[n] - if p then - p[k]=v - else - propertydata[n]={ [k]=v } - end - end -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.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 -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-2019-02-22.lua scope for “basics-nod”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “basics-chr” a8b8316248b40cc9bc1be19050f7074f] --- - - -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, - [1539]=4, - [1540]=4, - [1541]=4, - [1542]=6, - [1543]=6, - [1544]=4, - [1545]=6, - [1546]=6, - [1547]=4, - [1548]=6, - [1549]=6, - [1550]=6, - [1551]=6, - [1552]=5, - [1553]=5, - [1554]=5, - [1555]=5, - [1556]=5, - [1557]=5, - [1558]=5, - [1559]=5, - [1560]=5, - [1561]=5, - [1562]=5, - [1563]=6, - [1564]=6, - [1566]=6, - [1567]=6, - [1568]=2, - [1569]=4, - [1570]=3, - [1571]=3, - [1572]=3, - [1573]=3, - [1574]=2, - [1575]=3, - [1576]=2, - [1577]=3, - [1578]=2, - [1579]=2, - [1580]=2, - [1581]=2, - [1582]=2, - [1583]=3, - [1584]=3, - [1585]=3, - [1586]=3, - [1587]=2, - [1588]=2, - [1589]=2, - [1590]=2, - [1591]=2, - [1592]=2, - [1593]=2, - [1594]=2, - [1595]=2, - [1596]=2, - [1597]=2, - [1598]=2, - [1599]=2, - [1600]=2, - [1601]=2, - [1602]=2, - [1603]=2, - [1604]=2, - [1605]=2, - [1606]=2, - [1607]=2, - [1608]=3, - [1609]=2, - [1610]=2, - [1611]=5, - [1612]=5, - [1613]=5, - [1614]=5, - [1615]=5, - [1616]=5, - [1617]=5, - [1618]=5, - [1619]=5, - [1620]=5, - [1621]=5, - [1622]=5, - [1623]=5, - [1624]=5, - [1625]=5, - [1626]=5, - [1627]=5, - [1628]=5, - [1629]=5, - [1630]=5, - [1631]=5, - [1632]=6, - [1633]=6, - [1634]=6, - [1635]=6, - [1636]=6, - [1637]=6, - [1638]=6, - [1639]=6, - [1640]=6, - [1641]=6, - [1642]=6, - [1643]=6, - [1644]=6, - [1645]=6, - [1646]=2, - [1647]=2, - [1648]=5, - [1649]=3, - [1650]=3, - [1651]=3, - [1652]=4, - [1653]=3, - [1654]=3, - [1655]=3, - [1656]=2, - [1657]=2, - [1658]=2, - [1659]=2, - [1660]=2, - [1661]=2, - [1662]=2, - [1663]=2, - [1664]=2, - [1665]=2, - [1666]=2, - [1667]=2, - [1668]=2, - [1669]=2, - [1670]=2, - [1671]=2, - [1672]=3, - [1673]=3, - [1674]=3, - [1675]=3, - [1676]=3, - [1677]=3, - [1678]=3, - [1679]=3, - [1680]=3, - [1681]=3, - [1682]=3, - [1683]=3, - [1684]=3, - [1685]=3, - [1686]=3, - [1687]=3, - [1688]=3, - [1689]=3, - [1690]=2, - [1691]=2, - [1692]=2, - [1693]=2, - [1694]=2, - [1695]=2, - [1696]=2, - [1697]=2, - [1698]=2, - [1699]=2, - [1700]=2, - [1701]=2, - [1702]=2, - [1703]=2, - [1704]=2, - [1705]=2, - [1706]=2, - [1707]=2, - [1708]=2, - [1709]=2, - [1710]=2, - [1711]=2, - [1712]=2, - [1713]=2, - [1714]=2, - [1715]=2, - [1716]=2, - [1717]=2, - [1718]=2, - [1719]=2, - [1720]=2, - [1721]=2, - [1722]=2, - [1723]=2, - [1724]=2, - [1725]=2, - [1726]=2, - [1727]=2, - [1728]=3, - [1729]=2, - [1730]=2, - [1731]=3, - [1732]=3, - [1733]=3, - [1734]=3, - [1735]=3, - [1736]=3, - [1737]=3, - [1738]=3, - [1739]=3, - [1740]=2, - [1741]=3, - [1742]=2, - [1743]=3, - [1744]=2, - [1745]=2, - [1746]=3, - [1747]=3, - [1748]=6, - [1749]=3, - [1750]=5, - [1751]=5, - [1752]=5, - [1753]=5, - [1754]=5, - [1755]=5, - [1756]=5, - [1757]=4, - [1758]=6, - [1759]=5, - [1760]=5, - [1761]=5, - [1762]=5, - [1763]=5, - [1764]=5, - [1765]=6, - [1766]=6, - [1767]=5, - [1768]=5, - [1769]=6, - [1770]=5, - [1771]=5, - [1772]=5, - [1773]=5, - [1774]=3, - [1775]=3, - [1776]=6, - [1777]=6, - [1778]=6, - [1779]=6, - [1780]=6, - [1781]=6, - [1782]=6, - [1783]=6, - [1784]=6, - [1785]=6, - [1786]=2, - [1787]=2, - [1788]=2, - [1789]=6, - [1790]=6, - [1791]=2, - [1792]=6, - [1793]=6, - [1794]=6, - [1795]=6, - [1796]=6, - [1797]=6, - [1798]=6, - [1799]=6, - [1800]=6, - [1801]=6, - [1802]=6, - [1803]=6, - [1804]=6, - [1805]=6, - [1807]=6, - [1808]=3, - [1809]=5, - [1810]=2, - [1811]=2, - [1812]=2, - [1813]=3, - [1814]=3, - [1815]=3, - [1816]=3, - [1817]=3, - [1818]=2, - [1819]=2, - [1820]=2, - [1821]=2, - [1822]=3, - [1823]=2, - [1824]=2, - [1825]=2, - [1826]=2, - [1827]=2, - [1828]=2, - [1829]=2, - [1830]=2, - [1831]=2, - [1832]=3, - [1833]=2, - [1834]=3, - [1835]=2, - [1836]=3, - [1837]=2, - [1838]=2, - [1839]=3, - [1840]=5, - [1841]=5, - [1842]=5, - [1843]=5, - [1844]=5, - [1845]=5, - [1846]=5, - [1847]=5, - [1848]=5, - [1849]=5, - [1850]=5, - [1851]=5, - [1852]=5, - [1853]=5, - [1854]=5, - [1855]=5, - [1856]=5, - [1857]=5, - [1858]=5, - [1859]=5, - [1860]=5, - [1861]=5, - [1862]=5, - [1863]=5, - [1864]=5, - [1865]=5, - [1866]=5, - [1869]=3, - [1870]=2, - [1871]=2, - [1872]=2, - [1873]=2, - [1874]=2, - [1875]=2, - [1876]=2, - [1877]=2, - [1878]=2, - [1879]=2, - [1880]=2, - [1881]=3, - [1882]=3, - [1883]=3, - [1884]=2, - [1885]=2, - [1886]=2, - [1887]=2, - [1888]=2, - [1889]=2, - [1890]=2, - [1891]=2, - [1892]=2, - [1893]=2, - [1894]=2, - [1895]=2, - [1896]=2, - [1897]=2, - [1898]=2, - [1899]=3, - [1900]=3, - [1901]=2, - [1902]=2, - [1903]=2, - [1904]=2, - [1905]=3, - [1906]=2, - [1907]=3, - [1908]=3, - [1909]=2, - [1910]=2, - [1911]=2, - [1912]=3, - [1913]=3, - [1914]=2, - [1915]=2, - [1916]=2, - [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, - [1987]=6, - [1988]=6, - [1989]=6, - [1990]=6, - [1991]=6, - [1992]=6, - [1993]=6, - [1994]=2, - [1995]=2, - [1996]=2, - [1997]=2, - [1998]=2, - [1999]=2, - [2000]=2, - [2001]=2, - [2002]=2, - [2003]=2, - [2004]=2, - [2005]=2, - [2006]=2, - [2007]=2, - [2008]=2, - [2009]=2, - [2010]=2, - [2011]=2, - [2012]=2, - [2013]=2, - [2014]=2, - [2015]=2, - [2016]=2, - [2017]=2, - [2018]=2, - [2019]=2, - [2020]=2, - [2021]=2, - [2022]=2, - [2023]=2, - [2024]=2, - [2025]=2, - [2026]=2, - [2027]=5, - [2028]=5, - [2029]=5, - [2030]=5, - [2031]=5, - [2032]=5, - [2033]=5, - [2034]=5, - [2035]=5, - [2036]=6, - [2037]=6, - [2038]=6, - [2039]=6, - [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, - [2115]=2, - [2116]=2, - [2117]=2, - [2118]=3, - [2119]=3, - [2120]=2, - [2121]=3, - [2122]=2, - [2123]=2, - [2124]=2, - [2125]=2, - [2126]=2, - [2127]=2, - [2128]=2, - [2129]=2, - [2130]=2, - [2131]=2, - [2132]=3, - [2133]=2, - [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, - [2211]=2, - [2212]=2, - [2213]=2, - [2214]=2, - [2215]=2, - [2216]=2, - [2217]=2, - [2218]=3, - [2219]=3, - [2220]=3, - [2221]=4, - [2222]=3, - [2223]=2, - [2224]=2, - [2225]=3, - [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, - [6178]=2, - [6179]=2, - [6180]=2, - [6181]=2, - [6182]=2, - [6183]=2, - [6184]=2, - [6185]=2, - [6186]=2, - [6187]=2, - [6188]=2, - [6189]=2, - [6190]=2, - [6191]=2, - [6192]=2, - [6193]=2, - [6194]=2, - [6195]=2, - [6196]=2, - [6197]=2, - [6198]=2, - [6199]=2, - [6200]=2, - [6201]=2, - [6202]=2, - [6203]=2, - [6204]=2, - [6205]=2, - [6206]=2, - [6207]=2, - [6208]=2, - [6209]=2, - [6210]=2, - [6211]=2, - [6212]=2, - [6213]=2, - [6214]=2, - [6215]=2, - [6216]=2, - [6217]=2, - [6218]=2, - [6219]=2, - [6220]=2, - [6221]=2, - [6222]=2, - [6223]=2, - [6224]=2, - [6225]=2, - [6226]=2, - [6227]=2, - [6228]=2, - [6229]=2, - [6230]=2, - [6231]=2, - [6232]=2, - [6233]=2, - [6234]=2, - [6235]=2, - [6236]=2, - [6237]=2, - [6238]=2, - [6239]=2, - [6240]=2, - [6241]=2, - [6242]=2, - [6243]=2, - [6244]=2, - [6245]=2, - [6246]=2, - [6247]=2, - [6248]=2, - [6249]=2, - [6250]=2, - [6251]=2, - [6252]=2, - [6253]=2, - [6254]=2, - [6255]=2, - [6256]=2, - [6257]=2, - [6258]=2, - [6259]=2, - [6260]=2, - [6261]=2, - [6262]=2, - [6263]=2, - [6272]=4, - [6273]=4, - [6274]=4, - [6275]=4, - [6276]=4, - [6279]=2, - [6280]=2, - [6281]=2, - [6282]=2, - [6283]=2, - [6284]=2, - [6285]=2, - [6286]=2, - [6287]=2, - [6288]=2, - [6289]=2, - [6290]=2, - [6291]=2, - [6292]=2, - [6293]=2, - [6294]=2, - [6295]=2, - [6296]=2, - [6297]=2, - [6298]=2, - [6299]=2, - [6300]=2, - [6301]=2, - [6302]=2, - [6303]=2, - [6304]=2, - [6305]=2, - [6306]=2, - [6307]=2, - [6308]=2, - [6309]=2, - [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, - [43075]=2, - [43076]=2, - [43077]=2, - [43078]=2, - [43079]=2, - [43080]=2, - [43081]=2, - [43082]=2, - [43083]=2, - [43084]=2, - [43085]=2, - [43086]=2, - [43087]=2, - [43088]=2, - [43089]=2, - [43090]=2, - [43091]=2, - [43092]=2, - [43093]=2, - [43094]=2, - [43095]=2, - [43096]=2, - [43097]=2, - [43098]=2, - [43099]=2, - [43100]=2, - [43101]=2, - [43102]=2, - [43103]=2, - [43104]=2, - [43105]=2, - [43106]=2, - [43107]=2, - [43108]=2, - [43109]=2, - [43110]=2, - [43111]=2, - [43112]=2, - [43113]=2, - [43114]=2, - [43115]=2, - [43116]=2, - [43117]=2, - [43118]=2, - [43119]=2, - [43120]=2, - [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, - [68291]=2, - [68292]=2, - [68293]=3, - [68294]=4, - [68295]=3, - [68296]=4, - [68297]=3, - [68298]=3, - [68299]=4, - [68300]=4, - [68301]=1, - [68302]=3, - [68303]=3, - [68304]=3, - [68305]=3, - [68306]=3, - [68307]=2, - [68308]=2, - [68309]=2, - [68310]=2, - [68311]=1, - [68312]=2, - [68313]=2, - [68314]=2, - [68315]=2, - [68316]=2, - [68317]=3, - [68318]=2, - [68319]=2, - [68320]=2, - [68321]=3, - [68322]=4, - [68323]=4, - [68324]=3, - [68325]=5, - [68326]=5, - [68331]=2, - [68332]=2, - [68333]=2, - [68334]=2, - [68335]=3, - [68480]=2, - [68481]=3, - [68482]=2, - [68483]=3, - [68484]=3, - [68485]=3, - [68486]=2, - [68487]=2, - [68488]=2, - [68489]=3, - [68490]=2, - [68491]=2, - [68492]=3, - [68493]=2, - [68494]=3, - [68495]=3, - [68496]=2, - [68497]=3, - [68521]=3, - [68522]=3, - [68523]=3, - [68524]=3, - [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 --- [luaotfload, fontloader-2019-02-22.lua scope for “basics-chr”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ini” 4299a02110bbd7c0d27e131235c5319d] --- - -if not modules then modules={} end modules ['font-ini']={ - 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 allocate=utilities.storage.allocate -local sortedhash=table.sortedhash -fonts=fonts or {} -local fonts=fonts -local identifiers=allocate() -fonts.hashes=fonts.hashes or { identifiers=identifiers } -fonts.tables=fonts.tables or {} -fonts.helpers=fonts.helpers or {} -fonts.tracers=fonts.tracers or {} -fonts.specifiers=fonts.specifiers or {} -fonts.analyzers={} -fonts.readers={} -fonts.definers={ methods={} } -fonts.loggers={ register=function() end } -if context then - font.originaleach=font.each - function font.each() - return sortedhash(identifiers) - end - fontloader=nil -end -fonts.privateoffsets={ - textbase=0xF0000, - textextrabase=0xFD000, - mathextrabase=0xFE000, - mathbase=0xFF000, - keepnames=false, -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ini”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-mis” bc9eb43c27f63ce9d0fff67e104fe1c6] --- - -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) -function font.each() - return table.sortedhash(fonts.hashes.identifiers) -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-mis”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-con” ecfc697058b63e508300b6133f97c74c] --- - -if not modules then modules={} end modules ['font-con']={ - 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,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=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") -local fonts=fonts -local constructors=fonts.constructors or {} -fonts.constructors=constructors -local handlers=fonts.handlers or {} -fonts.handlers=handlers -local allocate=utilities.storage.allocate -local setmetatableindex=table.setmetatableindex -constructors.dontembed=allocate() -constructors.autocleanup=true -constructors.namemode="fullpath" -constructors.version=1.01 -constructors.cache=containers.define("fonts","constructors",constructors.version,false) -constructors.privateoffset=fonts.privateoffsets.textbase or 0xF0000 -constructors.cacheintex=true -constructors.addtounicode=true -local designsizes=allocate() -constructors.designsizes=designsizes -local loadedfonts=allocate() -constructors.loadedfonts=loadedfonts -local factors={ - pt=65536.0, - bp=65781.8, -} -function constructors.setfactor(f) - constructors.factor=factors[f or 'pt'] or factors.pt -end -constructors.setfactor() -function constructors.scaled(scaledpoints,designsize) - if scaledpoints<0 then - local factor=constructors.factor - if designsize then - if designsize>factor then - return (- scaledpoints/1000)*designsize - else - return (- scaledpoints/1000)*designsize*factor - end - else - return (- scaledpoints/1000)*10*factor - end - else - 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 - if v.commands then v.commands=nil end - end - end -end -function constructors.calculatescale(tfmdata,scaledpoints) - local parameters=tfmdata.parameters - if scaledpoints<0 then - scaledpoints=(- scaledpoints/1000)*(tfmdata.designsize or parameters.designsize) - end - return scaledpoints,scaledpoints/(parameters.units or 1000) -end -local unscaled={ - ScriptPercentScaleDown=true, - ScriptScriptPercentScaleDown=true, - RadicalDegreeBottomRaisePercent=true, - NoLimitSupFactor=true, - NoLimitSubFactor=true, -} -function constructors.assignmathparameters(target,original) - local mathparameters=original.mathparameters - if mathparameters and next(mathparameters) then - local targetparameters=target.parameters - local targetproperties=target.properties - local targetmathparameters={} - local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor - for name,value in next,mathparameters do - if unscaled[name] then - targetmathparameters[name]=value - else - targetmathparameters[name]=value*factor - end - end - if not targetmathparameters.FractionDelimiterSize then - targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size - end - if not mathparameters.FractionDelimiterDisplayStyleSize then - targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size - end - target.mathparameters=targetmathparameters - end -end -function constructors.beforecopyingcharacters(target,original) -end -function constructors.aftercopyingcharacters(target,original) -end -constructors.sharefonts=false -constructors.nofsharedfonts=0 -local sharednames={} -function constructors.trytosharefont(target,tfmdata) - if constructors.sharefonts then - local characters=target.characters - local n=1 - local t={ target.psname } - local u=sortedkeys(characters) - for i=1,#u do - local k=u[i] - n=n+1;t[n]=k - n=n+1;t[n]=characters[k].index or k - end - local h=md5.HEX(concat(t," ")) - local s=sharednames[h] - if s then - if trace_defining then - report_defining("font %a uses backend resources of font %a",target.fullname,s) - end - target.fullname=s - constructors.nofsharedfonts=constructors.nofsharedfonts+1 - target.properties.sharedwith=s - else - sharednames[h]=target.fullname - 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 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={} - for i=1,#v do - local entry=v[i] - local height=entry.height - local kern=entry.kern - k[i]={ - height=height and vdelta*height or 0, - kern=kern and vdelta*kern or 0, - } - end - return k -end -local psfake=0 -local function fixedpsname(psname,fallback) - local usedname=psname - if psname and psname~="" then - if find(psname," ",1,true) then - usedname=gsub(psname,"[%s]+","-") - else - end - elseif not fallback or fallback=="" then - psfake=psfake+1 - psname="fakename-"..psfake - else - psname=fallback - usedname=gsub(psname,"[^a-zA-Z0-9]+","-") - end - return usedname,psname~=usedname -end -function constructors.scale(tfmdata,specification) - local target={} - if tonumber(specification) then - specification={ size=specification } - end - target.specification=specification - local scaledpoints=specification.size - local relativeid=specification.relativeid - local properties=tfmdata.properties or {} - local goodies=tfmdata.goodies or {} - local resources=tfmdata.resources or {} - local descriptions=tfmdata.descriptions or {} - local characters=tfmdata.characters or {} - local changed=tfmdata.changed or {} - local shared=tfmdata.shared or {} - local parameters=tfmdata.parameters or {} - local mathparameters=tfmdata.mathparameters or {} - local targetcharacters={} - local targetdescriptions=derivetable(descriptions) - local targetparameters=derivetable(parameters) - local targetproperties=derivetable(properties) - local targetgoodies=goodies - target.characters=targetcharacters - target.descriptions=targetdescriptions - target.parameters=targetparameters - target.properties=targetproperties - target.goodies=targetgoodies - target.shared=shared - target.resources=resources - 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 extrafactor=tonumber(specification.factor ) or 1 - if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then - scaledpoints=parameters.scriptpercentage*textsize/100 - elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then - scaledpoints=parameters.scriptscriptpercentage*textsize/100 - elseif forcedsize>1000 then - scaledpoints=forcedsize - else - end - targetparameters.mathsize=mathsize - targetparameters.textsize=textsize - targetparameters.forcedsize=forcedsize - targetparameters.extrafactor=extrafactor - local addtounicode=constructors.addtounicode - local tounicode=fonts.mappings.tounicode - local unknowncode=tounicode(0xFFFD) - local defaultwidth=resources.defaultwidth or 0 - local defaultheight=resources.defaultheight or 0 - local defaultdepth=resources.defaultdepth or 0 - local units=parameters.units or 1000 - targetproperties.language=properties.language or "dflt" - targetproperties.script=properties.script or "dflt" - targetproperties.mode=properties.mode or "base" - local askedscaledpoints=scaledpoints - local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification) - local hdelta=delta - local vdelta=delta - target.designsize=parameters.designsize - target.units=units - target.units_per_em=units - local direction=properties.direction or tfmdata.direction or 0 - target.direction=direction - properties.direction=direction - target.size=scaledpoints - target.encodingbytes=properties.encodingbytes or 1 - target.embedding=properties.embedding or "subset" - target.tounicode=1 - target.cidinfo=properties.cidinfo - target.format=properties.format - target.cache=constructors.cacheintex and "yes" or "renew" - local fontname=properties.fontname or tfmdata.fontname - local fullname=properties.fullname or tfmdata.fullname - local filename=properties.filename or tfmdata.filename - local psname=properties.psname or tfmdata.psname - local name=properties.name or tfmdata.name - local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename)) - target.fontname=fontname - target.fullname=fullname - target.filename=filename - target.psname=psname - target.name=name - properties.fontname=fontname - properties.fullname=fullname - properties.filename=filename - properties.psname=psname - properties.name=name - local expansion=parameters.expansion - if expansion then - target.stretch=expansion.stretch - target.shrink=expansion.shrink - target.step=expansion.step - end - 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 - else - target.extend=1000 - end - local squeezefactor=parameters.squeezefactor or 0 - if squeezefactor~=0 and squeezefactor~=1 then - vdelta=vdelta*squeezefactor - target.squeeze=squeezefactor*1000 - else - 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 - targetparameters.vfactor=vdelta - 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=parameters.expansion or parameters.protrusion - local hasitalics=properties.hasitalics - local autoitalicamount=properties.autoitalicamount - local stackmath=not properties.nostackmath - local nonames=properties.noglyphnames - local haskerns=properties.haskerns or properties.mode=="base" - local hasligatures=properties.hasligatures or properties.mode=="base" - 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 - target.type=isvirtual and "virtual" or "real" - target.writingmode=writingmode=="vertical" and "vertical" or "horizontal" - target.identity=identity=="vertical" and "vertical" or "horizontal" - target.postprocessors=tfmdata.postprocessors - local targetslant=(parameters.slant or parameters[1] or 0)*factors.pt - local targetspace=(parameters.space or parameters[2] or 0)*hdelta - local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta - local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta - local targetx_height=(parameters.x_height or parameters[5] or 0)*vdelta - local targetquad=(parameters.quad or parameters[6] or 0)*hdelta - local targetextra_space=(parameters.extra_space or parameters[7] or 0)*hdelta - targetparameters.slant=targetslant - targetparameters.space=targetspace - targetparameters.space_stretch=targetspace_stretch - targetparameters.space_shrink=targetspace_shrink - targetparameters.x_height=targetx_height - targetparameters.quad=targetquad - targetparameters.extra_space=targetextra_space - local ascender=parameters.ascender - if ascender then - targetparameters.ascender=delta*ascender - end - local descender=parameters.descender - if descender then - targetparameters.descender=delta*descender - end - constructors.enhanceparameters(targetparameters) - local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0 - local scaledwidth=defaultwidth*hdelta - local scaledheight=defaultheight*vdelta - local scaleddepth=defaultdepth*vdelta - local hasmath=(properties.hasmath or next(mathparameters)) and true - if hasmath then - constructors.assignmathparameters(target,tfmdata) - properties.hasmath=true - target.nomath=false - target.MathConstants=target.mathparameters - else - properties.hasmath=false - target.nomath=true - target.mathparameters=nil - end - if hasmath then - local mathitalics=properties.mathitalics - if mathitalics==false then - if trace_defining then - report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename) - end - hasitalics=false - autoitalicamount=false - end - else - local textitalics=properties.textitalics - if textitalics==false then - if trace_defining then - report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename) - end - hasitalics=false - autoitalicamount=false - end - end - if trace_defining then - report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a", - name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta, - hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") - end - constructors.beforecopyingcharacters(target,tfmdata) - local sharedkerns={} - for unicode,character in next,characters do - local chr,description,index - if changed then - local c=changed[unicode] - 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 - end - else - description=descriptions[unicode] or character - index=description.index or unicode - end - local width=description.width - local height=description.height - local depth=description.depth - if realdimensions then - if not height or height==0 then - local bb=description.boundingbox - local ht=bb[4] - if ht~=0 then - height=ht - end - if not depth or depth==0 then - local dp=-bb[2] - if dp~=0 then - depth=dp - end - end - elseif not depth or depth==0 then - local dp=-description.boundingbox[2] - if dp~=0 then - depth=dp - end - end - end - if width then width=hdelta*width else width=scaledwidth end - if height then height=vdelta*height else height=scaledheight end - if depth and depth~=0 then - depth=delta*depth - if nonames then - chr={ - index=index, - height=height, - depth=depth, - width=width, - } - else - chr={ - name=description.name, - index=index, - height=height, - depth=depth, - width=width, - } - end - else - if nonames then - chr={ - index=index, - height=height, - width=width, - } - else - chr={ - name=description.name, - index=index, - height=height, - width=width, - } - end - end - local isunicode=description.unicode - if addtounicode then - if isunicode then - chr.unicode=isunicode - chr.tounicode=tounicode(isunicode) - else - chr.tounicode=unknowncode - end - else - if isunicode then - chr.unicode=isunicode - end - end - if hasquality then - local ve=character.expansion_factor - if ve then - chr.expansion_factor=ve*1000 - end - local vl=character.left_protruding - if vl then - chr.left_protruding=protrusionfactor*width*vl - end - local vr=character.right_protruding - if vr then - chr.right_protruding=protrusionfactor*width*vr - end - end - if hasmath then - local vn=character.next - if vn then - chr.next=vn - else - local vv=character.vert_variants - if vv then - local t={} - for i=1,#vv do - local vvi=vv[i] - 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"], - } - end - chr.vert_variants=t - else - local hv=character.horiz_variants - if hv then - local t={} - for i=1,#hv do - local hvi=hv[i] - 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"], - } - end - chr.horiz_variants=t - end - end - end - local vi=character.vert_italic - if vi and vi~=0 then - chr.vert_italic=vi*hdelta - end - local va=character.accent - if va then - chr.top_accent=vdelta*va - end - if stackmath then - local mk=character.mathkerns - if mk then - local tr,tl,br,bl=mk.topright,mk.topleft,mk.bottomright,mk.bottomleft - chr.mathkern={ - top_right=tr and mathkerns(tr,vdelta) or nil, - top_left=tl and mathkerns(tl,vdelta) or nil, - bottom_right=br and mathkerns(br,vdelta) or nil, - bottom_left=bl and mathkerns(bl,vdelta) or nil, - } - end - end - if hasitalics then - local vi=character.italic - if vi and vi~=0 then - chr.italic=vi*hdelta - end - end - elseif autoitalicamount then - local vi=description.italic - if not vi then - local bb=description.boundingbox - if bb then - local vi=bb[3]-description.width+autoitalicamount - if vi>0 then - chr.italic=vi*hdelta - end - else - end - elseif vi~=0 then - chr.italic=vi*hdelta - end - elseif hasitalics then - local vi=character.italic - if vi and vi~=0 then - chr.italic=vi*hdelta - end - end - if haskerns then - local vk=character.kerns - if vk then - local s=sharedkerns[vk] - if not s then - s={} - for k,v in next,vk do s[k]=v*hdelta end - sharedkerns[vk]=s - end - chr.kerns=s - end - end - if hasligatures then - local vl=character.ligatures - if vl then - if true then - chr.ligatures=vl - else - local tt={} - for i,l in next,vl do - tt[i]=l - end - chr.ligatures=tt - end - end - end - if isvirtual then - local vc=character.commands - if vc then - local ok=false - for i=1,#vc do - local key=vc[i][1] - if key=="right" or key=="down" or key=="rule" then - ok=true - break - end - end - if ok then - local tt={} - for i=1,#vc do - local ivc=vc[i] - local key=ivc[1] - if key=="right" then - tt[i]={ key,ivc[2]*hdelta } - elseif key=="down" then - tt[i]={ key,ivc[2]*vdelta } - elseif key=="rule" then - tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta } - else - tt[i]=ivc - end - end - chr.commands=tt - else - chr.commands=vc - end - end - end - targetcharacters[unicode]=chr - end - 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) - if tfmdata.properties and tfmdata.properties.finalized then - return - end - if not tfmdata.characters then - return nil - end - if not tfmdata.goodies then - tfmdata.goodies={} - end - local parameters=tfmdata.parameters - if not parameters then - return nil - end - if not parameters.expansion then - parameters.expansion={ - 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.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 - parameters.maxsize=tfmdata.maxsize or designsize - else - designsize=factors.pt*10 - parameters.designsize=designsize - parameters.minsize=designsize - parameters.maxsize=designsize - end - parameters.minsize=tfmdata.minsize or parameters.designsize - parameters.maxsize=tfmdata.maxsize or parameters.designsize - if not parameters.units then - parameters.units=tfmdata.units or tfmdata.units_per_em or 1000 - end - if not tfmdata.descriptions then - local descriptions={} - setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end) - tfmdata.descriptions=descriptions - end - local properties=tfmdata.properties - if not properties then - properties={} - tfmdata.properties=properties - end - if not properties.virtualized then - properties.virtualized=tfmdata.type=="virtual" - end - properties.fontname=tfmdata.fontname - properties.filename=tfmdata.filename - properties.fullname=tfmdata.fullname - properties.name=tfmdata.name - properties.psname=tfmdata.psname - properties.encodingbytes=tfmdata.encodingbytes or 1 - properties.embedding=tfmdata.embedding or "subset" - properties.tounicode=tfmdata.tounicode or 1 - properties.cidinfo=tfmdata.cidinfo or nil - properties.format=tfmdata.format or "type1" - properties.direction=tfmdata.direction or 0 - properties.writingmode=tfmdata.writingmode or "horizontal" - properties.identity=tfmdata.identity or "horizontal" - properties.usedbitmap=tfmdata.usedbitmap - if not tfmdata.resources then - tfmdata.resources={} - end - if not tfmdata.shared then - tfmdata.shared={} - end - if not properties.hasmath then - properties.hasmath=not tfmdata.nomath - end - tfmdata.MathConstants=nil - tfmdata.postprocessors=nil - tfmdata.fontname=nil - tfmdata.filename=nil - tfmdata.fullname=nil - tfmdata.name=nil - tfmdata.psname=nil - tfmdata.encodingbytes=nil - tfmdata.embedding=nil - tfmdata.tounicode=nil - tfmdata.cidinfo=nil - tfmdata.format=nil - tfmdata.direction=nil - tfmdata.type=nil - tfmdata.nomath=nil - tfmdata.designsize=nil - tfmdata.size=nil - tfmdata.stretch=nil - tfmdata.shrink=nil - tfmdata.step=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 - properties.finalized=true - return tfmdata -end -local hashmethods={} -constructors.hashmethods=hashmethods -function constructors.hashfeatures(specification) - local features=specification.features - if features then - 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 - n=n+1 - t[n]=category..":"..hash - end - end - end - end - 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 - elseif k=="number" or k=="features" then - else - n=n+1 - 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 - sort(s) - return concat(s,"+") - end -end -function constructors.hashinstance(specification,force) - local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks - if force or not hash then - hash=constructors.hashfeatures(specification) - specification.hash=hash - end - if size<1000 and designsizes[hash] then - size=round(constructors.scaled(size,designsizes[hash])) - else - size=round(size) - end - specification.size=size - if fallbacks then - return hash..' @ '..size..' @ '..fallbacks - else - return hash..' @ '..size - end -end -function constructors.setname(tfmdata,specification) - if constructors.namemode=="specification" then - local specname=specification.specification - if specname then - tfmdata.properties.name=specname - if trace_defining then - report_otf("overloaded fontname %a",specname) - end - end - end -end -function constructors.checkedfilename(data) - local foundfilename=data.foundfilename - if not foundfilename then - local askedfilename=data.filename or "" - if askedfilename~="" then - askedfilename=resolvers.resolve(askedfilename) - foundfilename=resolvers.findbinfile(askedfilename,"") or "" - if foundfilename=="" then - report_defining("source file %a is not found",askedfilename) - foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or "" - if foundfilename~="" then - report_defining("using source file %a due to cache mismatch",foundfilename) - end - end - end - data.foundfilename=foundfilename - end - return foundfilename -end -local formats=allocate() -fonts.formats=formats -setmetatableindex(formats,function(t,k) - local l=lower(k) - if rawget(t,k) then - t[k]=l - return l - end - return rawget(t,file.suffix(l)) -end) -do - local function setindeed(mode,source,target,group,name,position) - local action=source[mode] - if not action then - return - end - local t=target[mode] - if not t then - report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode) - os.exit() - elseif position then - insert(t,position,{ name=name,action=action }) - else - for i=1,#t do - local ti=t[i] - if ti.name==name then - ti.action=action - return - end - end - insert(t,{ name=name,action=action }) - end - end - local function set(group,name,target,source) - target=target[group] - if not target then - report_defining("fatal target error in setting feature %a, group %a",name,group) - os.exit() - end - local source=source[group] - if not source then - report_defining("fatal source error in setting feature %a, group %a",name,group) - os.exit() - end - local position=source.position - setindeed("node",source,target,group,name,position) - setindeed("base",source,target,group,name,position) - setindeed("plug",source,target,group,name,position) - end - local function register(where,specification) - local name=specification.name - if name and name~="" then - local default=specification.default - local description=specification.description - local initializers=specification.initializers - local processors=specification.processors - local manipulators=specification.manipulators - local modechecker=specification.modechecker - if default then - where.defaults[name]=default - end - if description and description~="" then - where.descriptions[name]=description - end - if initializers then - set('initializers',name,where,specification) - end - if processors then - set('processors',name,where,specification) - end - if manipulators then - set('manipulators',name,where,specification) - end - if modechecker then - where.modechecker=modechecker - end - end - end - constructors.registerfeature=register - function constructors.getfeatureaction(what,where,mode,name) - what=handlers[what].features - if what then - where=what[where] - if where then - mode=where[mode] - if mode then - for i=1,#mode do - local m=mode[i] - if m.name==name then - return m.action - end - end - end - end - end - end - local newfeatures={} - constructors.newfeatures=newfeatures - constructors.features=newfeatures - local function setnewfeatures(what) - local handler=handlers[what] - local features=handler.features - if not features then - local tables=handler.tables - local statistics=handler.statistics - features=allocate { - defaults={}, - descriptions=tables and tables.features or {}, - used=statistics and statistics.usedfeatures or {}, - initializers={ base={},node={},plug={} }, - processors={ base={},node={},plug={} }, - manipulators={ base={},node={},plug={} }, - } - features.register=function(specification) return register(features,specification) end - handler.features=features - end - return features - end - setmetatable(newfeatures,{ - __call=function(t,k) local v=t[k] return v end, - __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end, - }) -end -do - local newhandler={} - constructors.handlers=newhandler - constructors.newhandler=newhandler - local function setnewhandler(what) - local handler=handlers[what] - if not handler then - handler={} - handlers[what]=handler - end - return handler - end - setmetatable(newhandler,{ - __call=function(t,k) local v=t[k] return v end, - __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end, - }) -end -do - local newenhancer={} - constructors.enhancers=newenhancer - constructors.newenhancer=newenhancer - local function setnewenhancer(format) - local handler=handlers[format] - local enhancers=handler.enhancers - if not enhancers then - 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") - trackers.register(format..".loading",function(v) trace=v end) - local function enhance(name,data,filename,raw) - local enhancer=actions[name] - if enhancer then - if trace then - report("apply enhancement %a to file %a",name,filename) - ioflush() - end - enhancer(data,filename,raw) - else - end - end - local function apply(data,filename,raw) - local basename=file.basename(lower(filename)) - if trace then - report("%s enhancing file %a","start",filename) - end - ioflush() - for e=1,nofsteps do - local enhancer=order[e] - local b=before[enhancer] - if b then - for pattern,action in next,b do - if find(basename,pattern) then - action(data,filename,raw) - end - end - end - enhance(enhancer,data,filename,raw) - local a=after[enhancer] - if a then - for pattern,action in next,a do - if find(basename,pattern) then - action(data,filename,raw) - end - end - end - ioflush() - end - if trace then - report("%s enhancing file %a","stop",filename) - end - ioflush() - end - local function register(what,action) - if action then - if actions[what] then - else - nofsteps=nofsteps+1 - order[nofsteps]=what - known[what]=nofsteps - end - actions[what]=action - else - report("bad enhancer %a",what) - end - end - local function patch(what,where,pattern,action) - local pw=patches[what] - if pw then - local ww=pw[where] - if ww then - ww[pattern]=action - else - pw[where]={ [pattern]=action } - if not known[where] then - nofsteps=nofsteps+1 - order[nofsteps]=where - known[where]=nofsteps - end - end - end - end - enhancers={ - register=register, - apply=apply, - patch=patch, - report=report, - patches={ - register=patch, - report=report, - }, - } - handler.enhancers=enhancers - end - return enhancers - end - setmetatable(newenhancer,{ - __call=function(t,k) local v=t[k] return v end, - __index=function(t,k) local v=setnewenhancer(k) t[k]=v return v end, - }) -end -function constructors.checkedfeatures(what,features) - local defaults=handlers[what].features.defaults - if features and next(features) then - features=fastcopy(features) - for key,value in next,defaults do - if features[key]==nil then - features[key]=value - end - end - return features - else - return fastcopy(defaults) - end -end -function constructors.initializefeatures(what,tfmdata,features,trace,report) - if features and next(features) then - local properties=tfmdata.properties or {} - local whathandler=handlers[what] - local whatfeatures=whathandler.features - local whatmodechecker=whatfeatures.modechecker - local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base" - properties.mode=mode - features.mode=mode - local done={} - while true do - local redo=false - local initializers=whatfeatures.initializers[mode] - if initializers then - for i=1,#initializers do - local step=initializers[i] - local feature=step.name - local value=features[feature] - if not value then - elseif done[feature] then - else - local action=step.action - if trace then - report("initializing feature %a to %a for mode %a for font %a",feature, - value,mode,tfmdata.properties.fullname) - end - action(tfmdata,value,features) - if mode~=properties.mode or mode~=features.mode then - if whatmodechecker then - properties.mode=whatmodechecker(tfmdata,features,properties.mode) - features.mode=properties.mode - end - if mode~=properties.mode then - mode=properties.mode - redo=true - end - end - done[feature]=true - end - if redo then - break - end - end - if not redo then - break - end - else - break - end - end - properties.mode=mode - return true - else - return false - end -end -function constructors.collectprocessors(what,tfmdata,features,trace,report) - local processes,nofprocesses={},0 - if features and next(features) then - local properties=tfmdata.properties - local whathandler=handlers[what] - local whatfeatures=whathandler.features - local whatprocessors=whatfeatures.processors - local mode=properties.mode - local processors=whatprocessors[mode] - if processors then - for i=1,#processors do - local step=processors[i] - local feature=step.name - if features[feature] then - local action=step.action - if trace then - report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) - end - if action then - nofprocesses=nofprocesses+1 - processes[nofprocesses]=action - end - end - end - elseif trace then - report("no feature processors for mode %a for font %a",mode,properties.fullname) - end - end - return processes -end -function constructors.applymanipulators(what,tfmdata,features,trace,report) - if features and next(features) then - local properties=tfmdata.properties - local whathandler=handlers[what] - local whatfeatures=whathandler.features - local whatmanipulators=whatfeatures.manipulators - local mode=properties.mode - local manipulators=whatmanipulators[mode] - if manipulators then - for i=1,#manipulators do - local step=manipulators[i] - local feature=step.name - local value=features[feature] - if value then - local action=step.action - if trace then - report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname) - end - if action then - action(tfmdata,feature,value) - end - end - end - end - end -end -function constructors.addcoreunicodes(unicodes) - if not unicodes then - unicodes={} - end - unicodes.space=0x0020 - unicodes.hyphen=0x002D - unicodes.zwj=0x200D - unicodes.zwnj=0x200C - return unicodes -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-con”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-enc” 3e71a54297e8f85a1ac438bb0f20dd79] --- - -if not modules then modules={} end modules ['luatex-font-enc']={ - 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 -local encodings={} -fonts.encodings=encodings -encodings.agl={} -encodings.known={} -setmetatable(encodings.agl,{ __index=function(t,k) - if k=="unicodes" then - logs.report("fonts","loading (extended) adobe glyph list") - local unicodes=dofile(resolvers.findfile("font-age.lua")) - encodings.agl={ unicodes=unicodes } - return unicodes - else - return nil - end -end }) -encodings.cache=containers.define("fonts","enc",encodings.version,true) -function encodings.load(filename) - local name=file.removesuffix(filename) - local data=containers.read(encodings.cache,name) - if data then - return data - end - local vector,tag,hash,unicodes={},"",{},{} - local foundname=resolvers.findfile(filename,'enc') - if foundname and foundname~="" then - local ok,encoding,size=resolvers.loadbinfile(foundname) - if ok and encoding then - encoding=string.gsub(encoding,"%%(.-)\n","") - local unicoding=encodings.agl.unicodes - local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def") - local i=0 - for ch in string.gmatch(vec,"/([%a%d%.]+)") do - if ch~=".notdef" then - vector[i]=ch - if not hash[ch] then - hash[ch]=i - else - end - local u=unicoding[ch] - if u then - unicodes[u]=i - end - end - i=i+1 - end - end - end - local data={ - name=name, - tag=tag, - vector=vector, - hash=hash, - unicodes=unicodes - } - return containers.write(encodings.cache,name,data) -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-enc”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-cid” 4d87988efa86020a14708ee03c23415f] --- - -if not modules then modules={} end modules ['font-cid']={ - 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 format,match,lower=string.format,string.match,string.lower -local tonumber=tonumber -local P,S,R,C,V,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.match -local fonts,logs,trackers=fonts,logs,trackers -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -local report_otf=logs.reporter("fonts","otf loading") -local cid={} -fonts.cid=cid -local cidmap={} -local cidmax=10 -local number=C(R("09","af","AF")^1) -local space=S(" \n\r\t") -local spaces=space^0 -local period=P(".") -local periods=period*period -local name=P("/")*C((1-space)^1) -local unicodes,names={},{} -local function do_one(a,b) - unicodes[tonumber(a)]=tonumber(b,16) -end -local function do_range(a,b,c) - c=tonumber(c,16) - for i=tonumber(a),tonumber(b) do - unicodes[i]=c - c=c+1 - end -end -local function do_name(a,b) - names[tonumber(a)]=b -end -local grammar=P { "start", - start=number*spaces*number*V("series"), - series=(spaces*(V("one")+V("range")+V("named")))^1, - one=(number*spaces*number)/do_one, - range=(number*periods*number*spaces*number)/do_range, - named=(number*spaces*name)/do_name -} -local function loadcidfile(filename) - local data=io.loaddata(filename) - if data then - unicodes,names={},{} - lpegmatch(grammar,data) - local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$") - return { - supplement=supplement, - registry=registry, - ordering=ordering, - filename=filename, - unicodes=unicodes, - names=names, - } - end -end -cid.loadfile=loadcidfile -local template="%s-%s-%s.cidmap" -local function locate(registry,ordering,supplement) - local filename=format(template,registry,ordering,supplement) - local hashname=lower(filename) - local found=cidmap[hashname] - if not found then - if trace_loading then - report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename) - end - local fullname=resolvers.findfile(filename,'cid') or "" - if fullname~="" then - found=loadcidfile(fullname) - if found then - if trace_loading then - report_otf("using cidmap file %a",filename) - end - cidmap[hashname]=found - found.usedname=file.basename(filename) - end - end - end - return found -end -function cid.getmap(specification) - if not specification then - report_otf("invalid cidinfo specification, table expected") - return - end - local registry=specification.registry - local ordering=specification.ordering - local supplement=specification.supplement - local filename=format(registry,ordering,supplement) - local lowername=lower(filename) - local found=cidmap[lowername] - if found then - return found - end - if ordering=="Identity" then - local found={ - supplement=supplement, - registry=registry, - ordering=ordering, - filename=filename, - unicodes={}, - names={}, - } - cidmap[lowername]=found - return found - end - if trace_loading then - report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement) - end - found=locate(registry,ordering,supplement) - if not found then - local supnum=tonumber(supplement) - local cidnum=nil - if supnum<cidmax then - for s=supnum+1,cidmax do - local c=locate(registry,ordering,s) - if c then - found,cidnum=c,s - break - end - end - end - if not found and supnum>0 then - for s=supnum-1,0,-1 do - local c=locate(registry,ordering,s) - if c then - found,cidnum=c,s - break - end - end - end - registry=lower(registry) - ordering=lower(ordering) - if found and cidnum>0 then - for s=0,cidnum-1 do - local filename=format(template,registry,ordering,s) - if not cidmap[filename] then - cidmap[filename]=found - end - end - end - end - return found -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-cid”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-map” 210b9288eef0df624da638b65d27291b] --- - -if not modules then modules={} end modules ['font-map']={ - 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 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 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 force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end) -local fonts=fonts or {} -local mappings=fonts.mappings or {} -fonts.mappings=mappings -local allocate=utilities.storage.allocate -local hex=R("AF","af","09") -local hexfour=(hex*hex*hex^-2)/function(s) return tonumber(s,16) end -local hexsix=(hex*hex*hex^-4)/function(s) return tonumber(s,16) end -local dec=(R("09")^1)/tonumber -local period=P(".") -local unicode=(P("uni")+P("UNI"))*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) -local ucode=(P("u")+P("U") )*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) -local index=P("index")*dec*Cc(false) -local parser=unicode+ucode+index -local parsers={} -local function makenameparser(str) - if not str or str=="" then - return parser - else - local p=parsers[str] - if not p then - p=P(str)*period*dec*Cc(false) - parsers[str]=p - end - return p - end -end -local f_single=formatters["%04X"] -local f_double=formatters["%04X%04X"] -local function tounicode16(unicode) - 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 -local function tounicode16sequence(unicodes) - local t={} - for l=1,#unicodes do - local u=unicodes[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) -end -local unknown=f_single(0xFFFD) -local hash={} -local conc={} -table.setmetatableindex(hash,function(t,k) - if k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then - v=f_single(k) - else - local k=k-0x10000 - v=f_double(rshift(k,10)+0xD800,k%1024+0xDC00) - end - t[k]=v - return v -end) -local function tounicode(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) - elseif k>=0x00E000 and k<=0x00F8FF then - return unknown - elseif k>=0x0F0000 and k<=0x0FFFFF then - return unknown - elseif k>=0x100000 and k<=0x10FFFF then - return unknown - else - return hash[k] - end -end -local function fromunicode16(str) - if #str==4 then - return tonumber(str,16) - else - local l,r=match(str,"(....)(....)") - return 0x10000+(tonumber(l,16)-0xD800)*0x400+tonumber(r,16)-0xDC00 - end -end -mappings.makenameparser=makenameparser -mappings.tounicode=tounicode -mappings.tounicode16=tounicode16 -mappings.tounicode16sequence=tounicode16sequence -mappings.fromunicode16=fromunicode16 -local ligseparator=P("_") -local varseparator=P(".") -local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0) -do - 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 }, - fi={ name="f_i",unicode={ 0x66,0x69 },mess=0xFB01 }, - fl={ name="f_l",unicode={ 0x66,0x6C },mess=0xFB02 }, - ffi={ name="f_f_i",unicode={ 0x66,0x66,0x69 },mess=0xFB03 }, - 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 } }, - } - local o=allocate {} - for k,v in next,overloads do - local name=v.name - local mess=v.mess - if name then - o[name]=v - end - if mess then - o[mess]=v - end - o[k]=v - end - mappings.overloads=o -end -function mappings.addtounicode(data,filename,checklookups,forceligatures) - local resources=data.resources - local unicodes=resources.unicodes - if not unicodes then - if trace_mapping then - report_fonts("no unicode list, quitting tounicode for %a",filename) - end - return - end - local properties=data.properties - local descriptions=data.descriptions - local overloads=mappings.overloads - unicodes['space']=unicodes['space'] or 32 - unicodes['hyphen']=unicodes['hyphen'] or 45 - unicodes['zwj']=unicodes['zwj'] or 0x200D - unicodes['zwnj']=unicodes['zwnj'] or 0x200C - local private=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 - local unicodevector=fonts.encodings.agl.unicodes or {} - local contextvector=fonts.encodings.agl.ctxcodes or {} - local missing={} - local nofmissing=0 - local oparser=nil - local cidnames=nil - local cidcodes=nil - local cidinfo=properties.cidinfo - local usedmap=cidinfo and fonts.cid.getmap(cidinfo) - local uparser=makenameparser() - if usedmap then - oparser=usedmap and makenameparser(cidinfo.ordering) - cidnames=usedmap.names - cidcodes=usedmap.unicodes - end - local ns=0 - local nl=0 - local dlist=sortedkeys(descriptions) - for i=1,#dlist do - local du=dlist[i] - local glyph=descriptions[du] - local name=glyph.name - if name then - local overload=overloads[name] or overloads[du] - if overload then - glyph.unicode=overload.unicode - else - local gu=glyph.unicode - if not gu or gu==-1 or du>=private or (du>=0xE000 and du<=0xF8FF) or du==0xFFFE or du==0xFFFF then - local unicode=unicodevector[name] or contextvector[name] - if unicode then - glyph.unicode=unicode - ns=ns+1 - end - if (not unicode) and usedmap then - local foundindex=lpegmatch(oparser,name) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - glyph.unicode=unicode - ns=ns+1 - else - local reference=cidnames[foundindex] - if reference then - local foundindex=lpegmatch(oparser,reference) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - glyph.unicode=unicode - ns=ns+1 - end - end - if not unicode or unicode=="" then - local foundcodes,multiple=lpegmatch(uparser,reference) - if foundcodes then - glyph.unicode=foundcodes - if multiple then - nl=nl+1 - unicode=true - else - ns=ns+1 - unicode=foundcodes - end - end - end - end - end - end - end - if not unicode or unicode=="" then - local split=lpegmatch(namesplitter,name) - local nsplit=split and #split or 0 - if nsplit==0 then - elseif nsplit==1 then - local base=split[1] - local u=unicodes[base] or unicodevector[base] or contextvector[name] - if not u then - elseif type(u)=="table" then - if u[1]<private then - unicode=u - glyph.unicode=unicode - end - elseif u<private then - unicode=u - glyph.unicode=unicode - end - else - local t,n={},0 - for l=1,nsplit do - local base=split[l] - local u=unicodes[base] or unicodevector[base] or contextvector[name] - if not u then - break - elseif type(u)=="table" then - if u[1]>=private then - break - end - n=n+1 - t[n]=u[1] - else - if u>=private then - break - end - n=n+1 - t[n]=u - end - end - if n>0 then - if n==1 then - unicode=t[1] - else - unicode=t - end - glyph.unicode=unicode - end - end - nl=nl+1 - end - if not unicode or unicode=="" then - local foundcodes,multiple=lpegmatch(uparser,name) - if foundcodes then - glyph.unicode=foundcodes - if multiple then - nl=nl+1 - unicode=true - else - ns=ns+1 - unicode=foundcodes - end - end - end - local r=overloads[unicode] - if r then - unicode=r.unicode - glyph.unicode=unicode - end - if not unicode then - missing[du]=true - nofmissing=nofmissing+1 - end - else - end - end - else - local overload=overloads[du] - if overload then - glyph.unicode=overload.unicode - elseif not glyph.unicode then - missing[du]=true - nofmissing=nofmissing+1 - end - end - end - if type(checklookups)=="function" then - checklookups(data,missing,nofmissing) - end - local unicoded=0 - 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 - 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 - 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 - end - end - end - end - if trace_mapping and unicoded>0 then - report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded) - end - if trace_mapping then - for i=1,#dlist do - local du=dlist[i] - local glyph=descriptions[du] - local name=glyph.name or "-" - local index=glyph.index or 0 - local unicode=glyph.unicode - if unicode then - if type(unicode)=="table" then - local unicodes={} - for i=1,#unicode do - unicodes[i]=formatters("%U",unicode[i]) - end - report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,du,unicodes) - else - report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,du,unicode) - end - else - report_fonts("internal slot %U, name %a, unicode %U",index,name,du) - end - end - end - if trace_loading and (ns>0 or nl>0) then - report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns) - end -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-map”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-vfc” 94937140f2c909e9c831ba021f1ab303] --- - -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,type=select,type -local insert=table.insert -local fonts=fonts -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 -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 -function helpers.prependcommandtable(commands,t) - insert(commands,1,push) - for i=#t,1,-1 do - local s=t[i] - if s then - insert(commands,1,s) - end - end - insert(commands,pop) - return commands -end -function helpers.appendcommandtable(commands,t) - insert(commands,1,push) - insert(commands,pop) - for i=1,#t do - local s=t[i] - if s then - insert(commands,s) - end - end - return commands -end -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, -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-vfc”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otr” 2c35abf43f9a64bdd99240593d432d8a] --- - -if not modules then modules={} end modules ['font-otr']={ - 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,type,tonumber=next,type,tonumber -local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub -local fullstrip=string.fullstrip -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.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 -local otf=handlers.otf or {} -handlers.otf=otf -local readers=otf.readers or {} -otf.readers=readers -local streamreader=utilities.files -local streamwriter=utilities.files -readers.streamreader=streamreader -readers.streamwriter=streamwriter -local openfile=streamreader.open -local closefile=streamreader.close -local setposition=streamreader.setposition -local skipshort=streamreader.skipshort -local readbytes=streamreader.readbytes -local readstring=streamreader.readstring -local readbyte=streamreader.readcardinal1 -local readushort=streamreader.readcardinal2 -local readuint=streamreader.readcardinal3 -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 readcardinaltable=streamreader.readcardinaltable -local readintegertable=streamreader.readintegertable -function streamreader.readtag(f) - 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 reservednames={ [0]="copyright", - "family", - "subfamily", - "uniqueid", - "fullname", - "version", - "postscriptname", - "trademark", - "manufacturer", - "designer", - "description", - "vendorurl", - "designerurl", - "license", - "licenseurl", - "reserved", - "typographicfamily", - "typographicsubfamily", - "compatiblefullname", - "sampletext", - "cidfindfontname", - "wwsfamily", - "wwssubfamily", - "lightbackgroundpalette", - "darkbackgroundpalette", - "variationspostscriptnameprefix", -} -local platforms={ [0]="unicode", - "macintosh", - "iso", - "windows", - "custom", -} -local encodings={ - unicode={ [0]="unicode 1.0 semantics", - "unicode 1.1 semantics", - "iso/iec 10646", - "unicode 2.0 bmp", - "unicode 2.0 full", - "unicode variation sequences", - "unicode full repertoire", - }, - macintosh={ [0]="roman","japanese","chinese (traditional)","korean","arabic","hebrew","greek","russian", - "rsymbol","devanagari","gurmukhi","gujarati","oriya","bengali","tamil","telugu","kannada", - "malayalam","sinhalese","burmese","khmer","thai","laotian","georgian","armenian", - "chinese (simplified)","tibetan","mongolian","geez","slavic","vietnamese","sindhi", - "uninterpreted", - }, - iso={ [0]="7-bit ascii", - "iso 10646", - "iso 8859-1", - }, - windows={ [0]="symbol", - "unicode bmp", - "shiftjis", - "prc", - "big5", - "wansung", - "johab", - "reserved 7", - "reserved 8", - "reserved 9", - "unicode ucs-4", - }, - custom={ - } -} -local decoders={ - unicode={}, - macintosh={}, - iso={}, - windows={ - ["unicode semantics"]=utf16_to_utf8_be, - ["unicode bmp"]=utf16_to_utf8_be, - ["unicode full"]=utf16_to_utf8_be, - ["unicode 1.0 semantics"]=utf16_to_utf8_be, - ["unicode 1.1 semantics"]=utf16_to_utf8_be, - ["unicode 2.0 bmp"]=utf16_to_utf8_be, - ["unicode 2.0 full"]=utf16_to_utf8_be, - ["unicode variation sequences"]=utf16_to_utf8_be, - ["unicode full repertoire"]=utf16_to_utf8_be, - }, - custom={}, -} -local languages={ - unicode={ - [ 0]="english", - }, - macintosh={ - [ 0]="english", - }, - iso={}, - windows={ - [0x0409]="english - united states", - }, - custom={}, -} -local standardromanencoding={ [0]= - "notdef",".null","nonmarkingreturn","space","exclam","quotedbl", - "numbersign","dollar","percent","ampersand","quotesingle","parenleft", - "parenright","asterisk","plus","comma","hyphen","period","slash", - "zero","one","two","three","four","five","six","seven","eight", - "nine","colon","semicolon","less","equal","greater","question","at", - "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O", - "P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft", - "backslash","bracketright","asciicircum","underscore","grave","a","b", - "c","d","e","f","g","h","i","j","k","l","m","n","o","p","q", - "r","s","t","u","v","w","x","y","z","braceleft","bar", - "braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute", - "Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex", - "adieresis","atilde","aring","ccedilla","eacute","egrave", - "ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis", - "ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute", - "ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling", - "section","bullet","paragraph","germandbls","registered","copyright", - "trademark","acute","dieresis","notequal","AE","Oslash","infinity", - "plusminus","lessequal","greaterequal","yen","mu","partialdiff", - "summation","product","pi","integral","ordfeminine","ordmasculine", - "Omega","ae","oslash","questiondown","exclamdown","logicalnot", - "radical","florin","approxequal","Delta","guillemotleft", - "guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde", - "Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright", - "quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis", - "fraction","currency","guilsinglleft","guilsinglright","fi","fl", - "daggerdbl","periodcentered","quotesinglbase","quotedblbase", - "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave", - "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex", - "apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi", - "circumflex","tilde","macron","breve","dotaccent","ring","cedilla", - "hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron", - "Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn", - "thorn","minus","multiply","onesuperior","twosuperior","threesuperior", - "onehalf","onequarter","threequarters","franc","Gbreve","gbreve", - "Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron", - "dcroat", -} -local weights={ - [100]="thin", - [200]="extralight", - [300]="light", - [400]="normal", - [500]="medium", - [600]="semibold", - [700]="bold", - [800]="extrabold", - [900]="black", -} -local widths={ - [1]="ultracondensed", - [2]="extracondensed", - [3]="condensed", - [4]="semicondensed", - [5]="normal", - [6]="semiexpanded", - [7]="expanded", - [8]="extraexpanded", - [9]="ultraexpanded", -} -setmetatableindex(weights,function(t,k) - local r=floor((k+50)/100)*100 - local v=(r>900 and "black") or rawget(t,r) or "normal" - return v -end) -setmetatableindex(widths,function(t,k) - return "normal" -end) -local panoseweights={ - [ 0]="normal", - [ 1]="normal", - [ 2]="verylight", - [ 3]="light", - [ 4]="thin", - [ 5]="book", - [ 6]="medium", - [ 7]="demi", - [ 8]="bold", - [ 9]="heavy", - [10]="black", -} -local panosewidths={ - [ 0]="normal", - [ 1]="normal", - [ 2]="normal", - [ 3]="normal", - [ 4]="normal", - [ 5]="expanded", - [ 6]="condensed", - [ 7]="veryexpanded", - [ 8]="verycondensed", - [ 9]="monospaced", -} -local helpers={} -readers.helpers=helpers -local function gotodatatable(f,fontdata,tag,criterium) - if criterium and f then - local tables=fontdata.tables - if tables then - local datatable=tables[tag] - if datatable then - local tableoffset=datatable.offset - setposition(f,tableoffset) - return tableoffset - end - else - report("no tables") - end - end -end -local function reportskippedtable(f,fontdata,tag,criterium) - if criterium and f then - local tables=fontdata.tables - if tables then - local datatable=tables[tag] - if datatable then - report("loading of table %a skipped",tag) - end - else - report("no tables") - 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, - family=true, - subfamily=true, - typographicfamily=true, - typographicsubfamily=true, - compatiblefullname=true, -} -local platformextras={ - uniqueid=true, - version=true, - copyright=true, - license=true, - licenseurl=true, - manufacturer=true, - vendorurl=true, -} -function readers.name(f,fontdata,specification) - local tableoffset=gotodatatable(f,fontdata,"name",true) - if tableoffset then - local format=readushort(f) - local nofnames=readushort(f) - local offset=readushort(f) - local start=tableoffset+offset - local namelists={ - unicode={}, - windows={}, - macintosh={}, - } - for i=1,nofnames do - local platform=platforms[readushort(f)] - if platform then - local namelist=namelists[platform] - if namelist then - local encoding=readushort(f) - local language=readushort(f) - local encodings=encodings[platform] - local languages=languages[platform] - if encodings and languages then - local encoding=encodings[encoding] - local language=languages[language] - if encoding and language then - 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 - else - skipshort(f,3) - end - else - skipshort(f,5) - end - else - skipshort(f,5) - end - end - local names={} - local done={} - local extras={} - local function decoded(platform,encoding,content) - local decoder=decoders[platform] - if decoder then - decoder=decoder[encoding] - end - if decoder then - return decoder(content) - else - return content - end - end - local function filter(platform,e,l) - local namelist=namelists[platform] - for i=1,#namelist do - local name=namelist[i] - local nametag=name.name - 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 - setposition(f,name.offset) - local content=decoded(platform,encoding,readstring(f,name.length)) - 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 - end - filter("windows","unicode bmp","english - united states") - filter("macintosh","roman","english") - filter("windows") - filter("macintosh") - filter("unicode") - fontdata.names=names - fontdata.extras=extras - if specification.platformnames then - local collected={} - local platformextras=specification.platformextras and platformextras - for platform,namelist in next,namelists do - local filtered=false - for i=1,#namelist do - local entry=namelist[i] - local name=entry.name - if platformnames[name] or (platformextras and platformextras[name]) then - setposition(f,entry.offset) - local content=decoded(platform,entry.encoding,readstring(f,entry.length)) - if filtered then - filtered[name]=content - else - filtered={ [name]=content } - end - end - end - if filtered then - collected[platform]=filtered - end - end - fontdata.platformnames=collected - end - else - fontdata.names={} - end -end -local validutf=lpeg.patterns.validutf8 -local function getname(fontdata,key) - local names=fontdata.names - if names then - local value=names[key] - if value then - local content=value.content - return lpegmatch(validutf,content) and content or nil - end - end -end -readers["os/2"]=function(f,fontdata) - local tableoffset=gotodatatable(f,fontdata,"os/2",true) - if tableoffset then - local version=readushort(f) - local windowsmetrics={ - version=version, - averagewidth=readshort(f), - weightclass=readushort(f), - widthclass=readushort(f), - fstype=readushort(f), - subscriptxsize=readshort(f), - subscriptysize=readshort(f), - subscriptxoffset=readshort(f), - subscriptyoffset=readshort(f), - superscriptxsize=readshort(f), - superscriptysize=readshort(f), - superscriptxoffset=readshort(f), - superscriptyoffset=readshort(f), - strikeoutsize=readshort(f), - strikeoutpos=readshort(f), - familyclass=readshort(f), - panose={ readbytes(f,10) }, - unicoderanges={ readulong(f),readulong(f),readulong(f),readulong(f) }, - vendor=readstring(f,4), - fsselection=readushort(f), - firstcharindex=readushort(f), - lastcharindex=readushort(f), - typoascender=readshort(f), - typodescender=readshort(f), - typolinegap=readshort(f), - winascent=readushort(f), - windescent=readushort(f), - } - if version>=1 then - windowsmetrics.codepageranges={ readulong(f),readulong(f) } - end - if version>=2 then - windowsmetrics.xheight=readshort(f) - windowsmetrics.capheight=readshort(f) - windowsmetrics.defaultchar=readushort(f) - windowsmetrics.breakchar=readushort(f) - end - windowsmetrics.weight=windowsmetrics.weightclass and weights[windowsmetrics.weightclass] - windowsmetrics.width=windowsmetrics.widthclass and widths [windowsmetrics.widthclass] - windowsmetrics.panoseweight=panoseweights[windowsmetrics.panose[3]] - windowsmetrics.panosewidth=panosewidths [windowsmetrics.panose[4]] - fontdata.windowsmetrics=windowsmetrics - else - fontdata.windowsmetrics={} - end -end -readers.head=function(f,fontdata) - local tableoffset=gotodatatable(f,fontdata,"head",true) - if tableoffset then - local version=readulong(f) - local fontversion=readulong(f) - local fontheader={ - version=version, - fontversion=number.to16dot16(fontversion), - fontversionnumber=fontversion, - checksum=readushort(f)*0x10000+readushort(f), - magic=readulong(f), - flags=readushort(f), - units=readushort(f), - created=readlongdatetime(f), - modified=readlongdatetime(f), - xmin=readshort(f), - ymin=readshort(f), - xmax=readshort(f), - ymax=readshort(f), - macstyle=readushort(f), - smallpixels=readushort(f), - directionhint=readshort(f), - indextolocformat=readshort(f), - glyphformat=readshort(f), - } - fontdata.fontheader=fontheader - else - fontdata.fontheader={} - end - fontdata.nofglyphs=0 -end -readers.hhea=function(f,fontdata,specification) - local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details) - if tableoffset then - fontdata.horizontalheader={ - version=readulong(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) - local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details) - if tableoffset then - fontdata.verticalheader={ - version=readulong(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=readulong(f) - local nofglyphs=readushort(f) - fontdata.nofglyphs=nofglyphs - if version==0x00005000 then - fontdata.maximumprofile={ - version=version, - nofglyphs=nofglyphs, - } - elseif version==0x00010000 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 - end -end -readers.hmtx=function(f,fontdata,specification) - 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 - 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) - 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 - 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) - reportskippedtable(f,fontdata,"vorg",specification.glyphs) -end -readers.post=function(f,fontdata,specification) - local tableoffset=gotodatatable(f,fontdata,"post",true) - if tableoffset then - local version=readulong(f) - fontdata.postscript={ - version=version, - italicangle=round(1000*readfixed(f))/1000, - underlineposition=readfword(f), - underlinethickness=readfword(f), - monospaced=readulong(f), - minmemtype42=readulong(f), - maxmemtype42=readulong(f), - minmemtype1=readulong(f), - maxmemtype1=readulong(f), - } - if not specification.glyphs then - elseif version==0x00010000 then - for index=0,#standardromanencoding do - glyphs[index].name=standardromanencoding[index] - end - elseif version==0x00020000 then - local glyphs=fontdata.glyphs - local nofglyphs=readushort(f) - local indices={} - local names={} - local maxnames=0 - for i=0,nofglyphs-1 do - local nameindex=readushort(f) - if nameindex>=258 then - maxnames=maxnames+1 - nameindex=nameindex-257 - indices[nameindex]=i - else - glyphs[i].name=standardromanencoding[nameindex] - end - end - for i=1,maxnames do - local mapping=indices[i] - if not mapping then - report("quit post name fetching at %a of %a: %s",i,maxnames,"no index") - break - else - local length=readbyte(f) - if length>0 then - glyphs[mapping].name=readstring(f,length) - else - report("quit post name fetching at %a of %a: %s",i,maxnames,"overflow") - break - end - end - end - end - else - fontdata.postscript={} - end -end -readers.cff=function(f,fontdata,specification) - reportskippedtable(f,fontdata,"cff",specification.glyphs) -end -local formatreaders={} -local duplicatestoo=true -local sequence={ - { 3,1,4 }, - { 3,10,12 }, - { 0,3,4 }, - { 0,1,4 }, - { 0,0,6 }, - { 3,0,6 }, - { 0,5,14 }, -{ 0,4,12 }, - { 3,10,13 }, -} -local supported={} -for i=1,#sequence do - local si=sequence[i] - local sp,se,sf=si[1],si[2],si[3] - local p=supported[sp] - if not p then - p={} - supported[sp]=p - end - local e=p[se] - if not e then - e={} - p[se]=e - end - e[sf]=true -end -formatreaders[4]=function(f,fontdata,offset) - setposition(f,offset+2) - local length=readushort(f) - local language=readushort(f) - local nofsegments=readushort(f)/2 - skipshort(f,3) - local mapping=fontdata.mapping - local glyphs=fontdata.glyphs - local duplicates=fontdata.duplicates - local nofdone=0 - local endchars=readcardinaltable(f,nofsegments,ushort) - local reserved=readushort(f) - 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] - local offset=offsets[segment] - local delta=deltas[segment] - if startchar==0xFFFF and endchar==0xFFFF then - elseif startchar==0xFFFF and offset==0 then - elseif offset==0xFFFF then - elseif offset==0 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 - local index=(unicode+delta)%65536 - if index and index>0 then - local glyph=glyphs[index] - if glyph then - local gu=glyph.unicode - if not gu then - glyph.unicode=unicode - nofdone=nofdone+1 - elseif gu~=unicode then - if duplicatestoo then - local d=duplicates[gu] - if d then - d[unicode]=true - else - duplicates[gu]={ [unicode]=true } - end - else - report("duplicate case 1: %C %04i %s",unicode,index,glyphs[index].name) - end - end - if not mapping[index] then - mapping[index]=unicode - end - end - end - end - else - local shift=(segment-nofsegments+offset/2)-startchar - 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 - local slot=shift+unicode - local index=indices[slot] - if index and index>0 then - index=(index+delta)%65536 - local glyph=glyphs[index] - if glyph then - local gu=glyph.unicode - if not gu then - glyph.unicode=unicode - nofdone=nofdone+1 - elseif gu~=unicode then - if duplicatestoo then - local d=duplicates[gu] - if d then - d[unicode]=true - else - duplicates[gu]={ [unicode]=true } - end - else - report("duplicate case 2: %C %04i %s",unicode,index,glyphs[index].name) - end - end - if not mapping[index] then - mapping[index]=unicode - end - end - end - end - end - end - return nofdone -end -formatreaders[6]=function(f,fontdata,offset) - setposition(f,offset) - local format=readushort(f) - local length=readushort(f) - local language=readushort(f) - local mapping=fontdata.mapping - local glyphs=fontdata.glyphs - local duplicates=fontdata.duplicates - local start=readushort(f) - local count=readushort(f) - local stop=start+count-1 - local nofdone=0 - if trace_cmap_detail then - report("format 6 from %C to %C",2,start,stop) - end - for unicode=start,stop do - local index=readushort(f) - if index>0 then - local glyph=glyphs[index] - if glyph then - local gu=glyph.unicode - if not gu then - glyph.unicode=unicode - nofdone=nofdone+1 - elseif gu~=unicode then - end - if not mapping[index] then - mapping[index]=unicode - end - end - end - end - return nofdone -end -formatreaders[12]=function(f,fontdata,offset) - setposition(f,offset+2+2+4+4) - local mapping=fontdata.mapping - local glyphs=fontdata.glyphs - local duplicates=fontdata.duplicates - local nofgroups=readulong(f) - local nofdone=0 - for i=1,nofgroups do - local first=readulong(f) - local last=readulong(f) - local index=readulong(f) - 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 - local glyph=glyphs[index] - if glyph then - local gu=glyph.unicode - if not gu then - glyph.unicode=unicode - nofdone=nofdone+1 - elseif gu~=unicode then - local d=duplicates[gu] - if d then - d[unicode]=true - else - duplicates[gu]={ [unicode]=true } - end - end - if not mapping[index] then - mapping[index]=unicode - end - end - index=index+1 - end - end - return nofdone -end -formatreaders[13]=function(f,fontdata,offset) - setposition(f,offset+2+2+4+4) - local mapping=fontdata.mapping - local glyphs=fontdata.glyphs - local duplicates=fontdata.duplicates - local nofgroups=readulong(f) - local nofdone=0 - for i=1,nofgroups do - local first=readulong(f) - local last=readulong(f) - local index=readulong(f) - if first<privateoffset then - if trace_cmap_detail then - report("format 13 from %C to %C get index %i",first,last,index) - end - local glyph=glyphs[index] - local unicode=glyph.unicode - if not unicode then - unicode=first - glyph.unicode=unicode - first=first+1 - end - local list=duplicates[unicode] - mapping[index]=unicode - if not list then - list={} - duplicates[unicode]=list - end - if last>=privateoffset then - local limit=privateoffset-1 - report("format 13 from %C to %C pruned to %C",first,last,limit) - last=limit - end - for unicode=first,last do - list[unicode]=true - end - nofdone=nofdone+last-first+1 - else - report("format 13 from %C to %C ignored",first,last) - end - end - return nofdone -end -formatreaders[14]=function(f,fontdata,offset) - if offset and offset~=0 then - setposition(f,offset) - local format=readushort(f) - local length=readulong(f) - local nofrecords=readulong(f) - local records={} - local variants={} - local nofdone=0 - fontdata.variants=variants - for i=1,nofrecords do - records[i]={ - selector=readuint(f), - default=readulong(f), - other=readulong(f), - } - end - for i=1,nofrecords do - local record=records[i] - local selector=record.selector - local default=record.default - local other=record.other - local other=record.other - if other~=0 then - setposition(f,offset+other) - local mapping={} - local count=readulong(f) - for i=1,count do - mapping[readuint(f)]=readushort(f) - end - nofdone=nofdone+count - variants[selector]=mapping - end - end - return nofdone - else - return 0 - end -end -local function checkcmap(f,fontdata,records,platform,encoding,format) - local data=records[platform] - if not data then - return 0 - end - data=data[encoding] - if not data then - return 0 - end - data=data[format] - if not data then - return 0 - end - local reader=formatreaders[format] - if not reader then - return 0 - end - local p=platforms[platform] - local e=encodings[p] - local n=reader(f,fontdata,data) or 0 - 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) - 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 offsets=subtables.offsets - offsets[#offsets+1]=offset - end - end - end - if trace_cmap then - report("found cmaps:") - 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 - 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 - 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 - list[i]=list[i].." (unsupported)" - end - end - report(" formats: % t",list) - end - end - 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 - 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) - reportskippedtable(f,fontdata,"loca",specification.glyphs) -end -function readers.glyf(f,fontdata,specification) - reportskippedtable(f,fontdata,"glyf",specification.glyphs) -end -function readers.colr(f,fontdata,specification) - reportskippedtable(f,fontdata,"colr",specification.glyphs) -end -function readers.cpal(f,fontdata,specification) - reportskippedtable(f,fontdata,"cpal",specification.glyphs) -end -function readers.svg(f,fontdata,specification) - 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) - 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) - 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 - end - elseif format==2 then - report("todo: kern classes") - else - report("todo: kerns") - end - end - end -end -function readers.gdef(f,fontdata,specification) - reportskippedtable(f,fontdata,"gdef",specification.details) -end -function readers.gsub(f,fontdata,specification) - reportskippedtable(f,fontdata,"gsub",specification.details) -end -function readers.gpos(f,fontdata,specification) - reportskippedtable(f,fontdata,"gpos",specification.details) -end -function readers.math(f,fontdata,specification) - reportskippedtable(f,fontdata,"math",specification.details) -end -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 - if names then - local metrics=fontdata.windowsmetrics or {} - local postscript=fontdata.postscript or {} - local fontheader=fontdata.fontheader or {} - local cffinfo=fontdata.cffinfo or {} - local filename=fontdata.filename - local weight=getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight) - local width=getname(fontdata,"width") or (cffinfo and cffinfo.width ) or (metrics and metrics.width ) - local fontname=getname(fontdata,"postscriptname") - local fullname=getname(fontdata,"fullname") - local family=getname(fontdata,"family") - local subfamily=getname(fontdata,"subfamily") - local familyname=getname(fontdata,"typographicfamily") - local subfamilyname=getname(fontdata,"typographicsubfamily") - local compatiblename=getname(fontdata,"compatiblefullname") - if rawfamilynames then - else - 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"), - fontname=fontname, - fullname=fullname, - family=family, - subfamily=subfamily, - familyname=familyname, - subfamilyname=subfamilyname, - compatiblename=compatiblename, - weight=weight and lower(weight), - width=width and lower(width), - pfmweight=metrics.weightclass or 400, - pfmwidth=metrics.widthclass or 5, - panosewidth=metrics.panosewidth, - panoseweight=metrics.panoseweight, - italicangle=postscript.italicangle or 0, - units=fontheader.units or 0, - designsize=fontdata.designsize, - minsize=fontdata.minsize, - maxsize=fontdata.maxsize, - boundingbox=fontheader and { fontheader.xmin or 0,fontheader.ymin or 0,fontheader.xmax or 0,fontheader.ymax or 0 } or nil, - monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced", - averagewidth=metrics.averagewidth, - xheight=metrics.xheight, - capheight=metrics.capheight or fontdata.maxy, - ascender=metrics.typoascender, - descender=metrics.typodescender, - platformnames=platformnames or nil, - instancenames=instancenames or nil, - tableoffsets=fontdata.tableoffsets, - } - if metricstoo then - local keys={ - "version", - "ascender","descender","linegap", - "maxadvancewidth","maxadvanceheight","maxextent", - "minbottomsidebearing","mintopsidebearing", - } - local h=fontdata.horizontalheader or {} - local v=fontdata.verticalheader or {} - if h then - local th={} - local tv={} - for i=1,#keys do - local key=keys[i] - th[key]=h[key] or 0 - tv[key]=v[key] or 0 - end - info.horizontalmetrics=th - info.verticalmetrics=tv - end - end - elseif n then - info={ - filename=fontdata.filename, - comment="there is no info for subfont "..n, - } - else - info={ - filename=fontdata.filename, - comment="there is no info", - } - end - return info -end -local function loadtables(f,specification,offset) - if offset then - setposition(f,offset) - end - local tables={} - local basename=file.basename(specification.filename) - local filesize=specification.filesize - local filetime=specification.filetime - local fontdata={ - filename=basename, - filesize=filesize, - filetime=filetime, - version=readstring(f,4), - noftables=readushort(f), - searchrange=readushort(f), - entryselector=readushort(f), - rangeshift=readushort(f), - tables=tables, - foundtables=false, - } - for i=1,fontdata.noftables do - local tag=lower(stripstring(readstring(f,4))) - local checksum=readushort(f)*0x10000+readushort(f) - local offset=readulong(f) - local length=readulong(f) - if offset+length>filesize then - report("bad %a table in file %a",tag,basename) - end - tables[tag]={ - checksum=checksum, - offset=offset, - length=length, - } - end - fontdata.foundtables=sortedkeys(tables) - if tables.cff or tables.cff2 then - fontdata.format="opentype" - else - fontdata.format="truetype" - end - return fontdata,tables -end -local function prepareglyps(fontdata) - local glyphs=setmetatableindex(function(t,k) - local v={ - index=k, - } - t[k]=v - return v - end) - 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,tables=loadtables(f,specification,offset) - if specification.glyphs then - prepareglyps(fontdata) - end - 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 "" - local cleanname=gsub(askedname,"[^a-zA-Z0-9]","") - local foundname=gsub(fullname,"[^a-zA-Z0-9]","") - if lower(cleanname)~=lower(foundname) then - return - end - end - 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.cidmaps=nil - fontdata.dictionaries=nil - if specification.tableoffsets then - fontdata.tableoffsets=tables - setmetatableindex(tables,{ - version=fontdata.version, - noftables=fontdata.noftables, - searchrange=fontdata.searchrange, - entryselector=fontdata.entryselector, - rangeshift=fontdata.rangeshift, - }) - end - return fontdata -end -local function loadfontdata(specification) - local filename=specification.filename - local fileattr=lfs.attributes(filename) - local filesize=fileattr and fileattr.size or 0 - local filetime=fileattr and fileattr.modification or 0 - local f=openfile(filename,true) - if not f then - report("unable to open %a",filename) - elseif filesize==0 then - report("empty file %a",filename) - closefile(f) - else - specification.filesize=filesize - specification.filetime=filetime - local version=readstring(f,4) - local fontdata=nil - if version=="OTTO" or version=="true" or version=="\0\1\0\0" then - fontdata=readdata(f,0,specification) - elseif version=="ttcf" then - local subfont=tonumber(specification.subfont) - local ttcversion=readulong(f) - local nofsubfonts=readulong(f) - local offsets=readcardinaltable(f,nofsubfonts,ulong) - if subfont then - if subfont>=1 and subfont<=nofsubfonts then - fontdata=readdata(f,offsets[subfont],specification) - else - report("no subfont %a in file %a",subfont,filename) - end - else - subfont=specification.subfont - if type(subfont)=="string" and subfont~="" then - specification.askedname=subfont - for i=1,nofsubfonts do - fontdata=readdata(f,offsets[i],specification) - if fontdata then - fontdata.subfontindex=i - report("subfont named %a has index %a",subfont,i) - break - end - end - if not fontdata then - report("no subfont named %a",subfont) - end - else - local subfonts={} - fontdata={ - filename=filename, - filesize=filesize, - filetime=filetime, - version=version, - subfonts=subfonts, - ttcversion=ttcversion, - nofsubfonts=nofsubfonts, - } - for i=1,nofsubfonts do - subfonts[i]=readdata(f,offsets[i],specification) - end - end - end - else - report("unknown version %a in file %a",version,filename) - end - closefile(f) - return fontdata or {} - end -end -local function loadfont(specification,n,instance) - if type(specification)=="string" then - specification={ - filename=specification, - info=true, - details=true, - 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 - specification.glyphs=true - end - if specification.glyphs then - specification.details=true - end - if specification.details then - specification.info=true - end - 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 and debug.traceback()) - end - local ok,result=xpcall(loadfontdata,message,specification) - if ok then - return result - end -end -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 - v.class=nil - v.index=nil - v.math=nil - end - local names=fontdata.names - if names then - for k,v in next,names do - names[k]=fullstrip(v.content) - end - end - end - return fontdata and { - filename=filename, - format=fontdata.format, - glyphs=fontdata.glyphs, - units=fontdata.fontheader.units, - cffinfo=fontdata.cffinfo, - fontheader=fontdata.fontheader, - horizontalheader=fontdata.horizontalheader, - verticalheader=fontdata.verticalheader, - maximumprofile=fontdata.maximumprofile, - names=fontdata.names, - postscript=fontdata.postscript, - } or { - filename=filename, - format="unknown", - glyphs={}, - units=0, - } -end -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 { - tableversion=tableversion, - creator="context mkiv", - size=fontdata.filesize, - time=fontdata.filetime, - glyphs=fontdata.glyphs, - descriptions=fontdata.descriptions, - format=fontdata.format, - goodies={}, - 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, - private=privateoffset, - duplicates=fontdata.duplicates or {}, - features=fontdata.features or {}, - sublookups=fontdata.sublookups or {}, - marks=fontdata.marks or {}, - markclasses=fontdata.markclasses or {}, - marksets=fontdata.marksets or {}, - sequences=fontdata.sequences or {}, - variants=fontdata.variants, - version=getname(fontdata,"version"), - cidinfo=fontdata.cidinfo, - mathconstants=fontdata.mathconstants, - colorpalettes=fontdata.colorpalettes, - svgshapes=fontdata.svgshapes, - pngshapes=fontdata.pngshapes, - variabledata=fontdata.variabledata, - foundtables=fontdata.foundtables, - }, - } - end -end -function readers.getinfo(filename,specification) - local subfont=nil - local platformnames=false - local rawfamilynames=false - local instancenames=true - local tableoffsets=false - if type(specification)=="table" then - subfont=tonumber(specification.subfont) - platformnames=specification.platformnames - rawfamilynames=specification.rawfamilynames - tableoffsets=specification.tableoffsets - else - subfont=tonumber(specification) - end - local fontdata=loadfont { - filename=filename, - details=true, - platformnames=platformnames, - instancenames=true, - tableoffsets=tableoffsets, - } - if fontdata then - local subfonts=fontdata.subfonts - if not subfonts then - 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,false,instancenames) - end - return info - elseif subfont>=1 and subfont<=#subfonts then - return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames) - else - return { - filename=filename, - comment="there is no subfont "..subfont.." in this file" - } - end - else - return { - filename=filename, - comment="the file cannot be opened for reading", - } - end -end -function readers.rehash(fontdata,hashmethod) - report("the %a helper is not yet implemented","rehash") -end -function readers.checkhash(fontdata) - report("the %a helper is not yet implemented","checkhash") -end -function readers.pack(fontdata,hashmethod) - report("the %a helper is not yet implemented","pack") -end -function readers.unpack(fontdata) - report("the %a helper is not yet implemented","unpack") -end -function readers.expand(fontdata) - report("the %a helper is not yet implemented","unpack") -end -function readers.compact(fontdata) - report("the %a helper is not yet implemented","compact") -end -local extenders={} -function readers.registerextender(extender) - extenders[#extenders+1]=extender -end -function readers.extend(fontdata) - for i=1,#extenders do - local extender=extenders[i] - local name=extender.name or "unknown" - local action=extender.action - if action then - action(fontdata) - end - end -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otr”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-oti” dbae7722baae24d917a17176553825cf] --- - -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-2019-02-22.lua scope for “font-oti”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ott” a8b78a27cbb22d4f697a8dd801a73eea] --- - -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", - ["kjz" ]="bumthangkha", - ["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", - ["mfa" ]="pattani malay", - ["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", - ["tsj" ]="tshangla", - ["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", - ["xkf" ]="khengkha", - ["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,wrap) - 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 - if wrap and find(value,",") then - uv="{"..lower(value).."}" - else - uv=lower(value) - end - 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-2019-02-22.lua scope for “font-ott”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-cff” fda3887cbaad0b82d06d3cbffdfff560] --- - -if not modules then modules={} end modules ['font-cff']={ - 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,type,tonumber,rawget=next,type,tonumber,rawget -local byte,char,gmatch=string.byte,string.char,string.gmatch -local concat,remove,unpack=table.concat,table.remove,table.unpack -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 idiv=number.idiv -local rshift,band,extract=bit32.rshift,bit32.band,bit32.extract -local readers=fonts.handlers.otf.readers -local streamreader=readers.streamreader -local readstring=streamreader.readstring -local readbyte=streamreader.readcardinal1 -local readushort=streamreader.readcardinal2 -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") -local parsedictionaries -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", - "comma","hyphen","period","slash","zero","one","two","three","four", - "five","six","seven","eight","nine","colon","semicolon","less", - "equal","greater","question","at","A","B","C","D","E","F","G","H", - "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W", - "X","Y","Z","bracketleft","backslash","bracketright","asciicircum", - "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j", - "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y", - "z","braceleft","bar","braceright","asciitilde","exclamdown","cent", - "sterling","fraction","yen","florin","section","currency", - "quotesingle","quotedblleft","guillemotleft","guilsinglleft", - "guilsinglright","fi","fl","endash","dagger","daggerdbl", - "periodcentered","paragraph","bullet","quotesinglbase","quotedblbase", - "quotedblright","guillemotright","ellipsis","perthousand","questiondown", - "grave","acute","circumflex","tilde","macron","breve","dotaccent", - "dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash", - "AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae", - "dotlessi","lslash","oslash","oe","germandbls","onesuperior", - "logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn", - "onequarter","divide","brokenbar","degree","thorn","threequarters", - "twosuperior","registered","minus","eth","multiply","threesuperior", - "copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring", - "Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave", - "Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute", - "Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute", - "Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron", - "aacute","acircumflex","adieresis","agrave","aring","atilde", - "ccedilla","eacute","ecircumflex","edieresis","egrave","iacute", - "icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex", - "odieresis","ograve","otilde","scaron","uacute","ucircumflex", - "udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall", - "Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall", - "Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader", - "onedotenleader","zerooldstyle","oneoldstyle","twooldstyle", - "threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle", - "sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior", - "threequartersemdash","periodsuperior","questionsmall","asuperior", - "bsuperior","centsuperior","dsuperior","esuperior","isuperior", - "lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior", - "tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior", - "Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall", - "Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall", - "Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall", - "Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall", - "Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah", - "Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall", - "Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall", - "Dotaccentsmall","Macronsmall","figuredash","hypheninferior", - "Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth", - "threeeighths","fiveeighths","seveneighths","onethird","twothirds", - "zerosuperior","foursuperior","fivesuperior","sixsuperior", - "sevensuperior","eightsuperior","ninesuperior","zeroinferior", - "oneinferior","twoinferior","threeinferior","fourinferior", - "fiveinferior","sixinferior","seveninferior","eightinferior", - "nineinferior","centinferior","dollarinferior","periodinferior", - "commainferior","Agravesmall","Aacutesmall","Acircumflexsmall", - "Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall", - "Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall", - "Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall", - "Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall", - "Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall", - "Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall", - "Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003", - "Black","Bold","Book","Light","Medium","Regular","Roman","Semibold", -} -local cffreaders={ - readbyte, - readushort, - readuint, - readulong, -} -local function readheader(f) - local offset=getposition(f) - local major=readbyte(f) - local header={ - offset=offset, - major=major, - minor=readbyte(f), - size=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,longcount) - local count=longcount and readulong(f) or readushort(f) - if count==0 then - return {} - end - local osize=readbyte(f) - local read=cffreaders[osize] - if not read then - report("bad offset size: %i",osize) - return {} - end - local lengths={} - local previous=read(f) - for i=1,count do - local offset=read(f) - local length=offset-previous - if length<0 then - report("bad offset: %i",length) - length=0 - end - lengths[i]=length - previous=offset - end - return lengths -end -local function readfontnames(f) - local names=readlengths(f) - for i=1,#names do - names[i]=readstring(f,names[i]) - end - return names -end -local function readtopdictionaries(f) - local dictionaries=readlengths(f) - for i=1,#dictionaries do - dictionaries[i]=readstring(f,dictionaries[i]) - end - return dictionaries -end -local function readstrings(f) - local lengths=readlengths(f) - local strings=setmetatableindex({},defaultstrings) - local index=#defaultstrings - for i=1,#lengths do - index=index+1 - strings[index]=readstring(f,lengths[i]) - end - return strings -end -do - local stack={} - local top=0 - local result={} - local strings={} - local p_single=P("\00")/function() - result.version=strings[stack[top]] or "unset" - top=0 - end+P("\01")/function() - result.notice=strings[stack[top]] or "unset" - top=0 - end+P("\02")/function() - result.fullname=strings[stack[top]] or "unset" - top=0 - end+P("\03")/function() - result.familyname=strings[stack[top]] or "unset" - top=0 - end+P("\04")/function() - result.weight=strings[stack[top]] or "unset" - top=0 - end+P("\05")/function() - result.fontbbox={ unpack(stack,1,4) } - top=0 - end+P("\06")/function() - result.bluevalues={ unpack(stack,1,top) } - top=0 - end+P("\07")/function() - result.otherblues={ unpack(stack,1,top) } - top=0 - end+P("\08")/function() - result.familyblues={ unpack(stack,1,top) } - top=0 - end+P("\09")/function() - result.familyotherblues={ unpack(stack,1,top) } - top=0 - end+P("\10")/function() - result.strhw=stack[top] - top=0 - end+P("\11")/function() - result.strvw=stack[top] - top=0 - end+P("\13")/function() - result.uniqueid=stack[top] - top=0 - end+P("\14")/function() - result.xuid=concat(stack,"",1,top) - top=0 - end+P("\15")/function() - result.charset=stack[top] - top=0 - end+P("\16")/function() - result.encoding=stack[top] - top=0 - end+P("\17")/function() - result.charstrings=stack[top] - top=0 - end+P("\18")/function() - result.private={ - size=stack[top-1], - offset=stack[top], - } - 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() - result.copyright=stack[top] - top=0 - end+P("\01")/function() - result.monospaced=stack[top]==1 and true or false - top=0 - end+P("\02")/function() - result.italicangle=stack[top] - top=0 - end+P("\03")/function() - result.underlineposition=stack[top] - top=0 - end+P("\04")/function() - result.underlinethickness=stack[top] - top=0 - end+P("\05")/function() - result.painttype=stack[top] - top=0 - end+P("\06")/function() - result.charstringtype=stack[top] - top=0 - end+P("\07")/function() - result.fontmatrix={ unpack(stack,1,6) } - top=0 - end+P("\08")/function() - result.strokewidth=stack[top] - top=0 - end+P("\09")/function() - result.bluescale=stack[top] - top=0 - end+P("\10")/function() - result.bluesnap=stack[top] - top=0 - end+P("\11")/function() - result.bluefuzz=stack[top] - top=0 - end+P("\12")/function() - result.stemsnaph={ unpack(stack,1,top) } - top=0 - end+P("\13")/function() - result.stemsnapv={ unpack(stack,1,top) } - top=0 - end+P("\20")/function() - result.syntheticbase=stack[top] - top=0 - end+P("\21")/function() - result.postscript=strings[stack[top]] or "unset" - top=0 - end+P("\22")/function() - result.basefontname=strings[stack[top]] or "unset" - top=0 - end+P("\21")/function() - result.basefontblend=stack[top] - top=0 - end+P("\30")/function() - result.cid.registry=strings[stack[top-2]] or "unset" - result.cid.ordering=strings[stack[top-1]] or "unset" - result.cid.supplement=stack[top] - top=0 - end+P("\31")/function() - result.cid.fontversion=stack[top] - top=0 - end+P("\32")/function() - result.cid.fontrevision=stack[top] - top=0 - end+P("\33")/function() - result.cid.fonttype=stack[top] - top=0 - end+P("\34")/function() - result.cid.count=stack[top] - top=0 - end+P("\35")/function() - result.cid.uidbase=stack[top] - top=0 - end+P("\36")/function() - result.cid.fdarray=stack[top] - top=0 - end+P("\37")/function() - result.cid.fdselect=stack[top] - top=0 - end+P("\38")/function() - result.cid.fontname=strings[stack[top]] or "unset" - top=0 - end - ) - local remap={ - ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0", - ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1", - ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2", - ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="3.",["\x3B"]="3E",["\x3C"]="3E-",["\x3D"]="3",["\x3E"]="3-",["\x3F"]="3", - ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="4.",["\x4B"]="4E",["\x4C"]="4E-",["\x4D"]="4",["\x4E"]="4-",["\x4F"]="4", - ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="5.",["\x5B"]="5E",["\x5C"]="5E-",["\x5D"]="5",["\x5E"]="5-",["\x5F"]="5", - ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="6.",["\x6B"]="6E",["\x6C"]="6E-",["\x6D"]="6",["\x6E"]="6-",["\x6F"]="6", - ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="7.",["\x7B"]="7E",["\x7C"]="7E-",["\x7D"]="7",["\x7E"]="7-",["\x7F"]="7", - ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="8.",["\x8B"]="8E",["\x8C"]="8E-",["\x8D"]="8",["\x8E"]="8-",["\x8F"]="8", - ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="9.",["\x9B"]="9E",["\x9C"]="9E-",["\x9D"]="9",["\x9E"]="9-",["\x9F"]="9", - ["\xA0"]=".0",["\xA1"]=".1",["\xA2"]=".2",["\xA3"]=".3",["\xA4"]=".4",["\xA5"]=".5",["\xA6"]=".6",["\xA7"]=".7",["\xA8"]=".8",["\xA9"]=".9",["\xAA"]="..",["\xAB"]=".E",["\xAC"]=".E-",["\xAD"]=".",["\xAE"]=".-",["\xAF"]=".", - ["\xB0"]="E0",["\xB1"]="E1",["\xB2"]="E2",["\xB3"]="E3",["\xB4"]="E4",["\xB5"]="E5",["\xB6"]="E6",["\xB7"]="E7",["\xB8"]="E8",["\xB9"]="E9",["\xBA"]="E.",["\xBB"]="EE",["\xBC"]="EE-",["\xBD"]="E",["\xBE"]="E-",["\xBF"]="E", - ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-", - ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-", - } - local p_last=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")+R("\xF0\xFF") - local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0*(P(1)/remap))/function(n) - top=top+1 - stack[top]=tonumber(n) or 0 - end - local p_byte=C(R("\32\246"))/function(b0) - top=top+1 - stack[top]=byte(b0)-139 - end - local p_positive=C(R("\247\250"))*C(1)/function(b0,b1) - top=top+1 - stack[top]=(byte(b0)-247)*256+byte(b1)+108 - end - local p_negative=C(R("\251\254"))*C(1)/function(b0,b1) - top=top+1 - stack[top]=-(byte(b0)-251)*256-byte(b1)-108 - end - local p_short=P("\28")*C(1)*C(1)/function(b1,b2) - top=top+1 - local n=0x100*byte(b1)+byte(b2) - if n>=0x8000 then - stack[top]=n-0xFFFF-1 - else - stack[top]=n - end - end - local p_long=P("\29")*C(1)*C(1)*C(1)*C(1)/function(b1,b2,b3,b4) - top=top+1 - local n=0x1000000*byte(b1)+0x10000*byte(b2)+0x100*byte(b3)+byte(b4) - if n>=0x8000000 then - stack[top]=n-0xFFFFFFFF-1 - else - stack[top]=n - end - end - local p_unsupported=P(1)/function(detail) - top=0 - end - 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,what) - stack={} - strings=data.strings - for i=1,#dictionaries do - top=0 - result=what=="cff" and { - monospaced=false, - italicangle=0, - underlineposition=-100, - underlinethickness=50, - painttype=0, - charstringtype=2, - fontmatrix={ 0.001,0,0,0.001,0,0 }, - fontbbox={ 0,0,0,0 }, - strokewidth=0, - charset=0, - encoding=0, - cid={ - fontversion=0, - fontrevision=0, - fonttype=0, - count=8720, - } - } or { - charstringtype=2, - charset=0, - vstore=0, - cid={ - }, - } - lpegmatch(p_dictionary,dictionaries[i]) - dictionaries[i]=result - end - result={} - top=0 - stack={} - end - parseprivates=function(data,dictionaries) - stack={} - strings=data.strings - for i=1,#dictionaries do - local private=dictionaries[i].private - if private and private.data then - top=0 - result={ - forcebold=false, - languagegroup=0, - expansionfactor=0.06, - initialrandomseed=0, - subroutines=0, - defaultwidthx=0, - nominalwidthx=0, - cid={ - }, - } - lpegmatch(p_dictionary,private.data) - private.data=result - end - end - result={} - top=0 - stack={} - end - 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) - end - local function showvalue(where,value,showstack) - if showstack then - report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top) - else - report("%w%-10s : %s",depth*2,where,tostring(value)) - end - end - local function xymoveto() - if keepcurve then - r=r+1 - result[r]={ x,y,"m" } - end - if checked then - 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 - xmax=x - ymax=y - checked=true - end - end - 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>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 - xmax=x - ymax=y - checked=true - end - end - 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>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 - xmax=x1 - ymax=y1 - checked=true - 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 not width then - if top>2 then - width=stack[1] - if trace_charstrings then - showvalue("backtrack width",width) - end - else - width=true - end - end - if trace_charstrings then - showstate("rmoveto") - end - x=x+stack[top-1] - y=y+stack[top] - top=0 - xymoveto() - end - local function hmoveto() - if not width then - if top>1 then - width=stack[1] - if trace_charstrings then - showvalue("backtrack width",width) - end - else - width=true - end - end - if trace_charstrings then - showstate("hmoveto") - end - x=x+stack[top] - top=0 - xmoveto() - end - local function vmoveto() - if not width then - if top>1 then - width=stack[1] - if trace_charstrings then - showvalue("backtrack width",width) - end - else - width=true - end - end - if trace_charstrings then - showstate("vmoveto") - end - y=y+stack[top] - top=0 - ymoveto() - end - local function rlineto() - if trace_charstrings then - showstate("rlineto") - end - for i=1,top,2 do - x=x+stack[i] - y=y+stack[i+1] - xylineto() - end - top=0 - end - local function hlineto() - if trace_charstrings then - showstate("hlineto") - end - 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 - 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 - showstate("rrcurveto") - end - for i=1,top,6 do - local ax=x+stack[i] - 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] - xycurveto(ax,ay,bx,by,x,y) - end - top=0 - end - local function hhcurveto() - if trace_charstrings then - showstate("hhcurveto") - end - local s=1 - if top%2~=0 then - y=y+stack[1] - s=2 - end - for i=s,top,4 do - 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] - y=by - xycurveto(ax,ay,bx,by,x,y) - end - top=0 - end - local function vvcurveto() - if trace_charstrings then - showstate("vvcurveto") - end - local s=1 - local d=0 - if top%2~=0 then - d=stack[1] - s=2 - end - for i=s,top,4 do - local ax=x+d - local ay=y+stack[i] - local bx=ax+stack[i+1] - local by=ay+stack[i+2] - x=bx - y=by+stack[i+3] - 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 hvcurveto() - if trace_charstrings then - showstate("hvcurveto") - end - xxcurveto(true) - end - local function vhcurveto() - if trace_charstrings then - showstate("vhcurveto") - end - xxcurveto(false) - end - local function rcurveline() - if trace_charstrings then - showstate("rcurveline") - end - for i=1,top-2,6 do - local ax=x+stack[i] - 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] - xycurveto(ax,ay,bx,by,x,y) - end - x=x+stack[top-1] - y=y+stack[top] - xylineto() - top=0 - end - local function rlinecurve() - if trace_charstrings then - showstate("rlinecurve") - end - if top>6 then - for i=1,top-6,2 do - x=x+stack[i] - y=y+stack[i+1] - xylineto() - end - end - local ax=x+stack[top-5] - local ay=y+stack[top-4] - local bx=ax+stack[top-3] - local by=ay+stack[top-2] - x=bx+stack[top-1] - y=by+stack[top] - xycurveto(ax,ay,bx,by,x,y) - top=0 - end - local function flex() - if trace_charstrings then - showstate("flex") - end - local ax=x+stack[1] - local ay=y+stack[2] - local bx=ax+stack[3] - local by=ay+stack[4] - local cx=bx+stack[5] - local cy=by+stack[6] - 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] - 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 ay=y - local bx=ax+stack[2] - local by=ay+stack[3] - local cx=bx+stack[4] - local cy=by - 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] - xycurveto(dx,dy,ex,ey,x,y) - top=0 - end - local function hflex1() - if trace_charstrings then - showstate("hflex1") - end - local ax=x+stack[1] - local ay=y+stack[2] - local bx=ax+stack[3] - local by=ay+stack[4] - local cx=bx+stack[5] - local cy=by - 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] - xycurveto(dx,dy,ex,ey,x,y) - top=0 - end - local function flex1() - if trace_charstrings then - showstate("flex1") - end - local ax=x+stack[1] - local ay=y+stack[2] - local bx=ax+stack[3] - local by=ay+stack[4] - local cx=bx+stack[5] - local cy=by+stack[6] - 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] - if abs(ex-x)>abs(ey-y) then - x=ex+stack[11] - else - y=ey+stack[11] - end - xycurveto(dx,dy,ex,ey,x,y) - top=0 - end - local function getstem() - if top==0 then - elseif top%2~=0 then - if width then - remove(stack,1) - else - width=remove(stack,1) - if trace_charstrings then - showvalue("width",width) - end - end - top=top-1 - end - if trace_charstrings then - showstate("stem") - end - stems=stems+idiv(top,2) - top=0 - end - local function getmask() - if top==0 then - elseif top%2~=0 then - if width then - remove(stack,1) - else - width=remove(stack,1) - if trace_charstrings then - showvalue("width",width) - end - end - top=top-1 - end - if trace_charstrings then - showstate(operator==19 and "hintmark" or "cntrmask") - end - stems=stems+idiv(top,2) - top=0 - if stems==0 then - elseif stems<=8 then - return 1 - else - return idiv(stems+7,8) - end - end - local function unsupported(t) - if trace_charstrings then - showstate("unsupported "..t) - end - top=0 - end - local function unsupportedsub(t) - if trace_charstrings then - showstate("unsupported sub "..t) - end - top=0 - end - local function getstem3() - if trace_charstrings then - showstate("stem3") - end - top=0 - end - local function divide() - if version==1 then - local d=stack[top] - top=top-1 - stack[top]=stack[top]/d - end - end - local function closepath() - if version==1 then - if trace_charstrings then - showstate("closepath") - end - end - top=0 - end - local function hsbw() - if version==1 then - if trace_charstrings then - showstate("hsbw") - end - width=stack[top] - end - top=0 - end - local function seac() - if version==1 then - if trace_charstrings then - showstate("seac") - end - end - top=0 - end - local function sbw() - if version==1 then - if trace_charstrings then - showstate("sbw") - end - width=stack[top-1] - end - top=0 - end - local function callothersubr() - if version==1 then - if trace_charstrings then - showstate("callothersubr (unsupported)") - end - end - top=0 - end - local function pop() - if version==1 then - if trace_charstrings then - showstate("pop (unsupported)") - end - top=top+1 - stack[top]=0 - else - top=0 - end - end - local function setcurrentpoint() - if version==1 then - if trace_charstrings then - showstate("pop (unsupported)") - end - x=x+stack[top-1] - y=y+stack[top] - 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, - getstem, - vmoveto, - rlineto, - hlineto, - vlineto, - rrcurveto, - unsupported, - unsupported, - unsupported, - unsupported, - hsbw, - unsupported, - setvsindex, - blend, - unsupported, - getstem, - getmask, - getmask, - rmoveto, - hmoveto, - getstem, - rcurveline, - rlinecurve, - vvcurveto, - hhcurveto, - unsupported, - unsupported, - vhcurveto, - hvcurveto, - } - local subactions={ - [000]=dotsection, - [001]=getstem3, - [002]=getstem3, - [006]=seac, - [007]=sbw, - [012]=divide, - [016]=callothersubr, - [017]=pop, - [033]=setcurrentpoint, - [034]=hflex, - [035]=flex, - [036]=hflex1, - [037]=flex1, - } - local chars=setmetatableindex(function (t,k) - local v=char(k) - t[k]=v - return v - end) - local c_endchar=chars[14] - local encode={} - setmetatableindex(encode,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]=chars[i+139] - end - for i=108,1131 do - local v=0xF700+i-108 - t[i]=char(extract(v,8,8),extract(v,0,8)) - end - for i=1132,2048 do - t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) - end - setmetatableindex(encode,function(t,k) - local r=round(k) - local v=rawget(t,r) - if v then - return v - end - local v1=floor(k) - local v2=floor((k-v1)*0x10000) - return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8)) - end) - return t[i] - end) - readers.cffencoder=encode - local function p_setvsindex() - local vsindex=stack[top] - updateregions(vsindex) - top=top-1 - end - local function p_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 - local function p_getstem() - local n=0 - if top%2~=0 then - n=1 - end - if top>n then - stems=stems+idiv(top-n,2) - end - end - local function p_getmask() - local n=0 - if top%2~=0 then - n=1 - end - if top>n then - stems=stems+idiv(top-n,2) - end - if stems==0 then - return 0 - elseif stems<=8 then - return 1 - else - return idiv(stems+7,8) - end - end - local process - local function call(scope,list,bias) - depth=depth+1 - if top==0 then - showstate(formatters["unknown %s call"](scope)) - top=0 - else - local index=stack[top]+bias - top=top-1 - if trace_charstrings then - showvalue(scope,index,true) - end - local tab=list[index] - if tab then - process(tab) - else - showstate(formatters["unknown %s call %i"](scope,index)) - top=0 - end - end - depth=depth-1 - end - local justpass=false - process=function(tab) - local i=1 - local n=#tab - while i<=n do - local t=tab[i] - if t>=32 then - top=top+1 - 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-0x10000 - else - stack[top]=n - end - i=i+3 - elseif t==11 then - if trace_charstrings then - showstate("return") - end - return - elseif t==10 then - call("local",locals,localbias) - i=i+1 - elseif t==14 then - if width then - elseif top>0 then - width=stack[1] - if trace_charstrings then - showvalue("width",width) - end - else - width=true - end - if trace_charstrings then - showstate("endchar") - end - return - elseif t==29 then - call("global",globals,globalbias) - i=i+1 - elseif t==12 then - i=i+1 - local t=tab[i] - if justpass then - if t>=34 or t<=37 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] - end - r=r+1;result[r]=chars[12] - r=r+1;result[r]=chars[t] - top=0 - else - local a=subactions[t] - if a then - a(t) - else - top=0 - end - end - else - local a=subactions[t] - if a then - a(t) - else - if trace_charstrings then - showvalue("<subaction>",t) - end - top=0 - end - end - i=i+1 - elseif justpass then - if t==15 then - p_setvsindex() - i=i+1 - elseif t==16 then - local s=p_blend() or 0 - i=i+s+1 - elseif t==1 or t==3 or t==18 or operation==23 then - p_getstem() -if true then - if top>0 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] - end - top=0 - end - r=r+1;result[r]=chars[t] -else - top=0 -end - i=i+1 - elseif t==19 or t==20 then - local s=p_getmask() or 0 -if true then - if top>0 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] - end - top=0 - end - r=r+1;result[r]=chars[t] - for j=1,s do - i=i+1 - r=r+1;result[r]=chars[tab[i]] - end -else - i=i+s - top=0 -end - i=i+1 - elseif t==9 then - top=0 - i=i+1 - elseif t==13 then - local s=hsbw() or 0 - i=i+s+1 - else - if top>0 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] - end - top=0 - end - r=r+1;result[r]=chars[t] - i=i+1 - end - else - local a=actions[t] - if a then - local s=a(t) - if s then - i=i+s+1 - else - i=i+1 - end - else - if trace_charstrings then - showvalue("<action>",t) - end - top=0 - i=i+1 - end - end - end - end - local function setbias(globals,locals) - local g,l=#globals,#locals - return - ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, - ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 - end - local function processshape(tab,index) - if not tab then - glyphs[index]={ - boundingbox={ 0,0,0,0 }, - width=0, - name=charset and charset[index] or nil, - } - return - end - tab=bytetable(tab) - 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 - if regions then - updateregions(vsindex) - 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 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 - end - 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("boundingbox: % t",boundingbox) - end - end - 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 - 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) - if charstrings then - startparsing(fontdata,data,streams) - for index=1,#charstrings do - processshape(charstrings[index],index-1) - end - stopparsing(fontdata,data) - else - report("no charstrings") - end - return glyphs - end - parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams) - 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 {} - justpass=streams==true - 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]=readbytetable(f,routines[i]) - end - data.routines=routines -end -local function readencodings(f,data) - data.encodings={} -end -local function readcharsets(f,data,dictionary) - local header=data.header - local strings=data.strings - local nofglyphs=data.nofglyphs - local charsetoffset=dictionary.charset - if charsetoffset and charsetoffset~=0 then - setposition(f,header.offset+charsetoffset) - local format=readbyte(f) - local charset={ [0]=".notdef" } - dictionary.charset=charset - if format==0 then - for i=1,nofglyphs do - charset[i]=strings[readushort(f)] - end - elseif format==1 or format==2 then - local readcount=format==1 and readbyte or readushort - local i=1 - while i<=nofglyphs do - local sid=readushort(f) - local n=readcount(f) - for s=sid,sid+n do - charset[i]=strings[s] - i=i+1 - if i>nofglyphs then - break - end - end - end - else - report("cff parser: unsupported charset format %a",format) - end - else - dictionary.nocharset=true - dictionary.charset=nil - end -end -local function readprivates(f,data) - local header=data.header - local dictionaries=data.dictionaries - local private=dictionaries[1].private - if private then - setposition(f,header.offset+private.offset) - private.data=readstring(f,private.size) - end -end -local function readlocals(f,data,dictionary) - local header=data.header - local private=dictionary.private - if private then - local subroutineoffset=private.data.subroutines - if subroutineoffset~=0 then - setposition(f,header.offset+private.offset+subroutineoffset) - local subroutines=readlengths(f) - for i=1,#subroutines do - subroutines[i]=readbytetable(f,subroutines[i]) - end - dictionary.subroutines=subroutines - private.data.subroutines=nil - else - dictionary.subroutines={} - end - else - dictionary.subroutines={} - end -end -local function readcharstrings(f,data,what) - local header=data.header - local dictionaries=data.dictionaries - local dictionary=dictionaries[1] - local stringtype=dictionary.charstringtype - local offset=dictionary.charstrings - if type(offset)~="number" then - elseif stringtype==2 then - setposition(f,header.offset+offset) - local charstrings=readlengths(f,what=="cff2") - local nofglyphs=#charstrings - for i=1,nofglyphs do - charstrings[i]=readstring(f,charstrings[i]) - end - data.nofglyphs=nofglyphs - dictionary.charstrings=charstrings - else - report("unsupported charstr type %i",stringtype) - data.nofglyphs=0 - dictionary.charstrings={} - end -end -local function readcidprivates(f,data) - local header=data.header - local dictionaries=data.dictionaries[1].cid.dictionaries - for i=1,#dictionaries do - local dictionary=dictionaries[i] - local private=dictionary.private - if private then - setposition(f,header.offset+private.offset) - private.data=readstring(f,private.size) - end - end - parseprivates(data,dictionaries) -end -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,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) - startparsing(fontdata,data,streams) - parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) - stopparsing(fontdata,data) -end -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,version) - if version~="cff2" then - readencodings(f,data) - end - local charstrings=dictionary.charstrings - local fdindex={} - local nofglyphs=data.nofglyphs - local maxindex=-1 - setposition(f,header.offset+cidselect) - local format=readbyte(f) - if format==1 then - for i=0,nofglyphs do - local index=readbyte(f) - fdindex[i]=index - if index>maxindex then - maxindex=index - end - end - elseif format==3 then - local nofranges=readushort(f) - local first=readushort(f) - local index=readbyte(f) - while true do - local last=readushort(f) - if index>maxindex then - maxindex=index - end - for i=first,last do - fdindex[i]=index - end - if last>=nofglyphs then - break - else - first=last+1 - index=readbyte(f) - end - end - else - end - if maxindex>=0 then - local cidarray=cid.fdarray - if cidarray then - setposition(f,header.offset+cidarray) - local dictionaries=readlengths(f) - for i=1,#dictionaries do - dictionaries[i]=readstring(f,dictionaries[i]) - end - parsedictionaries(data,dictionaries) - cid.dictionaries=dictionaries - readcidprivates(f,data) - for i=1,#dictionaries do - readlocals(f,data,dictionaries[i]) - end - startparsing(fontdata,data,streams) - for i=1,#charstrings do - parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version,streams) - end - stopparsing(fontdata,data) - else - report("no cid array") - end - end -end -local gotodatatable=readers.helpers.gotodatatable -local function cleanup(data,dictionaries) -end -function readers.cff(f,fontdata,specification) - local tableoffset=gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs) - 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 - local cffinfo={ - familyname=dic.familyname, - fullname=dic.fullname, - boundingbox=dic.boundingbox, - weight=dic.weight, - italicangle=dic.italicangle, - underlineposition=dic.underlineposition, - underlinethickness=dic.underlinethickness, - defaultwidth=dic.defaultwidthx, - nominalwidth=dic.nominalwidthx, - monospaced=dic.monospaced, - } - fontdata.cidinfo=cid and { - registry=cid.registry, - ordering=cid.ordering, - supplement=cid.supplement, - } - fontdata.cffinfo=cffinfo - local all=specification.shapes or specification.streams or false - if specification.glyphs or all then - if cid and cid.fdselect then - readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams) - else - readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams) - end - end - local private=dic.private - if private then - local data=private.data - if type(data)=="table" then - cffinfo.defaultwidth=data.defaultwidth or cffinfo.defaultwidth - cffinfo.nominalwidth=data.nominalwidth or cffinfo.nominalwidth - cffinfo.bluevalues=data.bluevalues - cffinfo.otherblues=data.otherblues - cffinfo.familyblues=data.familyblues - cffinfo.familyotherblues=data.familyotherblues - cffinfo.bluescale=data.bluescale - cffinfo.blueshift=data.blueshift - cffinfo.bluefuzz=data.bluefuzz - cffinfo.stdhw=data.stdhw - cffinfo.stdvw=data.stdvw - 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 specification.streams 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=0, - } - 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-2019-02-22.lua scope for “font-cff”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ttf” fe1b771df5d6442a10fcfa1388f3eed2] --- - -if not modules then modules={} end modules ['font-ttf']={ - 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,type,unpack=next,type,unpack -local band,rshift=bit32.band,bit32.rshift -local sqrt,round=math.sqrt,math.round -local char,rep=string.char,string.rep -local concat=table.concat -local idiv=number.idiv -local setmetatableindex=table.setmetatableindex -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 -local readushort=streamreader.readcardinal2 -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,subpoints=merge(subindex,subshape,subcomponents) - end - end - if subpoints then - local matrix=component.matrix - local xscale=matrix[1] - local xrotate=matrix[2] - local yrotate=matrix[3] - local yscale=matrix[4] - local xoffset=matrix[5] - local yoffset=matrix[6] - local count=#subpoints - if xscale==1 and yscale==1 and xrotate==0 and yrotate==0 then - for i=1,count do - local p=subpoints[i] - nofpoints=nofpoints+1 - points[nofpoints]={ - p[1]+xoffset, - p[2]+yoffset, - p[3] - } - end - else - for i=1,count 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 - end - local subcount=#subcontours - if subcount==1 then - nofcontours=nofcontours+1 - contours[nofcontours]=offset+subcontours[1] - else - for i=1,#subcontours do - nofcontours=nofcontours+1 - contours[nofcontours]=offset+subcontours[i] - end - end - offset=offset+count - 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,points - end - for index=0,#glyphs-1 do - local shape=shapes[index] - if shape then - local components=shape.components - if components then - merge(index,shape,components) - end - end - end -end -local function readnothing(f) - return { - type="nothing", - } -end -local function curveto(m_x,m_y,l_x,l_y,r_x,r_y) - 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" -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 quadratic=false -local function contours2outlines_normal(glyphs,shapes) - for index=0,#glyphs-1 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={} - 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] - 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 - 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 - 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 - 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 - previous_pt=current_pt - end - if first_pt==last_pt then - else - nofsegments=nofsegments+1 - 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 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 - end - end - end - first=last+1 - end - end - end - end - end -end -local function contours2outlines_shaped(glyphs,shapes,keepcurve) - for index=0,#glyphs-1 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 - 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 - 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 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 - end - end - 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 chars=setmetatableindex(function(t,k) - for i=0,255 do local v=char(i) t[i]=v end return t[k] -end) -local function repackpoints(glyphs,shapes) - local noboundingbox={ 0,0,0,0 } - local result={} - local xpoints={} - local ypoints={} - for index=0,#glyphs-1 do - local shape=shapes[index] - if shape then - local r=0 - local glyph=glyphs[index] - 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 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) - x=x+1 - if dx<-255 or dx>255 then - xpoints[x]=toshort(dx) - elseif dx<0 then - fl=fl+0x02 - xpoints[x]=chars[-dx] - elseif dx>0 then - fl=fl+0x12 - xpoints[x]=chars[dx] - else - fl=fl+0x02 - xpoints[x]=c_zero - end - end - if py==currenty then - fl=fl+0x20 - else - local dy=round(py-currenty) - y=y+1 - if dy<-255 or dy>255 then - ypoints[y]=toshort(dy) - elseif dy<0 then - fl=fl+0x04 - ypoints[y]=chars[-dy] - elseif dy>0 then - fl=fl+0x24 - ypoints[y]=chars[dy] - else - fl=fl+0x04 - 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]=chars[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]=chars[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,"",1,x) - r=r+1 result[r]=concat(ypoints,"",1,y) - end - local stream=concat(result,"",1,r) - local length=#stream - local padding=idiv(length+3,4)*4-length - if padding>0 then - if padding==1 then - padding="\0" - elseif padding==2 then - padding="\0\0" - else - padding="\0\0\0" - end - padding=stream..padding - end - glyph.stream=stream - end - end -end -local flags={} -local function readglyph(f,nofcontours) - local points={} - local contours={} - for i=1,nofcontours do - contours[i]=readshort(f)+1 - end - 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 band(flag,0x08)~=0 then - local n=readbyte(f) - if n==1 then - i=i+1 - flags[i]=flag - else - for j=1,n do - i=i+1 - flags[i]=flag - end - end - end - i=i+1 - end - local x=0 - for i=1,nofpoints do - local flag=flags[i] - if band(flag,0x02)~=0 then - if band(flag,0x10)~=0 then - x=x+readbyte(f) - else - x=x-readbyte(f) - end - elseif band(flag,0x10)~=0 then - else - x=x+readshort(f) - end - points[i]={ x,0,band(flag,0x01)~=0 } - end - local y=0 - for i=1,nofpoints do - local flag=flags[i] - if band(flag,0x04)~=0 then - if band(flag,0x20)~=0 then - y=y+readbyte(f) - else - y=y-readbyte(f) - end - elseif band(flag,0x20)~=0 then - else - y=y+readshort(f) - end - points[i][2]=y - end - return { - type="glyph", - points=points, - contours=contours, - nofpoints=nofpoints, - } -end -local function readcomposite(f) - local components={} - local nofcomponents=0 - local instructions=false - while true do - local flags=readushort(f) - local index=readushort(f) - local f_xyarg=band(flags,0x0002)~=0 - local f_offset=band(flags,0x0800)~=0 - local xscale=1 - local xrotate=0 - local yrotate=0 - local yscale=1 - local xoffset=0 - local yoffset=0 - local base=false - local reference=false - if f_xyarg then - if band(flags,0x0001)~=0 then - xoffset=readshort(f) - yoffset=readshort(f) - else - xoffset=readchar(f) - yoffset=readchar(f) - end - else - if band(flags,0x0001)~=0 then - base=readshort(f) - reference=readshort(f) - else - base=readchar(f) - reference=readchar(f) - end - end - 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 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 band(flags,0x0080)~=0 then - xscale=read2dot14(f) - xrotate=read2dot14(f) - yrotate=read2dot14(f) - yscale=read2dot14(f) - if f_xyarg and f_offset then - xoffset=xoffset*sqrt(xscale^2+xrotate^2) - yoffset=yoffset*sqrt(yrotate^2+yscale^2) - end - end - nofcomponents=nofcomponents+1 - components[nofcomponents]={ - index=index, - usemine=band(flags,0x0200)~=0, - round=band(flags,0x0006)~=0, - base=base, - reference=reference, - matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset }, - } - if band(flags,0x0100)~=0 then - instructions=true - end - if band(flags,0x0020)==0 then - break - end - end - return { - type="composite", - components=components, - } -end -function readers.loca(f,fontdata,specification) - if specification.glyphs then - local datatable=fontdata.tables.loca - if datatable then - local offset=fontdata.tables.glyf.offset - local format=fontdata.fontheader.indextolocformat - local profile=fontdata.maximumprofile - local nofglyphs=profile and profile.nofglyphs - local locations={} - setposition(f,datatable.offset) - if format==1 then - if not nofglyphs then - nofglyphs=idiv(datatable.length,4)-1 - end - for i=0,nofglyphs do - locations[i]=offset+readulong(f) - end - fontdata.nofglyphs=nofglyphs - else - if not nofglyphs then - nofglyphs=idiv(datatable.length,2)-1 - end - for i=0,nofglyphs do - locations[i]=offset+readushort(f)*2 - end - end - fontdata.nofglyphs=nofglyphs - fontdata.locations=locations - end - end -end -function readers.glyf(f,fontdata,specification) - 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 or specification.streams - for index=0,nofglyphs-1 do - local location=locations[index] - local length=locations[index+1]-location - 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 length>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) - elseif nofcontours>0 then - shapes[index]=readglyph(f,nofcontours) - else - shapes[index]=readcomposite(f,nofcontours) - end - else - if loadshapes then - shapes[index]=readnothing(f) - 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 - if specification.streams then - repackpoints(glyphs,shapes) - else - contours2outlines_normal(glyphs,shapes) - end - elseif specification.streams then - repackpoints(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 - if index+1>#tuples then - report("error, bad tuple index",index) - end - peak=tuples[index+1] - end - 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 - end - 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-2019-02-22.lua scope for “font-ttf”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-dsp” 7959312318af6ed8fbd9edbeb2b1a335] --- - -if not modules then modules={} end modules ['font-dsp']={ - 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,type,tonumber=next,type,tonumber -local band=bit32.band -local extract=bit32.extract -local bor=bit32.bor -local lshift=bit32.lshift -local rshift=bit32.rshift -local gsub=string.gsub -local lower=string.lower -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 readuinteger=streamreader.readcardinal1 -local readushort=streamreader.readcardinal2 -local readulong=streamreader.readcardinal4 -local readinteger=streamreader.readinteger1 -local readshort=streamreader.readinteger2 -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 - readuinteger=streamreader.readcardinal1 - 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", - "ligature", - "mark", - "component", -} -local gsubtypes={ - "single", - "multiple", - "alternate", - "ligature", - "context", - "chainedcontext", - "extension", - "reversechainedcontextsingle", -} -local gpostypes={ - "single", - "pair", - "cursive", - "marktobase", - "marktoligature", - "marktomark", - "context", - "chainedcontext", - "extension", -} -local chaindirections={ - context=0, - 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", - multiple="gsub_multiple", - alternate="gsub_alternate", - ligature="gsub_ligature", - context="gsub_context", - chainedcontext="gsub_contextchain", - reversechainedcontextsingle="gsub_reversecontextchain", - }, - gpos={ - single="gpos_single", - pair="gpos_pair", - cursive="gpos_cursive", - marktobase="gpos_mark2base", - marktoligature="gpos_mark2ligature", - marktomark="gpos_mark2mark", - context="gpos_context", - chainedcontext="gpos_contextchain", - } -} -local lookupflags=setmetatableindex(function(t,k) - local v={ - 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) - if coverageformat==1 then - local nofcoverage=readushort(f) - if simple then - 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) - local lastindex=readushort(f) - local coverindex=readushort(f) - if simple then - for i=firstindex,lastindex do - coverage[n]=i - n=n+1 - end - else - for i=firstindex,lastindex do - coverage[i]=n - n=n+1 - end - end - end - return coverage - else - report("unknown coverage format %a ",coverageformat) - return {} - end -end -local function readclassdef(f,offset,preset) - setposition(f,offset) - local classdefformat=readushort(f) - local classdef={} - if type(preset)=="number" then - for k=0,preset-1 do - classdef[k]=1 - end - end - if classdefformat==1 then - local index=readushort(f) - local nofclassdef=readushort(f) - for i=1,nofclassdef do - classdef[index]=readushort(f)+1 - index=index+1 - end - elseif classdefformat==2 then - local nofranges=readushort(f) - local n=0 - for i=1,nofranges do - local firstindex=readushort(f) - local lastindex=readushort(f) - local class=readushort(f)+1 - for i=firstindex,lastindex do - classdef[i]=class - end - end - else - report("unknown classdef format %a ",classdefformat) - end - if type(preset)=="table" then - for k in next,preset do - if not classdef[k] then - classdef[k]=1 - end - end - end - return classdef -end -local function classtocoverage(defs) - if defs then - local list={} - for index,class in next,defs do - local c=list[class] - if c then - c[#c+1]=index - else - list[class]={ index } - end - end - return list - end -end -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 false - end - 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,getdelta) - if not offset or offset==0 then - return nil - end - setposition(f,offset) - 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 -end -local function readfirst(f,offset) - if offset then - setposition(f,offset) - end - return { readushort(f) } -end -function readarray(f,offset) - if offset then - setposition(f,offset) - end - local n=readushort(f) - if n==1 then - return { readushort(f) },1 - elseif n>0 then - return readcardinaltable(f,n,ushort),n - end -end -local function readcoveragearray(f,offset,t,simple) - if not t then - return nil - end - local n=#t - if n==0 then - return nil - end - for i=1,n do - t[i]=readcoverage(f,offset+t[i],simple) - end - return t -end -local function covered(subset,all) - local used,u - for i=1,#subset do - local s=subset[i] - if all[s] then - if used then - u=u+1 - used[u]=s - else - u=1 - used={ s } - end - end - end - return used -end -local function readlookuparray(f,noflookups,nofcurrent) - local lookups={} - if noflookups>0 then - local length=0 - for i=1,noflookups do - local index=readushort(f)+1 - if index>length then - length=index - end - 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 - lookups[index]=false - end - end - end - return lookups -end -local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local coverage=readushort(f) - local subclasssets=readarray(f) - local rules={} - if subclasssets then - coverage=readcoverage(f,tableoffset+coverage,true) - for i=1,#subclasssets do - local offset=subclasssets[i] - if offset>0 then - local firstcoverage=coverage[i] - local rulesoffset=tableoffset+offset - local subclassrules=readarray(f,rulesoffset) - for rule=1,#subclassrules do - setposition(f,rulesoffset+subclassrules[rule]) - local nofcurrent=readushort(f) - local noflookups=readushort(f) - local current={ { firstcoverage } } - for i=2,nofcurrent do - current[i]={ readushort(f) } - end - local lookups=readlookuparray(f,noflookups,nofcurrent) - rules[#rules+1]={ - current=current, - lookups=lookups - } - end - end - end - else - report("empty subclassset in %a subtype %i","unchainedcontext",subtype) - end - return { - format="glyphs", - rules=rules, - } - elseif subtype==2 then - local coverage=readushort(f) - local currentclassdef=readushort(f) - local subclasssets=readarray(f) - local rules={} - if subclasssets then - coverage=readcoverage(f,tableoffset+coverage) - currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) - local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) - for class=1,#subclasssets do - local offset=subclasssets[class] - if offset>0 then - local firstcoverage=currentclasses[class] - if firstcoverage then - firstcoverage=covered(firstcoverage,coverage) - if firstcoverage then - local rulesoffset=tableoffset+offset - local subclassrules=readarray(f,rulesoffset) - for rule=1,#subclassrules do - setposition(f,rulesoffset+subclassrules[rule]) - local nofcurrent=readushort(f) - local noflookups=readushort(f) - local current={ firstcoverage } - for i=2,nofcurrent do - current[i]=currentclasses[readushort(f)+1] - end - local lookups=readlookuparray(f,noflookups,nofcurrent) - rules[#rules+1]={ - current=current, - lookups=lookups - } - end - else - report("no coverage") - end - else - report("no coverage class") - end - end - end - else - report("empty subclassset in %a subtype %i","unchainedcontext",subtype) - end - return { - format="class", - rules=rules, - } - elseif subtype==3 then - local nofglyphs=readushort(f) - local noflookups=readushort(f) - local current=readcardinaltable(f,nofglyphs,ushort) - local lookups=readlookuparray(f,noflookups,#current) - current=readcoveragearray(f,tableoffset,current,true) - return { - format="coverage", - rules={ - { - current=current, - lookups=lookups, - } - } - } - else - report("unsupported subtype %a in %a %s",subtype,"unchainedcontext",what) - end -end -local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local coverage=readushort(f) - local subclasssets=readarray(f) - local rules={} - if subclasssets then - coverage=readcoverage(f,tableoffset+coverage,true) - for i=1,#subclasssets do - local offset=subclasssets[i] - if offset>0 then - local firstcoverage=coverage[i] - local rulesoffset=tableoffset+offset - local subclassrules=readarray(f,rulesoffset) - for rule=1,#subclassrules do - setposition(f,rulesoffset+subclassrules[rule]) - local nofbefore=readushort(f) - local before - if nofbefore>0 then - before={} - for i=1,nofbefore do - before[i]={ readushort(f) } - end - end - local nofcurrent=readushort(f) - local current={ { firstcoverage } } - for i=2,nofcurrent do - current[i]={ readushort(f) } - end - local nofafter=readushort(f) - local after - if nofafter>0 then - after={} - for i=1,nofafter do - after[i]={ readushort(f) } - end - end - local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups,nofcurrent) - rules[#rules+1]={ - before=before, - current=current, - after=after, - lookups=lookups, - } - end - end - end - else - report("empty subclassset in %a subtype %i","chainedcontext",subtype) - end - return { - format="glyphs", - rules=rules, - } - elseif subtype==2 then - local coverage=readushort(f) - local beforeclassdef=readushort(f) - local currentclassdef=readushort(f) - local afterclassdef=readushort(f) - local subclasssets=readarray(f) - local rules={} - if subclasssets then - local coverage=readcoverage(f,tableoffset+coverage) - local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs) - local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) - local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs) - local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs) - local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) - local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs) - for class=1,#subclasssets do - local offset=subclasssets[class] - if offset>0 then - local firstcoverage=currentclasses[class] - if firstcoverage then - firstcoverage=covered(firstcoverage,coverage) - if firstcoverage then - local rulesoffset=tableoffset+offset - local subclassrules=readarray(f,rulesoffset) - for rule=1,#subclassrules do - setposition(f,rulesoffset+subclassrules[rule]) - local nofbefore=readushort(f) - local before - if nofbefore>0 then - before={} - for i=1,nofbefore do - before[i]=beforeclasses[readushort(f)+1] - end - end - local nofcurrent=readushort(f) - local current={ firstcoverage } - for i=2,nofcurrent do - current[i]=currentclasses[readushort(f)+1] - end - local nofafter=readushort(f) - local after - if nofafter>0 then - after={} - for i=1,nofafter do - after[i]=afterclasses[readushort(f)+1] - end - end - local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups,nofcurrent) - rules[#rules+1]={ - before=before, - current=current, - after=after, - lookups=lookups, - } - end - else - report("no coverage") - end - else - report("class is not covered") - end - end - end - else - report("empty subclassset in %a subtype %i","chainedcontext",subtype) - end - return { - format="class", - rules=rules, - } - elseif subtype==3 then - local before=readarray(f) - local current=readarray(f) - local after=readarray(f) - local noflookups=readushort(f) - local lookups=readlookuparray(f,noflookups,#current) - before=readcoveragearray(f,tableoffset,before,true) - current=readcoveragearray(f,tableoffset,current,true) - after=readcoveragearray(f,tableoffset,after,true) - return { - format="coverage", - rules={ - { - before=before, - current=current, - after=after, - lookups=lookups, - } - } - } - else - report("unsupported subtype %a in %a %s",subtype,"chainedcontext",what) - end -end -local function extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,types,handlers,what) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local lookuptype=types[readushort(f)] - local faroffset=readulong(f) - local handler=handlers[lookuptype] - if handler then - return handler(f,fontdata,lookupid,tableoffset+faroffset,0,glyphs,nofglyphs),lookuptype - else - report("no handler for lookuptype %a subtype %a in %s %s",lookuptype,subtype,what,"extension") - end - else - report("unsupported subtype %a in %s %s",subtype,what,"extension") - end -end -function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local coverage=readushort(f) - local delta=readshort(f) - local coverage=readcoverage(f,tableoffset+coverage) - for index in next,coverage do - local newindex=(index+delta)%65536 - if index>nofglyphs or newindex>nofglyphs then - report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs) - coverage[index]=nil - else - coverage[index]=newindex - end - end - return { - coverage=coverage - } - elseif subtype==2 then - local coverage=readushort(f) - local nofreplacements=readushort(f) - local replacements=readcardinaltable(f,nofreplacements,ushort) - local coverage=readcoverage(f,tableoffset+coverage) - for index,newindex in next,coverage do - newindex=newindex+1 - if index>nofglyphs or newindex>nofglyphs then - report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs) - coverage[index]=nil - else - coverage[index]=replacements[newindex] - end - end - return { - coverage=coverage - } - else - report("unsupported subtype %a in %a substitution",subtype,"single") - end -end -local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local coverage=readushort(f) - local nofsequence=readushort(f) - local sequences=readcardinaltable(f,nofsequence,ushort) - for i=1,nofsequence do - setposition(f,tableoffset+sequences[i]) - sequences[i]=readcardinaltable(f,readushort(f),ushort) - end - local coverage=readcoverage(f,tableoffset+coverage) - for index,newindex in next,coverage do - newindex=newindex+1 - if index>nofglyphs or newindex>nofglyphs then - report("invalid index in %s format %i: %i -> %i (max %i)",what,subtype,index,newindex,nofglyphs) - coverage[index]=nil - else - coverage[index]=sequences[newindex] - end - end - return { - coverage=coverage - } - else - report("unsupported subtype %a in %a substitution",subtype,what) - end -end -function gsubhandlers.multiple(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"multiple") -end -function gsubhandlers.alternate(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"alternate") -end -function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local coverage=readushort(f) - local nofsets=readushort(f) - local ligatures=readcardinaltable(f,nofsets,ushort) - for i=1,nofsets do - local offset=lookupoffset+offset+ligatures[i] - setposition(f,offset) - local n=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 - end - local coverage=readcoverage(f,tableoffset+coverage) - for index,newindex in next,coverage do - local hash={} - local ligatures=ligatures[newindex+1] - for i=1,#ligatures do - local offset=ligatures[i] - setposition(f,offset) - local lig=readushort(f) - local cnt=readushort(f) - local hsh=hash - for i=2,cnt do - local c=readushort(f) - local h=hsh[c] - if not h then - h={} - hsh[c]=h - end - hsh=h - end - hsh.ligature=lig - end - coverage[index]=hash - end - return { - coverage=coverage - } - else - report("unsupported subtype %a in %a substitution",subtype,"ligature") - end -end -function gsubhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"context" -end -function gsubhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"chainedcontext" -end -function gsubhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gsubtypes,gsubhandlers,"substitution") -end -function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - local tableoffset=lookupoffset+offset - setposition(f,tableoffset) - local subtype=readushort(f) - if subtype==1 then - local current=readfirst(f) - local before=readarray(f) - local after=readarray(f) - local replacements=readarray(f) - current=readcoveragearray(f,tableoffset,current,true) - before=readcoveragearray(f,tableoffset,before,true) - after=readcoveragearray(f,tableoffset,after,true) - return { - 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,mainoffset,getdelta) - local done={} - for i=1,#sets do - local offset=sets[i] - local reused=done[offset] - if not reused then - offset=tableoffset+offset - setposition(f,offset) - local n=readushort(f) - reused={} - for i=1,n do - reused[i]={ - readushort(f), - readposition(f,format1,offset,getdelta), - readposition(f,format2,offset,getdelta), - } - end - done[offset]=reused - end - sets[i]=reused - end - return sets -end -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,mainoffset,getdelta) - local two=readposition(f,format2,mainoffset,getdelta) - if one or two then - classlist2[j]={ one,two } - else - classlist2[j]=false - end - end - end - return classlist1 -end -function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - 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,tableoffset,getdelta) - local coverage=readcoverage(f,tableoffset+coverage) - for index,newindex in next,coverage do - coverage[index]=value - end - return { - format="single", - coverage=coverage, - } - elseif subtype==2 then - local coverage=readushort(f) - local format=readushort(f) - local nofvalues=readushort(f) - local values={} - for i=1,nofvalues do - 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="single", - coverage=coverage, - } - else - report("unsupported subtype %a in %a positioning",subtype,"single") - end -end -function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - 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,mainoffset,getdelta) - coverage=readcoverage(f,tableoffset+coverage) - for index,newindex in next,coverage do - local set=sets[newindex+1] - local hash={} - for i=1,#set do - local value=set[i] - if value then - local other=value[1] - local first=value[2] - local second=value[3] - if first or second then - hash[other]={ first,second or nil } - else - hash[other]=nil - end - end - end - coverage[index]=hash - end - return { - format="pair", - coverage=coverage, - } - elseif subtype==2 then - local coverage=readushort(f) - local format1=readushort(f) - local format2=readushort(f) - local classdef1=readushort(f) - local classdef2=readushort(f) - local nofclasses1=readushort(f) - local nofclasses2=readushort(f) - 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) - local usedcoverage={} - for g1,c1 in next,classdef1 do - if coverage[g1] then - local l1=classlist[c1] - if l1 then - local hash={} - for paired,class in next,classdef2 do - local offsets=l1[class] - if offsets then - local first=offsets[1] - local second=offsets[2] - if first or second then - hash[paired]={ first,second or nil } - else - end - end - end - usedcoverage[g1]=hash - end - end - end - return { - format="pair", - coverage=usedcoverage, - } - elseif subtype==3 then - report("yet unsupported subtype %a in %a positioning",subtype,"pair") - else - report("unsupported subtype %a in %a positioning",subtype,"pair") - end -end -function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - 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) - local records={} - for i=1,nofrecords do - local entry=readushort(f) - local exit=readushort(f) - records[i]={ - 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]={ - 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, - } - else - report("unsupported subtype %a in %a positioning",subtype,"cursive") - end -end -local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature) - 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) - local nofclasses=readushort(f) - local markoffset=tableoffset+readushort(f) - local baseoffset=tableoffset+readushort(f) - local markcoverage=readcoverage(f,markcoverage) - local basecoverage=readcoverage(f,basecoverage,true) - setposition(f,markoffset) - local markclasses={} - local nofmarkclasses=readushort(f) - local lastanchor=fontdata.lastanchor or 0 - local usedanchors={} - for i=1,nofmarkclasses do - local class=readushort(f)+1 - local offset=readushort(f) - if offset==0 then - markclasses[i]=false - else - markclasses[i]={ class,markoffset+offset } - end - usedanchors[class]=true - end - for i=1,nofmarkclasses do - local mc=markclasses[i] - if mc then - mc[2]=readanchor(f,mc[2],getdelta) - end - end - setposition(f,baseoffset) - local nofbaserecords=readushort(f) - local baserecords={} - if ligature then - for i=1,nofbaserecords do - local offset=readushort(f) - if offset==0 then - baserecords[i]=false - else - baserecords[i]=baseoffset+offset - end - end - for i=1,nofbaserecords do - local recordoffset=baserecords[i] - if recordoffset then - setposition(f,recordoffset) - local nofcomponents=readushort(f) - local components={} - for i=1,nofcomponents do - local classes={} - for i=1,nofclasses do - local offset=readushort(f) - if offset~=0 then - classes[i]=recordoffset+offset - else - classes[i]=false - end - end - components[i]=classes - end - baserecords[i]=components - end - end - local baseclasses={} - for i=1,nofclasses do - baseclasses[i]={} - end - for i=1,nofbaserecords do - local components=baserecords[i] - if components then - local b=basecoverage[i] - for c=1,#components do - local classes=components[c] - if classes then - for i=1,nofclasses do - local anchor=readanchor(f,classes[i],getdelta) - local bclass=baseclasses[i] - local bentry=bclass[b] - if bentry then - bentry[c]=anchor - else - bclass[b]={ [c]=anchor } - end - end - end - end - end - end - for index,newindex in next,markcoverage do - markcoverage[index]=markclasses[newindex+1] or nil - end - return { - format="ligature", - baseclasses=baseclasses, - coverage=markcoverage, - } - else - for i=1,nofbaserecords do - local r={} - for j=1,nofclasses do - local offset=readushort(f) - if offset==0 then - r[j]=false - else - r[j]=baseoffset+offset - end - end - baserecords[i]=r - end - local baseclasses={} - for i=1,nofclasses do - baseclasses[i]={} - end - for i=1,nofbaserecords do - local r=baserecords[i] - local b=basecoverage[i] - for j=1,nofclasses do - baseclasses[j][b]=readanchor(f,r[j],getdelta) - end - end - for index,newindex in next,markcoverage do - markcoverage[index]=markclasses[newindex+1] or nil - end - return { - format="base", - baseclasses=baseclasses, - coverage=markcoverage, - } - end - else - report("unsupported subtype %a in",subtype) - end -end -function gposhandlers.marktobase(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) -end -function gposhandlers.marktoligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,true) -end -function gposhandlers.marktomark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) -end -function gposhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"context" -end -function gposhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"chainedcontext" -end -function gposhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) - return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gpostypes,gposhandlers,"positioning") -end -do - local plugins={} - function plugins.size(f,fontdata,tableoffset,feature) - if fontdata.designsize then - else - local function check(offset) - setposition(f,offset) - local designsize=readushort(f) - if designsize>0 then - 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 - end - if designsize>=minsize and designsize<=maxsize then - return minsize,maxsize,designsize - end - end - end - local minsize,maxsize,designsize=check(tableoffset+feature.offset+feature.parameters) - if not designsize then - minsize,maxsize,designsize=check(tableoffset+feature.parameters) - if designsize then - report("bad size feature in %a, falling back to wrong offset",fontdata.filename or "?") - else - report("bad size feature in %a,",fontdata.filename or "?") - end - end - if designsize then - fontdata.minsize=minsize - fontdata.maxsize=maxsize - fontdata.designsize=designsize - end - end - end - local function reorderfeatures(fontdata,scripts,features) - local scriptlangs={} - local featurehash={} - local featureorder={} - for script,languages in next,scripts do - for language,record in next,languages do - local hash={} - local list=record.featureindices - for k=1,#list do - local index=list[k] - local feature=features[index] - local lookups=feature.lookups - local tag=feature.tag - if tag then - hash[tag]=true - end - if lookups then - for i=1,#lookups do - local lookup=lookups[i] - local o=featureorder[lookup] - if o then - local okay=true - for i=1,#o do - if o[i]==tag then - okay=false - break - end - end - if okay then - o[#o+1]=tag - end - else - featureorder[lookup]={ tag } - end - local f=featurehash[lookup] - if f then - local h=f[tag] - if h then - local s=h[script] - if s then - s[language]=true - else - h[script]={ [language]=true } - end - else - f[tag]={ [script]={ [language]=true } } - end - else - featurehash[lookup]={ [tag]={ [script]={ [language]=true } } } - end - local h=scriptlangs[tag] - if h then - local s=h[script] - if s then - s[language]=true - else - h[script]={ [language]=true } - end - else - scriptlangs[tag]={ [script]={ [language]=true } } - end - end - end - end - end - end - return scriptlangs,featurehash,featureorder - end - local function readscriplan(f,fontdata,scriptoffset) - setposition(f,scriptoffset) - local nofscripts=readushort(f) - local scripts={} - for i=1,nofscripts do - scripts[readtag(f)]=scriptoffset+readushort(f) - end - local languagesystems=setmetatableindex("table") - for script,offset in next,scripts do - setposition(f,offset) - local defaultoffset=readushort(f) - local noflanguages=readushort(f) - local languages={} - if defaultoffset>0 then - languages.dflt=languagesystems[offset+defaultoffset] - end - for i=1,noflanguages do - local language=readtag(f) - local offset=offset+readushort(f) - languages[language]=languagesystems[offset] - end - scripts[script]=languages - end - for offset,usedfeatures in next,languagesystems do - if offset>0 then - setposition(f,offset) - local featureindices={} - usedfeatures.featureindices=featureindices - usedfeatures.lookuporder=readushort(f) - usedfeatures.requiredindex=readushort(f) - local noffeatures=readushort(f) - for i=1,noffeatures do - featureindices[i]=readushort(f)+1 - end - end - end - return scripts - end - local function readfeatures(f,fontdata,featureoffset) - setposition(f,featureoffset) - local features={} - local noffeatures=readushort(f) - for i=1,noffeatures do - features[i]={ - tag=readtag(f), - offset=readushort(f) - } - end - for i=1,noffeatures do - local feature=features[i] - local offset=featureoffset+feature.offset - setposition(f,offset) - local parameters=readushort(f) - local noflookups=readushort(f) - if noflookups>0 then - local lookups=readcardinaltable(f,noflookups,ushort) - feature.lookups=lookups - for j=1,noflookups do - lookups[j]=lookups[j]+1 - end - end - if parameters>0 then - feature.parameters=parameters - local plugin=plugins[feature.tag] - if plugin then - plugin(f,fontdata,featureoffset,feature) - end - end - end - return features - end - local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder) - setposition(f,lookupoffset) - local noflookups=readushort(f) - local lookups=readcardinaltable(f,noflookups,ushort) - for lookupid=1,noflookups do - local offset=lookups[lookupid] - setposition(f,lookupoffset+offset) - local subtables={} - local typebits=readushort(f) - local flagbits=readushort(f) - local lookuptype=lookuptypes[typebits] - local lookupflags=lookupflags[flagbits] - local nofsubtables=readushort(f) - for j=1,nofsubtables do - subtables[j]=offset+readushort(f) - end - local markclass=band(flagbits,0x0010)~=0 - if markclass then - markclass=readushort(f) - end - local markset=rshift(flagbits,8) - if markset>0 then - markclass=markset - end - lookups[lookupid]={ - type=lookuptype, - flags=lookupflags, - name=lookupid, - subtables=subtables, - markclass=markclass, - features=featurehash[lookupid], - order=featureorder[lookupid], - } - end - return lookups - end - local f_lookupname=formatters["%s_%s_%s"] - 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 - local nofsublookups=#sublookuplist - local nofsequences=#sequences - local lastsublookup=nofsublookups - local lastsequence=nofsequences - local lookupnames=lookupnames[what] - local sublookuphash={} - local sublookupcheck={} - local glyphs=fontdata.glyphs - 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 - local subtables=lookup.subtables - local features=lookup.features - local handler=lookuphandlers[lookuptype] - if handler then - local nofsubtables=#subtables - local order=lookup.order - local flags=lookup.flags - if flags[1] then flags[1]="mark" end - if flags[2] then flags[2]="ligature" end - if flags[3] then flags[3]="base" end - local markclass=lookup.markclass - if nofsubtables>0 then - local steps={} - local nofsteps=0 - local oldtype=nil - for s=1,nofsubtables do - local step,lt=handler(f,fontdata,lookupid,lookupoffset,subtables[s],glyphs,nofglyphs) - if lt then - lookuptype=lt - if oldtype and lt~=oldtype then - report("messy %s lookup type %a and %a",what,lookuptype,oldtype) - end - oldtype=lookuptype - end - if not step then - report("unsupported %s lookup type %a",what,lookuptype) - else - nofsteps=nofsteps+1 - steps[nofsteps]=step - 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 replacements=rule.replacements - if before then - for i=1,#before do - before[i]=tohash(before[i]) - end - rule.before=reversed(before) - end - if current then - 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 - end - if nofsteps~=nofsubtables then - report("bogus subtables removed in %s lookup type %a",what,lookuptype) - end - lookuptype=lookupnames[lookuptype] or lookuptype - if features then - nofsequences=nofsequences+1 - local l={ - index=nofsequences, - name=f_lookupname(lookupprefix,"s",lookupid+lookupidoffset), - steps=steps, - nofsteps=nofsteps, - type=lookuptype, - markclass=markclass or nil, - flags=flags, - order=order, - features=features, - } - sequences[nofsequences]=l - lookup.done=l - else - nofsublookups=nofsublookups+1 - local l={ - index=nofsublookups, - name=f_lookupname(lookupprefix,"l",lookupid+lookupidoffset), - steps=steps, - nofsteps=nofsteps, - type=lookuptype, - markclass=markclass or nil, - flags=flags, - } - sublookuplist[nofsublookups]=l - sublookuphash[lookupid]=nofsublookups - sublookupcheck[lookupid]=0 - lookup.done=l - end - else - report("no subtables for lookup %a",lookupid) - end - else - 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 - if not reported[name] then - report("rule %i in %s lookup %a has %s lookups",i,what,name,kind) - reported[name]=true - end - end - for i=lastsequence+1,nofsequences do - local sequence=sequences[i] - local steps=sequence.steps - for i=1,#steps do - local step=steps[i] - local rules=step.rules - if rules then - for i=1,#rules do - local rule=rules[i] - local rlookups=rule.lookups - if not rlookups then - report_issue(i,what,sequence,"no") - elseif not next(rlookups) then - rule.lookups=nil - else - local length=#rlookups - for index=1,length do - 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 - sublookupcheck[lookupid]=sublookupcheck[lookupid]+1 - end - if h then - noffound=noffound+1 - found[noffound]=h - end - end - end - rlookups[index]=noffound>0 and found or false - else - rlookups[index]=false - end - end - end - end - end - end - end - for i,n in sortedhash(sublookupcheck) do - local l=lookups[i] - local t=l.type - 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) - end - end - end - 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 - 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 - 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 - 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 - 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) - local datatable=fontdata.tables.kern - if not datatable then - return - end - local features=fontdata.features - local gposfeatures=features and features.gpos - local name - if not gposfeatures or not gposfeatures.kern then - name="kern" - elseif specification.globalkerns then - name="globalkern" - else - report("ignoring global kern table, using gpos kern feature") - return - end - setposition(f,datatable.offset) - local version=readushort(f) - local noftables=readushort(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 - 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", - }, - }, - 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) - if specification.details then - readscripts(f,fontdata,"gsub",gsubtypes,gsubhandlers,specification.lookups) - end - end - function readers.gpos(f,fontdata,specification) - if specification.details then - readscripts(f,fontdata,"gpos",gpostypes,gposhandlers,specification.lookups) - if specification.lookups then - checkkerns(f,fontdata,specification) - end - end - end -end -function readers.gdef(f,fontdata,specification) - 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) - local lastindex=firstindex+readushort(f)-1 - for index=firstindex,lastindex do - local class=classes[readushort(f)] - if class=="mark" then - marks[index]=true - end - glyphs[index].class=class - end - elseif classformat==2 then - local nofranges=readushort(f) - for i=1,nofranges do - local firstindex=readushort(f) - local lastindex=readushort(f) - local class=classes[readushort(f)] - if class then - for index=firstindex,lastindex do - glyphs[index].class=class - if class=="mark" then - marks[index]=true - end - end - end - end - end - end - if markclassoffset~=0 then - setposition(f,tableoffset+markclassoffset) - local classformat=readushort(f) - if classformat==1 then - local firstindex=readushort(f) - local lastindex=firstindex+readushort(f)-1 - for index=firstindex,lastindex do - markclasses[readushort(f)][index]=true - end - elseif classformat==2 then - local nofranges=readushort(f) - for i=1,nofranges do - local firstindex=readushort(f) - local lastindex=readushort(f) - local class=markclasses[readushort(f)] - for index=firstindex,lastindex do - class[index]=true - end - end - end - 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 - end -end -local function readmathvalue(f) - local v=readshort(f) - skipshort(f,1) - return v -end -local function readmathconstants(f,fontdata,offset) - setposition(f,offset) - fontdata.mathconstants={ - ScriptPercentScaleDown=readshort(f), - ScriptScriptPercentScaleDown=readshort(f), - DelimitedSubFormulaMinHeight=readushort(f), - DisplayOperatorMinHeight=readushort(f), - MathLeading=readmathvalue(f), - AxisHeight=readmathvalue(f), - AccentBaseHeight=readmathvalue(f), - FlattenedAccentBaseHeight=readmathvalue(f), - SubscriptShiftDown=readmathvalue(f), - SubscriptTopMax=readmathvalue(f), - SubscriptBaselineDropMin=readmathvalue(f), - SuperscriptShiftUp=readmathvalue(f), - SuperscriptShiftUpCramped=readmathvalue(f), - SuperscriptBottomMin=readmathvalue(f), - SuperscriptBaselineDropMax=readmathvalue(f), - SubSuperscriptGapMin=readmathvalue(f), - SuperscriptBottomMaxWithSubscript=readmathvalue(f), - SpaceAfterScript=readmathvalue(f), - UpperLimitGapMin=readmathvalue(f), - UpperLimitBaselineRiseMin=readmathvalue(f), - LowerLimitGapMin=readmathvalue(f), - LowerLimitBaselineDropMin=readmathvalue(f), - StackTopShiftUp=readmathvalue(f), - StackTopDisplayStyleShiftUp=readmathvalue(f), - StackBottomShiftDown=readmathvalue(f), - StackBottomDisplayStyleShiftDown=readmathvalue(f), - StackGapMin=readmathvalue(f), - StackDisplayStyleGapMin=readmathvalue(f), - StretchStackTopShiftUp=readmathvalue(f), - StretchStackBottomShiftDown=readmathvalue(f), - StretchStackGapAboveMin=readmathvalue(f), - StretchStackGapBelowMin=readmathvalue(f), - FractionNumeratorShiftUp=readmathvalue(f), - FractionNumeratorDisplayStyleShiftUp=readmathvalue(f), - FractionDenominatorShiftDown=readmathvalue(f), - FractionDenominatorDisplayStyleShiftDown=readmathvalue(f), - FractionNumeratorGapMin=readmathvalue(f), - FractionNumeratorDisplayStyleGapMin=readmathvalue(f), - FractionRuleThickness=readmathvalue(f), - FractionDenominatorGapMin=readmathvalue(f), - FractionDenominatorDisplayStyleGapMin=readmathvalue(f), - SkewedFractionHorizontalGap=readmathvalue(f), - SkewedFractionVerticalGap=readmathvalue(f), - OverbarVerticalGap=readmathvalue(f), - OverbarRuleThickness=readmathvalue(f), - OverbarExtraAscender=readmathvalue(f), - UnderbarVerticalGap=readmathvalue(f), - UnderbarRuleThickness=readmathvalue(f), - UnderbarExtraDescender=readmathvalue(f), - RadicalVerticalGap=readmathvalue(f), - RadicalDisplayStyleVerticalGap=readmathvalue(f), - RadicalRuleThickness=readmathvalue(f), - RadicalExtraAscender=readmathvalue(f), - RadicalKernBeforeDegree=readmathvalue(f), - RadicalKernAfterDegree=readmathvalue(f), - RadicalDegreeBottomRaisePercent=readshort(f), - } -end -local function readmathglyphinfo(f,fontdata,offset) - setposition(f,offset) - local italics=readushort(f) - local accents=readushort(f) - local extensions=readushort(f) - local kerns=readushort(f) - local glyphs=fontdata.glyphs - if italics~=0 then - setposition(f,offset+italics) - local coverage=readushort(f) - local nofglyphs=readushort(f) - coverage=readcoverage(f,offset+italics+coverage,true) - setposition(f,offset+italics+4) - for i=1,nofglyphs do - local italic=readmathvalue(f) - if italic~=0 then - local glyph=glyphs[coverage[i]] - local math=glyph.math - if not math then - glyph.math={ italic=italic } - else - math.italic=italic - end - end - end - fontdata.hasitalics=true - end - if accents~=0 then - setposition(f,offset+accents) - local coverage=readushort(f) - local nofglyphs=readushort(f) - coverage=readcoverage(f,offset+accents+coverage,true) - setposition(f,offset+accents+4) - for i=1,nofglyphs do - local accent=readmathvalue(f) - if accent~=0 then - local glyph=glyphs[coverage[i]] - local math=glyph.math - if not math then - glyph.math={ accent=accent } - else - math.accent=accent - end - end - end - end - if extensions~=0 then - setposition(f,offset+extensions) - end - if kerns~=0 then - local kernoffset=offset+kerns - setposition(f,kernoffset) - local coverage=readushort(f) - local nofglyphs=readushort(f) - if nofglyphs>0 then - local function get(offset) - setposition(f,kernoffset+offset) - local n=readushort(f) - if n==0 then - local k=readmathvalue(f) - if k==0 then - else - return { { kern=k } } - end - else - local l={} - for i=1,n do - l[i]={ height=readmathvalue(f) } - end - for i=1,n do - l[i].kern=readmathvalue(f) - end - l[n+1]={ kern=readmathvalue(f) } - return l - end - end - local kernsets={} - for i=1,nofglyphs do - local topright=readushort(f) - local topleft=readushort(f) - local bottomright=readushort(f) - local bottomleft=readushort(f) - kernsets[i]={ - topright=topright~=0 and topright or nil, - topleft=topleft~=0 and topleft or nil, - bottomright=bottomright~=0 and bottomright or nil, - bottomleft=bottomleft~=0 and bottomleft or nil, - } - end - coverage=readcoverage(f,kernoffset+coverage,true) - for i=1,nofglyphs do - local kernset=kernsets[i] - if next(kernset) then - local k=kernset.topright if k then kernset.topright=get(k) end - local k=kernset.topleft if k then kernset.topleft=get(k) end - local k=kernset.bottomright if k then kernset.bottomright=get(k) end - local k=kernset.bottomleft if k then kernset.bottomleft=get(k) end - if next(kernset) then - local glyph=glyphs[coverage[i]] - local math=glyph.math - if math then - math.kerns=kernset - else - glyph.math={ kerns=kernset } - end - end - end - end - end - end -end -local function readmathvariants(f,fontdata,offset) - setposition(f,offset) - local glyphs=fontdata.glyphs - local minoverlap=readushort(f) - local vcoverage=readushort(f) - local hcoverage=readushort(f) - local vnofglyphs=readushort(f) - local hnofglyphs=readushort(f) - 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 - local coverage=readcoverage(f,offset+coverage,true) - for i=1,nofglyphs do - local c=construction[i] - if c~=0 then - local index=coverage[i] - local glyph=glyphs[index] - local math=glyph.math - setposition(f,offset+c) - local assembly=readushort(f) - local nofvariants=readushort(f) - if nofvariants>0 then - local variants,v=nil,0 - for i=1,nofvariants do - local variant=readushort(f) - if variant==index then - elseif variants then - v=v+1 - variants[v]=variant - else - v=1 - variants={ variant } - end - skipshort(f) - end - if not variants then - elseif not math then - math={ [kvariants]=variants } - glyph.math=math - else - math[kvariants]=variants - end - end - if assembly~=0 then - setposition(f,offset+c+assembly) - local italic=readmathvalue(f) - local nofparts=readushort(f) - local parts={} - for i=1,nofparts do - local p={ - glyph=readushort(f), - start=readushort(f), - ["end"]=readushort(f), - advance=readushort(f), - } - local flags=readushort(f) - if band(flags,0x0001)~=0 then - p.extender=1 - end - parts[i]=p - end - if not math then - math={ - [kparts]=parts - } - glyph.math=math - else - math[kparts]=parts - end - if italic and italic~=0 then - math[kitalic]=italic - end - end - end - end - end - end - get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic") - get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic") -end -function readers.math(f,fontdata,specification) - 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 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 t={} - for i=1,noflayers do - t[i]=layerrecords[firstlayer+i] - end - 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) - 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 - 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 - 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 - end - fontdata.pngshapes=shapes - end -end -do - local function getmetrics(f) - return { - ascender=readinteger(f), - descender=readinteger(f), - widthmax=readuinteger(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 function getbigmetrics(f) - return { - height=readuinteger(f), - width=readuinteger(f), - horiBearingX=readinteger(f), - horiBearingY=readinteger(f), - horiAdvance=readuinteger(f), - vertBearingX=readinteger(f), - vertBearingY=readinteger(f), - vertAdvance=readuinteger(f), - } - end - local function getsmallmetrics(f) - return { - height=readuinteger(f), - width=readuinteger(f), - bearingX=readinteger(f), - bearingY=readinteger(f), - advance=readuinteger(f), - } - end - function readers.cblc(f,fontdata,specification) - local ctdttableoffset=gotodatatable(f,fontdata,"cbdt",specification.glyphs) - if not ctdttableoffset then - return - end - local cblctableoffset=gotodatatable(f,fontdata,"cblc",specification.glyphs) - if cblctableoffset then - local majorversion=readushort(f) - local minorversion=readushort(f) - local nofsizetables=readulong(f) - local sizetables={} - local shapes={} - local subtables={} - for i=1,nofsizetables do - sizetables[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(sizetables,function(a,b) - if b.ppemx==a.ppemx then - return b.bitdepth<a.bitdepth - else - return b.ppemx<a.ppemx - end - end) - for i=1,nofsizetables do - local s=sizetables[i] - local d=false - for j=s.firstindex,s.lastindex do - if not shapes[j] then - shapes[j]=i - d=true - end - end - if d then - s.used=true - end - end - for i=1,nofsizetables do - local s=sizetables[i] - if s.used then - local offset=s.subtables - setposition(f,cblctableoffset+offset) - for j=1,s.nofsubtables do - local firstindex=readushort(f) - local lastindex=readushort(f) - local tableoffset=readulong(f)+offset - for k=firstindex,lastindex do - if shapes[k]==i then - local s=subtables[tableoffset] - if not s then - s={ - firstindex=firstindex, - lastindex=lastindex, - } - subtables[tableoffset]=s - end - shapes[k]=s - end - end - end - end - end - for offset,subtable in sortedhash(subtables) do - local tabletype=readushort(f) - subtable.format=readushort(f) - local baseoffset=readulong(f)+ctdttableoffset - local offsets={} - local metrics=nil - if tabletype==1 then - for i=subtable.firstindex,subtable.lastindex do - offsets[i]=readulong(f)+baseoffset - end - skipbytes(f,4) - elseif tabletype==2 then - local size=readulong(f) - local done=baseoffset - metrics=getbigmetrics(f) - for i=subtable.firstindex,subtable.lastindex do - offsets[i]=done - done=done+size - end - elseif tabletype==3 then - local n=subtable.lastindex-subtable.firstindex+2 - for i=subtable.firstindex,subtable.lastindex do - offsets[i]=readushort(f)+baseoffset - end - if math.odd(n) then - skipbytes(f,4) - else - skipbytes(f,2) - end - elseif tabletype==4 then - for i=1,readulong(f) do - offsets[readushort(f)]=readushort(f)+baseoffset - end - elseif tabletype==5 then - local size=readulong(f) - local done=baseoffset - metrics=getbigmetrics(f) - local n=readulong(f) - for i=1,n do - offsets[readushort(f)]=done - done=done+size - end - if math.odd(n) then - skipbytes(f,2) - end - else - return - end - subtable.offsets=offsets - subtable.metrics=metrics - end - local default={ width=0,height=0 } - local glyphs=fontdata.glyphs - for index,subtable in sortedhash(shapes) do - if type(subtable)=="table" then - local data=nil - local metrics=default - local format=subtable.format - local offset=subtable.offsets[index] - setposition(f,offset) - if format==17 then - metrics=getsmallmetrics(f) - data=readstring(f,readulong(f)) - elseif format==18 then - metrics=getbigmetrics(f) - data=readstring(f,readulong(f)) - elseif format==19 then - metrics=subtable.metrics - data=readstring(f,readulong(f)) - else - end - local x=metrics.width - local y=metrics.height - shapes[index]={ - x=x, - y=y, - data=data, - } - local glyph=glyphs[index] - if not glyph.boundingbox then - local width=glyph.width - local height=width*y/x - glyph.boundingbox={ 0,0,width,height } - end - else - shapes[index]={ - x=0, - y=0, - data="", - } - end - end - fontdata.pngshapes=shapes - end - end - function readers.cbdt(f,fontdata,specification) - end -end -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 - return false - end - local version=readulong(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 - 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 - end -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-dsp”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-oup” 26b481cd9efebf7047810800930dff58] --- - -if not modules then modules={} end modules ['font-oup']={ - 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,type=next,type -local P,R,S=lpeg.P,lpeg.R,lpeg.S -local lpegmatch=lpeg.match -local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack -local formatters=string.formatters -local sortedkeys=table.sortedkeys -local sortedhash=table.sortedhash -local tohash=table.tohash -local setmetatableindex=table.setmetatableindex -local report_error=logs.reporter("otf reader","error") -local report_markwidth=logs.reporter("otf reader","markwidth") -local report_cleanup=logs.reporter("otf reader","cleanup") -local report_optimizations=logs.reporter("otf reader","merges") -local report_unicodes=logs.reporter("otf reader","unicodes") -local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end) -local trace_cleanup=false trackers.register("otf.cleanups",function(v) trace_cleanups=v end) -local trace_optimizations=false trackers.register("otf.optimizations",function(v) trace_optimizations=v end) -local trace_unicodes=false trackers.register("otf.unicodes",function(v) trace_unicodes=v end) -local readers=fonts.handlers.otf.readers -local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -local f_private=formatters["P%05X"] -local f_unicode=formatters["U%05X"] -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=true -directives.register("otf.checksofthyphen",function(v) - check_soft_hyphen=v -end) -local function replaced(list,index,replacement) - if type(list)=="number" then - return replacement - elseif type(replacement)=="table" then - local t={} - local n=index-1 - for i=1,n do - t[i]=list[i] - end - for i=1,#replacement do - n=n+1 - t[n]=replacement[i] - end - for i=index+1,#list do - n=n+1 - t[n]=list[i] - end - else - list[index]=replacement - return list - end -end -local function unifyresources(fontdata,indices) - local descriptions=fontdata.descriptions - local resources=fontdata.resources - if not descriptions or not resources then - return - end - local nofindices=#indices - local variants=fontdata.resources.variants - if variants then - for selector,unicodes in next,variants do - for unicode,index in next,unicodes do - unicodes[unicode]=indices[index] - end - end - end - local function remark(marks) - if marks then - local newmarks={} - for k,v in next,marks do - local u=indices[k] - if u then - newmarks[u]=v - elseif trace_optimizations then - report_optimizations("discarding mark %i",k) - end - end - return newmarks - end - end - local marks=resources.marks - if marks then - resources.marks=remark(marks) - end - local markclasses=resources.markclasses - if markclasses then - for class,marks in next,markclasses do - markclasses[class]=remark(marks) - end - end - local marksets=resources.marksets - if marksets then - for class,marks in next,marksets do - marksets[class]=remark(marks) - end - end - local done={} - local duplicates=check_duplicates and resources.duplicates - if duplicates and not next(duplicates) then - duplicates=false - end - local function recover(cover) - for i=1,#cover do - local c=cover[i] - if not done[c] then - local t={} - for k,v in next,c do - local ug=indices[k] - if ug then - t[ug]=v - else - report_error("case %i, bad index in unifying %s: %s of %s",1,"coverage",k,nofindices) - end - end - cover[i]=t - done[c]=d - end - end - end - local function recursed(c,kind) - local t={} - for g,d in next,c do - if type(d)=="table" then - local ug=indices[g] - if ug then - t[ug]=recursed(d,kind) - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g,nofindices) - end - else - t[g]=indices[d] - end - end - return t - end - local function unifythem(sequences) - if not sequences then - return - end - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - local features=sequence.features - if steps then - for i=1,#steps do - local step=steps[i] - if kind=="gsub_single" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - if duplicates then - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - local ud1=indices[d1] - if ud1 then - t1[ug1]=ud1 - local dg1=duplicates[ug1] - if dg1 then - for u in next,dg1 do - t1[u]=ud1 - end - end - else - report_error("case %i, bad index in unifying %s: %s of %s",3,kind,d1,nofindices) - end - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) - end - end - else - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=indices[d1] - else - report_error("fuzzy case %i in unifying %s: %i",2,kind,g1) - end - end - end - done[c]=t1 - end - step.coverage=t1 - end - elseif kind=="gpos_pair" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - local t2=done[d1] - if not t2 then - t2={} - for g2,d2 in next,d1 do - local ug2=indices[g2] - if ug2 then - t2[ug2]=d2 - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g2,nofindices,nofindices) - end - end - done[d1]=t2 - end - t1[ug1]=t2 - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) - end - end - done[c]=t1 - end - step.coverage=t1 - end - elseif kind=="gsub_ligature" then - local c=step.coverage - if c then - step.coverage=recursed(c,kind) - end - elseif kind=="gsub_alternate" or kind=="gsub_multiple" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - if duplicates then - for g1,d1 in next,c do - for i=1,#d1 do - local d1i=d1[i] - local d1u=indices[d1i] - if d1u then - d1[i]=d1u - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,i,d1i,nofindices) - end - end - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - local dg1=duplicates[ug1] - if dg1 then - for u in next,dg1 do - t1[u]=copy(d1) - end - end - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) - end - end - else - for g1,d1 in next,c do - for i=1,#d1 do - local d1i=d1[i] - local d1u=indices[d1i] - if d1u then - d1[i]=d1u - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,d1i,nofindices) - end - end - t1[indices[g1]]=d1 - end - end - done[c]=t1 - end - step.coverage=t1 - end - elseif kind=="gpos_single" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - if duplicates then - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - local dg1=duplicates[ug1] - if dg1 then - for u in next,dg1 do - t1[u]=d1 - end - end - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) - end - end - else - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) - end - end - end - done[c]=t1 - end - step.coverage=t1 - end - elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) - end - end - done[c]=t1 - end - step.coverage=t1 - end - local c=step.baseclasses - if c then - local t1=done[c] - if not t1 then - for g1,d1 in next,c do - local t2=done[d1] - if not t2 then - t2={} - for g2,d2 in next,d1 do - local ug2=indices[g2] - if ug2 then - t2[ug2]=d2 - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g2,nofindices) - end - end - done[d1]=t2 - end - c[g1]=t2 - end - done[c]=c - end - end - elseif kind=="gpos_cursive" then - local c=step.coverage - if c then - local t1=done[c] - if not t1 then - t1={} - if duplicates then - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - local dg1=duplicates[ug1] - if dg1 then - for u in next,dg1 do - t1[u]=copy(d1) - end - end - else - report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) - end - end - else - for g1,d1 in next,c do - local ug1=indices[g1] - if ug1 then - t1[ug1]=d1 - else - report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) - end - end - end - done[c]=t1 - end - step.coverage=t1 - end - end - local rules=step.rules - if rules then - for i=1,#rules do - local rule=rules[i] - local before=rule.before if before then recover(before) end - local after=rule.after if after then recover(after) end - local current=rule.current if current then recover(current) end - local replacements=rule.replacements - if replacements then - if not done[replacements] then - local r={} - for k,v in next,replacements do - r[indices[k]]=indices[v] - end - rule.replacements=r - done[replacements]=r - end - end - end - end - end - end - end - end - unifythem(resources.sequences) - unifythem(resources.sublookups) -end -local function copyduplicates(fontdata) - if check_duplicates then - local descriptions=fontdata.descriptions - local resources=fontdata.resources - local duplicates=resources.duplicates - if check_soft_hyphen then - local ds=descriptions[0xAD] - if not ds or ds.width==0 then - if ds then - descriptions[0xAD]=nil - if trace_unicodes then - report_unicodes("patching soft hyphen") - end - else - if trace_unicodes then - report_unicodes("adding soft hyphen") - end - end - if not duplicates then - duplicates={} - resources.duplicates=duplicates - end - local dh=duplicates[0x2D] - if dh then - dh[#dh+1]={ [0xAD]=true } - else - duplicates[0x2D]={ [0xAD]=true } - end - end - end - if duplicates then - for u,d in next,duplicates do - local du=descriptions[u] - if du then - local t={ f_character_y(u),"@",f_index(du.index),"->" } - local n=0 - local m=25 - for u in next,d do - if descriptions[u] then - if n<m then - t[n+4]=f_character_n(u) - end - else - local c=copy(du) - c.unicode=u - descriptions[u]=c - if n<m then - t[n+4]=f_character_y(u) - end - end - n=n+1 - end - if trace_unicodes then - if n<=m then - report_unicodes("%i : % t",n,t) - else - report_unicodes("%i : % t ...",n,t) - end - end - else - end - end - end - end -end -local ignore={ - ["notdef"]=true, - [".notdef"]=true, - ["null"]=true, - [".null"]=true, - ["nonmarkingreturn"]=true, -} -local function checklookups(fontdata,missing,nofmissing) - local descriptions=fontdata.descriptions - local resources=fontdata.resources - if missing and nofmissing and nofmissing<=0 then - return - end - local singles={} - local alternates={} - local ligatures={} - if not missing then - missing={} - nofmissing=0 - for u,d in next,descriptions do - if not d.unicode then - nofmissing=nofmissing+1 - missing[u]=true - end - end - end - local function collectthem(sequences) - if not sequences then - return - end - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - if steps then - for i=1,#steps do - local step=steps[i] - if kind=="gsub_single" then - local c=step.coverage - if c then - singles[#singles+1]=c - end - elseif kind=="gsub_alternate" then - local c=step.coverage - if c then - alternates[#alternates+1]=c - end - elseif kind=="gsub_ligature" then - local c=step.coverage - if c then - ligatures[#ligatures+1]=c - end - end - end - end - end - end - collectthem(resources.sequences) - collectthem(resources.sublookups) - local loops=0 - while true do - loops=loops+1 - local old=nofmissing - for i=1,#singles do - local c=singles[i] - for g1,g2 in next,c do - if missing[g1] then - local u2=descriptions[g2].unicode - if u2 then - missing[g1]=false - descriptions[g1].unicode=u2 - nofmissing=nofmissing-1 - end - end - if missing[g2] then - local u1=descriptions[g1].unicode - if u1 then - missing[g2]=false - descriptions[g2].unicode=u1 - nofmissing=nofmissing-1 - end - end - end - end - for i=1,#alternates do - local c=alternates[i] - for g1,d1 in next,c do - if missing[g1] then - for i=1,#d1 do - local g2=d1[i] - local u2=descriptions[g2].unicode - if u2 then - missing[g1]=false - descriptions[g1].unicode=u2 - nofmissing=nofmissing-1 - end - end - end - if not missing[g1] then - for i=1,#d1 do - local g2=d1[i] - if missing[g2] then - local u1=descriptions[g1].unicode - if u1 then - missing[g2]=false - descriptions[g2].unicode=u1 - nofmissing=nofmissing-1 - end - end - end - end - end - end - if nofmissing<=0 then - if trace_unicodes then - report_unicodes("all missings done in %s loops",loops) - end - return - elseif old==nofmissing then - break - end - end - local t,n - local function recursed(c) - for g,d in next,c do - if g~="ligature" then - local u=descriptions[g].unicode - if u then - n=n+1 - t[n]=u - recursed(d) - n=n-1 - end - elseif missing[d] then - local l={} - local m=0 - for i=1,n do - local u=t[i] - if type(u)=="table" then - for i=1,#u do - m=m+1 - l[m]=u[i] - end - else - m=m+1 - l[m]=u - end - end - missing[d]=false - descriptions[d].unicode=l - nofmissing=nofmissing-1 - end - end - end - if nofmissing>0 then - t={} - n=0 - local loops=0 - while true do - loops=loops+1 - local old=nofmissing - for i=1,#ligatures do - recursed(ligatures[i]) - end - if nofmissing<=0 then - if trace_unicodes then - report_unicodes("all missings done in %s loops",loops) - end - return - elseif old==nofmissing then - break - end - end - t=nil - n=0 - end - if trace_unicodes and nofmissing>0 then - local done={} - for i,r in next,missing do - if r then - local data=descriptions[i] - local name=data and data.name or f_index(i) - if not ignore[name] then - done[name]=true - end - end - end - if next(done) then - report_unicodes("not unicoded: % t",sortedkeys(done)) - end - end -end -local function unifymissing(fontdata) - if not fonts.mappings then - require("font-map") - require("font-agl") - end - local unicodes={} - local resources=fontdata.resources - resources.unicodes=unicodes - for unicode,d in next,fontdata.descriptions do - if unicode<privateoffset then - local name=d.name - if name then - unicodes[name]=unicode - end - end - end - fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups) - resources.unicodes=nil -end -local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000 -local puafirst=0xE000 -local pualast=0xF8FF -local function unifyglyphs(fontdata,usenames) - local private=fontdata.private or privateoffset - local glyphs=fontdata.glyphs - local indices={} - local descriptions={} - local names=usenames and {} - local resources=fontdata.resources - local zero=glyphs[0] - local zerocode=zero.unicode - if not zerocode then - zerocode=private - zero.unicode=zerocode - private=private+1 - end - descriptions[zerocode]=zero - if names then - local name=glyphs[0].name or f_private(zerocode) - indices[0]=name - names[name]=zerocode - else - indices[0]=zerocode - end - if names then - for index=1,#glyphs do - local glyph=glyphs[index] - local unicode=glyph.unicode - if not unicode then - unicode=private - local name=glyph.name or f_private(unicode) - indices[index]=name - names[name]=unicode - private=private+1 - elseif unicode>=firstprivate then - unicode=private - local name=glyph.name or f_private(unicode) - indices[index]=name - names[name]=unicode - private=private+1 - elseif unicode>=puafirst and unicode<=pualast then - local name=glyph.name or f_private(unicode) - indices[index]=name - names[name]=unicode - elseif descriptions[unicode] then - unicode=private - local name=glyph.name or f_private(unicode) - indices[index]=name - names[name]=unicode - private=private+1 - else - local name=glyph.name or f_unicode(unicode) - indices[index]=name - names[name]=unicode - end - descriptions[unicode]=glyph - end - elseif trace_unicodes then - for index=1,#glyphs do - local glyph=glyphs[index] - local unicode=glyph.unicode - if not unicode then - unicode=private - indices[index]=unicode - private=private+1 - elseif unicode>=firstprivate then - local name=glyph.name - if name then - report_unicodes("moving glyph %a indexed %05X from private %U to %U ",name,index,unicode,private) - else - report_unicodes("moving glyph indexed %05X from private %U to %U ",index,unicode,private) - end - unicode=private - indices[index]=unicode - private=private+1 - elseif unicode>=puafirst and unicode<=pualast then - local name=glyph.name - if name then - report_unicodes("keeping private unicode %U for glyph %a indexed %05X",unicode,name,index) - else - report_unicodes("keeping private unicode %U for glyph indexed %05X",unicode,index) - end - indices[index]=unicode - elseif descriptions[unicode] then - local name=glyph.name - if name then - report_unicodes("assigning duplicate unicode %U to %U for glyph %a indexed %05X ",unicode,private,name,index) - else - report_unicodes("assigning duplicate unicode %U to %U for glyph indexed %05X ",unicode,private,index) - end - unicode=private - indices[index]=unicode - private=private+1 - else - indices[index]=unicode - end - descriptions[unicode]=glyph - end - else - for index=1,#glyphs do - local glyph=glyphs[index] - local unicode=glyph.unicode - if not unicode then - unicode=private - indices[index]=unicode - private=private+1 - elseif unicode>=firstprivate then - local name=glyph.name - unicode=private - indices[index]=unicode - private=private+1 - elseif unicode>=puafirst and unicode<=pualast then - local name=glyph.name - indices[index]=unicode - elseif descriptions[unicode] then - local name=glyph.name - unicode=private - indices[index]=unicode - private=private+1 - else - indices[index]=unicode - end - descriptions[unicode]=glyph - end - end - for index=1,#glyphs do - local math=glyphs[index].math - if math then - local list=math.vparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.hparts - if list then - for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end - end - local list=math.vvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end - end - local list=math.hvariants - if list then - for i=1,#list do list[i]=indices[list[i]] end - end - end - end - local colorpalettes=resources.colorpalettes - if colorpalettes then - for index=1,#glyphs do - local colors=glyphs[index].colors - if colors then - for i=1,#colors do - local c=colors[i] - c.slot=indices[c.slot] - end - end - end - end - fontdata.private=private - fontdata.glyphs=nil - fontdata.names=names - fontdata.descriptions=descriptions - fontdata.hashmethod=hashmethod - return indices,names -end -local p_crappyname do - local p_hex=R("af","AF","09") - local p_digit=R("09") - local p_done=S("._-")^0+P(-1) - local p_alpha=R("az","AZ") - local p_ALPHA=R("AZ") - p_crappyname=( - lpeg.utfchartabletopattern({ "uni","u" },true)*S("Xx_")^0*p_hex^1 -+lpeg.utfchartabletopattern({ "identity","glyph","jamo" },true)*p_hex^1 -+lpeg.utfchartabletopattern({ "index","afii" },true)*p_digit^1 -+p_digit*p_hex^3+p_alpha*p_digit^1 -+P("aj")*p_digit^1+P("eh_")*(p_digit^1+p_ALPHA*p_digit^1)+(1-P("_"))^1*P("_uni")*p_hex^1+P("_")*P(1)^1 - )*p_done -end -local forcekeep=false -directives.register("otf.keepnames",function(v) - report_cleanup("keeping weird glyph names, expect larger files and more memory usage") - forcekeep=v -end) -local function stripredundant(fontdata) - local descriptions=fontdata.descriptions - if descriptions then - local n=0 - local c=0 - if (not context and fonts.privateoffsets.keepnames) or forcekeep then - for unicode,d in next,descriptions do - if d.class=="base" then - d.class=nil - c=c+1 - end - end - else - for unicode,d in next,descriptions do - local name=d.name - if name and lpegmatch(p_crappyname,name) then - d.name=nil - n=n+1 - end - if d.class=="base" then - d.class=nil - c=c+1 - end - end - end - if trace_cleanup then - if n>0 then - report_cleanup("%s bogus names removed (verbose unicode)",n) - end - if c>0 then - report_cleanup("%s base class tags removed (default is base)",c) - end - end - end -end -readers.stripredundant=stripredundant -function readers.getcomponents(fontdata) - local resources=fontdata.resources - if resources then - local sequences=resources.sequences - if sequences then - local collected={} - for i=1,#sequences do - local sequence=sequences[i] - if sequence.type=="gsub_ligature" then - local steps=sequence.steps - if steps then - local l={} - local function traverse(p,k,v) - if k=="ligature" then - collected[v]={ unpack(l) } - else - insert(l,k) - for k,vv in next,v do - traverse(p,k,vv) - end - remove(l) - end - end - for i=1,#steps do - local c=steps[i].coverage - if c then - for k,v in next,c do - traverse(k,k,v) - end - end - end - end - end - end - if next(collected) then - while true do - local done=false - for k,v in next,collected do - for i=1,#v do - local vi=v[i] - if vi==k then - collected[k]=nil - break - else - local c=collected[vi] - if c then - done=true - local t={} - local n=i-1 - for j=1,n do - t[j]=v[j] - end - for j=1,#c do - n=n+1 - t[n]=c[j] - end - for j=i+1,#v do - n=n+1 - t[n]=v[j] - end - collected[k]=t - break - end - end - end - end - if not done then - break - end - end - return collected - end - end - end -end -readers.unifymissing=unifymissing -function readers.rehash(fontdata,hashmethod) - if not (fontdata and fontdata.glyphs) then - return - end - if hashmethod=="indices" then - fontdata.hashmethod="indices" - elseif hashmethod=="names" then - fontdata.hashmethod="names" - local indices=unifyglyphs(fontdata,true) - unifyresources(fontdata,indices) - copyduplicates(fontdata) - unifymissing(fontdata) - else - fontdata.hashmethod="unicodes" - local indices=unifyglyphs(fontdata) - unifyresources(fontdata,indices) - copyduplicates(fontdata) - unifymissing(fontdata) - stripredundant(fontdata) - end -end -function readers.checkhash(fontdata) - local hashmethod=fontdata.hashmethod - if hashmethod=="unicodes" then - fontdata.names=nil - elseif hashmethod=="names" and fontdata.names then - unifyresources(fontdata,fontdata.names) - copyduplicates(fontdata) - fontdata.hashmethod="unicodes" - fontdata.names=nil - else - readers.rehash(fontdata,"unicodes") - end -end -function readers.addunicodetable(fontdata) - local resources=fontdata.resources - local unicodes=resources.unicodes - if not unicodes then - local descriptions=fontdata.descriptions - if descriptions then - unicodes={} - resources.unicodes=unicodes - for u,d in next,descriptions do - local n=d.name - if n then - unicodes[n]=u - end - end - end - end -end -local concat,sort=table.concat,table.sort -local next,type,tostring=next,type,tostring -local criterium=1 -local threshold=0 -local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end) -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -local report_otf=logs.reporter("fonts","otf loading") -local function tabstr_normal(t) - local s={} - local n=0 - for k,v in next,t do - n=n+1 - if type(v)=="table" then - s[n]=k..">"..tabstr_normal(v) - elseif v==true then - s[n]=k.."+" - elseif v then - s[n]=k.."="..v - else - s[n]=k.."-" - end - end - if n==0 then - return "" - elseif n==1 then - return s[1] - else - sort(s) - return concat(s,",") - end -end -local function tabstr_flat(t) - local s={} - local n=0 - for k,v in next,t do - n=n+1 - s[n]=k.."="..v - end - if n==0 then - return "" - elseif n==1 then - return s[1] - else - sort(s) - return concat(s,",") - end -end -local function tabstr_mixed(t) - local s={} - local n=#t - if n==0 then - return "" - elseif n==1 then - local k=t[1] - if k==true then - return "++" - elseif k==false then - return "--" - else - return tostring(k) - end - else - for i=1,n do - local k=t[i] - if k==true then - s[i]="++" - elseif k==false then - s[i]="--" - else - s[i]=k - end - end - return concat(s,",") - end -end -local function tabstr_boolean(t) - local s={} - local n=0 - for k,v in next,t do - n=n+1 - if v then - s[n]=k.."+" - else - s[n]=k.."-" - end - end - if n==0 then - return "" - elseif n==1 then - return s[1] - else - sort(s) - return concat(s,",") - end -end -function readers.pack(data) - if data then - local h,t,c={},{},{} - local hh,tt,cc={},{},{} - local nt,ntt=0,0 - local function pack_normal(v) - local tag=tabstr_normal(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_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 - c[nt]=1 - return nt - end - end - local function pack_flat(v) - local tag=tabstr_flat(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_indexed(v) - local tag=concat(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_mixed(v) - local tag=tabstr_mixed(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_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] - 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 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 - report_otf("pack quality: nothing to pack") - end - return false - elseif nt>=threshold then - local one,two,rest=0,0,0 - if pass==1 then - for k,v in next,c do - if v==1 then - one=one+1 - elseif v==2 then - two=two+1 - else - rest=rest+1 - end - end - else - for k,v in next,cc do - if v>20 then - rest=rest+1 - elseif v>10 then - two=two+1 - else - one=one+1 - end - end - data.tables=tt - end - if trace_loading or trace_packing then - report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", - stage,pass,one+two+rest,one,two,rest,criterium) - end - return true - else - if trace_loading or trace_packing then - report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", - stage,pass,nt,threshold) - end - return false - end - end - local function packers(pass) - if pass==1 then - 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,pack_final_cc - end - end - local resources=data.resources - local sequences=resources.sequences - 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 - 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,pack_normal_cc=packers(pass) - for unicode,description in next,descriptions do - local boundingbox=description.boundingbox - if boundingbox then - description.boundingbox=pack_indexed(boundingbox) - end - local math=description.math - if math then - local kerns=math.kerns - if kerns then - for tag,kern in next,kerns do - kerns[tag]=pack_normal(kern) - end - end - end - end - local function packthem(sequences) - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - local order=sequence.order - local features=sequence.features - local flags=sequence.flags - 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=="pair" then - for g1,d1 in next,c do - 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 - c[g1]=pack_normal(d1) - end - end - end - elseif kind=="gpos_single" then - local c=step.coverage - if c then - if step.format=="single" then - for g1,d1 in next,c do - 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 - local c=step.coverage - if c then - for g1,d1 in next,c do - local f=d1[2] if f then d1[2]=pack_indexed(f) end - local s=d1[3] if s then d1[3]=pack_indexed(s) end - end - end - elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" 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_indexed(d2) - end - end - end - local c=step.coverage - if c then - for g1,d1 in next,c do - d1[2]=pack_indexed(d1[2]) - 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 - for g3,d3 in next,d2 do - d2[g3]=pack_indexed(d3) - end - end - end - end - local c=step.coverage - if c then - for g1,d1 in next,c do - d1[2]=pack_indexed(d1[2]) - end - end - end - local rules=step.rules - if rules then - for i=1,#rules do - local rule=rules[i] - 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.replacements if r then rule.replacements=pack_flat (r) end - end - end - end - end - if order then - sequence.order=pack_indexed(order) - end - if features then - for script,feature in next,features do - features[script]=pack_normal(feature) - end - end - if flags then - sequence.flags=pack_normal(flags) - end - end - end - if sequences then - packthem(sequences) - end - if sublookups then - packthem(sublookups) - end - if features then - for k,list in next,features do - for feature,spec in next,list do - list[feature]=pack_normal(spec) - end - end - end - if palettes then - for i=1,#palettes do - local p=palettes[i] - for j=1,#p do - p[j]=pack_indexed(p[j]) - 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 - end - if nt>0 then - for pass=1,2 do - 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,pack_normal_cc=packers(pass) - for unicode,description in next,descriptions do - local math=description.math - if math then - local kerns=math.kerns - if kerns then - math.kerns=pack_normal(kerns) - end - end - end - local function packthem(sequences) - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - local features=sequence.features - 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=="pair" then - for g1,d1 in next,c do - for g2,d2 in next,d1 do - d1[g2]=pack_normal(d2) - end - 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 - for i=1,#rules do - local rule=rules[i] - local r=rule.before if r then rule.before=pack_normal(r) end - local r=rule.after if r then rule.after=pack_normal(r) end - local r=rule.current if r then rule.current=pack_normal(r) end - end - end - end - end - if features then - sequence.features=pack_normal(features) - end - end - end - if sequences then - packthem(sequences) - end - if sublookups then - packthem(sublookups) - end - 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,pack_normal_cc=packers(pass) - local function packthem(sequences) - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - local features=sequence.features - 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=="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 - if sequences then - packthem(sequences) - end - if sublookups then - packthem(sublookups) - end - end - end - end -end -local unpacked_mt={ - __index=function(t,k) - t[k]=false - return k - end -} -function readers.unpack(data) - if data then - local tables=data.tables - if tables then - local resources=data.resources - local descriptions=data.descriptions or data.glyphs - local sequences=resources.sequences - 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 - local tv=tables[description.boundingbox] - if tv then - description.boundingbox=tv - end - local math=description.math - if math then - local kerns=math.kerns - if kerns then - local tm=tables[kerns] - if tm then - math.kerns=tm - kerns=unpacked[tm] - end - if kerns then - for k,kern in next,kerns do - local tv=tables[kern] - if tv then - kerns[k]=tv - end - end - end - end - end - end - local function unpackthem(sequences) - for i=1,#sequences do - local sequence=sequences[i] - local kind=sequence.type - local steps=sequence.steps - local order=sequence.order - 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=="pair" then - for g1,d1 in next,c do - local tv=tables[d1] - if tv then - c[g1]=tv - d1=tv - end - for g2,d2 in next,d1 do - local tv=tables[d2] - if tv then - d1[g2]=tv - d2=tv - end - local f=tables[d2[1]] if f then d2[1]=f end - 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=="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 - end - elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then - local c=step.baseclasses - if c then - for g1,d1 in next,c do - for g2,d2 in next,d1 do - local tv=tables[d2] - if tv then - d1[g2]=tv - end - end - end - end - local c=step.coverage - if c then - for g1,d1 in next,c do - local tv=tables[d1[2]] - if tv then - d1[2]=tv - 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 - 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 - d2[g3]=tv - end - end - end - end - end - local c=step.coverage - if c then - for g1,d1 in next,c do - local tv=tables[d1[2]] - if tv then - d1[2]=tv - end - end - end - end - local rules=step.rules - if rules then - for i=1,#rules do - local rule=rules[i] - local before=rule.before - if before then - local tv=tables[before] - if tv then - rule.before=tv - before=tv - end - for i=1,#before do - local tv=tables[before[i]] - if tv then - before[i]=tv - end - end - end - local after=rule.after - if after then - local tv=tables[after] - if tv then - rule.after=tv - after=tv - end - for i=1,#after do - local tv=tables[after[i]] - if tv then - after[i]=tv - end - end - end - local current=rule.current - if current then - local tv=tables[current] - if tv then - rule.current=tv - current=tv - end - for i=1,#current do - local tv=tables[current[i]] - if tv then - current[i]=tv - end - end - end - local replacements=rule.replacements - if replacements then - local tv=tables[replacements] - if tv then - rule.replacements=tv - end - end - end - end - end - end - if order then - local tv=tables[order] - if tv then - sequence.order=tv - end - end - if flags then - local tv=tables[flags] - if tv then - sequence.flags=tv - end - end - end - end - if sequences then - unpackthem(sequences) - end - if sublookups then - unpackthem(sublookups) - end - if features then - for k,list in next,features do - for feature,spec in next,list do - local tv=tables[spec] - if tv then - list[feature]=tv - end - end - end - end - if palettes then - for i=1,#palettes do - local p=palettes[i] - for j=1,#p do - local tv=tables[p[j]] - if tv then - p[j]=tv - end - 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 -end -local mt={ - __index=function(t,k) - if k=="height" then - local ht=t.boundingbox[4] - return ht<0 and 0 or ht - elseif k=="depth" then - local dp=-t.boundingbox[2] - return dp<0 and 0 or dp - elseif k=="width" then - return 0 - elseif k=="name" then - return forcenotdef and ".notdef" - end - end -} -local function sameformat(sequence,steps,first,nofsteps,kind) - return true -end -local function mergesteps_1(lookup,strict) - local steps=lookup.steps - local nofsteps=lookup.nofsteps - local first=steps[1] - if strict then - local f=first.format - for i=2,nofsteps do - if steps[i].format~=f then - if trace_optimizations then - report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) - end - return 0 - end - end - end - if trace_optimizations then - report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - end - local target=first.coverage - for i=2,nofsteps do - 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 - lookup.nofsteps=1 - lookup.merged=true - lookup.steps={ first } - return nofsteps-1 -end -local function mergesteps_2(lookup) - local steps=lookup.steps - local nofsteps=lookup.nofsteps - local first=steps[1] - if strict then - local f=first.format - for i=2,nofsteps do - if steps[i].format~=f then - if trace_optimizations then - report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) - end - return 0 - end - end - end - if trace_optimizations then - report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - end - local target=first.coverage - 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 - for kk,vv in next,v do - if tk[kk]==nil then - tk[kk]=vv - end - end - else - target[k]=v - end - 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 - if trace_optimizations then - report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - end - local coverage={} - for i=1,nofsteps do - local c=steps[i].coverage - if c then - for k,v in next,c do - local tk=coverage[k] - if tk then - if trace_optimizations then - report_optimizations("quitting merge due to multiple checks") - end - 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 - 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 -local function nested(old,new) - for k,v in next,old do - if k=="ligature" then - if not new.ligature then - new.ligature=v - end - else - local n=new[k] - if n then - nested(v,n) - else - new[k]=v - end - end - end -end -local function mergesteps_4(lookup) - local steps=lookup.steps - local nofsteps=lookup.nofsteps - local first=steps[1] - if trace_optimizations then - report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - end - local target=first.coverage - 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 - 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] - if trace_optimizations then - report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) - end - 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==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 - if trace_optimizations then - report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) - end - local c={} - for g1,d1 in next,coverage do - if d1 and d1~=true then - c[g1]=d1[3] - end - end - 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 - 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 - 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 - if trace_optimizations then - report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) - end - for g1,d1 in next,coverage do - local d={} - for g2,d2 in next,d1 do - local v=d2[1] - if v==true then - elseif v then - d[g2]=v[3] - end - end - coverage[g1]=d - end - 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 - else - data.compacted=true - end - local resources=data.resources - local merged=0 - local kerned=0 - local allsteps=0 - local function compact(what) - local lookups=resources[what] - if lookups then - 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 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 - if merge_ligatures then - merged=merged+mergesteps_4(lookup) - end - elseif kind=="gpos_single" then - 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 - if merge_pairs then - merged=merged+mergesteps_2(lookup) - end - if compact_pairs then - kerned=kerned+checkpairs(lookup) - end - elseif kind=="gpos_cursive" then - if merge_cursives then - merged=merged+mergesteps_5(lookup) - end - elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then - 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 - elseif trace_optimizations then - report_optimizations("no lookups in %a",what) - end - end - compact("sequences") - compact("sublookups") - if trace_optimizations then - if merged>0 then - report_optimizations("%i steps of %i removed due to merging",merged,allsteps) - end - if kerned>0 then - report_optimizations("%i steps of %i steps turned from pairs into kerns",kerned,allsteps) - end - 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 - else - data.expanded=true - end - local resources=data.resources - local sublookups=resources.sublookups - local sequences=resources.sequences - local markclasses=resources.markclasses - local descriptions=data.descriptions - if descriptions then - local defaultwidth=resources.defaultwidth or 0 - local defaultheight=resources.defaultheight or 0 - local defaultdepth=resources.defaultdepth or 0 - local basename=trace_markwidth and file.basename(resources.filename) - for u,d in next,descriptions do - local bb=d.boundingbox - local wd=d.width - if not wd then - d.width=defaultwidth - elseif trace_markwidth and wd~=0 and d.class=="mark" then - report_markwidth("mark %a with width %b found in %a",d.name or "<noname>",wd,basename) - end - if bb then - local ht=bb[4] - local dp=-bb[2] - if ht==0 or ht<0 then - else - d.height=ht - end - if dp==0 or dp<0 then - else - d.depth=dp - end - end - end - end - local function expandlookups(sequences) - if sequences then - for i=1,#sequences do - 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 - if not markclasses then - report_warning("missing markclasses") - sequence.markclass=false - else - sequence.markclass=markclasses[markclass] - end - end - for i=1,nofsteps do - local step=steps[i] - local baseclasses=step.baseclasses - if baseclasses then - local coverage=step.coverage - for k,v in next,coverage do - v[1]=baseclasses[v[1]] - end - elseif kind=="gpos_cursive" then - local coverage=step.coverage - for k,v in next,coverage do - v[1]=coverage - end - end - local rules=step.rules - if rules then - local rulehash={ n=0 } - local rulesize=0 - local coverage={} - local lookuptype=sequence.type - local nofrules=#rules - step.coverage=coverage - for currentrule=1,nofrules do - local rule=rules[currentrule] - local current=rule.current - local before=rule.before - local after=rule.after - local replacements=rule.replacements or false - local sequence={} - local nofsequences=0 - if before then - for n=1,#before do - nofsequences=nofsequences+1 - sequence[nofsequences]=before[n] - end - end - local start=nofsequences+1 - for n=1,#current do - nofsequences=nofsequences+1 - sequence[nofsequences]=current[n] - end - local stop=nofsequences - if after then - for n=1,#after do - nofsequences=nofsequences+1 - sequence[nofsequences]=after[n] - end - end - local lookups=rule.lookups or false - local subtype=nil - if lookups then - 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 - end - end - end - if sequence[1] then - sequence.n=#sequence - local ruledata={ - currentrule, - lookuptype, - sequence, - start, - stop, - lookups, - replacements, - subtype, - } - 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 - end - expandlookups(sequences) - expandlookups(sublookups) -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-oup”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otl” 0836c8396cae2bcfd4020186e5e8d7e0] --- - -if not modules then modules={} end modules ['font-otl']={ - 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 type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack -local abs=math.abs -local derivetable=table.derive -local formatters=string.formatters -local setmetatableindex=table.setmetatableindex -local allocate=utilities.storage.allocate -local registertracker=trackers.register -local registerdirective=directives.register -local starttiming=statistics.starttiming -local stoptiming=statistics.stoptiming -local elapsedtime=statistics.elapsedtime -local findbinfile=resolvers.findbinfile -local trace_loading=false registertracker("otf.loading",function(v) trace_loading=v end) -local trace_features=false registertracker("otf.features",function(v) trace_features=v end) -local trace_defining=false registertracker("fonts.defining",function(v) trace_defining=v end) -local report_otf=logs.reporter("fonts","otf loading") -local fonts=fonts -local otf=fonts.handlers.otf -otf.version=3.107 -otf.cache=containers.define("fonts","otl",otf.version,true) -otf.svgcache=containers.define("fonts","svg",otf.version,true) -otf.pngcache=containers.define("fonts","png",otf.version,true) -otf.pdfcache=containers.define("fonts","pdf",otf.version,true) -otf.svgenabled=false -otf.pngenabled=false -local otfreaders=otf.readers -local hashes=fonts.hashes -local definers=fonts.definers -local readers=fonts.readers -local constructors=fonts.constructors -local otffeatures=constructors.features.otf -local registerotffeature=otffeatures.register -local otfenhancers=constructors.enhancers.otf -local registerotfenhancer=otfenhancers.register -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" -local formats=fonts.formats -formats.otf="opentype" -formats.ttf="truetype" -formats.ttc="truetype" -registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end) -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) -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 attr=lfs.attributes(filename) - local size=attr and attr.size or 0 - local time=attr and attr.modification or 0 - if sub=="" then - sub=false - end - local hash=name - if sub then - hash=hash.."-"..sub - 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 reload then - report_otf("loading %a, hash %a",filename,hash) - starttiming(otfreaders,true) - data=otfreaders.loadfont(filename,sub or 1,instance) - if data then - local used=checkmemory() - local resources=data.resources - local svgshapes=resources.svgshapes - local pngshapes=resources.pngshapes - if cleanup==0 then - checkmemory(used,threshold,tracememory) - end - if svgshapes then - resources.svgshapes=nil - if otf.svgenabled then - local timestamp=os.date() - containers.write(otf.svgcache,hash,{ - svgshapes=svgshapes, - timestamp=timestamp, - }) - data.properties.svg={ - hash=hash, - timestamp=timestamp, - } - end - if cleanup>1 then - collectgarbage("collect") - else - checkmemory(used,threshold,tracememory) - end - end - if pngshapes then - resources.pngshapes=nil - if otf.pngenabled then - local timestamp=os.date() - containers.write(otf.pngcache,hash,{ - pngshapes=pngshapes, - timestamp=timestamp, - }) - data.properties.png={ - 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 - report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders)) - 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 - stoptiming(otfreaders) - data=nil - report_otf("loading failed due to read error") - end - end - if data then - if trace_defining then - report_otf("loading from cache using hash %a",hash) - end - otfreaders.unpack(data) - otfreaders.expand(data) - otfreaders.addunicodetable(data) - otfenhancers.apply(data,filename,data) - if applyruntimefixes then - 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 -function otf.setfeatures(tfmdata,features) - local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf) - if okay then - return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf) - else - return {} - end -end -local function copytotfm(data,cache_id) - if data then - local metadata=data.metadata - local properties=derivetable(data.properties) - local descriptions=derivetable(data.descriptions) - local goodies=derivetable(data.goodies) - local characters={} - local parameters={} - local mathparameters={} - local resources=data.resources - local unicodes=resources.unicodes - local spaceunits=500 - local spacer="space" - local designsize=metadata.designsize or 100 - local minsize=metadata.minsize or designsize - local maxsize=metadata.maxsize or designsize - local mathspecs=metadata.math - if designsize==0 then - designsize=100 - minsize=100 - maxsize=100 - end - if mathspecs then - for name,value in next,mathspecs do - mathparameters[name]=value - end - end - for unicode in next,data.descriptions do - characters[unicode]={} - end - if mathspecs then - for unicode,character in next,characters do - local d=descriptions[unicode] - local m=d.math - if m then - local italic=m.italic - local vitalic=m.vitalic - local variants=m.hvariants - local parts=m.hparts - if variants then - local c=character - for i=1,#variants do - local un=variants[i] - c.next=un - c=characters[un] - end - c.horiz_variants=parts - elseif parts then - character.horiz_variants=parts - italic=m.hitalic - end - local variants=m.vvariants - local parts=m.vparts - if variants then - local c=character - for i=1,#variants do - local un=variants[i] - c.next=un - c=characters[un] - end - c.vert_variants=parts - elseif parts then - character.vert_variants=parts - end - if italic and italic~=0 then - character.italic=italic - end - if vitalic and vitalic~=0 then - character.vert_italic=vitalic - end - local accent=m.accent - if accent then - character.accent=accent - end - local kerns=m.kerns - if kerns then - character.mathkerns=kerns - end - end - end - end - local filename=constructors.checkedfilename(resources) - 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 - metadata.units=1000 - report_otf("changing %a units to %a",0,units) - end - local monospaced=metadata.monospaced - local charwidth=metadata.averagewidth - local charxheight=metadata.xheight - local italicangle=metadata.italicangle - local hasitalics=metadata.hasitalics - properties.monospaced=monospaced - properties.hasitalics=hasitalics - parameters.italicangle=italicangle - parameters.charwidth=charwidth - parameters.charxheight=charxheight - local space=0x0020 - local emdash=0x2014 - if monospaced then - if descriptions[space] then - spaceunits,spacer=descriptions[space].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width,"emdash" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" - end - else - if descriptions[space] then - spaceunits,spacer=descriptions[space].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width/2,"emdash/2" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" - end - end - spaceunits=tonumber(spaceunits) or units/2 - parameters.slant=0 - parameters.space=spaceunits - parameters.space_stretch=1*units/2 - parameters.space_shrink=1*units/3 - parameters.x_height=2*units/5 - parameters.quad=units - if spaceunits<2*units/5 then - end - if italicangle and italicangle~=0 then - parameters.italicangle=italicangle - parameters.italicfactor=math.cos(math.rad(90+italicangle)) - parameters.slant=- math.tan(italicangle*math.pi/180) - end - if monospaced then - parameters.space_stretch=0 - parameters.space_shrink=0 - elseif syncspace then - parameters.space_stretch=spaceunits/2 - parameters.space_shrink=spaceunits/3 - end - parameters.extra_space=parameters.space_shrink - if charxheight then - parameters.x_height=charxheight - else - local x=0x0078 - if x then - local x=descriptions[x] - if x then - parameters.x_height=x.height - end - end - end - parameters.designsize=(designsize/10)*65536 - parameters.minsize=(minsize/10)*65536 - parameters.maxsize=(maxsize/10)*65536 - parameters.ascender=abs(metadata.ascender or 0) - parameters.descender=abs(metadata.descender or 0) - parameters.units=units - properties.space=spacer - properties.encodingbytes=2 - properties.format=data.format or formats.otf - properties.noglyphnames=true - properties.filename=filename - properties.fontname=fontname - 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, - parameters=parameters, - mathparameters=mathparameters, - resources=resources, - properties=properties, - goodies=goodies, - } - end -end -local converters={ - woff={ - cachename="webfonts", - action=otf.readers.woff2otf, - } -} -local function checkconversion(specification) - local filename=specification.filename - local converter=converters[lower(file.suffix(filename))] - if converter then - local base=file.basename(filename) - 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 size>0 then - local cleanname=containers.cleanname(name) - local cachename=caches.setfirstwritablefile(cleanname,converter.cachename) - if not io.exists(cachename) or (time~=lfs.attributes(cachename).modification) then - report_otf("caching font %a in %a",filename,cachename) - converter.action(filename,cachename) - lfs.touch(cachename,time,time) - end - specification.filename=cachename - end - end -end -local function otftotfm(specification) - local cache_id=specification.hash - local tfmdata=containers.read(constructors.cache,cache_id) - if not tfmdata then - checkconversion(specification) - local name=specification.name - local sub=specification.sub - local subindex=specification.subindex - local filename=specification.filename - local features=specification.features.normal - 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={} - tfmdata=copytotfm(rawdata,cache_id) - if tfmdata and next(tfmdata) then - local features=constructors.checkedfeatures("otf",features) - local shared=tfmdata.shared - if not shared then - shared={} - tfmdata.shared=shared - end - shared.rawdata=rawdata - shared.dynamics={} - tfmdata.changed={} - shared.features=features - shared.processes=otf.setfeatures(tfmdata,features) - end - end - containers.write(constructors.cache,cache_id,tfmdata) - end - return tfmdata -end -local function read_from_otf(specification) - local tfmdata=otftotfm(specification) - if tfmdata then - tfmdata.properties.name=specification.name - tfmdata.properties.sub=specification.sub - tfmdata=constructors.scale(tfmdata,specification) - local allfeatures=tfmdata.shared.features or specification.features.normal - constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf) - constructors.setname(tfmdata,specification) - fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification) - end - return tfmdata -end -local function checkmathsize(tfmdata,mathsize) - local mathdata=tfmdata.shared.rawdata.metadata.math - local mathsize=tonumber(mathsize) - if mathdata then - local parameters=tfmdata.parameters - parameters.scriptpercentage=mathdata.ScriptPercentScaleDown - parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown - parameters.mathsize=mathsize - end -end -registerotffeature { - name="mathsize", - description="apply mathsize specified in the font", - initializers={ - base=checkmathsize, - node=checkmathsize, - } -} -function otf.collectlookups(rawdata,kind,script,language) - if not kind then - return - end - if not script then - script=default - end - if not language then - language=default - end - local lookupcache=rawdata.lookupcache - if not lookupcache then - lookupcache={} - rawdata.lookupcache=lookupcache - end - local kindlookup=lookupcache[kind] - if not kindlookup then - kindlookup={} - lookupcache[kind]=kindlookup - end - local scriptlookup=kindlookup[script] - if not scriptlookup then - scriptlookup={} - kindlookup[script]=scriptlookup - end - local languagelookup=scriptlookup[language] - if not languagelookup then - local sequences=rawdata.resources.sequences - local featuremap={} - local featurelist={} - if sequences then - for s=1,#sequences do - local sequence=sequences[s] - local features=sequence.features - if features then - features=features[kind] - if features then - features=features[script] or features[wildcard] - if features then - features=features[language] or features[wildcard] - if features then - if not featuremap[sequence] then - featuremap[sequence]=true - featurelist[#featurelist+1]=sequence - end - end - end - end - end - end - if #featurelist==0 then - featuremap,featurelist=false,false - end - else - featuremap,featurelist=false,false - end - languagelookup={ featuremap,featurelist } - scriptlookup[language]=languagelookup - end - return unpack(languagelookup) -end -local function getgsub(tfmdata,k,kind,value) - local shared=tfmdata.shared - local rawdata=shared and shared.rawdata - if rawdata then - local sequences=rawdata.resources.sequences - if sequences then - local properties=tfmdata.properties - local validlookups,lookuplist=otf.collectlookups(rawdata,kind,properties.script,properties.language) - if validlookups then - for i=1,#lookuplist do - local lookup=lookuplist[i] - local steps=lookup.steps - local nofsteps=lookup.nofsteps - for i=1,nofsteps do - local coverage=steps[i].coverage - if coverage then - local found=coverage[k] - if found then - return found,lookup.type - end - end - end - end - end - end - end -end -otf.getgsub=getgsub -function otf.getsubstitution(tfmdata,k,kind,value) - local found,kind=getgsub(tfmdata,k,kind,value) - if not found then - elseif kind=="gsub_single" then - return found - elseif kind=="gsub_alternate" then - local choice=tonumber(value) or 1 - return found[choice] or found[1] or k - end - return k -end -otf.getalternate=otf.getsubstitution -function otf.getmultiple(tfmdata,k,kind) - local found,kind=getgsub(tfmdata,k,kind) - if found and kind=="gsub_multiple" then - return found - end - return { k } -end -function otf.getkern(tfmdata,left,right,kind) - local kerns=getgsub(tfmdata,left,kind or "kern",true) - if kerns then - local found=kerns[right] - local kind=type(found) - if kind=="table" then - found=found[1][3] - elseif kind~="number" then - found=false - end - if found then - return found*tfmdata.parameters.factor - end - end - return 0 -end -local function check_otf(forced,specification,suffix) - local name=specification.name - if forced then - name=specification.forcedname - end - local fullname=findbinfile(name,suffix) or "" - if fullname=="" then - fullname=fonts.names.getfilename(name,suffix) or "" - end - if fullname~="" and not fonts.names.ignoredfile(fullname) then - specification.filename=fullname - return read_from_otf(specification) - end -end -local function opentypereader(specification,suffix) - local forced=specification.forced or "" - if formats[forced] then - return check_otf(true,specification,forced) - else - return check_otf(false,specification,suffix) - end -end -readers.opentype=opentypereader -function readers.otf(specification) return opentypereader(specification,"otf") end -function readers.ttf(specification) return opentypereader(specification,"ttf") end -function readers.ttc(specification) return opentypereader(specification,"ttf") end -function readers.woff(specification) - checkconversion(specification) - opentypereader(specification,"") -end -function otf.scriptandlanguage(tfmdata,attr) - local properties=tfmdata.properties - return properties.script or "dflt",properties.language or "dflt" -end -local function justset(coverage,unicode,replacement) - coverage[unicode]=replacement -end -otf.coverup={ - stepkey="steps", - actions={ - chainsubstitution=justset, - chainposition=justset, - substitution=justset, - alternate=justset, - multiple=justset, - kern=justset, - pair=justset, - single=justset, - ligature=function(coverage,unicode,ligature) - local first=ligature[1] - local tree=coverage[first] - if not tree then - tree={} - coverage[first]=tree - end - for i=2,#ligature do - local l=ligature[i] - local t=tree[l] - if not t then - t={} - tree[l]=t - end - tree=t - end - tree.ligature=unicode - end, - }, - register=function(coverage,featuretype,format) - return { - format=format, - coverage=coverage, - } - end -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otl”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-oto” 6ba2e73177b18007e74de324c324806c] --- - -if not modules then modules={} end modules ['font-oto']={ - 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 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 -local type,next,tonumber,tostring,rawget=type,next,tonumber,tostring,rawget -local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end) -local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end) -local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) -local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end) -local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end) -local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end) -local trace_preparing=false trackers.register("otf.preparing",function(v) trace_preparing=v end) -local report_prepare=logs.reporter("fonts","otf prepare") -local fonts=fonts -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 -local f_unicode=formatters["%U"] -local f_uniname=formatters["%U (%s)"] -local f_unilist=formatters["% t (% t)"] -local function gref(descriptions,n) - if type(n)=="number" then - local name=descriptions[n].name - if name then - return f_uniname(n,name) - else - return f_unicode(n) - end - elseif n then - local num,nam,j={},{},0 - for i=1,#n do - local ni=n[i] - if tonumber(ni) then - j=j+1 - local di=descriptions[ni] - num[j]=f_unicode(ni) - nam[j]=di and di.name or "-" - end - end - return f_unilist(num,nam) - else - return "<error in base mode tracing>" - end -end -local function cref(feature,sequence) - return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name) -end -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_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", - cref(feature,sequence), - gref(descriptions,ligature), - gref(descriptions,unicode)) -end -local function report_kern(feature,sequence,descriptions,unicode,otherunicode,value) - report_prepare("%s: base kern %s + %s => %S", - cref(feature,sequence), - gref(descriptions,unicode), - gref(descriptions,otherunicode), - value) -end -local basehash,basehashes,applied={},1,{} -local function registerbasehash(tfmdata) - local properties=tfmdata.properties - local hash=concat(applied," ") - local base=basehash[hash] - if not base then - basehashes=basehashes+1 - base=basehashes - basehash[hash]=base - end - properties.basehash=base - properties.fullname=(properties.fullname or properties.name).."-"..base - applied={} -end -local function registerbasefeature(feature,value) - applied[#applied+1]=feature.."="..tostring(value) -end -local function makefake(tfmdata,name,present) - local private=getprivate(tfmdata) - local character={ intermediate=true,ligatures={} } - resources.unicodes[name]=private - tfmdata.characters[private]=character - tfmdata.descriptions[private]={ name=name } - present[name]=private - return character -end -local function make_1(present,tree,name) - for k,v in next,tree do - if k=="ligature" then - present[name]=v - else - make_1(present,v,name.."_"..k) - end - end -end -local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done) - for k,v in next,tree do - if k=="ligature" then - local character=characters[preceding] - if not character then - if trace_baseinit then - report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding) - end - character=makefake(tfmdata,name,present) - end - local ligatures=character.ligatures - if ligatures then - ligatures[unicode]={ char=v } - else - character.ligatures={ [unicode]={ char=v } } - end - if done then - local d=done[name] - if not d then - done[name]={ "dummy",v } - else - d[#d+1]=v - end - end - else - local code=present[name] or unicode - local name=name.."_"..k - make_2(present,tfmdata,characters,v,name,code,k,done) - end - end -end -local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local resources=tfmdata.resources - local changed=tfmdata.changed - local ligatures={} - local alternate=tonumber(value) or true and 1 - local defaultalt=otf.defaultbasealternate - local trace_singles=trace_baseinit and trace_singles - local trace_alternatives=trace_baseinit and trace_alternatives - local trace_ligatures=trace_baseinit and trace_ligatures - if not changed then - changed={} - tfmdata.changed=changed - end - for i=1,#lookuplist do - local sequence=lookuplist[i] - local steps=sequence.steps - local kind=sequence.type - if kind=="gsub_single" then - for i=1,#steps do - for unicode,data in next,steps[i].coverage do - 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 - local replacement=data[alternate] - if replacement then - if unicode~=replacement then - changed[unicode]=replacement - 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 - 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 - end - elseif kind=="gsub_ligature" then - for i=1,#steps do - for unicode,data in next,steps[i].coverage do - ligatures[#ligatures+1]={ unicode,data,"" } - if trace_ligatures then - report_ligature(feature,sequence,descriptions,unicode,data) - end - end - end - end - end - local nofligatures=#ligatures - if nofligatures>0 then - local characters=tfmdata.characters - local present={} - local done=trace_baseinit and trace_ligatures and {} - for i=1,nofligatures do - local ligature=ligatures[i] - local unicode,tree=ligature[1],ligature[2] - make_1(present,tree,"ctx_"..unicode) - end - for i=1,nofligatures do - local ligature=ligatures[i] - local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3] - make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) - end - end -end -local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local resources=tfmdata.resources - local properties=tfmdata.properties - local traceindeed=trace_baseinit and trace_kerns - for i=1,#lookuplist do - local sequence=lookuplist[i] - local steps=sequence.steps - local kind=sequence.type - local format=sequence.format - if kind=="gpos_pair" then - for i=1,#steps do - 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 - if not kerns then - kerns={} - character.kerns=kerns - end - if traceindeed then - for otherunicode,kern in next,data do - if not kerns[otherunicode] and kern~=0 then - kerns[otherunicode]=kern - report_kern(feature,sequence,descriptions,unicode,otherunicode,kern) - end - end - else - for otherunicode,kern in next,data do - if not kerns[otherunicode] and kern~=0 then - kerns[otherunicode]=kern - end - end - end - end - else - for unicode,data in next,steps[i].coverage do - local character=characters[unicode] - local kerns=character.kerns - for otherunicode,kern in next,data do - local other=kern[2] - if other==true or (not other and not (kerns and kerns[otherunicode])) then - local kern=kern[1] - 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 - if kerns then - kerns[otherunicode]=kern - else - kerns={ [otherunicode]=kern } - character.kerns=kerns - end - if traceindeed then - report_kern(feature,sequence,descriptions,unicode,otherunicode,kern) - end - end - end - end - end - end - end - end - end - end -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] - if u and r then - 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 - else - if trace_preparing then - report_prepare("error replacing %C by %U",unicode,replacement) - end - end - end - end - end -end -local function featuresinitializer(tfmdata,value) - if true then - local starttime=trace_preparing and os.clock() - local features=tfmdata.shared.features - local fullname=tfmdata.properties.fullname or "?" - if features then - initializehashes(tfmdata) - local collectlookups=otf.collectlookups - local rawdata=tfmdata.shared.rawdata - local properties=tfmdata.properties - local script=properties.script - local language=properties.language - local rawresources=rawdata.resources - 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 - local sequence=sequences[s] - local sfeatures=sequence.features - if sfeatures then - local order=sequence.order - if order then - for i=1,#order do - local feature=order[i] - local value=features[feature] - if value then - local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) - if not validlookups then - elseif basesubstitutions and basesubstitutions[feature] then - if trace_preparing then - report_prepare("filtering base %s feature %a for %a with value %a","sub",feature,fullname,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 - end - end - end - end - if substitutionsdone then - checkmathreplacements(tfmdata,fullname,features.fixitalics) - end - registerbasehash(tfmdata) - end - if trace_preparing then - report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,fullname) - end - end -end -registerotffeature { - name="features", - description="features", - default=true, - initializers={ - base=featuresinitializer, - } -} -otf.basemodeinitializer=featuresinitializer - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-oto”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otj” e49771140e5ed2f28ce680ad9d672dc7] --- - -if not modules then modules={} end modules ['font-otj']={ - version=1.001, - 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", -} -if not nodes.properties then return end -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 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 -local setcolor=tracers and tracers.colors.set -local resetcolor=tracers and tracers.colors.reset -local nodecodes=nodes.nodecodes -local glyph_code=nodecodes.glyph -local disc_code=nodecodes.disc -local kern_code=nodecodes.kern -local glue_code=nodecodes.glue -local nuts=nodes.nuts -local nodepool=nuts.pool -local tonode=nuts.tonode -local tonut=nuts.tonut -local setfield=nuts.setfield -local getnext=nuts.getnext -local getprev=nuts.getprev -local getid=nuts.getid -local getfont=nuts.getfont -local getchar=nuts.getchar -local getoffsets=nuts.getoffsets -local getboth=nuts.getboth -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 -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 -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 nofregisteredpositions=0 -local nofregisteredmarks=0 -local nofregisteredcursives=0 -local keepregisteredcounts=false -function injections.keepcounts() - keepregisteredcounts=true -end -function injections.resetcounts() - nofregisteredkerns=0 - nofregisteredpositions=0 - nofregisteredmarks=0 - nofregisteredcursives=0 - keepregisteredcounts=false -end -function injections.reset(n) - local p=rawget(properties,n) - if p then - p.injections=false - else - properties[n]=false - end -end -function injections.copy(target,source) - local sp=rawget(properties,source) - if sp then - local tp=rawget(properties,target) - local si=sp.injections - if si then - si=fastcopy(si) - if tp then - tp.injections=si - else - properties[target]={ - injections=si, - } - end - elseif tp then - tp.injections=false - else - properties[target]={ injections={} } - end - else - local tp=rawget(properties,target) - if tp then - tp.injections=false - else - properties[target]=false - end - end -end -function injections.setligaindex(n,index) - local p=rawget(properties,n) - if p then - local i=p.injections - if i then - i.ligaindex=index - else - p.injections={ - ligaindex=index - } - end - else - properties[n]={ - injections={ - ligaindex=index - } - } - end -end -function injections.getligaindex(n,default) - local p=rawget(properties,n) - if p then - local i=p.injections - if i then - return i.ligaindex or default - end - end - return default -end -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 - local wn=tfmnext.width - nofregisteredcursives=nofregisteredcursives+1 - if rlmode<0 then - dx=-(dx+wn) - else - dx=dx-ws - end - if dx==0 then - dx=0 - end - local p=rawget(properties,start) - if p then - local i=p.injections - if i then - i.cursiveanchor=true - else - p.injections={ - cursiveanchor=true, - } - end - else - properties[start]={ - injections={ - cursiveanchor=true, - }, - } - end - local p=rawget(properties,nxt) - if p then - local i=p.injections - if i then - i.cursivex=dx - i.cursivey=dy - else - p.injections={ - cursivex=dx, - cursivey=dy, - } - end - else - properties[nxt]={ - injections={ - cursivex=dx, - cursivey=dy, - }, - } - end - return dx,dy,nofregisteredcursives -end -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 - nofregisteredpositions=nofregisteredpositions+1 - if rlmode and rlmode<0 then - leftkern,rightkern=rightkern,leftkern - end - if not injection then - injection="injections" - end - local p=rawget(properties,current) - if p then - local i=p[injection] - if i then - if leftkern~=0 then - i.leftkern=(i.leftkern or 0)+leftkern - end - if rightkern~=0 then - i.rightkern=(i.rightkern or 0)+rightkern - end - if yoffset~=0 then - i.yoffset=(i.yoffset or 0)+yoffset - end - elseif leftkern~=0 or rightkern~=0 then - p[injection]={ - leftkern=leftkern, - rightkern=rightkern, - yoffset=yoffset, - } - else - p[injection]={ - yoffset=yoffset, - } - end - elseif leftkern~=0 or rightkern~=0 then - properties[current]={ - [injection]={ - leftkern=leftkern, - rightkern=rightkern, - yoffset=yoffset, - }, - } - else - properties[current]={ - [injection]={ - yoffset=yoffset, - }, - } - end - return x,y,w,h,nofregisteredpositions - end - end - return x,y,w,h -end -function injections.setkern(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 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 - return dx,nofregisteredkerns - else - 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 - if rlmode>=0 then - dx=tfmbase.width-dx - end - local p=rawget(properties,start) - if p then - local i=p.injections - if i then - if i.markmark then - else - i.markx=dx - i.marky=dy - i.markdir=rlmode or 0 - i.markbase=nofregisteredmarks - i.markbasenode=base - i.markmark=mkmk - i.checkmark=checkmark - end - else - p.injections={ - markx=dx, - marky=dy, - markdir=rlmode or 0, - markbase=nofregisteredmarks, - markbasenode=base, - markmark=mkmk, - checkmark=checkmark, - } - end - else - properties[start]={ - injections={ - markx=dx, - marky=dy, - markdir=rlmode or 0, - markbase=nofregisteredmarks, - markbasenode=base, - markmark=mkmk, - checkmark=checkmark, - }, - } - end - return dx,dy,nofregisteredmarks -end -local function dir(n) - return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" -end -local function showchar(n,nested) - local char=getchar(n) - report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char) -end -local function show(n,what,nested,symbol) - if n then - local p=rawget(properties,n) - if p then - local i=p[what] - if i then - local leftkern=i.leftkern or 0 - local rightkern=i.rightkern or 0 - local yoffset=i.yoffset or 0 - local markx=i.markx or 0 - local marky=i.marky or 0 - local markdir=i.markdir or 0 - local markbase=i.markbase or 0 - local cursivex=i.cursivex or 0 - local cursivey=i.cursivey or 0 - local ligaindex=i.ligaindex or 0 - local cursbase=i.cursiveanchor - local margin=nested and 4 or 2 - if rightkern~=0 or yoffset~=0 then - report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset) - elseif leftkern~=0 then - report_injections("%w%s kern: dx %p",margin,symbol,leftkern) - end - if markx~=0 or marky~=0 or markbase~=0 then - report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no") - end - if cursivex~=0 or cursivey~=0 then - if cursbase then - report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey) - else - report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) - end - elseif cursbase then - report_injections("%w%s curs: base",margin,symbol) - end - if ligaindex~=0 then - report_injections("%w%s liga: index %i",margin,symbol,ligaindex) - end - end - end - end -end -local function showsub(n,what,where) - report_injections("begin subrun: %s",where) - 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() - 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) - if id==glyph_code then - showchar(n) - show(n,"injections",false," ") - show(n,"preinjections",false,"<") - show(n,"postinjections",false,">") - show(n,"replaceinjections",false,"=") - show(n,"emptyinjections",false,"*") - elseif id==disc_code then - local pre,post,replace=getdisc(n) - if pre then - showsub(pre,"preinjections","pre") - end - if post then - showsub(post,"postinjections","post") - end - if replace then - showsub(replace,"replaceinjections","replace") - end - show(n,"emptyinjections",false,"*") - end - n=getnext(n) - end - report_injections("end run") -end -local function show_result(head) - local current=head - local skipping=false - while current do - local id=getid(current) - if id==glyph_code then - 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",getkern(current)) - skipping=false - elseif not skipping then - report_injections() - skipping=true - end - current=getnext(current) - end - report_injections() -end -local function inject_kerns_only(head,where) - if trace_injections then - trace(head,"kerns") - end - local current=head - local prev=nil - local next=nil - local prevdisc=nil - local pre=nil - local post=nil - local replace=nil - local pretail=nil - local posttail=nil - local replacetail=nil - while current do - local next=getnext(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 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 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 - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - replace=fontkern(leftkern) - done=true - end - end - end - if done then - setdisc(prevdisc,pre,post,replace) - end - end - end - prevdisc=nil - 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 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 - pre=insert_node_before(pre,n,fontkern(leftkern)) - done=true - end - end - end - end - end - if post then - 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 - post=insert_node_before(post,n,fontkern(leftkern)) - done=true - end - end - end - end - end - if replace then - 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 - replace=insert_node_before(replace,n,fontkern(leftkern)) - done=true - end - end - end - end - end - if done then - setdisc(current,pre,post,replace) - end - prevdisc=current - else - prevdisc=nil - end - prev=current - current=next - end - if keepregisteredcounts then - keepregisteredcounts=false - else - nofregisteredkerns=0 - end - if trace_injections then - show_result(head) - end - return head -end -local function inject_positions_only(head,where) - if trace_injections then - trace(head,"positions") - end - local current=head - local prev=nil - local next=nil - local prevdisc=nil - local prevglyph=nil - local pre=nil - local post=nil - local replace=nil - local pretail=nil - local posttail=nil - local replacetail=nil - while current do - local next=getnext(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 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 - if next and getid(next)==disc_code then - if replace then - else - replace=fontkern(rightkern) - done=true - end - 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 - setlink(posttail,fontkern(leftkern)) - done=true - end - 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 - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - replace=fontkern(leftkern) - done=true - 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 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - end - end - end - end - if post then - 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - end - end - end - end - if replace then - 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - end - end - end - end - if prevglyph then - if pre then - local p=rawget(properties,prevglyph) - if p then - local i=p.preinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - pre=insert_node_before(pre,pre,fontkern(rightkern)) - done=true - end - end - end - end - if replace then - local p=rawget(properties,prevglyph) - if p then - local i=p.replaceinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - replace=insert_node_before(replace,replace,fontkern(rightkern)) - done=true - end - end - end - end - end - if done then - setdisc(current,pre,post,replace) - end - prevglyph=nil - prevdisc=current - else - prevglyph=nil - prevdisc=nil - end - prev=current - current=next - end - if keepregisteredcounts then - keepregisteredcounts=false - else - nofregisteredpositions=0 - end - if trace_injections then - show_result(head) - end - return head -end -local function showoffset(n,flag) - local x,y=getoffsets(n) - if x~=0 or y~=0 then - setcolor(n,"darkgray") - end -end -local function inject_everything(head,where) - if trace_injections then - trace(head,"everything") - end - local hascursives=nofregisteredcursives>0 - local hasmarks=nofregisteredmarks>0 - local current=head - local last=nil - local prev=nil - local next=nil - local prevdisc=nil - local prevglyph=nil - local pre=nil - local post=nil - local replace=nil - local pretail=nil - local posttail=nil - local replacetail=nil - local cursiveanchor=nil - local minc=0 - local maxc=0 - local glyphs={} - local marks={} - local nofmarks=0 - local function processmark(p,n,pn) - 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=pp.injections - if pp then - rightkern=pp.rightkern - end - end - local markdir=pn.markdir - if rightkern then - 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=ox-leftkern - end - end - end - else - 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=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,fontkern(-wn)) - insert_node_after(n,n,fontkern(-wn)) - end - end - end - 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 next=getnext(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=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 - 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 - setoffsets(ti,false,ny) - if trace_cursive then - showoffset(ti) - end - end - maxc=0 - end - cursiveanchor=nil - end - 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 - 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 - replace=fontkern(rightkern) - done=true - end - 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 - setlink(posttail,fontkern(leftkern)) - done=true - end - 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 - else - local i=p.emptyinjections - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - replace=fontkern(leftkern) - done=true - end - end - end - if done then - setdisc(prevdisc,pre,post,replace) - end - 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 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - if hasmarks then - local pm=i.markbasenode - if pm then - processmark(pm,n,i) - end - end - end - end - end - end - if post then - 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - if hasmarks then - local pm=i.markbasenode - if pm then - processmark(pm,n,i) - end - end - end - end - end - end - if replace then - 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 - setoffsets(n,false,yoffset) - end - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - 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,fontkern(rightkern)) - done=true - end - if hasmarks then - local pm=i.markbasenode - if pm then - processmark(pm,n,i) - end - end - end - end - end - end - if prevglyph then - if pre then - local p=rawget(properties,prevglyph) - if p then - local i=p.preinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - pre=insert_node_before(pre,pre,fontkern(rightkern)) - done=true - end - end - end - end - if replace then - local p=rawget(properties,prevglyph) - if p then - local i=p.replaceinjections - if i then - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - replace=insert_node_before(replace,replace,fontkern(rightkern)) - done=true - end - end - end - end - end - if done then - setdisc(current,pre,post,replace) - end - prevglyph=nil - prevdisc=current - else - prevglyph=nil - prevdisc=nil - end - prev=current - current=next - end - if hascursives and maxc>0 then - local nx,ny=getoffsets(last) - 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 - end - if nofmarks>0 then - for i=1,nofmarks do - local m=marks[i] - local p=rawget(properties,m) - local i=p.injections - local b=i.markbasenode - processmark(b,m,i) - end - elseif hasmarks then - end - if keepregisteredcounts then - keepregisteredcounts=false - else - nofregisteredkerns=0 - nofregisteredpositions=0 - nofregisteredmarks=0 - nofregisteredcursives=0 - end - if trace_injections then - show_result(head) - end - return head -end -local triggers=false -function nodes.injections.setspacekerns(font,sequence) - if triggers then - triggers[font]=sequence - else - triggers={ [font]=sequence } - end -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 -else - injections.threshold=0 - getthreshold=function(font) - local p=fontdata[font].parameters - local f=p.factor - local s=p.spacing - local t=injections.threshold*(s and s.width or p.space or 0)-2 - return t>0 and t or 0,f - end -end -injections.getthreshold=getthreshold -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 - end - local lastfont=nil - local spacekerns=nil - local leftkerns=nil - local rightkerns=nil - local factor=0 - local threshold=0 - local leftkern=false - local rightkern=false - local function updatefont(font,trig) - leftkerns=trig.left - rightkerns=trig.right - lastfont=font - threshold, - factor=getthreshold(font) - end - 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] - if trig then - if lastfont~=font then - updatefont(font,trig) - end - if rightkerns then - rightkern=rightkerns[nextchar] - end - end - end - if prevchar then - local font=getfont(prev) - local trig=triggers[font] - if trig then - if lastfont~=font then - updatefont(font,trig) - end - if leftkerns then - leftkern=leftkerns[prevchar] - end - end - end - if leftkern then - local old=getwidth(n) - if old>threshold then - if rightkern then - 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 - rightkern=false - else - 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 - end - end - leftkern=false - elseif rightkern then - local old=getwidth(n) - if old>threshold then - 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 - end - rightkern=false - end - end - triggers=false - return head -end -function injections.handler(head,where) - if triggers then - head=injectspaces(head) - end - if nofregisteredmarks>0 or nofregisteredcursives>0 then - if trace_injections then - report_injections("injection variant %a","everything") - end - return inject_everything(head,where) - elseif nofregisteredpositions>0 then - if trace_injections then - report_injections("injection variant %a","positions") - end - 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 - end -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otj”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ota” 5503fc4d2bd8c6a2cbb2db1b1651e402] --- - -if not modules then modules={} end modules ['font-ota']={ - 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=type -if not trackers then trackers={ register=function() end } end -local fonts,nodes,node=fonts,nodes,node -local allocate=utilities.storage.allocate -local otf=fonts.handlers.otf -local analyzers=fonts.analyzers -local initializers=allocate() -local methods=allocate() -analyzers.initializers=initializers -analyzers.methods=methods -local a_state=attributes.private('state') -local nuts=nodes.nuts -local tonut=nuts.tonut -local getnext=nuts.getnext -local getprev=nuts.getprev -local getprev=nuts.getprev -local getprop=nuts.getprop -local setprop=nuts.setprop -local getsubtype=nuts.getsubtype -local getchar=nuts.getchar -local ischar=nuts.is_char -local end_of_math=nuts.end_of_math -local nodecodes=nodes.nodecodes -local disc_code=nodecodes.disc -local math_code=nodecodes.math -local fontdata=fonts.hashes.identifiers -local categories=characters and characters.categories or {} -local chardata=characters and characters.data -local otffeatures=fonts.constructors.features.otf -local registerotffeature=otffeatures.register -local s_init=1 local s_rphf=7 -local s_medi=2 local s_half=8 -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=allocate { - init=s_init, - medi=s_medi, - med2=s_medi, - fina=s_fina, - fin2=s_fina, - fin3=s_fina, - isol=s_isol, - mark=s_mark, - rest=s_rest, - rphf=s_rphf, - half=s_half, - pref=s_pref, - blwf=s_blwf, - pstf=s_pstf, -} -local features=allocate { - init=s_init, - medi=s_medi, - med2=s_medi, - fina=s_fina, - fin2=s_fina, - fin3=s_fina, - isol=s_isol, - rphf=s_rphf, - half=s_half, - pref=s_pref, - blwf=s_blwf, - pstf=s_pstf, -} -analyzers.states=states -analyzers.features=features -analyzers.useunicodemarks=false -function analyzers.setstate(head,font) - local useunicodemarks=analyzers.useunicodemarks - local tfmdata=fontdata[font] - local descriptions=tfmdata.descriptions - local first,last,current,n,done=nil,nil,head,0,false - current=tonut(current) - while current do - local char,id=ischar(current,font) - if char and not getprop(current,a_state) then - done=true - local d=descriptions[char] - if d then - if d.class=="mark" then - done=true - setprop(current,a_state,s_mark) - elseif useunicodemarks and categories[char]=="mn" then - done=true - setprop(current,a_state,s_mark) - elseif n==0 then - first,last,n=current,current,1 - setprop(current,a_state,s_init) - else - last,n=current,n+1 - setprop(current,a_state,s_medi) - end - else - if first and first==last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - first,last,n=nil,nil,0 - end - elseif char==false then - if first and first==last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - first,last,n=nil,nil,0 - if id==math_code then - current=end_of_math(current) - end - elseif id==disc_code then - setprop(current,a_state,s_medi) - last=current - else - if first and first==last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - first,last,n=nil,nil,0 - if id==math_code then - current=end_of_math(current) - end - end - current=getnext(current) - end - if first and first==last then - setprop(last,a_state,s_isol) - elseif last then - setprop(last,a_state,s_fina) - end - return head,done -end -local function analyzeinitializer(tfmdata,value) - local script,language=otf.scriptandlanguage(tfmdata) - local action=initializers[script] - if not action then - elseif type(action)=="function" then - return action(tfmdata,value) - else - local action=action[language] - if action then - return action(tfmdata,value) - end - end -end -local function analyzeprocessor(head,font,attr) - local tfmdata=fontdata[font] - local script,language=otf.scriptandlanguage(tfmdata,attr) - local action=methods[script] - if not action then - elseif type(action)=="function" then - return action(head,font,attr) - else - action=action[language] - if action then - return action(head,font,attr) - end - end - return head,false -end -registerotffeature { - name="analyze", - description="analysis of character classes", - default=true, - initializers={ - node=analyzeinitializer, - }, - processors={ - position=1, - node=analyzeprocessor, - } -} -methods.latn=analyzers.setstate -local arab_warned={} -local function warning(current,what) - local char=getchar(current) - if not arab_warned[char] then - log.report("analyze","arab: character %C has no %a class",char,what) - arab_warned[char]=true - end -end -local mappers=allocate { - l=s_init, - d=s_medi, - c=s_medi, - r=s_fina, - u=s_isol, -} -local classifiers=characters.classifiers -if not classifiers then - local f_arabic,l_arabic=characters.blockrange("arabic") - local f_syriac,l_syriac=characters.blockrange("syriac") - local f_mandiac,l_mandiac=characters.blockrange("mandiac") - local f_nko,l_nko=characters.blockrange("nko") - local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda") - classifiers=table.setmetatableindex(function(t,k) - if type(k)=="number" then - local c=chardata[k] - local v=false - if c then - local arabic=c.arabic - if arabic then - v=mappers[arabic] - if not v then - log.report("analyze","error in mapping arabic %C",k) - v=false - end - elseif (k>=f_arabic and k<=l_arabic) or - (k>=f_syriac and k<=l_syriac) or - (k>=f_mandiac and k<=l_mandiac) or - (k>=f_nko and k<=l_nko) or - (k>=f_ext_a and k<=l_ext_a) then - if categories[k]=="mn" then - v=s_mark - else - v=s_rest - end - end - end - t[k]=v - return v - end - end) - characters.classifiers=classifiers -end -function methods.arab(head,font,attr) - local first,last=nil,nil - local c_first,c_last=nil,nil - local current,done=head,false - current=tonut(current) - while current do - local char,id=ischar(current,font) - if char and not getprop(current,a_state) then - done=true - local classifier=classifiers[char] - if not classifier then - if last then - if c_last==s_medi or c_last==s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first,last=nil,nil - elseif first then - if c_first==s_medi or c_first==s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first=nil - end - elseif classifier==s_mark then - setprop(current,a_state,s_mark) - elseif classifier==s_isol then - if last then - if c_last==s_medi or c_last==s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first,last=nil,nil - elseif first then - if c_first==s_medi or c_first==s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first=nil - end - setprop(current,a_state,s_isol) - elseif classifier==s_medi then - if first then - last=current - c_last=classifier - setprop(current,a_state,s_medi) - else - setprop(current,a_state,s_init) - first=current - c_first=classifier - end - elseif classifier==s_fina then - if last then - if getprop(last,a_state)~=s_init then - setprop(last,a_state,s_medi) - end - setprop(current,a_state,s_fina) - first,last=nil,nil - elseif first then - setprop(current,a_state,s_fina) - first=nil - else - setprop(current,a_state,s_isol) - end - else - setprop(current,a_state,s_rest) - if last then - if c_last==s_medi or c_last==s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first,last=nil,nil - elseif first then - if c_first==s_medi or c_first==s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first=nil - end - end - else - if last then - if c_last==s_medi or c_last==s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - first,last=nil,nil - elseif first then - if c_first==s_medi or c_first==s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - first=nil - end - if id==math_code then - current=end_of_math(current) - end - end - current=getnext(current) - end - if last then - if c_last==s_medi or c_last==s_fina then - setprop(last,a_state,s_fina) - else - warning(last,"fina") - setprop(last,a_state,s_error) - end - elseif first then - if c_first==s_medi or c_first==s_fina then - setprop(first,a_state,s_isol) - else - warning(first,"isol") - setprop(first,a_state,s_error) - end - end - return head,done -end -methods.syrc=methods.arab -methods.mand=methods.arab -methods.nko=methods.arab -directives.register("otf.analyze.useunicodemarks",function(v) - analyzers.useunicodemarks=v -end) - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ota”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ots” e2bfdc0d27729ce54048d94ff701f37f] --- - -if not modules then modules={} end modules ['font-ots']={ - 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=type,next,tonumber -local random=math.random -local formatters=string.formatters -local insert=table.insert -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) -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 -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 getfield=nuts.getfield -local getnext=nuts.getnext -local setnext=nuts.setnext -local getprev=nuts.getprev -local setprev=nuts.setprev -local getboth=nuts.getboth -local setboth=nuts.setboth -local getid=nuts.getid -local getattr=nuts.getattr -local setattr=nuts.setattr -local getprop=nuts.getprop -local setprop=nuts.setprop -local getsubtype=nuts.getsubtype -local setsubtype=nuts.setsubtype -local getchar=nuts.getchar -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 getwidth=nuts.getwidth -local ischar=nuts.is_char -local isglyph=nuts.isglyph -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 setmetatable=setmetatable -local setmetatableindex=table.setmetatableindex -local nextnode=nuts.traversers.node -local nodecodes=nodes.nodecodes -local glyphcodes=nodes.glyphcodes -local disccodes=nodes.disccodes -local glyph_code=nodecodes.glyph -local glue_code=nodecodes.glue -local disc_code=nodecodes.disc -local math_code=nodecodes.math -local dir_code=nodecodes.dir -local localpar_code=nodecodes.localpar -local discretionarydisc_code=disccodes.discretionary -local ligatureglyph_code=glyphcodes.ligature -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 setmove=injections.setmove -local setposition=injections.setposition -local resetinjection=injections.reset -local copyinjection=injections.copy -local setligaindex=injections.setligaindex -local getligaindex=injections.getligaindex -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 -local getrandom=utilities and utilities.randomizer and utilities.randomizer.get -otf.defaultnodealternate="none" -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 sweephead={} -local notmatchpre={} -local notmatchpost={} -local notmatchreplace={} -local handlers={} -local isspace=injections.isspace -local getthreshold=injections.getthreshold -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 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 - end -end -local function cref(dataset,sequence,index) - if not dataset then - return "no valid dataset" - 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, %schain lookup %a"]( - dataset[4],sequence.type,merged,sequence.name) - end -end -local function pref(dataset,sequence) - 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 "l2r" - else - return "r2l" - end -end -local function flattendisk(head,disc) - local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) - local prev,next=getboth(disc) - local ishead=head==disc - setdisc(disc) - flush_node(disc) - if pre then - flush_node_list(pre) - end - if post then - flush_node_list(post) - end - if ishead then - if replace then - if next then - setlink(replacetail,next) - end - return replace,replace - elseif next then - return next,next - else - end - else - if replace then - if next then - setlink(replacetail,next) - end - setlink(prev,replace) - return head,replace - else - setlink(prev,next) - return head,next - end - end -end -local function appenddisc(disc,list) - local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) - local posthead=list - local replacehead=copy_node_list(list) - if post then - setlink(posttail,posthead) - else - post=posthead - end - if replace then - setlink(replacetail,replacehead) - else - replace=replacehead - end - setdisc(disc,pre,post,replace) -end -local copy_no_components=nuts.copy_no_components -local copy_only_glyphs=nuts.copy_only_glyphs -local set_components=setcomponents -local take_components=getcomponents -local function count_components(start,marks) - local char=isglyph(start) - if char then - if getsubtype(start)==ligatureglyph_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[char] then - return 1 - end - end - return 0 -end -local function markstoligature(head,start,stop,char) - if start==stop and getchar(start)==char then - return head,start - else - local prev=getprev(start) - local next=getnext(stop) - setprev(start) - setnext(stop) - local base=copy_no_components(start,copyinjection) - if head==start then - head=base - end - resetinjection(base) - setchar(base,char) - setsubtype(base,ligatureglyph_code) - set_components(base,start) - setlink(prev,base,next) - return head,base - end -end -local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) - if getattr(start,a_noligature)==1 then - return head,start - end - if start==stop and getchar(start)==char then - resetinjection(start) - setchar(start,char) - return head,start - end - local prev=getprev(start) - local next=getnext(stop) - local comp=start - setprev(start) - setnext(stop) - local base=copy_no_components(start,copyinjection) - if start==head then - head=base - end - resetinjection(base) - setchar(base,char) - setsubtype(base,ligatureglyph_code) - set_components(base,comp) - setlink(prev,base,next) - if not discfound then - local deletemarks=not skiphash or hasmarks - local components=start - local baseindex=0 - local componentindex=0 - local head=base - local current=base - while start do - local char=getchar(start) - if not marks[char] then - baseindex=baseindex+componentindex - 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) - head,current=insert_node_after(head,current,n) - elseif trace_marks then - logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char)) - end - start=getnext(start) - end - local start=getnext(current) - while start do - local char=ischar(start) - if char then - if marks[char] then - setligaindex(start,baseindex+getligaindex(start,componentindex)) - if trace_marks then - logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) - end - start=getnext(start) - else - break - end - else - break - end - end - else - local discprev,discnext=getboth(discfound) - if discprev and discnext then - local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true) - 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) - end - pre=comp - if post then - setlink(posttail,discnext) - setprev(post) - else - post=discnext - setprev(discnext) - end - setlink(prev,discfound,next) - setboth(base) - set_components(base,copied) - replace=base - if forcediscretionaries then - setdisc(discfound,pre,post,replace,discretionarydisc_code) - else - setdisc(discfound,pre,post,replace) - end - base=prev - end - end - end - return head,base -end -local function multiple_glyphs(head,start,multiple,skiphash,what,stop) - local nofmultiples=#multiple - if nofmultiples>0 then - resetinjection(start) - setchar(start,multiple[1]) - if nofmultiples>1 then - local sn=getnext(start) - for k=2,nofmultiples do - local n=copy_node(start) - resetinjection(n) - setchar(n,multiple[k]) - insert_node_after(head,start,n) - start=n - end - if what==true then - elseif what>1 then - local m=multiple[nofmultiples] - for i=2,what do - local n=copy_node(start) - resetinjection(n) - setchar(n,m) - insert_node_after(head,start,n) - start=n - end - end - end - return head,start,true - else - if trace_multiples then - logprocess("no multiple for %s",gref(getchar(start))) - end - return head,start,false - end -end -local function get_alternative_glyph(start,alternatives,value) - local n=#alternatives - 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 - return alternatives[1],trace_alternatives and formatters["value %a, taking %a"](value,1) - elseif value=="last" then - return alternatives[n],trace_alternatives and formatters["value %a, taking %a"](value,n) - end - value=value==true and 1 or tonumber(value) - if type(value)~="number" then - return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,1) - end - if value>n then - local defaultalt=otf.defaultnodealternate - if defaultalt=="first" then - return alternatives[n],trace_alternatives and formatters["invalid value %s, taking %a"](value,1) - elseif defaultalt=="last" then - return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,n) - else - return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range") - end - elseif value==0 then - return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change") - elseif value<1 then - return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1) - else - return alternatives[value],trace_alternatives and formatters["value %a, taking %a"](value,value) - end -end -function handlers.gsub_single(head,start,dataset,sequence,replacement) - if trace_singles then - logprocess("%s: replacing %s by single %s",pref(dataset,sequence),gref(getchar(start)),gref(replacement)) - end - resetinjection(start) - setchar(start,replacement) - return head,start,true -end -function handlers.gsub_alternate(head,start,dataset,sequence,alternative) - local kind=dataset[4] - local what=dataset[1] - local value=what==true and tfmdata.shared.features[kind] or what - local choice,comment=get_alternative_glyph(start,alternative,value) - if choice then - if trace_alternatives then - logprocess("%s: replacing %s by alternative %a to %s, %s",pref(dataset,sequence),gref(getchar(start)),gref(choice),comment) - end - resetinjection(start) - setchar(start,choice) - else - if trace_alternatives then - logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment) - end - end - return head,start,true -end -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,skiphash,dataset[1]) -end -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 skiphash and skiphash[startchar] then - while current do - local char=ischar(current,currentfont) - if char then - local lg=ligature[char] - if lg then - stop=current - ligature=lg - current=getnext(current) - else - break - end - else - break - end - end - if stop then - local lig=ligature.ligature - if lig then - if trace_ligatures then - local stopchar=getchar(stop) - head,start=markstoligature(head,start,stop,lig) - logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start))) - else - head,start=markstoligature(head,start,stop,lig) - end - return head,start,true,false - else - end - end - else - local discfound=false - local hasmarks=marks[startchar] - while current do - local char,id=ischar(current,currentfont) - if char then - if skiphash and skiphash[char] then - current=getnext(current) - else - local lg=ligature[char] - if lg then - if marks[char] then - hasmarks=true - end - stop=current - ligature=lg - current=getnext(current) - else - break - end - end - elseif char==false then - break - elseif id==disc_code then - discfound=current - break - else - break - end - end - if discfound then - local pre,post,replace=getdisc(discfound) - local match - if replace then - local char=ischar(replace,currentfont) - if char and ligature[char] then - match=true - end - end - if not match and pre then - local char=ischar(pre,currentfont) - if char and ligature[char] then - match=true - end - end - if not match and not pre or not replace then - local n=getnext(discfound) - local char=ischar(n,currentfont) - if char and ligature[char] then - match=true - end - end - if match then - local ishead=head==start - local prev=getprev(start) - if stop then - setnext(stop) - local tail=getprev(stop) - local copy=copy_node_list(start) - local liat=find_node_tail(copy) - if pre then - setlink(liat,pre) - end - if replace then - setlink(tail,replace) - end - pre=copy - replace=start - else - setnext(start) - local copy=copy_node(start) - if pre then - setlink(copy,pre) - end - if replace then - setlink(start,replace) - end - pre=copy - replace=start - end - setdisc(discfound,pre,post,replace) - if prev then - setlink(prev,discfound) - else - setprev(discfound) - head=discfound - end - start=discfound - return head,start,true,true - end - end - local lig=ligature.ligature - if lig then - if stop then - if trace_ligatures then - local stopchar=getchar(stop) - head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,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,skiphash,false,hasmarks) - end - else - resetinjection(start) - setchar(start,lig) - if trace_ligatures then - logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig)) - end - end - return head,start,true,false - else - end - end - return head,start,false,false -end -function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) - local startchar=getchar(start) - 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 %s xy (%p,%p) and wh (%p,%p)",pref(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",pref(dataset,sequence),gref(startchar),format,k) - end - end - return head,start,true -end -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 - while snext do - local nextchar=ischar(snext,currentfont) - if nextchar then - if skiphash and skiphash[nextchar] then - prev=snext - snext=getnext(snext) - 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 - 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 - end - 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 - 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 - 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 - end - else - break - end - end - return head,start,false - end -end -function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash) - local markchar=getchar(start) - if marks[markchar] 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 - 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),2) - end - return head,start,false - end - end - end - local ba=markanchors[1][basechar] - if ba then - 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, 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) - end - elseif trace_bugs then - logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),2) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) - end - return head,start,false -end -function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash) - local markchar=getchar(start) - if marks[markchar] 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 - 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),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, 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 - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(dataset,sequence),gref(markchar),gref(basechar),index) - end - end - end - elseif trace_bugs then - onetimemessage(currentfont,basechar,"no base anchors",report_fonts) - end - elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1) - end - elseif trace_bugs then - logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),2) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) - end - return head,start,false -end -function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash) - local markchar=getchar(start) - if marks[markchar] 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 - if base then - local basechar=ischar(base,currentfont) - if basechar then - local ba=markanchors[1][basechar] - if ba then - 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, 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 - end - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) - end - return head,start,false -end -function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step) - local startchar=getchar(start) - 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 - 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 - end - end - break - end - end - end - 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 -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,skiphash) - local char=getchar(start) - local replacement=replacements[char] - if replacement then - if trace_singles then - logprocess("%s: single reverse replacement of %s by %s",cref(dataset,sequence),gref(char),gref(replacement)) - end - resetinjection(start) - setchar(start,replacement) - return head,start,true - else - return head,start,false - 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 -local function getmapping(dataset,sequence,currentlookup) - local steps=currentlookup.steps - local nofsteps=currentlookup.nofsteps - 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 -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 - current=getnext(current) - end - end - end - return head,start,false -end -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 - 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 - end - return head,start,false -end -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 - else - 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,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 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 schar=getchar(current) - if skiphash and skiphash[schar] then - current=getnext(current) - else - 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 - 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 - 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 - end - return head,start,false,0,false -end -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 - 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,skiphash,chainindex) - local mapping=currentlookup.mapping - if mapping==nil then - mapping=getmapping(dataset,sequence,currentlookup) - end - 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: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) - end - return head,start,true - else - break - end - end - end - end - end - end - return head,start,false -end -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),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, 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 - 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),2) - end - elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) - end - end - return head,start,false -end -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,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, 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 - 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),2) - end - elseif trace_bugs then - logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) - end - end - return head,start,false -end -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 - 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 - 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),2) - end - elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) - end - end - return head,start,false -end -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 - 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 - 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 - end - elseif trace_bugs then - onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) - end - break - end - end - end - elseif trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) - end - 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 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=userkern(getwidth(current)) - if head==current then - local next=getnext(current) - if next then - setlink(kern,next) - end - flush_node(current) - head=kern - current=next - else - local prev,next=getboth(current) - setlink(prev,kern,next) - flush_node(current) - current=next - end - else - current=getnext(current) - end - end - return head -end -local function setdiscchecked(d,pre,post,replace) - if pre then pre=checked(pre) end - if post then post=checked(post) end - if replace then replace=checked(replace) end - setdisc(d,pre,post,replace) -end -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 - local startishead=start==head - local seq=ck[3] - local f=ck[4] - local l=ck[5] - local s=#seq - local done=false - local sweepnode=sweepnode - local sweeptype=sweeptype - local sweepoverflow=false - local keepdisc=not sweepnode - local lookaheaddisc=nil - local backtrackdisc=nil - local current=start - local last=start - local prev=getprev(start) - local hasglue=false - local i=f - while i<=l do - local id=getid(current) - if id==glyph_code then - i=i+1 - last=current - current=getnext(current) - elseif id==glue_code then - i=i+1 - last=current - current=getnext(current) - hasglue=true - elseif id==disc_code then - if keepdisc then - keepdisc=false - lookaheaddisc=current - local replace=getfield(current,"replace") - 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 - current=getnext(replace) - end - last=current - else - head,current=flattendisk(head,current) - end - else - last=current - current=getnext(current) - end - if current then - elseif sweepoverflow then - break - elseif sweeptype=="post" or sweeptype=="replace" then - current=getnext(sweepnode) - if current then - sweeptype=nil - sweepoverflow=true - else - break - end - else - break - end - end - if sweepoverflow then - local prev=current and getprev(current) - if not current or prev~=sweepnode then - local head=getnext(sweepnode) - local tail=nil - if prev then - tail=prev - setprev(current,sweepnode) - else - tail=find_node_tail(head) - end - setnext(sweepnode,current) - setprev(head) - setnext(tail) - appenddisc(sweepnode,head) - end - end - if l<s then - local i=l - local t=sweeptype=="post" or sweeptype=="replace" - while current and i<s do - local id=getid(current) - if id==glyph_code then - i=i+1 - current=getnext(current) - elseif id==glue_code then - i=i+1 - current=getnext(current) - hasglue=true - elseif id==disc_code then - if keepdisc then - keepdisc=false - if notmatchpre[current]~=notmatchreplace[current] then - lookaheaddisc=current - end - local replace=getfield(current,"replace") - while replace and i<s do - if getid(replace)==glyph_code then - i=i+1 - end - replace=getnext(replace) - end - current=getnext(current) - elseif notmatchpre[current]~=notmatchreplace[current] then - head,current=flattendisk(head,current) - else - current=getnext(current) - end - else - current=getnext(current) - end - if not current and t then - current=getnext(sweepnode) - if current then - sweeptype=nil - end - end - end - end - if f>1 then - local current=prev - local i=f - local t=sweeptype=="pre" or sweeptype=="replace" - if not current and t and current==checkdisk then - current=getprev(sweepnode) - end - while current and i>1 do - local id=getid(current) - if id==glyph_code then - i=i-1 - elseif id==glue_code then - i=i-1 - hasglue=true - elseif id==disc_code then - if keepdisc then - keepdisc=false - if notmatchpost[current]~=notmatchreplace[current] then - backtrackdisc=current - end - local replace=getfield(current,"replace") - while replace and i>1 do - if getid(replace)==glyph_code then - i=i-1 - end - replace=getnext(replace) - end - elseif notmatchpost[current]~=notmatchreplace[current] then - head,current=flattendisk(head,current) - end - end - current=getprev(current) - if t and current==checkdisk then - current=getprev(sweepnode) - end - end - end - local done=false - if lookaheaddisc then - local cf=start - local cl=getprev(lookaheaddisc) - local cprev=getprev(start) - local insertedmarks=0 - while cprev do - local char=ischar(cf,currentfont) - if char and marks[char] then - insertedmarks=insertedmarks+1 - cf=cprev - startishead=cf==head - cprev=getprev(cprev) - else - break - end - 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 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 - 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 - 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) - else - setdisc(lookaheaddisc,cf,post,new) - end - start=getprev(lookaheaddisc) - sweephead[cf]=getnext(clast) or false - sweephead[new]=getnext(cl) or false - elseif backtrackdisc then - local cf=getnext(backtrackdisc) - local cl=start - local cnext=getnext(start) - local insertedmarks=0 - while cnext do - local char=ischar(cnext,currentfont) - if char and marks[char] then - insertedmarks=insertedmarks+1 - cl=cnext - cnext=getnext(cnext) - else - break - end - end - setlink(backtrackdisc,cnext) - setprev(cf) - setnext(cl) - local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true) - local new=copy_node_list(cf) - local cnew=find_node_tail(new) - for i=1,insertedmarks do - cnew=getprev(cnew) - end - local clast=cnew - for i=f,l do - clast=getnext(clast) - end - if not notmatchpost[backtrackdisc] then - 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 - 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) - else - post=cf - end - if replace then - setlink(replacetail,new) - else - replace=new - end - if hasglue then - setdiscchecked(backtrackdisc,pre,post,replace) - else - setdisc(backtrackdisc,pre,post,replace) - end - start=getprev(backtrackdisc) - sweephead[post]=getnext(clast) or false - sweephead[replace]=getnext(last) or false - else - 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,done -end -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 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 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 - break - end - else - goto next - end - elseif char==false then - if discfound then - notmatchreplace[discfound]=true - if notmatchpre[discfound] then - goto next - else - break - end - 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 - pre=getnext(pre) - else - notmatchpre[last]=true - break - end - 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 - break - end - end - end - if notmatchpre[last] then - goto next - end - end - last=getnext(last) - else - goto next - end - else - goto next - end - end - end - if f>1 then - if startprev then - local prev=startprev - if prereplace and prev==checkdisc then - prev=getprev(sweepnode) - end - if prev then - 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 - break - end - else - goto next - end - elseif char==false then - if discfound then - notmatchreplace[discfound]=true - if notmatchpost[discfound] then - goto next - end - 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 - else - notmatchpost[prev]=true - break - end - end - if n>=1 then - notmatchpost[prev]=true - 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 - break - end - end - end - else - end - 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 - goto next - end - elseif seq[n][0xFFFC] then - n=n-1 - prev=getprev(prev) - else - goto next - end - else - goto next - end - end - else - goto next - end - else - goto next - 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 - break - end - else - goto next - end - elseif char==false then - if discfound then - notmatchreplace[discfound]=true - if notmatchpre[discfound] then - goto next - else - break - end - 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 - else - notmatchpre[current]=true - break - end - end - if n<=s then - notmatchpre[current]=true - end - 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) - end - else - notmatchreplace[current]=true - if notmatchpre[current] then - goto next - else - break - end - end - end - else - 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 - goto next - end - elseif seq[n][0xFFFC] then - n=n+1 - current=getnext(current) - else - goto next - end - else - goto next - end - end - else - 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 discseen then - notmatchpre={} - notmatchpost={} - notmatchreplace={} - end - return head,start,done -end -handlers.gsub_context=handle_contextchain -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,skiphash) - local steps=currentlookup.steps - local nofsteps=currentlookup.nofsteps - if nofsteps>1 then - reportmoresteps(dataset,sequence) - end - 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 -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 sequencelists=setmetatableindex(function(t,font) - local sequences=fontdata[font].resources.sequences - if not sequences or not next(sequences) then - sequences=false - end - t[font]=sequences - return sequences -end) -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 - 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 - end - end - end - end - return rl - end -end -local function report_disc(what,n) - report_run("%s: %s > %s",what,n,languages.serializediscretionary(n)) -end -local function kernrun(disc,k_run,font,attr,...) - if trace_kernruns then - report_disc("kern",disc) - end - local prev,next=getboth(disc) - local nextstart=next - local done=false - local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) - local prevmarks=prev - while prevmarks do - local char=ischar(prevmarks,font) - if char and marks[char] then - prevmarks=getprev(prevmarks) - else - break - end - end - if prev and not ischar(prev,font) then - prev=false - end - if next and not ischar(next,font) then - next=false - end - if pre then - if k_run(pre,"injections",nil,font,attr,...) then - done=true - end - if prev then - setlink(prev,pre) - if k_run(prevmarks,"preinjections",pre,font,attr,...) then - done=true - end - setprev(pre) - setlink(prev,disc) - end - end - if post then - if k_run(post,"injections",nil,font,attr,...) then - done=true - end - if next then - setlink(posttail,next) - if k_run(posttail,"postinjections",next,font,attr,...) then - done=true - end - setnext(posttail) - setlink(disc,next) - end - end - if replace then - if k_run(replace,"injections",nil,font,attr,...) then - done=true - end - if prev then - setlink(prev,replace) - if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then - done=true - end - setprev(replace) - setlink(prev,disc) - end - if next then - setlink(replacetail,next) - if k_run(replacetail,"replaceinjections",next,font,attr,...) then - done=true - end - setnext(replacetail) - 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,next) - end - if done and trace_testruns then - report_disc("done",disc) - end - return nextstart,done -end -local function comprun(disc,c_run,...) - if trace_compruns then - report_disc("comp",disc) - end - local pre,post,replace=getdisc(disc) - local renewed=false - if pre then - sweepnode=disc - sweeptype="pre" - local new,done=c_run(pre,...) - if done then - pre=new - renewed=true - end - end - if post then - sweepnode=disc - sweeptype="post" - local new,done=c_run(post,...) - if done then - post=new - renewed=true - end - end - if replace then - sweepnode=disc - sweeptype="replace" - local new,done=c_run(replace,...) - if done then - replace=new - renewed=true - end - end - 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 -local function testrun(disc,t_run,c_run,...) - if trace_testruns then - report_disc("test",disc) - end - local prev,next=getboth(disc) - if not next then - return - end - local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) - 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) - local tail=head - for i=2,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 - if pre then - sweepnode=disc - sweeptype="pre" - local new,ok=c_run(pre,...) - if ok then - pre=new - renewed=true - end - end - if post then - sweepnode=disc - sweeptype="post" - local new,ok=c_run(post,...) - if ok then - post=new - renewed=true - end - end - if replace then - sweepnode=disc - sweeptype="replace" - local new,ok=c_run(replace,...) - if ok then - replace=new - renewed=true - end - end - sweepnode=nil - sweeptype=nil - if renewed then - setdisc(disc,pre,post,replace) - 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,skiphash,handler) - local done=false - local sweep=sweephead[head] - if sweep then - start=sweep - sweephead[head]=false - else - start=head - end - while start do - local char,id=ischar(start,font) - if char then - 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,skiphash,step) - if ok then - done=true - end - end - if start then - start=getnext(start) - end - else - start=getnext(start) - end - elseif char==false then - return head,done - elseif sweep then - return head,done - else - start=getnext(start) - end - end - 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 - 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=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,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 - lastd=d - end - else - end - else - end - 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,skiphash,handler) - local a - if attr then - a=getattr(sub,0) - end - if not a or (a==attr) then - for n in nextnode,sub do - if n==last then - break - end - local char=ischar(n) - if char then - 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 - end - end - end - end -end -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]=false - else - start=head - end - while start do - local char=ischar(start,font) - if char then - 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 - 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 - end - end - if start then - start=getnext(start) - end - else - start=getnext(start) - end - elseif char==false then - return head,done - elseif sweep then - return head,done - else - start=getnext(start) - end - end - 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 - 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 - 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 - else - break - end - end - if l and l.ligature then - lastd=d - end - end - end - else - end - 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,skiphash,handler) - local a - if attr then - a=getattr(sub,0) - end - if not a or (a==attr) then - for n in nextnode,sub do - if n==last then - break - end - local char=ischar(n) - if char then - for i=1,nofsteps do - local step=steps[i] - local lookupcache=step.coverage - 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 - end - end - end - end - end -end -local txtdirstate,pardirstate do - local getdirection=nuts.getdirection - local lefttoright=0 - local righttoleft=1 - txtdirstate=function(start,stack,top,rlparmode) - local dir,pop=getdirection(start) - if pop then - if top==1 then - return 0,rlparmode - else - top=top-1 - if stack[top]==righttoleft then - return top,-1 - else - return top,1 - end - end - elseif dir==lefttoright then - top=top+1 - stack[top]=lefttoright - return top,1 - elseif dir==righttoleft then - top=top+1 - stack[top]=righttoleft - return top,-1 - else - return top,rlparmode - end - end - pardirstate=function(start) - local dir=getdirection(start) - if dir==lefttoright then - return 1,1 - elseif dir==righttoleft then - return -1,-1 - elseif dir=="TLT" then - return 1,1 - elseif dir=="TRT" then - return -1,-1 - else - return 0,0 - end - end -end -otf.helpers=otf.helpers or {} -otf.helpers.txtdirstate=txtdirstate -otf.helpers.pardirstate=pardirstate -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=0 - if getid(head)==localpar_code and getsubtype(head)==0 then - initialrl=pardirstate(head) - elseif direction==1 or direction=="TRT" then - initialrl=-1 - end - 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 - 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 - start=getprev(start) - end - else - start=getprev(start) - end - else - start=getprev(start) - end - end - 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 - if skiphash and skiphash[char] then - start=getnext(start) - else - local lookupmatch=lookupcache[char] - if lookupmatch 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 - local ok,df - head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - if df then - elseif start then - start=getnext(start) - end - else - start=getnext(start) - end - else - start=getnext(start) - end - end - 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_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,skiphash,handler) - end - else - start=getnext(start) - end - elseif id==math_code then - start=getnext(end_of_math(start)) - elseif id==dir_code then - topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) - start=getnext(start) - else - start=getnext(start) - end - end - 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 - local ok,df - for i=m[1],m[2] do - local step=steps[i] - local lookupcache=step.coverage - local lookupmatch=lookupcache[char] - if lookupmatch then - head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) - if df then - break - elseif ok then - break - elseif not start then - break - end - end - end - if df then - elseif start then - start=getnext(start) - end - else - start=getnext(start) - end - else - start=getnext(start) - end - end - 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 - topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) - start=getnext(start) - else - start=getnext(start) - end - 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==1 or 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) - 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 - end - if start then - start=getnext(start) - end - 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 - topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) - start=getnext(start) - else - start=getnext(start) - end - end - return head - end -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 -function otf.plugininitializer(tfmdata,value) - if type(value)=="string" then - tfmdata.shared.plugin=plugins[value] - end -end -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,attr,direction) - else - return head,false - end -end -function otf.featuresinitializer(tfmdata,value) -end -registerotffeature { - name="features", - description="features", - default=true, - initializers={ - position=1, - node=otf.featuresinitializer, - plug=otf.plugininitializer, - }, - processors={ - node=otf.featuresprocessor, - plug=otf.pluginprocessor, - } -} -otf.handlers=handlers -local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end -local tag="kern" -if fontfeatures then - function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr) - local features=fontfeatures[font] - local enabled=features and features.spacekern and features[tag] - if enabled then - setspacekerns(font,sequence) - end - return head,enabled - end -else - 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[tag] - if enabled then - setspacekerns(font,sequence) - end - return head,enabled - end -end -local function hasspacekerns(data) - 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 - end - end - end - return false -end -otf.readers.registerextender { - name="spacekerns", - action=function(data) - data.properties.hasspacekerns=hasspacekerns(data) - end -} -local function spaceinitializer(tfmdata,value) - local resources=tfmdata.resources - local spacekerns=resources and resources.spacekerns - 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 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 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 - 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={ [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 - end - end - resources.spacekerns=spacekerns - end - return spacekerns -end -registerotffeature { - name="spacekern", - description="space kern injection", - default=true, - initializers={ - node=spaceinitializer, - }, -} -local function markinitializer(tfmdata,value) - local properties=tfmdata.properties - properties.checkmarks=value -end -registerotffeature { - name="checkmarks", - description="check mark widths", - default=true, - initializers={ - node=markinitializer, - }, -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ots”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-osd” 883c29eaccf966c9ad9ab205a920de08] --- - -if not modules then modules={} end modules ['font-osd']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Kai Eigner, TAT Zetwerk / Hans Hagen, PRAGMA ADE", - copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local insert,imerge,copy=table.insert,table.imerge,table.copy -local next,type=next,type -local report=logs.reporter("otf","devanagari") -fonts=fonts or {} -fonts.analyzers=fonts.analyzers or {} -fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } } -local otf=fonts.handlers.otf -local handlers=otf.handlers -local methods=fonts.analyzers.methods -local otffeatures=fonts.constructors.features.otf -local registerotffeature=otffeatures.register -local nuts=nodes.nuts -local getnext=nuts.getnext -local getprev=nuts.getprev -local getboth=nuts.getboth -local getid=nuts.getid -local getchar=nuts.getchar -local getfont=nuts.getfont -local getsubtype=nuts.getsubtype -local setlink=nuts.setlink -local setnext=nuts.setnext -local setprev=nuts.setprev -local setchar=nuts.setchar -local getprop=nuts.getprop -local setprop=nuts.setprop -local ischar=nuts.is_char -local insert_node_after=nuts.insert_after -local copy_node=nuts.copy -local remove_node=nuts.remove -local flush_list=nuts.flush_list -local flush_node=nuts.flush_node -local copyinjection=nodes.injections.copy -local unsetvalue=attributes.unsetvalue -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 -local s_pref=states.pref -local s_blwf=states.blwf -local s_pstf=states.pstf -local replace_all_nbsp=nil -replace_all_nbsp=function(head) - replace_all_nbsp=typesetters and typesetters.characters and typesetters.characters.replacenbspaces or function(head) - return head - end - return replace_all_nbsp(head) -end -local processcharacters=nil -if context then - 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 - 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={ - [c_zwnj]=true, - [c_zwj ]=true, -} -local dflt_true={ - dflt=true -} -local two_defaults={ - dev2=dflt_true, -} -local one_defaults={ - dev2=dflt_true, - deva=dflt_true, -} -local false_flags={ false,false,false,false } -local sequence_reorder_matras={ - features={ dv01=two_defaults }, - flags=false_flags, - name="dv01_reorder_matras", - order={ "dv01" }, - type="devanagari_reorder_matras", - nofsteps=1, - steps={ - { - coverage=pre_mark, - } - } -} -local sequence_reorder_reph={ - features={ dv02=two_defaults }, - flags=false_flags, - name="dv02_reorder_reph", - order={ "dv02" }, - type="devanagari_reorder_reph", - nofsteps=1, - steps={ - { - coverage={}, - } - } -} -local sequence_reorder_pre_base_reordering_consonants={ - features={ dv03=two_defaults }, - flags=false_flags, - name="dv03_reorder_pre_base_reordering_consonants", - order={ "dv03" }, - type="devanagari_reorder_pre_base_reordering_consonants", - nofsteps=1, - steps={ - { - coverage={}, - } - } -} -local sequence_remove_joiners={ - features={ dv04=one_defaults }, - flags=false_flags, - name="dv04_remove_joiners", - order={ "dv04" }, - type="devanagari_remove_joiners", - nofsteps=1, - steps={ - { - coverage=zw_char, - }, - } -} -local basic_shaping_forms={ - akhn=true, - blwf=true, - cjct=true, - half=true, - nukt=true, - pref=true, - pstf=true, - rkrf=true, - rphf=true, - vatu=true, -} -local valid={ - abvs=true, - akhn=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 scripts[script] then - local resources=tfmdata.resources - local devanagari=resources.devanagari - if not devanagari then - report("adding devanagari features to font") - local gsubfeatures=resources.features.gsub - local sequences=resources.sequences - local sharedfeatures=tfmdata.shared.features - local lastmatch=0 - for s=1,#sequences do - local features=sequences[s].features - if features then - for k,v in next,features do - if basic_shaping_forms[k] then - lastmatch=s - end - end - end - end - local insertindex=lastmatch+1 - 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) - local remove_joiners=copy(sequence_remove_joiners) - insert(sequences,insertindex,reorder_pre_base_reordering_consonants) - insert(sequences,insertindex,reorder_reph) - insert(sequences,insertindex,reorder_matras) - insert(sequences,insertindex,remove_joiners) - local blwfcache={} - local seqsubset={} - local rephstep={ - coverage={} - } - local devanagari={ - reph=false, - vattu=false, - blwfcache=blwfcache, - seqsubset=seqsubset, - reorderreph=rephstep, - } - reorder_reph.steps={ rephstep } - local pre_base_reordering_consonants={} - reorder_pre_base_reordering_consonants.steps[1].coverage=pre_base_reordering_consonants - resources.devanagari=devanagari - for s=1,#sequences do - local sequence=sequences[s] - local steps=sequence.steps - local nofsteps=sequence.nofsteps - local features=sequence.features - local has_rphf=features.rphf - local has_blwf=features.blwf - if has_rphf and has_rphf.deva then - devanagari.reph=true - elseif has_blwf and has_blwf.deva then - devanagari.vattu=true - for i=1,nofsteps do - local step=steps[i] - local coverage=step.coverage - if coverage then - for k,v in next,coverage do - if not blwfcache[k] then - blwfcache[k]=v - end - end - end - end - end - 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 - 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 - end - end - seqsubset[#seqsubset+1]={ kind,coverage,reph } - end - end - end - if kind=="pref" then - local steps=sequence.steps - local nofsteps=sequence.nofsteps - for i=1,nofsteps do - local step=steps[i] - local coverage=step.coverage - if coverage then - for k,v in next,halant do - local h=coverage[k] - if h then - local found=false - for k,v in next,h do - found=v and v.ligature - if found then - pre_base_reordering_consonants[k]=found - break - end - end - if found then - break - end - end - end - end - end - end - end - end - if script=="deva" then - sharedfeatures["dv04"]=true - elseif script=="dev2" then - sharedfeatures["dv01"]=true - sharedfeatures["dv02"]=true - sharedfeatures["dv03"]=true - sharedfeatures["dv04"]=true - elseif script=="mlym" then - sharedfeatures["pstf"]=true - elseif script=="mlm2" then - sharedfeatures["pstf"]=true - sharedfeatures["pref"]=true - sharedfeatures["dv03"]=true - 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 -end -registerotffeature { - name="devanagari", - description="inject additional features", - default=true, - initializers={ - node=initializedevanagi, - }, -} -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 - if not devanagaridata then - devanagaridata={ - reph=false, - vattu=false, - blwfcache={}, - } - datasets.devanagari=devanagaridata - local resources=tfmdata.resources - local devanagari=resources.devanagari - for s=1,#datasets do - local dataset=datasets[s] - if dataset and dataset[1] then - local kind=dataset[4] - if kind=="rphf" then - devanagaridata.reph=true - elseif kind=="blwf" then - devanagaridata.vattu=true - devanagaridata.blwfcache=devanagari.blwfcache - end - end - end - end - return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache -end -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 - local firstcons=nil - local lastcons=nil - local basefound=false - if reph and ra[getchar(start)] and halant[getchar(n)] then - if n==stop then - return head,stop,nbspaces - end - if getchar(getnext(n))==c_zwj then - current=start - else - current=getnext(n) - setprop(start,a_state,s_rphf) - end - end - if getchar(current)==c_nbsp then - if current==stop then - stop=getprev(stop) - head=remove_node(head,current) - flush_node(current) - return head,stop,nbspaces - else - nbspaces=nbspaces+1 - base=current - firstcons=current - lastcons=current - current=getnext(current) - if current~=stop then - local char=getchar(current) - if nukta[char] then - current=getnext(current) - char=getchar(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 - end - end - end - end - while not basefound do - local char=getchar(current) - if consonant[char] then - setprop(current,a_state,s_half) - if not firstcons then - firstcons=current - end - lastcons=current - if not base then - base=current - elseif blwfcache[char] then - setprop(current,a_state,s_blwf) - else - base=current - end - end - basefound=current==stop - current=getnext(current) - end - if base~=lastcons then - local np=base - local n=getnext(base) - local ch=getchar(n) - if nukta[ch] then - np=n - n=getnext(n) - ch=getchar(n) - end - if halant[ch] then - if lastcons~=stop then - local ln=getnext(lastcons) - if nukta[getchar(ln)] then - lastcons=ln - end - end - local nn=getnext(n) - local ln=getnext(lastcons) - setlink(np,nn) - setnext(lastcons,n) - if ln then - setprev(ln,n) - end - setnext(n,ln) - setprev(n,lastcons) - if lastcons==stop then - stop=n - end - end - end - n=getnext(start) - if n~=stop and ra[getchar(start)] and halant[getchar(n)] and not zw_char[getchar(getnext(n))] then - local matra=base - if base~=stop then - local next=getnext(base) - if dependent_vowel[getchar(next)] then - matra=next - end - end - local sp=getprev(start) - local nn=getnext(n) - local mn=getnext(matra) - setlink(sp,nn) - setlink(matra,start) - setlink(n,mn) - if head==start then - head=nn - end - start=nn - if matra==stop then - stop=n - end - end - local current=start - while current~=stop do - local next=getnext(current) - if next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwnj then - setprop(current,a_state,unsetvalue) - end - current=next - end - if base~=stop and getprop(base,a_state) then - local next=getnext(base) - if halant[getchar(next)] and not (next~=stop and getchar(getnext(next))==c_zwj) then - setprop(base,a_state,unsetvalue) - end - end - local current,allreordered,moved=start,false,{ [base]=true } - local a,b,p,bn=base,base,base,getnext(base) - if base~=stop and nukta[getchar(bn)] then - a,b,p=bn,bn,bn - end - while not allreordered do - local c=current - local n=getnext(current) - local l=nil - if c~=stop then - local ch=getchar(n) - if nukta[ch] then - c=n - n=getnext(n) - ch=getchar(n) - end - if c~=stop then - if halant[ch] then - c=n - n=getnext(n) - ch=getchar(n) - end - while c~=stop and dependent_vowel[ch] do - c=n - n=getnext(n) - ch=getchar(n) - end - if c~=stop then - if vowel_modifier[ch] then - c=n - n=getnext(n) - ch=getchar(n) - end - if c~=stop and stress_tone_mark[ch] then - c=n - n=getnext(n) - end - end - end - end - local bp=getprev(firstcons) - local cn=getnext(current) - local last=getnext(c) - while cn~=last do - if pre_mark[getchar(cn)] then - if bp then - setnext(bp,cn) - end - local prev,next=getboth(cn) - if next then - setprev(next,prev) - end - setnext(prev,next) - if cn==stop then - stop=prev - end - setprev(cn,bp) - setlink(cn,firstcons) - if firstcons==start then - if head==start then - head=cn - end - start=cn - end - break - end - cn=getnext(cn) - end - allreordered=c==stop - current=getnext(c) - end - if reph or vattu then - local current,cns=start,nil - while current~=stop do - local c=current - local n=getnext(current) - if ra[getchar(current)] and halant[getchar(n)] then - c=n - n=getnext(n) - local b,bn=base,base - while bn~=stop do - local next=getnext(bn) - if dependent_vowel[getchar(next)] then - b=next - end - bn=next - end - if getprop(current,a_state)==s_rphf then - if b~=current then - if current==start then - if head==start then - head=n - end - start=n - end - if b==stop then - stop=c - end - local prev=getprev(current) - setlink(prev,n) - local next=getnext(b) - setlink(c,next) - setlink(b,current) - end - elseif cns and getnext(cns)~=current then - local cp=getprev(current) - local cnsn=getnext(cns) - setlink(cp,n) - setlink(cns,current) - setlink(c,cnsn) - if c==stop then - stop=cp - break - end - current=getprev(n) - end - else - local char=getchar(current) - if consonant[char] then - cns=current - local next=getnext(cns) - if halant[getchar(next)] then - cns=next - end - elseif char==c_nbsp then - nbspaces=nbspaces+1 - cns=current - local next=getnext(cns) - if halant[getchar(next)] then - cns=next - end - end - end - current=getnext(current) - end - end - if getchar(base)==c_nbsp then - nbspaces=nbspaces-1 - head=remove_node(head,base) - flush_node(base) - end - return head,stop,nbspaces -end -function handlers.devanagari_reorder_matras(head,start) - local current=start - local startfont=getfont(start) - local startattr=getprop(start,a_syllabe) - while current do - local char=ischar(current,startfont) - local next=getnext(current) - if char and getprop(current,a_syllabe)==startattr then - if halant[char] and not getprop(current,a_state) then - if next then - local char=ischar(next,startfont) - if char and zw_char[char] and getprop(next,a_syllabe)==startattr then - current=next - next=getnext(current) - end - end - local startnext=getnext(start) - head=remove_node(head,start) - setlink(start,next) - setlink(current,start) - start=startnext - break - end - else - break - end - current=next - end - return head,start,true -end -function handlers.devanagari_reorder_reph(head,start) - local current=getnext(start) - local startnext=nil - 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 halant[char] and not getprop(current,a_state) then - local next=getnext(current) - if next then - local nextchar=ischar(next,startfont) - if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then - current=next - next=getnext(current) - end - end - startnext=getnext(start) - head=remove_node(head,start) - setlink(start,next) - setlink(current,start) - start=startnext - startattr=getprop(start,a_syllabe) - break - end - current=getnext(current) - else - 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 getprop(current,a_state)==s_pstf then - startnext=getnext(start) - head=remove_node(head,start) - setlink(getprev(current),start) - setlink(start,current) - start=startnext - startattr=getprop(start,a_syllabe) - break - end - current=getnext(current) - else - break - 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 not after_subscript[char] then - c=current - end - current=getnext(current) - else - break - end - end - if c then - startnext=getnext(start) - head=remove_node(head,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 - current=next - next=getnext(current) - else - break - end - end - if start~=current then - startnext=getnext(start) - head=remove_node(head,start) - setlink(start,getnext(current)) - setlink(current,start) - start=startnext - end - end - return head,start,true -end -function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) - local current=start - local startnext=nil - local startprev=nil - local startfont=getfont(start) - local startattr=getprop(start,a_syllabe) - while current do - local char=ischar(current,startfont) - if char and getprop(current,a_syllabe)==startattr then - local next=getnext(current) - if halant[char] and not getprop(current,a_state) then - if next then - local nextchar=ischar(next,startfont) - if nextchar and getprop(next,a_syllabe)==startattr then - if nextchar==c_zwnj or nextchar==c_zwj then - current=next - next=getnext(current) - end - end - end - startnext=getnext(start) - removenode(start,start) - setlink(start,next) - setlink(current,start) - start=startnext - break - end - current=next - else - break - end - end - if not startnext then - current=getnext(start) - startattr=getprop(start,a_syllabe) - while current do - local char=ischar(current,startfont) - if char and getprop(current,a_syllabe)==startattr then - if not consonant[char] and getprop(current,a_state) then - startnext=getnext(start) - removenode(start,start) - setlink(getprev(current),start) - setlink(start,current) - start=startnext - break - end - current=getnext(current) - else - break - end - end - end - return head,start,true -end -function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) - local stop=getnext(start) - local font=getfont(start) - local last=start - while stop do - local char=ischar(stop,font) - if char and (char==c_zwnj or char==c_zwj) then - last=stop - stop=getnext(stop) - else - break - end - end - local prev=getprev(start) - if stop then - setnext(last) - setlink(prev,stop) - elseif prev then - setnext(prev) - end - if head==start then - head=stop - end - flush_list(start) - return head,stop,true -end -local function initialize_two(font,attr) - local devanagari=fontdata[font].resources.devanagari - if devanagari then - return devanagari.seqsubset or {},devanagari.reorderreph or {} - else - return {},{} - end -end -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 - local subpos=nil - local postpos=nil - local locl={} - for i=1,#seqsubset do - local subset=seqsubset[i] - local kind=subset[1] - local lookupcache=subset[2] - if kind=="rphf" then - reph=subset[3] - local current=start - local last=getnext(stop) - while current~=last do - if current~=stop then - local c=locl[current] or getchar(current) - local found=lookupcache[c] - if found then - local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - local afternext=next~=stop and getnext(next) - if afternext and zw_char[getchar(afternext)] then - current=afternext - elseif current==start then - setprop(current,a_state,s_rphf) - current=next - else - current=next - end - end - end - end - current=getnext(current) - end - elseif kind=="pref" then - local current=start - local last=getnext(stop) - while current~=last do - if current~=stop then - local c=locl[current] or getchar(current) - local found=lookupcache[c] - if found then - local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_pref) - setprop(next,a_state,s_pref) - current=next - end - end - end - current=getnext(current) - end - elseif kind=="half" then - local current=start - local last=getnext(stop) - while current~=last do - if current~=stop then - local c=locl[current] or getchar(current) - local found=lookupcache[c] - if found then - local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - if next~=stop and getchar(getnext(next))==c_zwnj then - current=next - else - setprop(current,a_state,s_half) - if not halfpos then - halfpos=current - end - end - current=getnext(current) - end - end - end - current=getnext(current) - end - elseif kind=="blwf" then - local current=start - local last=getnext(stop) - while current~=last do - if current~=stop then - local c=locl[current] or getchar(current) - local found=lookupcache[c] - if found then - local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_blwf) - setprop(next,a_state,s_blwf) - current=next - subpos=current - end - end - end - current=getnext(current) - end - elseif kind=="pstf" then - local current=start - local last=getnext(stop) - while current~=last do - if current~=stop then - local c=locl[current] or getchar(current) - local found=lookupcache[c] - if found then - local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_pstf) - setprop(next,a_state,s_pstf) - current=next - postpos=current - end - end - end - current=getnext(current) - end - end - end - reorderreph.coverage={ [reph]=true } - local current,base,firstcons=start,nil,nil - if getprop(start,a_state)==s_rphf then - current=getnext(getnext(start)) - end - if current~=getnext(stop) and getchar(current)==c_nbsp then - if current==stop then - stop=getprev(stop) - head=remove_node(head,current) - flush_node(current) - return head,stop,nbspaces - else - nbspaces=nbspaces+1 - base=current - current=getnext(current) - if current~=stop then - local char=getchar(current) - if nukta[char] then - current=getnext(current) - char=getchar(current) - end - if char==c_zwj then - local next=getnext(current) - if current~=stop and next~=stop and halant[getchar(next)] then - current=next - next=getnext(current) - local tmp=getnext(next) - local changestop=next==stop - setnext(next) - setprop(current,a_state,s_pref) - current=processcharacters(current,font) - setprop(current,a_state,s_blwf) - current=processcharacters(current,font) - setprop(current,a_state,s_pstf) - current=processcharacters(current,font) - setprop(current,a_state,unsetvalue) - if halant[getchar(current)] then - setnext(getnext(current),tmp) - if show_syntax_errors then - head,current=inject_syntax_error(head,current,char) - end - else - setnext(current,tmp) - if changestop then - stop=current - end - end - end - end - end - end - else - local last=getnext(stop) - while current~=last do - local next=getnext(current) - if consonant[getchar(current)] then - if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then - if not firstcons then - firstcons=current - end - local a=getprop(current,a_state) - if not (a==s_pref or a==s_blwf or a==s_pstf) then - base=current - end - end - end - current=next - end - if not base then - base=firstcons - end - end - if not base then - if getprop(start,a_state)==s_rphf then - setprop(start,a_state,unsetvalue) - end - return head,stop,nbspaces - else - if getprop(base,a_state) then - setprop(base,a_state,unsetvalue) - end - basepos=base - end - if not halfpos then - halfpos=base - end - if not subpos then - subpos=base - end - if not postpos then - postpos=subpos or base - end - local moved={} - local current=start - local last=getnext(stop) - while current~=last do - local char,target,cn=locl[current] or getchar(current),nil,getnext(current) - local tpm=twopart_mark[char] - if tpm then - local extra=copy_node(current) - copyinjection(extra,current) - char=tpm[1] - setchar(current,char) - setchar(extra,tpm[2]) - head=insert_node_after(head,current,extra) - end - if not moved[current] and dependent_vowel[char] then - if pre_mark[char] then - moved[current]=true - local prev,next=getboth(current) - setlink(prev,next) - if current==stop then - stop=getprev(current) - end - if halfpos==start then - if head==start then - head=current - end - start=current - end - setlink(getprev(halfpos),current) - setlink(current,halfpos) - halfpos=current - elseif above_mark[char] then - target=basepos - if subpos==basepos then - subpos=current - end - if postpos==basepos then - postpos=current - end - basepos=current - elseif below_mark[char] then - target=subpos - if postpos==subpos then - postpos=current - end - subpos=current - elseif post_mark[char] then - target=postpos - postpos=current - end - if mark_above_below_post[char] then - local prev=getprev(current) - if prev~=target then - local next=getnext(current) - setlink(prev,next) - if current==stop then - stop=prev - end - setlink(current,getnext(target)) - setlink(target,current) - end - end - end - current=cn - end - local current,c=start,nil - while current~=stop do - local char=getchar(current) - if halant[char] or stress_tone_mark[char] then - if not c then - c=current - end - else - c=nil - end - local next=getnext(current) - if c and nukta[getchar(next)] then - if head==c then - head=next - end - if stop==next then - stop=current - end - setlink(getprev(c),next) - local nextnext=getnext(next) - setnext(current,nextnext) - local nextnextnext=getnext(nextnext) - if nextnextnext then - setprev(nextnextnext,current) - end - setlink(nextnext,c) - end - if stop==current then break end - current=getnext(current) - end - if getchar(base)==c_nbsp then - if base==stop then - stop=getprev(stop) - end - nbspaces=nbspaces-1 - head=remove_node(head,base) - flush_node(base) - end - return head,stop,nbspaces -end -local separator={} -imerge(separator,consonant) -imerge(separator,independent_vowel) -imerge(separator,dependent_vowel) -imerge(separator,vowel_modifier) -imerge(separator,stress_tone_mark) -for k,v in next,nukta do separator[k]=true end -for k,v in next,halant do separator[k]=true end -local function analyze_next_chars_one(c,font,variant) - local n=getnext(c) - if not n then - return c - end - if variant==1 then - local v=ischar(n,font) - if v and nukta[v] then - n=getnext(n) - if n then - v=ischar(n,font) - end - end - if n and v then - local nn=getnext(n) - if nn then - local vv=ischar(nn,font) - if vv then - local nnn=getnext(nn) - if nnn then - local vvv=ischar(nnn,font) - if vvv then - if vv==c_zwj and consonant[vvv] then - c=nnn - elseif (vv==c_zwnj or vv==c_zwj) and halant[vvv] then - local nnnn=getnext(nnn) - if nnnn then - local vvvv=ischar(nnnn,font) - if vvvv and consonant[vvvv] then - c=nnnn - end - end - end - end - end - end - end - end - elseif variant==2 then - local v=ischar(n,font) - if v and nukta[v] then - c=n - end - n=getnext(c) - if n then - v=ischar(n,font) - if v then - local nn=getnext(n) - if nn then - local vv=ischar(nn,font) - if vv and zw_char[v] then - n=nn - v=vv - nn=getnext(nn) - vv=nn and ischar(nn,font) - end - if vv and halant[v] and consonant[vv] then - c=nn - end - end - end - end - end - local n=getnext(c) - if not n then - return c - end - local v=ischar(n,font) - if not v then - return c - end - if dependent_vowel[v] then - c=getnext(c) - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if nukta[v] then - c=getnext(c) - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if halant[v] then - c=getnext(c) - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if vowel_modifier[v] then - c=getnext(c) - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if stress_tone_mark[v] then - c=getnext(c) - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if stress_tone_mark[v] then - return n - else - return c - end -end -local function analyze_next_chars_two(c,font) - local n=getnext(c) - if not n then - return c - end - local v=ischar(n,font) - if v and nukta[v] then - c=n - end - n=c - while true do - local nn=getnext(n) - if nn then - local vv=ischar(nn,font) - if vv then - if halant[vv] then - n=nn - local nnn=getnext(nn) - if nnn then - local vvv=ischar(nnn,font) - if vvv and zw_char[vvv] then - n=nnn - end - end - elseif vv==c_zwnj or vv==c_zwj then - local nnn=getnext(nn) - if nnn then - local vvv=ischar(nnn,font) - if vvv and halant[vvv] then - n=nnn - end - end - else - break - end - local nn=getnext(n) - if nn then - local vv=ischar(nn,font) - if vv and consonant[vv] then - n=nn - local nnn=getnext(nn) - if nnn then - local vvv=ischar(nnn,font) - if vvv and nukta[vvv] then - n=nnn - end - end - c=n - else - break - end - else - break - end - else - break - end - else - break - end - end - if not c then - return - end - local n=getnext(c) - if not n then - return c - end - local v=ischar(n,font) - if not v then - return c - end - if anudatta[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if halant[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - if v==c_zwnj or v==c_zwj then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - else - if dependent_vowel[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if nukta[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if halant[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - end - if vowel_modifier[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if stress_tone_mark[v] then - c=n - n=getnext(c) - if not n then - return c - end - v=ischar(n,font) - if not v then - return c - end - end - if stress_tone_mark[v] then - return n - else - return c - end -end -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) - if char then - done=true - local syllablestart=current - local syllableend=nil - local c=current - local n=getnext(c) - local first=char - if n and ra[first] then - local second=ischar(n,font) - if second and halant[second] then - local n=getnext(n) - if n then - local third=ischar(n,font) - if third then - c=n - first=third - end - end - end - end - local standalone=first==c_nbsp - if standalone then - local prev=getprev(current) - if prev then - local prevchar=ischar(prev,font) - if not prevchar then - elseif not separator[prevchar] then - else - standalone=false - end - else - end - end - if standalone then - local syllableend=analyze_next_chars_one(c,font,2) - current=getnext(syllableend) - if syllablestart~=syllableend then - head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces) - current=getnext(current) - end - else - if consonant[char] then - local prevc=true - while prevc do - prevc=false - local n=getnext(current) - if not n then - break - end - local v=ischar(n,font) - if not v then - break - end - if nukta[v] then - n=getnext(n) - if not n then - break - end - v=ischar(n,font) - if not v then - break - end - end - if halant[v] then - n=getnext(n) - if not n then - break - end - v=ischar(n,font) - if not v then - break - end - if v==c_zwnj or v==c_zwj then - n=getnext(n) - if not n then - break - end - v=ischar(n,font) - if not v then - break - end - end - if consonant[v] then - prevc=true - current=n - end - end - end - local n=getnext(current) - if n then - local v=ischar(n,font) - if v and nukta[v] then - current=n - n=getnext(current) - end - end - syllableend=current - current=n - if current then - local v=ischar(current,font) - if not v then - elseif halant[v] then - local n=getnext(current) - if n then - local v=ischar(n,font) - if v and zw_char[v] then - syllableend=n - current=getnext(n) - else - syllableend=current - current=n - end - else - syllableend=current - current=n - end - else - if dependent_vowel[v] then - syllableend=current - current=getnext(current) - v=ischar(current,font) - end - if v and vowel_modifier[v] then - syllableend=current - current=getnext(current) - v=ischar(current,font) - end - if v and stress_tone_mark[v] then - syllableend=current - current=getnext(current) - end - end - end - if syllablestart~=syllableend then - head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces) - current=getnext(current) - end - elseif independent_vowel[char] then - syllableend=current - current=getnext(current) - if current then - local v=ischar(current,font) - if v then - if vowel_modifier[v] then - syllableend=current - current=getnext(current) - v=ischar(current,font) - end - if v and stress_tone_mark[v] then - syllableend=current - current=getnext(current) - end - end - end - else - 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 - end - else - current=getnext(current) - end - start=false - end - if nbspaces>0 then - head=replace_all_nbsp(head) - end - return head,done -end -local function method_two(head,font,attr) - local current=head - local start=true - local done=false - local syllabe=0 - local nbspaces=0 - while current do - local syllablestart=nil - local syllableend=nil - local char=ischar(current,font) - if char then - done=true - syllablestart=current - local c=current - local n=getnext(current) - if n and ra[char] then - local nextchar=ischar(n,font) - if nextchar and halant[nextchar] then - local n=getnext(n) - if n then - local nextnextchar=ischar(n,font) - if nextnextchar then - c=n - char=nextnextchar - end - end - end - end - if independent_vowel[char] then - current=analyze_next_chars_one(c,font,1) - syllableend=current - else - local standalone=char==c_nbsp - if standalone then - nbspaces=nbspaces+1 - local p=getprev(current) - if not p then - elseif ischar(p,font) then - elseif not separator[getchar(p)] then - else - standalone=false - end - end - if standalone then - current=analyze_next_chars_one(c,font,2) - syllableend=current - elseif consonant[getchar(current)] then - current=analyze_next_chars_two(current,font) - syllableend=current - end - end - end - if syllableend then - syllabe=syllabe+1 - local c=syllablestart - local n=getnext(syllableend) - while c~=n do - setprop(c,a_syllabe,syllabe) - c=getnext(c) - end - end - if syllableend and syllablestart~=syllableend then - head,current,nbspaces=reorder_two(head,syllablestart,syllableend,font,attr,nbspaces) - end - 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,char) - end - end - end - start=false - current=getnext(current) - end - if nbspaces>0 then - head=replace_all_nbsp(head) - end - return head,done -end -for i=1,nofscripts do - methods[scripts_one[i]]=method_one - methods[scripts_two[i]]=method_two -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-osd”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ocl” 280ad7888c7c386010598e9fdb83f466] --- - -if not modules then modules={} end modules ['font-ocl']={ - 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 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["%.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 -else - local tounicode=fonts.mappings.tounicode16 - function otf.getactualtext(s) - return - "/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 colors=attributes.list[attributes.private('color')] or {} - local transparencies=attributes.list[attributes.private('transparency')] or {} - function otf.registerpalette(name,values) - sharedpalettes[name]=values - local color=lpdf.color - local transparency=lpdf.transparency - local register=colors.register - for i=1,#values do - local v=values[i] - if v=="textcolor" then - values[i]=false - else - local c=nil - local t=nil - if type(v)=="table" then - c=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 - c=colors[v] - t=transparencies[v] - end - if c and t then - values[i]=hash[color(1,c).." "..transparency(t)] - elseif c then - values[i]=hash[color(1,c)] - elseif t then - values[i]=hash[color(1,t)] - end - end - end - end -else - function otf.registerpalette(name,values) - sharedpalettes[name]=values - for i=1,#values do - local v=values[i] - if v then - 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 -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" } -local function initialize(tfmdata,kind,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] - local default=false - if colorvalues then - default=colorvalues[#colorvalues] - else - colorvalues=converted[palettes[tonumber(value) or 1] or palettes[1]] or {} - end - 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 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 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={ - start, - not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) } - } - local n=2 - local l=nil - local f=false - for i=1,s do - local entry=colorlist[i] - 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 - else - if f then - n=n+1 t[n]=pop - end - f=false - l=nil - 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 - if f then - n=n+1 t[n]=pop - end - n=n+1 t[n]=actuale - character.commands=t - end - end - end - end - end -end -fonts.handlers.otf.features.register { - name="colr", - description="color glyphs", - manipulators={ - base=initialize, - node=initialize, - } -} -do - 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 - done=f_used(n) - hashed[pdf]=done - end - return done - 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 done - end - end -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 } - local vfimage=lpdf and lpdf.vfimage or function(wd,ht,dp,data,name) - local name=storepdfdata(data) - return { "image",{ filename=name,width=wd,height=ht,depth=dp } } - end - 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 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], - vfimage(wd,ht,dp,data,name), - actuale, - } - character[kind]=true - end - 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 - local savedata=io.savedata - local remove=os.remove - if context and xml.convert then - local xmlconvert=xml.convert - local xmlfirst=xml.first - function otfsvg.filterglyph(entry,index) - local svg=xmlconvert(entry.data) - local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']") - local data=root and tostring(root) - return data - end - else - function otfsvg.filterglyph(entry,index) - 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 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 - 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 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 - local svgfile=containers.read(otf.svgcache,hash) - local svgshapes=svgfile and svgfile.svgshapes - pdfshapes=svgshapes and otfsvg.topdf(svgshapes) or {} - containers.write(otf.pdfcache,hash,{ - pdfshapes=pdfshapes, - timestamp=timestamp, - }) - end - pdftovirtual(tfmdata,pdfshapes,"svg") - end -end -fonts.handlers.otf.features.register { - name="svg", - description="svg glyphs", - manipulators={ - base=initializesvg, - node=initializesvg, - } -} -local otfpng=otf.png or {} -otf.png=otfpng -otf.pngenabled=true -do - local report_png=logs.reporter("fonts","png conversion") - local loaddata=io.loaddata - local savedata=io.savedata - local remove=os.remove - local runner=sandbox and sandbox.registerrunner { - name="otfpng", - program="gm", - template="convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log", - } - if not runner then - runner=function() - return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log") - end - end - function otfpng.topdf(pngshapes) - local pdfshapes={} - local pngfile="temp-otf-png-shape.png" - local pdffile="temp-otf-png-shape.pdf" - local nofdone=0 - local indices=sortedkeys(pngshapes) - local nofindices=#indices - report_png("processing %i png containers",nofindices) - statistics.starttiming() - for i=1,nofindices do - local index=indices[i] - local entry=pngshapes[index] - local data=entry.data - local x=entry.x - local y=entry.y - savedata(pngfile,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_png("%i shapes processed",nofdone) - end - end - report_png("processing %i pdf results",nofindices) - remove(pngfile) - remove(pdffile) - statistics.stoptiming() - if statistics.elapsedseconds then - report_png("png conversion time %s",statistics.elapsedseconds() or "-") - end - return pdfshapes - end -end -local function initializepng(tfmdata,kind,value) - if value and otf.pngenabled then - local png=tfmdata.properties.png - local hash=png and png.hash - local timestamp=png and png.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 pngfile=containers.read(otf.pngcache,hash) - local pngshapes=pngfile and pngfile.pngshapes - pdfshapes=pngshapes and otfpng.topdf(pngshapes) or {} - containers.write(otf.pdfcache,hash,{ - pdfshapes=pdfshapes, - timestamp=timestamp, - }) - end - pdftovirtual(tfmdata,pdfshapes,"png") - end -end -fonts.handlers.otf.features.register { - name="sbix", - description="sbix glyphs", - manipulators={ - base=initializepng, - node=initializepng, - } -} -fonts.handlers.otf.features.register { - name="cblc", - description="cblc glyphs", - manipulators={ - base=initializepng, - node=initializepng, - } -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-ocl”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otc” 088ba25667dfc5036867d007797e1602] --- - -if not modules then modules={} end modules ['font-otc']={ - 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 insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash -local type,next,tonumber=type,next,tonumber -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", - ligature="ligature", - alternate="alternate", - multiple="multiple", - kern="kern", - pair="pair", - single="single", - chainsubstitution="chainsubstitution", - chainposition="chainposition", -} -local types={ - substitution="gsub_single", - ligature="gsub_ligature", - alternate="gsub_alternate", - multiple="gsub_multiple", - kern="gpos_pair", - pair="gpos_pair", - single="gpos_single", - chainsubstitution="gsub_contextchain", - chainposition="gpos_contextchain", -} -local names={ - gsub_single="gsub", - gsub_multiple="gsub", - gsub_alternate="gsub", - gsub_ligature="gsub", - gsub_context="gsub", - gsub_contextchain="gsub", - gsub_reversecontextchain="gsub", - gpos_single="gpos", - gpos_pair="gpos", - gpos_cursive="gpos", - gpos_mark2base="gpos", - gpos_mark2ligature="gpos", - gpos_mark2mark="gpos", - gpos_context="gpos", - gpos_contextchain="gpos", -} -setmetatableindex(types,function(t,k) t[k]=k return k end) -local everywhere={ ["*"]={ ["*"]=true } } -local noflags={ false,false,false,false } -local function getrange(sequences,category) - local count=#sequences - local first=nil - local last=nil - for i=1,count do - local t=sequences[i].type - if t and names[t]==category then - if not first then - first=i - end - last=i - end - end - return first or 1,last or count -end -local function validspecification(specification,name) - local dataset=specification.dataset - if dataset then - elseif specification[1] then - dataset=specification - specification={ dataset=dataset } - else - dataset={ { data=specification.data } } - specification.data=nil - specification.dataset=dataset - end - local first=dataset[1] - if first then - first=first.data - end - if not first then - report_otf("invalid feature specification, no dataset") - return - end - if type(name)~="string" then - name=specification.name or first.name - end - if type(name)~="string" then - report_otf("invalid feature specification, no name") - return - end - local n=#dataset - if n>0 then - for i=1,n do - setmetatableindex(dataset[i],specification) - end - return specification,name - end -end -local function addfeature(data,feature,specifications) - if not specifications then - report_otf("missing specification") - return - end - local descriptions=data.descriptions - local resources=data.resources - local features=resources.features - local sequences=resources.sequences - if not features or not sequences then - report_otf("missing specification") - return - end - local alreadydone=resources.alreadydone - if not alreadydone then - alreadydone={} - resources.alreadydone=alreadydone - end - if alreadydone[specifications] then - return - else - alreadydone[specifications]=true - end - local fontfeatures=resources.features or everywhere - local unicodes=resources.unicodes - local splitter=lpeg.splitter(" ",unicodes) - local done=0 - local skip=0 - local aglunicodes=false - local specifications=validspecification(specifications,feature) - if not specifications then - return - end - local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1) - local function tounicode(code) - if not code then - return - end - if type(code)=="number" then - return code - end - local u=unicodes[code] - if u then - return u - end - if utflen(code)==1 then - u=utfbyte(code) - if u then - return u - end - end - local u=lpegmatch(p,code) - if u then - return u - end - if not aglunicodes then - aglunicodes=fonts.encodings.agl.unicodes - end - local u=aglunicodes[code] - if u then - return u - end - end - local coverup=otf.coverup - local coveractions=coverup.actions - local stepkey=coverup.stepkey - local register=coverup.register - 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 not nocheck and not description then - skip=skip+1 - else - if type(replacement)=="table" then - replacement=replacement[1] - end - replacement=tounicode(replacement) - if replacement and descriptions[replacement] then - cover(coverage,unicode,replacement) - done=done+1 - else - skip=skip+1 - end - end - end - return coverage - end - 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 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]=(nocheck or descriptions[u]) and u or unicode - end - cover(coverage,unicode,r) - done=done+1 - else - local u=tounicode(replacement) - if u then - cover(coverage,unicode,{ u }) - done=done+1 - else - skip=skip+1 - end - end - end - return coverage - end - 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 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 nocheck or descriptions[u] then - n=n+1 - r[n]=u - end - end - if n>0 then - cover(coverage,unicode,r) - done=done+1 - else - skip=skip+1 - end - else - local u=tounicode(replacement) - if u then - cover(coverage,unicode,{ u }) - done=done+1 - else - skip=skip+1 - end - end - end - return coverage - end - 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 not nocheck and not description then - skip=skip+1 - else - if type(ligature)=="string" then - ligature={ lpegmatch(splitter,ligature) } - end - local present=true - for i=1,#ligature do - local l=ligature[i] - local u=tounicode(l) - if nocheck or descriptions[u] then - ligature[i]=u - else - present=false - break - end - end - if present then - cover(coverage,unicode,ligature) - done=done+1 - else - skip=skip+1 - end - 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] - if description and type(replacement)=="table" then - local r={} - for k,v in next,replacement do - 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 - else - skip=skip+1 - end - end - if isspace then - resetspacekerns() - end - return coverage - end - local function prepare_pair(list,featuretype) - local coverage={} - local cover=coveractions[featuretype] - if cover then - for code,replacement in next,list do - local unicode=tounicode(code) - local description=descriptions[unicode] - if description and type(replacement)=="table" then - local r={} - for k,v in next,replacement do - 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 - else - 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 lookuptype=types[featuretype] - for nofrules=1,#rules do - local rule=rules[nofrules] - local current=rule.current - local before=rule.before - local after=rule.after - local replacements=rule.replacements or false - local sequence={} - local nofsequences=0 - if before then - for n=1,#before do - nofsequences=nofsequences+1 - sequence[nofsequences]=before[n] - end - end - local start=nofsequences+1 - for n=1,#current do - nofsequences=nofsequences+1 - sequence[nofsequences]=current[n] - end - local stop=nofsequences - if after then - for n=1,#after do - nofsequences=nofsequences+1 - sequence[nofsequences]=after[n] - end - end - local lookups=rule.lookups or false - local subtype=nil - if lookups and sublookups then - 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 - if nofsequences>0 then - local hashed={} - for i=1,nofsequences do - local t={} - local s=sequence[i] - for i=1,#s do - local u=tounicode(s[i]) - if u then - t[u]=true - end - end - hashed[i]=t - end - sequence=hashed - rulesize=rulesize+1 - rulehash[rulesize]={ - nofrules, - lookuptype, - sequence, - start, - stop, - lookups, - replacements, - subtype, - } - 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 - local dataset=specifications.dataset - local function report(name,category,position,first,last,sequences) - report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]", - name,category,position,first,last,1,#sequences) - end - local function inject(specification,sequences,sequence,first,last,category,name) - local position=specification.position or false - if not position then - position=specification.prepend - if position==true then - if trace_loading then - report(name,category,first,first,last,sequences) - end - insert(sequences,first,sequence) - return - end - end - if not position then - position=specification.append - if position==true then - if trace_loading then - report(name,category,last+1,first,last,sequences) - end - insert(sequences,last+1,sequence) - return - end - end - local kind=type(position) - if kind=="string" then - local index=false - for i=first,last do - local s=sequences[i] - local f=s.features - if f then - for k in sortedhash(f) do - if k==position then - index=i - break - end - end - if index then - break - end - end - end - if index then - position=index - else - position=last+1 - end - elseif kind=="number" then - if position<0 then - position=last-position+1 - end - if position>last then - position=last+1 - elseif position<first then - position=first - end - else - position=last+1 - end - if trace_loading then - report(name,category,position,first,last,sequences) - end - insert(sequences,position,sequence) - end - for s=1,#dataset do - local specification=dataset[s] - local valid=specification.valid - local feature=specification.name or feature - if not feature or feature=="" then - report_otf("no valid name given for extra feature") - elseif not valid or valid(data,specification,feature) then - local initialize=specification.initialize - if initialize then - specification.initialize=initialize(specification,data) and initialize or nil - end - local askedfeatures=specification.features or everywhere - 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 - local specification=sublookups[i] - 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 nofsteps=0 - local steps={} - for i=1,#askedsteps do - local list=askedsteps[i] - local coverage=nil - local format=nil - if featuretype=="substitution" then - coverage=prepare_substitution(list,featuretype,nocheck) - elseif featuretype=="ligature" then - coverage=prepare_ligature(list,featuretype,nocheck) - elseif featuretype=="alternate" then - coverage=prepare_alternate(list,featuretype,nocheck) - elseif featuretype=="multiple" then - 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 - sublookups=s - end - for i=1,#askedsteps do - local list=askedsteps[i] - local coverage=nil - local format=nil - if featuretype=="substitution" then - category="gsub" - coverage=prepare_substitution(list,featuretype,nocheck) - elseif featuretype=="ligature" then - category="gsub" - coverage=prepare_ligature(list,featuretype,nocheck) - elseif featuretype=="alternate" then - category="gsub" - coverage=prepare_alternate(list,featuretype,nocheck) - elseif featuretype=="multiple" then - category="gsub" - coverage=prepare_multiple(list,featuretype,nocheck) - elseif featuretype=="kern" or featuretype=="move" then - category="gpos" - 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) - elseif featuretype=="chainposition" then - category="gpos" - coverage=prepare_chain(list,featuretype,sublookups) - else - report_otf("not registering feature %a, unknown category",feature) - return - end - if coverage and next(coverage) then - nofsteps=nofsteps+1 - steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) - end - end - if nofsteps>0 then - for k,v in next,askedfeatures do - if v[1] then - 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 - local steptype=types[featuretype] - local sequence={ - chain=featurechain, - features={ [feature]=askedfeatures }, - flags=featureflags, - name=feature, - order=featureorder, - [stepkey]=steps, - 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] - if not features then - features={} - fontfeatures[category]=features - end - local k=features[feature] - if not k then - k={} - features[feature]=k - end - for script,languages in next,askedfeatures do - local kk=k[script] - if not kk then - kk={} - k[script]=kk - end - for language,value in next,languages do - kk[language]=value - end - end - end - end - end - if trace_loading then - report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) - end -end -otf.enhancers.addfeature=addfeature -local extrafeatures={} -local knownfeatures={} -function otf.addfeature(name,specification) - if type(name)=="table" then - specification=name - end - if type(specification)~="table" then - report_otf("invalid feature specification, no valid table") - return - end - specification,name=validspecification(specification,name) - if name and specification then - local slot=knownfeatures[name] - 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 - end -end -local function enhance(data,filename,raw) - for slot=1,#extrafeatures do - local specification=extrafeatures[slot] - addfeature(data,specification.name,specification) - end -end -otf.enhancers.enhance=enhance -otf.enhancers.register("check extra features",enhance) - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-otc”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-onr” 20b0d2753f58ff91180947ce4078571e] --- - -if not modules then modules={} end modules ['font-onr']={ - 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 fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers -local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset -local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find -local char,byte,sub=string.char,string.byte,string.sub -local abs=math.abs -local bxor,rshift=bit32.bxor,bit32.rshift -local P,S,R,V,Cmt,C,Ct,Cs,Carg,Cf,Cg,Cc=lpeg.P,lpeg.S,lpeg.R,lpeg.V,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg,lpeg.Cc -local lpegmatch,patterns=lpeg.match,lpeg.patterns -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) -local report_afm=logs.reporter("fonts","afm loading") -local report_pfb=logs.reporter("fonts","pfb loading") -local handlers=fonts.handlers -local afm=handlers.afm or {} -handlers.afm=afm -local readers=afm.readers or {} -afm.readers=readers -afm.version=1.513 -local get_indexes,get_shapes -do - local decrypt - do - local r,c1,c2,n=0,0,0,0 - local function step(c) - local cipher=byte(c) - local plain=bxor(cipher,rshift(r,8)) - r=((cipher+r)*c1+c2)%65536 - return char(plain) - end - decrypt=function(binary,initial,seed) - r,c1,c2,n=initial,52845,22719,seed - binary=gsub(binary,".",step) - return sub(binary,n+1) - end - end - local charstrings=P("/CharStrings") - local subroutines=P("/Subrs") - local encoding=P("/Encoding") - local dup=P("dup") - local put=P("put") - local array=P("array") - local name=P("/")*C((R("az","AZ","09")+S("-_."))^1) - local digits=R("09")^1 - local cardinal=digits/tonumber - local spaces=P(" ")^1 - local spacing=patterns.whitespace^0 - local routines,vector,chars,n,m - local initialize=function(str,position,size) - n=0 - m=size - return position+1 - end - local setroutine=function(str,position,index,size,filename) - if routines[index] then - return false - end - local forward=position+size - local stream=decrypt(sub(str,position+1,forward),4330,4) - routines[index]={ byte(stream,1,#stream) } - n=n+1 - if n>=m then - return #str - end - return forward+1 - end - 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 - return forward - else - return #str - end - end - 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) - return forward - else - return #str - end - end - local p_rd=spacing*(P("RD")+P("-|")) - 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*Carg(1),setroutine)*p_np+(1-p_nd))^1 - local p_filtershapes= - (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*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 -,rawset) - local key=spacing*P("/")*R("az","AZ") - local str=spacing*Cs { (P("(")/"")*((1-P("\\(")-P("\\)")-S("()"))+V(1))^0*(P(")")/"") } - local num=spacing*(R("09")+S("+-."))^1/tonumber - local arr=spacing*Ct (S("[{")*(num)^0*spacing*S("]}")) - local boo=spacing*(P("true")*Cc(true)+P("false")*Cc(false)) - local nam=spacing*P("/")*Cs(R("az","AZ")^1) - local p_filtermetadata=( - P("/")*Carg(1)*(( - C("version")*str+C("Copyright")*str+C("Notice")*str+C("FullName")*str+C("FamilyName")*str+C("Weight")*str+C("ItalicAngle")*num+C("isFixedPitch")*boo+C("UnderlinePosition")*num+C("UnderlineThickness")*num+C("FontName")*nam+C("FontMatrix")*arr+C("FontBBox")*arr - ) )/function(t,k,v) t[lower(k)]=v end+P(1) - )^0*Carg(1) - local function loadpfbvector(filename,shapestoo,streams) - local data=io.loaddata(resolvers.findfile(filename)) - if not data then - report_pfb("no data in %a",filename) - return - end - if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then - report_pfb("no font in %a",filename) - return - end - local ascii,binary=match(data,"(.*)eexec%s+......(.*)") - if not binary then - report_pfb("no binary data in %a",filename) - return - end - binary=decrypt(binary,55665,4) - local names={} - local encoding=lpegmatch(p_filterencoding,ascii) - local metadata=lpegmatch(p_filtermetadata,ascii,1,{}) - local glyphs={} - routines,vector,chars={},{},{} - if shapestoo or streams then - lpegmatch(p_filterroutines,binary,1,filename) - lpegmatch(p_filtershapes,binary,1,filename) - local data={ - dictionaries={ - { - charstrings=chars, - charset=vector, - subroutines=routines, - } - }, - } - fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams) - else - lpegmatch(p_filternames,binary,1,filename) - end - names=vector - routines,vector,chars=nil,nil,nil - return names,encoding,glyphs,metadata - end - local pfb=handlers.pfb or {} - handlers.pfb=pfb - pfb.loadvector=loadpfbvector - get_indexes=function(data,pfbname) - local vector=loadpfbvector(pfbname) - if vector then - local characters=data.characters - if trace_loading then - report_afm("getting index data from %a",pfbname) - end - for index=0,#vector do - local name=vector[index] - local char=characters[name] - if char then - if trace_indexing then - 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 - end - get_shapes=function(pfbname) - local vector,encoding,glyphs=loadpfbvector(pfbname,true) - return glyphs - end -end -local spacer=patterns.spacer -local whitespace=patterns.whitespace -local lineend=patterns.newline -local spacing=spacer^0 -local number=spacing*S("+-")^-1*(R("09")+S("."))^1/tonumber -local name=spacing*C((1-whitespace)^1) -local words=spacing*((1-lineend)^1/strip) -local rest=(1-lineend)^0 -local fontdata=Carg(1) -local semicolon=spacing*P(";") -local plus=spacing*P("plus")*number -local minus=spacing*P("minus")*number -local function addkernpair(data,one,two,value) - local chr=data.characters[one] - if chr then - local kerns=chr.kerns - if kerns then - kerns[two]=tonumber(value) - else - chr.kerns={ [two]=tonumber(value) } - end - end -end -local p_kernpair=(fontdata*P("KPX")*name*name*number)/addkernpair -local chr=false -local ind=0 -local function start(data,version) - data.metadata.afmversion=version - ind=0 - chr={} -end -local function stop() - ind=0 - chr=false -end -local function setindex(i) - if i<0 then - ind=ind+1 - else - ind=i - end - chr={ - index=ind - } -end -local function setwidth(width) - chr.width=width -end -local function setname(data,name) - data.characters[name]=chr -end -local function setboundingbox(boundingbox) - chr.boundingbox=boundingbox -end -local function setligature(plus,becomes) - local ligatures=chr.ligatures - if ligatures then - ligatures[plus]=becomes - else - chr.ligatures={ [plus]=becomes } - end -end -local p_charmetric=(( - P("C")*number/setindex+P("WX")*number/setwidth+P("N")*fontdata*name/setname+P("B")*Ct((number)^4)/setboundingbox+P("L")*(name)^2/setligature - )*semicolon )^1 -local p_charmetrics=P("StartCharMetrics")*number*(p_charmetric+(1-P("EndCharMetrics")))^0*P("EndCharMetrics") -local p_kernpairs=P("StartKernPairs")*number*(p_kernpair+(1-P("EndKernPairs" )))^0*P("EndKernPairs" ) -local function set_1(data,key,a) data.metadata[lower(key)]=a end -local function set_2(data,key,a,b) data.metadata[lower(key)]={ a,b } end -local function set_3(data,key,a,b,c) data.metadata[lower(key)]={ a,b,c } end -local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName"))/lower)*words/function(data,key,value) - data.metadata[key]=value - end+fontdata*((P("Weight")+P("Version"))/lower)*name/function(data,key,value) - data.metadata[key]=value - end+fontdata*P("IsFixedPitch")*name/function(data,pitch) - data.metadata.monospaced=toboolean(pitch,true) - end+fontdata*P("FontBBox")*Ct(number^4)/function(data,boundingbox) - data.metadata.boundingbox=boundingbox - end+fontdata*((P("CharWidth")+P("CapHeight")+P("XHeight")+P("Descender")+P("Ascender")+P("ItalicAngle"))/lower)*number/function(data,key,value) - data.metadata[key]=value - end+P("Comment")*spacing*(P(false)+(fontdata*C("DESIGNSIZE")*number*rest)/set_1 -+(fontdata*C("TFM designsize")*number*rest)/set_1+(fontdata*C("DesignSize")*number*rest)/set_1+(fontdata*C("CODINGSCHEME")*words*rest)/set_1 -+(fontdata*C("CHECKSUM")*number*words*rest)/set_1 -+(fontdata*C("SPACE")*number*plus*minus*rest)/set_3 -+(fontdata*C("QUAD")*number*rest)/set_1 -+(fontdata*C("EXTRASPACE")*number*rest)/set_1 -+(fontdata*C("NUM")*number*number*number*rest)/set_3 -+(fontdata*C("DENOM")*number*number*rest)/set_2 -+(fontdata*C("SUP")*number*number*number*rest)/set_3 -+(fontdata*C("SUB")*number*number*rest)/set_2 -+(fontdata*C("SUPDROP")*number*rest)/set_1 -+(fontdata*C("SUBDROP")*number*rest)/set_1 -+(fontdata*C("DELIM")*number*number*rest)/set_2 -+(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 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) - if afmblob then - local data={ - resources={ - filename=resolvers.unresolve(filename), - version=afm.version, - creator="context mkiv", - }, - properties={ - hasitalics=false, - }, - goodies={}, - metadata={ - filename=file.removesuffix(file.basename(filename)) - }, - characters={ - }, - descriptions={ - }, - } - if trace_loading then - report_afm("parsing afm file %a",filename) - end - lpegmatch(parser,afmblob,1,data) - return data - else - if trace_loading then - report_afm("no valid afm file %a",filename) - end - return nil - end -end -function readers.loadfont(afmname,pfbname) - local data=read(resolvers.findfile(afmname),fullparser) - if data then - if not pfbname or pfbname=="" then - 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) - return data - else - report_afm("no pfb file for %a",afmname) - end - end -end -function readers.loadshapes(filename) - local fullname=resolvers.findfile(filename) or "" - if fullname=="" then - return { - filename="not found: "..filename, - glyphs={} - } - else - return { - filename=fullname, - format="opentype", - glyphs=get_shapes(fullname) or {}, - units=1000, - } - end -end -function readers.getinfo(filename) - local data=read(resolvers.findfile(filename),infoparser) - if data then - return data.metadata - end -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-onr”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-one” b0a175e8f123feb797c7a5a9b02b85a0] --- - -if not modules then modules={} end modules ['font-one']={ - 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 fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers -local next,type,tonumber,rawget=next,type,tonumber,rawget -local match,gsub=string.match,string.gsub -local abs=math.abs -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) -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -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 -local afm=constructors.handlers.afm -local pfb=constructors.handlers.pfb -local otf=fonts.handlers.otf -local otfreaders=otf.readers -local otfenhancers=otf.enhancers -local afmfeatures=constructors.features.afm -local registerafmfeature=afmfeatures.register -local afmenhancers=constructors.enhancers.afm -local registerafmenhancer=afmenhancers.register -afm.version=1.513 -afm.cache=containers.define("fonts","one",afm.version,true) -afm.autoprefixed=true -afm.helpdata={} -afm.syncspace=true -local overloads=fonts.mappings.overloads -local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes -function afm.load(filename) - filename=resolvers.findfile(filename,'afm') or "" - if filename~="" and not fonts.names.ignoredfile(filename) then - local name=file.removesuffix(file.basename(filename)) - local data=containers.read(afm.cache,name) - local attr=lfs.attributes(filename) - 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 - pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or "" - end - local pfbsize,pfbtime=0,0 - if pfbname~="" then - local attr=lfs.attributes(pfbname) - pfbsize=attr.size or 0 - pfbtime=attr.modification or 0 - end - if not data or data.size~=size or data.time~=time or data.pfbsize~=pfbsize or data.pfbtime~=pfbtime then - report_afm("reading %a",filename) - data=afm.readers.loadfont(filename,pfbname) - if data then - afmenhancers.apply(data,filename) - fonts.mappings.addtounicode(data,filename) - otfreaders.stripredundant(data) - otfreaders.pack(data) - data.size=size - data.time=time - data.pfbsize=pfbsize - data.pfbtime=pfbtime - report_afm("saving %a in cache",name) - data=containers.write(afm.cache,name,data) - data=containers.read(afm.cache,name) - end - end - if data then - otfreaders.unpack(data) - otfreaders.expand(data) - otfreaders.addunicodetable(data) - otfenhancers.apply(data,filename,data) - if applyruntimefixes then - applyruntimefixes(filename,data) - end - end - return data - end -end -local uparser=fonts.mappings.makenameparser() -local function enhance_unify_names(data,filename) - local unicodevector=fonts.encodings.agl.unicodes - local unicodes={} - local names={} - local private=data.private or privateoffset - local descriptions=data.descriptions - for name,blob in sortedhash(data.characters) do - local code=unicodevector[name] - if not code then - code=lpegmatch(uparser,name) - if type(code)~="number" then - code=private - private=private+1 - report_afm("assigning private slot %U for unknown glyph name %a",code,name) - end - end - local index=blob.index - unicodes[name]=code - names[name]=index - blob.name=name - descriptions[code]={ - boundingbox=blob.boundingbox, - width=blob.width, - kerns=blob.kerns, - index=index, - name=name, - } - end - for unicode,description in next,descriptions do - local kerns=description.kerns - if kerns then - local krn={} - for name,kern in next,kerns do - local unicode=unicodes[name] - if unicode then - krn[unicode]=kern - else - end - end - description.kerns=krn - 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={} -end -local everywhere={ ["*"]={ ["*"]=true } } -local noflags={ false,false,false,false } -local function enhance_normalize_features(data) - local ligatures=setmetatableindex("table") - local kerns=setmetatableindex("table") - local extrakerns=setmetatableindex("table") - for u,c in next,data.descriptions do - local l=c.ligatures - local k=c.kerns - local e=c.extrakerns - if l then - ligatures[u]=l - for u,v in next,l do - l[u]={ ligature=v } - end - c.ligatures=nil - end - if k then - kerns[u]=k - for u,v in next,k do - k[u]=v - end - c.kerns=nil - end - if e then - extrakerns[u]=e - for u,v in next,e do - e[u]=v - end - c.extrakerns=nil - end - end - local features={ - gpos={}, - gsub={}, - } - local sequences={ - } - if next(ligatures) then - features.gsub.liga=everywhere - data.properties.hasligatures=true - sequences[#sequences+1]={ - features={ - liga=everywhere, - }, - flags=noflags, - name="s_s_0", - nofsteps=1, - order={ "liga" }, - type="gsub_ligature", - steps={ - { - coverage=ligatures, - }, - }, - } - end - if next(kerns) then - features.gpos.kern=everywhere - data.properties.haskerns=true - sequences[#sequences+1]={ - features={ - kern=everywhere, - }, - flags=noflags, - name="p_s_0", - nofsteps=1, - order={ "kern" }, - type="gpos_pair", - steps={ - { - format="kern", - coverage=kerns, - }, - }, - } - end - if next(extrakerns) then - features.gpos.extrakerns=everywhere - data.properties.haskerns=true - sequences[#sequences+1]={ - features={ - extrakerns=everywhere, - }, - flags=noflags, - name="p_s_1", - nofsteps=1, - order={ "extrakerns" }, - type="gpos_pair", - steps={ - { - format="kern", - coverage=extrakerns, - }, - }, - } - end - data.resources.features=features - data.resources.sequences=sequences -end -local function enhance_fix_names(data) - for k,v in next,data.descriptions do - local n=v.name - local r=overloads[n] - if r then - local name=r.name - if trace_indexing then - report_afm("renaming characters %a to %a",n,name) - end - v.name=name - v.unicode=r.unicode - end - end -end -local addthem=function(rawdata,ligatures) - if ligatures then - local descriptions=rawdata.descriptions - local resources=rawdata.resources - local unicodes=resources.unicodes - for ligname,ligdata in next,ligatures do - local one=descriptions[unicodes[ligname]] - if one then - for _,pair in next,ligdata do - local two,three=unicodes[pair[1]],unicodes[pair[2]] - if two and three then - local ol=one.ligatures - if ol then - if not ol[two] then - ol[two]=three - end - else - one.ligatures={ [two]=three } - end - end - end - end - end - end -end -local function enhance_add_ligatures(rawdata) - addthem(rawdata,afm.helpdata.ligatures) -end -local function enhance_add_extra_kerns(rawdata) - local descriptions=rawdata.descriptions - local resources=rawdata.resources - local unicodes=resources.unicodes - local function do_it_left(what) - if what then - for unicode,description in next,descriptions do - local kerns=description.kerns - if kerns then - local extrakerns - for complex,simple in next,what do - complex=unicodes[complex] - simple=unicodes[simple] - if complex and simple then - local ks=kerns[simple] - if ks and not kerns[complex] then - if extrakerns then - extrakerns[complex]=ks - else - extrakerns={ [complex]=ks } - end - end - end - end - if extrakerns then - description.extrakerns=extrakerns - end - end - end - end - end - local function do_it_copy(what) - if what then - for complex,simple in next,what do - complex=unicodes[complex] - simple=unicodes[simple] - if complex and simple then - local complexdescription=descriptions[complex] - if complexdescription then - local simpledescription=descriptions[complex] - if simpledescription then - local extrakerns - local kerns=simpledescription.kerns - if kerns then - for unicode,kern in next,kerns do - if extrakerns then - extrakerns[unicode]=kern - else - extrakerns={ [unicode]=kern } - end - end - end - local extrakerns=simpledescription.extrakerns - if extrakerns then - for unicode,kern in next,extrakerns do - if extrakerns then - extrakerns[unicode]=kern - else - extrakerns={ [unicode]=kern } - end - end - end - if extrakerns then - complexdescription.extrakerns=extrakerns - end - end - end - end - end - end - end - do_it_left(afm.helpdata.leftkerned) - do_it_left(afm.helpdata.bothkerned) - do_it_copy(afm.helpdata.bothkerned) - do_it_copy(afm.helpdata.rightkerned) -end -local function adddimensions(data) - if data then - for unicode,description in next,data.descriptions do - local bb=description.boundingbox - if bb then - local ht,dp=bb[4],-bb[2] - if ht==0 or ht<0 then - else - description.height=ht - end - if dp==0 or dp<0 then - else - description.depth=dp - end - end - end - end -end -local function copytotfm(data) - if data and data.descriptions then - local metadata=data.metadata - local resources=data.resources - local properties=derivetable(data.properties) - local descriptions=derivetable(data.descriptions) - local goodies=derivetable(data.goodies) - local characters={} - local parameters={} - local unicodes=resources.unicodes - for unicode,description in next,data.descriptions do - characters[unicode]={} - end - local filename=constructors.checkedfilename(resources) - local fontname=metadata.fontname or metadata.fullname - local fullname=metadata.fullname or metadata.fontname - local endash=0x0020 - local emdash=0x2014 - local spacer="space" - local spaceunits=500 - local monospaced=metadata.monospaced - local charwidth=metadata.charwidth - local italicangle=metadata.italicangle - local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight - properties.monospaced=monospaced - parameters.italicangle=italicangle - parameters.charwidth=charwidth - parameters.charxheight=charxheight - if properties.monospaced then - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width,"emdash" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" - end - else - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" - end - end - spaceunits=tonumber(spaceunits) - if spaceunits<200 then - end - parameters.slant=0 - parameters.space=spaceunits - parameters.space_stretch=500 - parameters.space_shrink=333 - parameters.x_height=400 - parameters.quad=1000 - if italicangle and italicangle~=0 then - parameters.italicangle=italicangle - parameters.italicfactor=math.cos(math.rad(90+italicangle)) - parameters.slant=- math.tan(italicangle*math.pi/180) - end - if monospaced then - parameters.space_stretch=0 - parameters.space_shrink=0 - elseif afm.syncspace then - parameters.space_stretch=spaceunits/2 - parameters.space_shrink=spaceunits/3 - end - parameters.extra_space=parameters.space_shrink - if charxheight then - parameters.x_height=charxheight - else - local x=0x0078 - if x then - local x=descriptions[x] - if x then - parameters.x_height=x.height - end - end - end - if metadata.sup then - local dummy={ 0,0,0 } - parameters[ 1]=metadata.designsize or 0 - parameters[ 2]=metadata.checksum or 0 - parameters[ 3], - parameters[ 4], - parameters[ 5]=unpack(metadata.space or dummy) - parameters[ 6]=metadata.quad or 0 - parameters[ 7]=metadata.extraspace or 0 - parameters[ 8], - parameters[ 9], - parameters[10]=unpack(metadata.num or dummy) - parameters[11], - parameters[12]=unpack(metadata.denom or dummy) - parameters[13], - parameters[14], - parameters[15]=unpack(metadata.sup or dummy) - parameters[16], - parameters[17]=unpack(metadata.sub or dummy) - parameters[18]=metadata.supdrop or 0 - parameters[19]=metadata.subdrop or 0 - parameters[20], - parameters[21]=unpack(metadata.delim or dummy) - parameters[22]=metadata.axisheight or 0 - end - parameters.designsize=(metadata.designsize or 10)*65536 - parameters.ascender=abs(metadata.ascender or 0) - parameters.descender=abs(metadata.descender or 0) - parameters.units=1000 - properties.spacer=spacer - properties.encodingbytes=2 - properties.format=fonts.formats[filename] or "type1" - properties.filename=filename - properties.fontname=fontname - 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, - descriptions=descriptions, - parameters=parameters, - resources=resources, - properties=properties, - goodies=goodies, - } - end - end - return nil -end -function afm.setfeatures(tfmdata,features) - local okay=constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm) - if okay then - return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm) - else - return {} - end -end -local function addtables(data) - local resources=data.resources - local lookuptags=resources.lookuptags - local unicodes=resources.unicodes - if not lookuptags then - lookuptags={} - resources.lookuptags=lookuptags - end - setmetatableindex(lookuptags,function(t,k) - local v=type(k)=="number" and ("lookup "..k) or k - t[k]=v - return v - end) - if not unicodes then - unicodes={} - resources.unicodes=unicodes - setmetatableindex(unicodes,function(t,k) - setmetatableindex(unicodes,nil) - for u,d in next,data.descriptions do - local n=d.name - if n then - t[n]=u - end - end - return rawget(t,k) - end) - end - constructors.addcoreunicodes(unicodes) -end -local function afmtotfm(specification) - local afmname=specification.filename or specification.name - if specification.forced=="afm" or specification.format=="afm" then - if trace_loading then - report_afm("forcing afm format for %a",afmname) - end - else - local tfmname=findbinfile(afmname,"ofm") or "" - if tfmname~="" then - if trace_loading then - report_afm("fallback from afm to tfm for %a",afmname) - end - return - end - end - if afmname~="" then - local features=constructors.checkedfeatures("afm",specification.features.normal) - specification.features.normal=features - constructors.hashinstance(specification,true) - specification=definers.resolve(specification) - local cache_id=specification.hash - local tfmdata=containers.read(constructors.cache,cache_id) - if not tfmdata then - local rawdata=afm.load(afmname) - if rawdata and next(rawdata) then - addtables(rawdata) - adddimensions(rawdata) - tfmdata=copytotfm(rawdata) - if tfmdata and next(tfmdata) then - local shared=tfmdata.shared - if not shared then - shared={} - tfmdata.shared=shared - end - shared.rawdata=rawdata - shared.dynamics={} - tfmdata.changed={} - shared.features=features - shared.processes=afm.setfeatures(tfmdata,features) - end - elseif trace_loading then - report_afm("no (valid) afm file found with name %a",afmname) - end - tfmdata=containers.write(constructors.cache,cache_id,tfmdata) - end - return tfmdata - end -end -local function read_from_afm(specification) - local tfmdata=afmtotfm(specification) - if tfmdata then - tfmdata.properties.name=specification.name - tfmdata=constructors.scale(tfmdata,specification) - local allfeatures=tfmdata.shared.features or specification.features.normal - constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm) - fonts.loggers.register(tfmdata,'afm',specification) - end - return tfmdata -end -registerafmfeature { - name="mode", - description="mode", - initializers={ - base=otf.modeinitializer, - node=otf.modeinitializer, - } -} -registerafmfeature { - name="features", - description="features", - default=true, - initializers={ - node=otf.nodemodeinitializer, - base=otf.basemodeinitializer, - }, - processors={ - node=otf.featuresprocessor, - } -} -fonts.formats.afm="type1" -fonts.formats.pfb="type1" -local function check_afm(specification,fullname) - local foundname=findbinfile(fullname,'afm') or "" - if foundname=="" then - foundname=fonts.names.getfilename(fullname,"afm") or "" - end - if foundname=="" and afm.autoprefixed then - local encoding,shortname=match(fullname,"^(.-)%-(.*)$") - if encoding and shortname and fonts.encodings.known[encoding] then - shortname=findbinfile(shortname,'afm') or "" - if shortname~="" then - foundname=shortname - if trace_defining then - report_afm("stripping encoding prefix from filename %a",afmname) - end - end - end - end - if foundname~="" then - specification.filename=foundname - specification.format="afm" - return read_from_afm(specification) - end -end -function readers.afm(specification,method) - local fullname=specification.filename or "" - local tfmdata=nil - if fullname=="" then - local forced=specification.forced or "" - if forced~="" then - tfmdata=check_afm(specification,specification.name.."."..forced) - end - if not tfmdata then - local check_tfm=readers.check_tfm - method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm" - if method=="tfm" then - tfmdata=check_tfm(specification,specification.name) - elseif method=="afm" then - tfmdata=check_afm(specification,specification.name) - elseif method=="tfm or afm" then - tfmdata=check_tfm(specification,specification.name) or check_afm(specification,specification.name) - else - tfmdata=check_afm(specification,specification.name) or check_tfm(specification,specification.name) - end - end - else - tfmdata=check_afm(specification,fullname) - end - return tfmdata -end -function readers.pfb(specification,method) - local original=specification.specification - if trace_defining then - report_afm("using afm reader for %a",original) - end - specification.forced="afm" - local function swap(name) - local value=specification[swap] - if value then - specification[swap]=gsub("%.pfb",".afm",1) - end - end - swap("filename") - swap("fullname") - swap("forcedname") - swap("specification") - return readers.afm(specification,method) -end -registerafmenhancer("unify names",enhance_unify_names) -registerafmenhancer("add ligatures",enhance_add_ligatures) -registerafmenhancer("add extra kerns",enhance_add_extra_kerns) -registerafmenhancer("normalize features",enhance_normalize_features) -registerafmenhancer("check extra features",otfenhancers.enhance) -registerafmenhancer("fix names",enhance_fix_names) - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-one”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-afk” 54d554530e75c57c56ee76234724e26d] --- - -if not modules then modules={} end modules ['font-afk']={ - version=1.001, - 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", - dataonly=true, -} -local allocate=utilities.storage.allocate -fonts.handlers.afm.helpdata={ - ligatures=allocate { - ['f']={ - { 'f','ff' }, - { 'i','fi' }, - { 'l','fl' }, - }, - ['ff']={ - { 'i','ffi' } - }, - ['fi']={ - { 'i','fii' } - }, - ['fl']={ - { 'i','fli' } - }, - ['s']={ - { 't','st' } - }, - ['i']={ - { 'j','ij' } - }, - }, - texligatures=allocate { - ['quoteleft']={ - { 'quoteleft','quotedblleft' } - }, - ['quoteright']={ - { 'quoteright','quotedblright' } - }, - ['hyphen']={ - { 'hyphen','endash' } - }, - ['endash']={ - { 'hyphen','emdash' } - } - }, - leftkerned=allocate { - AEligature="A",aeligature="a", - OEligature="O",oeligature="o", - IJligature="I",ijligature="i", - AE="A",ae="a", - OE="O",oe="o", - IJ="I",ij="i", - Ssharp="S",ssharp="s", - }, - rightkerned=allocate { - AEligature="E",aeligature="e", - OEligature="E",oeligature="e", - IJligature="J",ijligature="j", - AE="E",ae="e", - OE="E",oe="e", - IJ="J",ij="j", - Ssharp="S",ssharp="s", - }, - bothkerned=allocate { - Acircumflex="A",acircumflex="a", - Ccircumflex="C",ccircumflex="c", - Ecircumflex="E",ecircumflex="e", - Gcircumflex="G",gcircumflex="g", - Hcircumflex="H",hcircumflex="h", - Icircumflex="I",icircumflex="i", - Jcircumflex="J",jcircumflex="j", - Ocircumflex="O",ocircumflex="o", - Scircumflex="S",scircumflex="s", - Ucircumflex="U",ucircumflex="u", - Wcircumflex="W",wcircumflex="w", - Ycircumflex="Y",ycircumflex="y", - Agrave="A",agrave="a", - Egrave="E",egrave="e", - Igrave="I",igrave="i", - Ograve="O",ograve="o", - Ugrave="U",ugrave="u", - Ygrave="Y",ygrave="y", - Atilde="A",atilde="a", - Itilde="I",itilde="i", - Otilde="O",otilde="o", - Utilde="U",utilde="u", - Ntilde="N",ntilde="n", - Adiaeresis="A",adiaeresis="a",Adieresis="A",adieresis="a", - Ediaeresis="E",ediaeresis="e",Edieresis="E",edieresis="e", - Idiaeresis="I",idiaeresis="i",Idieresis="I",idieresis="i", - Odiaeresis="O",odiaeresis="o",Odieresis="O",odieresis="o", - Udiaeresis="U",udiaeresis="u",Udieresis="U",udieresis="u", - Ydiaeresis="Y",ydiaeresis="y",Ydieresis="Y",ydieresis="y", - Aacute="A",aacute="a", - Cacute="C",cacute="c", - Eacute="E",eacute="e", - Iacute="I",iacute="i", - Lacute="L",lacute="l", - Nacute="N",nacute="n", - Oacute="O",oacute="o", - Racute="R",racute="r", - Sacute="S",sacute="s", - Uacute="U",uacute="u", - Yacute="Y",yacute="y", - Zacute="Z",zacute="z", - Dstroke="D",dstroke="d", - Hstroke="H",hstroke="h", - Tstroke="T",tstroke="t", - Cdotaccent="C",cdotaccent="c", - Edotaccent="E",edotaccent="e", - Gdotaccent="G",gdotaccent="g", - Idotaccent="I",idotaccent="i", - Zdotaccent="Z",zdotaccent="z", - Amacron="A",amacron="a", - Emacron="E",emacron="e", - Imacron="I",imacron="i", - Omacron="O",omacron="o", - Umacron="U",umacron="u", - Ccedilla="C",ccedilla="c", - Kcedilla="K",kcedilla="k", - Lcedilla="L",lcedilla="l", - Ncedilla="N",ncedilla="n", - Rcedilla="R",rcedilla="r", - Scedilla="S",scedilla="s", - Tcedilla="T",tcedilla="t", - Ohungarumlaut="O",ohungarumlaut="o", - Uhungarumlaut="U",uhungarumlaut="u", - Aogonek="A",aogonek="a", - Eogonek="E",eogonek="e", - Iogonek="I",iogonek="i", - Uogonek="U",uogonek="u", - Aring="A",aring="a", - Uring="U",uring="u", - Abreve="A",abreve="a", - Ebreve="E",ebreve="e", - Gbreve="G",gbreve="g", - Ibreve="I",ibreve="i", - Obreve="O",obreve="o", - Ubreve="U",ubreve="u", - Ccaron="C",ccaron="c", - Dcaron="D",dcaron="d", - Ecaron="E",ecaron="e", - Lcaron="L",lcaron="l", - Ncaron="N",ncaron="n", - Rcaron="R",rcaron="r", - Scaron="S",scaron="s", - Tcaron="T",tcaron="t", - Zcaron="Z",zcaron="z", - dotlessI="I",dotlessi="i", - dotlessJ="J",dotlessj="j", - AEligature="AE",aeligature="ae",AE="AE",ae="ae", - OEligature="OE",oeligature="oe",OE="OE",oe="oe", - IJligature="IJ",ijligature="ij",IJ="IJ",ij="ij", - Lstroke="L",lstroke="l",Lslash="L",lslash="l", - Ostroke="O",ostroke="o",Oslash="O",oslash="o", - Ssharp="SS",ssharp="ss", - Aumlaut="A",aumlaut="a", - Eumlaut="E",eumlaut="e", - Iumlaut="I",iumlaut="i", - Oumlaut="O",oumlaut="o", - Uumlaut="U",uumlaut="u", - } -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-afk”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-tfm” f1a3796cce3838210248eb1daee6ea83] --- - -if not modules then modules={} end modules ['font-tfm']={ - 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,type=next,type -local match,format=string.match,string.format -local concat,sortedhash=table.concat,table.sortedhash -local idiv=number.idiv -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end) -local report_defining=logs.reporter("fonts","defining") -local report_tfm=logs.reporter("fonts","tfm loading") -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 -local tfm=constructors.handlers.tfm -tfm.version=1.000 -tfm.maxnestingdepth=5 -tfm.maxnestingsize=65536*1024 -local otf=fonts.handlers.otf -local otfenhancers=otf.enhancers -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" -function tfm.setfeatures(tfmdata,features) - local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) - if okay then - return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm) - else - return {} - end -end -local depth={} -local read_from_tfm,check_tfm do - local tfmreaders=context and tfm.readers - local loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - local loadtfm=font.read_tfm - local loadvf=font.read_vf - directives.register("fonts.tfm.builtin",function(v) - loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - if v and loadtfm then - loadtfmvf=false - end - end) - read_from_tfm=function(specification) - local filename=specification.filename - local size=specification.size - depth[filename]=(depth[filename] or 0)+1 - if trace_defining then - report_defining("loading tfm file %a at size %s",filename,size) - end - local tfmdata - if loadtfmvf then - tfmdata=loadtfmvf(filename,size) - else - tfmdata=loadtfm(filename,size) - end - if tfmdata then - local features=specification.features and specification.features.normal or {} - local features=constructors.checkedfeatures("tfm",features) - specification.features.normal=features - local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata=newtfmdata - end - local resources=tfmdata.resources or {} - local properties=tfmdata.properties or {} - local parameters=tfmdata.parameters or {} - local shared=tfmdata.shared or {} - shared.features=features - shared.resources=resources - properties.name=tfmdata.name - properties.fontname=tfmdata.fontname - properties.psname=tfmdata.psname - properties.fullname=tfmdata.fullname - properties.filename=specification.filename - properties.format=tfmdata.format or fonts.formats.tfm - properties.usedbitmap=tfmdata.usedbitmap - tfmdata.properties=properties - tfmdata.resources=resources - tfmdata.parameters=parameters - tfmdata.shared=shared - shared.rawdata={ resources=resources } - shared.features=features - if newtfmdata then - if not resources.marks then - resources.marks={} - end - if not resources.sequences then - resources.sequences={} - end - if not resources.features then - resources.features={ - gsub={}, - gpos={}, - } - end - if not tfmdata.changed then - tfmdata.changed={} - end - if not tfmdata.descriptions then - tfmdata.descriptions=tfmdata.characters - end - otf.readers.addunicodetable(tfmdata) - tfmenhancers.apply(tfmdata,filename) - constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) - otf.readers.unifymissing(tfmdata) - fonts.mappings.addtounicode(tfmdata,filename) - tfmdata.tounicode=1 - local tounicode=fonts.mappings.tounicode - for unicode,v in next,tfmdata.characters do - local u=v.unicode - if u then - v.tounicode=tounicode(u) - end - end - if tfmdata.usedbitmap then - tfm.addtounicode(tfmdata) - end - end - shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil - if size<0 then - size=idiv(65536*-size,100) - end - parameters.factor=1 - parameters.units=1000 - parameters.size=size - parameters.slant=parameters.slant or parameters[1] or 0 - parameters.space=parameters.space or parameters[2] or 0 - parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 - parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 - parameters.x_height=parameters.x_height or parameters[5] or 0 - 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 loadtfmvf then - local fonts=tfmdata.fonts - if fonts then - for i=1,#fonts do - local font=fonts[i] - local id=font.id - if not id then - local name=font.name - local size=font.size - if name and size then - local data,id=constructors.readanddefine(name,size) - if id then - font.id=id - font.name=nil - font.size=nil - end - end - end - end - end - elseif constructors.resolvevirtualtoo then - fonts.loggers.register(tfmdata,file.suffix(filename),specification) - local vfname=findbinfile(specification.name,'ovf') - if vfname and vfname~="" then - local vfdata=loadvf(vfname,size) - if vfdata then - local chars=tfmdata.characters - for k,v in next,vfdata.characters do - chars[k].commands=v.commands - end - properties.virtualized=true - tfmdata.fonts=vfdata.fonts - tfmdata.type="virtual" - local fontlist=vfdata.fonts - local name=file.nameonly(filename) - for i=1,#fontlist do - local n=fontlist[i].name - local s=fontlist[i].size - local d=depth[filename] - s=constructors.scaled(s,vfdata.designsize) - if d>tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i]={ id=0 } - elseif (d>1) and (s>tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i]={ id=0 } - else - local t,id=constructors.readanddefine(n,s) - fontlist[i]={ id=id } - end - end - end - end - end - properties.haskerns=true - properties.hasligatures=true - properties.hasitalics=true - resources.unicodes={} - resources.lookuptags={} - depth[filename]=depth[filename]-1 - return tfmdata - else - depth[filename]=depth[filename]-1 - end - end - check_tfm=function(specification,fullname) - local foundname=findbinfile(fullname,'tfm') or "" - if foundname=="" then - foundname=findbinfile(fullname,'ofm') or "" - end - if foundname=="" then - foundname=fonts.names.getfilename(fullname,"tfm") or "" - end - if foundname~="" then - specification.filename=foundname - specification.format="ofm" - return read_from_tfm(specification) - elseif trace_defining then - report_defining("loading tfm with name %a fails",specification.name) - end - end -end -readers.check_tfm=check_tfm -function readers.tfm(specification) - local fullname=specification.filename or "" - if fullname=="" then - local forced=specification.forced or "" - if forced~="" then - fullname=specification.name.."."..forced - else - fullname=specification.name - end - end - return check_tfm(specification,fullname) -end -readers.ofm=readers.tfm -do - local outfiles={} - local tfmcache=table.setmetatableindex(function(t,tfmdata) - local id=font.define(tfmdata) - t[tfmdata]=id - return id - end) - local encdone=table.setmetatableindex("table") - function tfm.reencode(tfmdata,specification) - local features=specification.features - if not features then - return - end - local features=features.normal - if not features then - return - end - local tfmfile=file.basename(tfmdata.name) - local encfile=features.reencode - local pfbfile=features.pfbfile - local bitmap=features.bitmap - if not encfile then - return - end - local pfbfile=outfiles[tfmfile] - if pfbfile==nil then - if bitmap then - pfbfile=false - elseif type(pfbfile)~="string" then - pfbfile=tfmfile - end - if type(pfbfile)=="string" then - pfbfile=file.addsuffix(pfbfile,"pfb") - report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile) - else - report_tfm("using bitmap shapes for %a",tfmfile) - pfbfile=false - end - outfiles[tfmfile]=pfbfile - end - local encoding=false - local vector=false - if type(pfbfile)=="string" then - local pfb=constructors.handlers.pfb - if pfb and pfb.loadvector then - local v,e=pfb.loadvector(pfbfile) - if v then - vector=v - end - if e then - encoding=e - end - end - end - if type(encfile)=="string" and encfile~="auto" then - encoding=fonts.encodings.load(file.addsuffix(encfile,"enc")) - if encoding then - encoding=encoding.vector - end - end - if not encoding then - report_tfm("bad encoding for %a, quitting",tfmfile) - return - end - local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes - local virtualid=tfmcache[tfmdata] - local tfmdata=table.copy(tfmdata) - local characters={} - local originals=tfmdata.characters - local indices={} - local parentfont={ "font",1 } - local private=tfmdata.privateoffset or constructors.privateoffset - local reported=encdone[tfmfile][encfile] - local backmap=vector and table.swapped(vector) - local done={} - for index,name in sortedhash(encoding) do - local unicode=unicoding[name] - local original=originals[index] - if original then - if unicode then - original.unicode=unicode - else - unicode=private - private=private+1 - if not reported then - report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode) - end - end - characters[unicode]=original - indices[index]=unicode - original.name=name - if backmap then - original.index=backmap[name] - else - original.commands={ parentfont,charcommand[index] } - original.oindex=index - end - done[name]=true - elseif not done[name] then - report_tfm("bad index %a in font %a with name %a",index,tfmfile,name) - end - end - encdone[tfmfile][encfile]=true - for k,v in next,characters do - local kerns=v.kerns - if kerns then - local t={} - for k,v in next,kerns do - local i=indices[k] - if i then - t[i]=v - end - end - v.kerns=next(t) and t or nil - end - local ligatures=v.ligatures - if ligatures then - local t={} - for k,v in next,ligatures do - local i=indices[k] - if i then - t[i]=v - v.char=indices[v.char] - end - end - v.ligatures=next(t) and t or nil - end - end - tfmdata.fonts={ { id=virtualid } } - tfmdata.characters=characters - tfmdata.fullname=tfmdata.fullname or tfmdata.name - tfmdata.psname=file.nameonly(pfbfile or tfmdata.name) - tfmdata.filename=pfbfile - tfmdata.encodingbytes=2 - tfmdata.format="type1" - tfmdata.tounicode=1 - tfmdata.embedding="subset" - tfmdata.usedbitmap=bitmap and virtualid - tfmdata.private=private - return tfmdata - end -end -do - local template=[[ -/CIDInit /ProcSet findresource begin - 12 dict begin - begincmap - /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def - /CMapName /TeX-bitmap-%s def - /CMapType 2 def - 1 begincodespacerange - <00> <FF> - endcodespacerange - %s beginbfchar -%s - endbfchar - endcmap -CMapName currentdict /CMap defineresource pop end -end -end -]] - local flushstreamobject=lpdf and lpdf.flushstreamobject - local setfontattributes=lpdf and lpdf.setfontattributes - if not flushstreamobject then - flushstreamobject=function(data) - return pdf.obj { immediate=true,type="stream",string=data } - end - end - if not setfontattributes then - setfontattributes=function(id,data) - return pdf.setfontattributes(id,data) - end - end - function tfm.addtounicode(tfmdata) - local id=tfmdata.usedbitmap - local map={} - local char={} - for k,v in next,tfmdata.characters do - local index=v.oindex - local tounicode=v.tounicode - if index and tounicode then - map[index]=tounicode - end - end - for k,v in sortedhash(map) do - char[#char+1]=format("<%02X> <%s>",k,v) - end - char=concat(char,"\n") - local stream=format(template,id,id,#char,char) - local reference=flushstreamobject(stream,nil,true) - setfontattributes(id,format("/ToUnicode %i 0 R",reference)) - end -end -do - local everywhere={ ["*"]={ ["*"]=true } } - local noflags={ false,false,false,false } - local function enhance_normalize_features(data) - local ligatures=setmetatableindex("table") - local kerns=setmetatableindex("table") - local characters=data.characters - for u,c in next,characters do - local l=c.ligatures - local k=c.kerns - if l then - ligatures[u]=l - for u,v in next,l do - l[u]={ ligature=v.char } - end - c.ligatures=nil - end - if k then - kerns[u]=k - for u,v in next,k do - k[u]=v - end - c.kerns=nil - end - end - for u,l in next,ligatures do - for k,v in next,l do - local vl=v.ligature - local dl=ligatures[vl] - if dl then - for kk,vv in next,dl do - v[kk]=vv - end - end - end - end - local features={ - gpos={}, - gsub={}, - } - local sequences={ - } - if next(ligatures) then - features.gsub.liga=everywhere - data.properties.hasligatures=true - sequences[#sequences+1]={ - features={ - liga=everywhere, - }, - flags=noflags, - name="s_s_0", - nofsteps=1, - order={ "liga" }, - type="gsub_ligature", - steps={ - { - coverage=ligatures, - }, - }, - } - end - if next(kerns) then - features.gpos.kern=everywhere - data.properties.haskerns=true - sequences[#sequences+1]={ - features={ - kern=everywhere, - }, - flags=noflags, - name="p_s_0", - nofsteps=1, - order={ "kern" }, - type="gpos_pair", - steps={ - { - format="kern", - coverage=kerns, - }, - }, - } - end - data.resources.features=features - data.resources.sequences=sequences - data.shared.resources=data.shared.resources or resources - end - registertfmenhancer("normalize features",enhance_normalize_features) - registertfmenhancer("check extra features",otfenhancers.enhance) -end -registertfmfeature { - name="mode", - description="mode", - initializers={ - base=otf.modeinitializer, - node=otf.modeinitializer, - } -} -registertfmfeature { - name="features", - description="features", - default=true, - initializers={ - base=otf.basemodeinitializer, - node=otf.nodemodeinitializer, - }, - processors={ - node=otf.featuresprocessor, - } -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-tfm”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-lua” 55b281fb98f7bd848fc19928f376f647] --- - -if not modules then modules={} end modules ['font-lua']={ - 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 trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -local report_lua=logs.reporter("fonts","lua loading") -local fonts=fonts -local readers=fonts.readers -fonts.formats.lua="lua" -local function check_lua(specification,fullname) - local fullname=resolvers.findfile(fullname) or "" - if fullname~="" then - local loader=loadfile(fullname) - loader=loader and loader() - return loader and loader(specification) - end -end -readers.check_lua=check_lua -function readers.lua(specification) - local original=specification.specification - if trace_defining then - report_lua("using lua reader for %a",original) - end - local fullname=specification.filename or "" - if fullname=="" then - local forced=specification.forced or "" - if forced~="" then - fullname=specification.name.."."..forced - else - fullname=specification.name - end - end - return check_lua(specification,fullname) -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-lua”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-def” f66c365dae4499f982d8bf16e5d37de3] --- - -if not modules then modules={} end modules ['font-def']={ - 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,gsub=string.lower,string.gsub -local tostring,next=tostring,next -local lpegmatch=lpeg.match -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") -local report_defining=logs.reporter("fonts","defining") -local fonts=fonts -local fontdata=fonts.hashes.identifiers -local readers=fonts.readers -local definers=fonts.definers -local specifiers=fonts.specifiers -local constructors=fonts.constructors -local fontgoodies=fonts.goodies -readers.sequence=allocate { 'otf','ttf','afm','tfm','lua' } -local variants=allocate() -specifiers.variants=variants -definers.methods=definers.methods or {} -local internalized=allocate() -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 function makespecification(specification,lookup,name,sub,method,detail,size) - size=size or 655360 - if not lookup or lookup=="" then - lookup=definers.defaultlookup - end - if trace_defining then - report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a", - specification,lookup,name,sub,method,detail) - end - local t={ - lookup=lookup, - specification=specification, - size=size, - name=name, - sub=sub, - method=method, - detail=detail, - resolved="", - forced="", - features={}, - } - return t -end -definers.makespecification=makespecification -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 -function resolvers.file(specification) - local name=resolvefile(specification.name) - local suffix=lower(suffixonly(name)) - if fonts.formats[suffix] then - specification.forced=suffix - specification.forcedname=name - specification.name=removesuffix(name) - else - specification.name=name - end -end -function resolvers.name(specification) - local resolve=fonts.names.resolve - if resolve then - 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 - end - local suffix=lower(suffixonly(resolved)) - if fonts.formats[suffix] then - specification.forced=suffix - specification.forcedname=resolved - specification.name=removesuffix(resolved) - else - specification.name=resolved - end - end - else - resolvers.file(specification) - end -end -function resolvers.spec(specification) - local resolvespec=fonts.names.resolvespec - if resolvespec then - local resolved,sub,subindex=resolvespec(specification.name,specification.sub,specification) - if resolved then - specification.resolved=resolved - specification.sub=sub - specification.subindex=subindex - specification.forced=lower(suffixonly(resolved)) - specification.forcedname=resolved - specification.name=removesuffix(resolved) - end - else - resolvers.name(specification) - end -end -function definers.resolve(specification) - if not specification.resolved or specification.resolved=="" then - local r=resolvers[specification.lookup] - if r then - r(specification) - end - end - if specification.forced=="" then - specification.forced=nil - specification.forcedname=nil - end - specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification)) - if specification.sub and specification.sub~="" then - specification.hash=specification.sub..' @ '..specification.hash - end - return specification -end -function definers.applypostprocessors(tfmdata) - local postprocessors=tfmdata.postprocessors - if postprocessors then - local properties=tfmdata.properties - for i=1,#postprocessors do - local extrahash=postprocessors[i](tfmdata) - if type(extrahash)=="string" and extrahash~="" then - extrahash=gsub(lower(extrahash),"[^a-z]","-") - properties.fullname=formatters["%s-%s"](properties.fullname,extrahash) - end - end - end - return tfmdata -end -local function checkembedding(tfmdata) - local properties=tfmdata.properties - local embedding - if directive_embedall then - embedding="full" - elseif properties and properties.filename and constructors.dontembed[properties.filename] then - embedding="no" - else - embedding="subset" - end - if properties then - properties.embedding=embedding - else - tfmdata.properties={ embedding=embedding } - 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 context and 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 context and 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] - if not tfmdata then - local forced=specification.forced or "" - if forced~="" then - local reader=readers[lower(forced)] - tfmdata=reader and reader(specification) - if not tfmdata then - report_defining("forced type %a of %a not found",forced,specification.name) - end - else - local sequence=readers.sequence - for s=1,#sequence do - local reader=sequence[s] - if readers[reader] then - if trace_defining then - report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename) - end - tfmdata=readers[reader](specification) - if tfmdata then - break - else - specification.filename=nil - end - end - end - end - if tfmdata then - tfmdata=definers.applypostprocessors(tfmdata) - checkembedding(tfmdata) - loadedfonts[hash]=tfmdata - designsizes[specification.hash]=tfmdata.parameters.designsize - checkfeatures(tfmdata) - end - end - if not tfmdata then - report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup) - end - return tfmdata -end -function constructors.readanddefine(name,size) - local specification=definers.analyze(name,size) - local method=specification.method - if method and variants[method] then - specification=variants[method](specification) - end - specification=definers.resolve(specification) - local hash=constructors.hashinstance(specification) - local id=definers.registered(hash) - if not id then - local tfmdata=definers.loadfont(specification) - if tfmdata then - tfmdata.properties.hash=hash - id=font.define(tfmdata) - definers.register(tfmdata,id) - else - id=0 - end - end - return fontdata[id],id -end -function definers.current() - return lastdefined -end -function definers.registered(hash) - local id=internalized[hash] - return id,id and fontdata[id] -end -function definers.register(tfmdata,id) - if tfmdata and id then - local hash=tfmdata.properties.hash - if not hash then - report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?") - elseif not internalized[hash] then - internalized[hash]=id - if trace_defining then - report_defining("registering font, id %s, hash %a",id,hash) - end - fontdata[id]=tfmdata - end - end -end -function definers.read(specification,size,id) - statistics.starttiming(fonts) - if type(specification)=="string" then - specification=definers.analyze(specification,size) - end - local method=specification.method - if method and variants[method] then - specification=variants[method](specification) - end - specification=definers.resolve(specification) - local hash=constructors.hashinstance(specification) - local tfmdata=definers.registered(hash) - if tfmdata then - if trace_defining then - report_defining("already hashed: %s",hash) - end - else - tfmdata=definers.loadfont(specification) - if tfmdata then - if trace_defining then - report_defining("loaded and hashed: %s",hash) - end - tfmdata.properties.hash=hash - if id then - definers.register(tfmdata,id) - end - else - if trace_defining then - report_defining("not loaded and hashed: %s",hash) - end - end - end - lastdefined=tfmdata or id - if not tfmdata then - report_defining("unknown font %a, loading aborted",specification.name) - elseif trace_defining and type(tfmdata)=="table" then - 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 or "-",properties.name,parameters.size,properties.encodingbytes, - properties.encodingname,properties.fullname,basename(properties.filename)) - end - statistics.stoptiming(fonts) - return tfmdata -end -function font.getfont(id) - return fontdata[id] -end -callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “font-def”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-def” 5ad79120ebc5e60f4d322fb3ee13bffe] --- - -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 -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 -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 - return tfmdata -end - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-def”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-ext” 01015ab3758cdc2af29394e6d502a91a] --- - -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" -} -if context then - os.exit() -end -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] - if setup then - local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1 - local emwidth=tfmdata.parameters.quad - tfmdata.parameters.protrusion={ - auto=true, - } - for i,chr in next,tfmdata.characters do - local v,pl,pr=setup[i],nil,nil - if v then - pl,pr=v[1],v[2] - end - if pl and pl~=0 then chr.left_protruding=left*pl*factor end - if pr and pr~=0 then chr.right_protruding=right*pr*factor end - end - end - end -end -local specification={ - name="protrusion", - description="shift characters into the left and or right margin", - initializers={ - base=initializeprotrusion, - 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] - if setup then - local factor=setup.factor or 1 - tfmdata.parameters.expansion={ - stretch=10*(setup.stretch or 0), - shrink=10*(setup.shrink or 0), - step=10*(setup.step or 0), - auto=true, - } - for i,chr in next,tfmdata.characters do - local v=setup[i] - if v and v~=0 then - chr.expansion_factor=v*factor - else - chr.expansion_factor=factor - end - end - end - end -end -local specification={ - name="expansion", - description="apply hz optimization", - initializers={ - base=initializeexpansion, - node=initializeexpansion, - } -} -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 -end -function fonts.helpers.nametoslot(name) - local t=type(name) - if t=="string" then - local tfmdata=fonts.hashes.identifiers[currentfont()] - local shared=tfmdata and tfmdata.shared - local fntdata=shared and shared.rawdata - return fntdata and fntdata.resources.unicodes[name] - elseif t=="number" then - return n - end -end -fonts.encodings=fonts.encodings or {} -local reencodings={} -fonts.encodings.reencodings=reencodings -local function specialreencode(tfmdata,value) - local encoding=value and reencodings[value] - if encoding then - local temp={} - local char=tfmdata.characters - for k,v in next,encoding do - temp[k]=char[v] - end - for k,v in next,temp do - char[k]=temp[k] - end - return string.format("reencoded:%s",value) - end -end -local function initialize(tfmdata,value) - tfmdata.postprocessors=tfmdata.postprocessors or {} - table.insert(tfmdata.postprocessors, - function(tfmdata) - return specialreencode(tfmdata,value) - end - ) -end -registerotffeature { - name="reencode", - description="reencode characters", - manipulators={ - base=initialize, - node=initialize, - } -} -local function initialize(tfmdata,key,value) - if value then - tfmdata.mathparameters=nil - end -end -registerotffeature { - name="ignoremathconstants", - description="ignore math constants table", - initializers={ - base=initialize, - node=initialize, - } -} - -end --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-ext”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-imp-tex” 77c374b0ef00c2fb12188ec42beb4257] --- - -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-2019-02-22.lua scope for “font-imp-tex”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-imp-ligatures” 043daa4fcccf2560868da359d71d3a4a] --- - -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-2019-02-22.lua scope for “font-imp-ligatures”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-imp-italics” fe1ca80fb5ea4a2f8d2d5c484e7ba913] --- - -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-2019-02-22.lua scope for “font-imp-italics”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “font-imp-effects” 73a660359a0ec71e44cc2b7225a715ac] --- - -if not modules then modules={} end modules ['font-imp-effects']={ - 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,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-2019-02-22.lua scope for “font-imp-effects”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-lig” b9dbe77ce747d4c35bb2a20ffbe5aa51] --- - - -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-2019-02-22.lua scope for “fonts-lig”] --- - - -do --- [luaotfload, fontloader-2019-02-22.lua scope for “fonts-gbn” d25472d54c4841db43a745764a63533e] --- - -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", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -if context then - os.exit() -end -local next=next -local fonts=fonts -local nodes=nodes -local nuts=nodes.nuts -local traverse_id=nuts.traverse_id -local flush_node=nuts.flush_node -local glyph_code=nodes.nodecodes.glyph -local disc_code=nodes.nodecodes.disc -local tonode=nuts.tonode -local tonut=nuts.tonut -local getfont=nuts.getfont -local getchar=nuts.getchar -local getid=nuts.getid -local getboth=nuts.getboth -local getprev=nuts.getprev -local getnext=nuts.getnext -local getdisc=nuts.getdisc -local setchar=nuts.setchar -local setlink=nuts.setlink -local setprev=nuts.setprev -local n_ligaturing=node.ligaturing -local n_kerning=node.kerning -local d_ligaturing=nuts.ligaturing -local d_kerning=nuts.kerning -local basemodepass=true -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() - end - return n_ligaturing(...) -end -function node.kerning(...) - if basemodepass and k_warning then - k_warning() - 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 -local function nodepass(head,groupcode,size,packtype,direction) - local fontdata=fonts.hashes.identifiers - if fontdata then - local usedfonts={} - local basefonts={} - local prevfont=nil - local basefont=nil - local variants=nil - local redundant=nil - local nofused=0 - for n in traverse_id(glyph_code,head) do - local font=getfont(n) - if font~=prevfont then - if basefont then - basefont[2]=getprev(n) - end - prevfont=font - local used=usedfonts[font] - if not used then - local tfmdata=fontdata[font] - if tfmdata then - local shared=tfmdata.shared - if shared then - 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 - end - end - local resources=tfmdata.resources - variants=resources and resources.variants - variants=variants and next(variants) and variants or false - end - else - local tfmdata=fontdata[prevfont] - if tfmdata then - local resources=tfmdata.resources - variants=resources and resources.variants - variants=variants and next(variants) and variants or false - end - end - end - if variants then - local char=getchar(n) - if (char>=0xFE00 and char<=0xFE0F) or (char>=0xE0100 and char<=0xE01EF) then - local hash=variants[char] - if hash then - local p=getprev(n) - if p and getid(p)==glyph_code then - local variant=hash[getchar(p)] - if variant then - setchar(p,variant) - end - end - end - if not redundant then - redundant={ n } - else - redundant[#redundant+1]=n - end - end - end - end - local nofbasefonts=#basefonts - if redundant then - for i=1,#redundant do - local r=redundant[i] - local p,n=getboth(r) - if r==head then - head=n - setprev(n) - else - setlink(p,n) - end - if nofbasefonts>0 then - for i=1,nofbasefonts do - local bi=basefonts[i] - if r==bi[1] then - bi[1]=n - end - if r==bi[2] then - bi[2]=n - end - end - end - flush_node(r) - end - end - 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 - local font=getfont(n) - if font~=prevfont then - prevfont=font - local used=usedfonts[font] - if not used then - local tfmdata=fontdata[font] - if tfmdata then - local shared=tfmdata.shared - if shared then - local processors=shared.processes - if processors and #processors>0 then - usedfonts[font]=processors - nofused=nofused+1 - end - end - end - end - end - end - end - end - if next(usedfonts) then - for font,processors in next,usedfonts do - for i=1,#processors do - head=processors[i](head,font,0,direction,nofused) or head - end - end - end - if basemodepass and nofbasefonts>0 then - for i=1,nofbasefonts do - local range=basefonts[i] - local start=range[1] - local stop=range[2] - if start then - local front=head==start - local prev,next - if stop then - 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 next then - setlink(stop,next) - end - if front and head~=start then - head=start - end - end - end - end - 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 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) - head=tonode(head) - end - return head -end - -end --- [luaotfload, fontloader-2019-02-22.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-2019-05-18.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2019-05-18.lua new file mode 100644 index 00000000000..a413f976917 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-2019-05-18.lua @@ -0,0 +1,33209 @@ +--[[info----------------------------------------------------------------------- + Luaotfload fontloader package + build 2019-05-18 17:51:48 +------------------------------------------------------------------------------- + + © 2019 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. + + Report bugs to github.com/u-fischer/luaotfload + + This file has been assembled from components taken from Context. See + the Luaotfload documentation for details: + + $ texdoc luaotfload + $ man 1 luaotfload-tool + $ man 5 luaotfload.conf + + Included files: + + · fontloader-data-con.lua + · fontloader-basics-nod.lua + · fontloader-basics-chr.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-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 + · fontloader-font-oup.lua + · fontloader-font-otl.lua + · fontloader-font-oto.lua + · fontloader-font-otj.lua + · fontloader-font-ota.lua + · fontloader-font-ots.lua + · fontloader-font-osd.lua + · fontloader-font-ocl.lua + · fontloader-font-otc.lua + · fontloader-font-onr.lua + · fontloader-font-one.lua + · fontloader-font-afk.lua + · fontloader-fonts-tfm.lua + · fontloader-font-lua.lua + · fontloader-font-def.lua + · fontloader-fonts-def.lua + · fontloader-fonts-ext.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-2019-05-18.lua scope for “data-con” 7ce546725b1550f655c78ac9d69419ca] --- + +if not modules then modules={} end modules ['data-con']={ + version=1.100, + 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" +} +local format,lower,gsub=string.format,string.lower,string.gsub +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) +local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) +containers=containers or {} +local containers=containers +containers.usecache=true +local report_containers=logs.reporter("resolvers","containers") +local allocated={} +local mt={ + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true +} +function containers.define(category,subcategory,version,enabled) + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, + version=version or math.pi, + trace=false, + } + setmetatable(s,mt) + c[subcategory]=s + end + return s + end +end +function containers.is_usable(container,name) + return container.enabled and caches and caches.is_writable(container.writable,name) +end +function containers.is_valid(container,name) + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end +end +function containers.read(container,name) + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name,container.writable) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil + end + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored +end +function containers.write(container,name,data) + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared + end + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data +end +function containers.content(container,name) + return container.storage[name] +end +function containers.cleanname(name) + return (gsub(lower(name),"[^%w\128-\255]+","-")) +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “data-con”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “basics-nod” aa71dcb849fbe4bdf2464cb2a1ef0456] --- + +if not modules then modules={} end modules ['luatex-fonts-nod']={ + version=1.001, + comment="companion to luatex-fonts.lua", + 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 +if tex.attribute[0]~=0 then + texio.write_nl("log","!") + texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") + texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") + texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.") + texio.write_nl("log","!") + tex.attribute[0]=0 +end +attributes=attributes or {} +attributes.unsetvalue=-0x7FFFFFFF +local numbers,last={},127 +attributes.private=attributes.private or function(name) + local number=numbers[name] + if not number then + if last<255 then + last=last+1 + end + number=last + numbers[name]=number + end + return number +end +nodes={} +nodes.handlers={} +local nodecodes={} +local glyphcodes=node.subtypes("glyph") +local disccodes=node.subtypes("disc") +for k,v in next,node.types() do + v=string.gsub(v,"_","") + nodecodes[k]=v + nodecodes[v]=k +end +for k,v in next,glyphcodes do + glyphcodes[v]=k +end +for k,v in next,disccodes do + disccodes[v]=k +end +nodes.nodecodes=nodecodes +nodes.glyphcodes=glyphcodes +nodes.disccodes=disccodes +nodes.handlers.protectglyphs=node.protect_glyphs +nodes.handlers.unprotectglyphs=node.unprotect_glyphs +local direct=node.direct +local nuts={} +nodes.nuts=nuts +local tonode=direct.tonode +local tonut=direct.todirect +nodes.tonode=tonode +nodes.tonut=tonut +nuts.tonode=tonode +nuts.tonut=tonut +nuts.getattr=direct.get_attribute +nuts.getboth=direct.getboth +nuts.getchar=direct.getchar +nuts.getcomponents=direct.getcomponents +nuts.getdirection=direct.getdirection +nuts.getdisc=direct.getdisc +nuts.getfield=direct.getfield +nuts.getfont=direct.getfont +nuts.getid=direct.getid +nuts.getkern=direct.getkern +nuts.getlist=direct.getlist +nuts.getnext=direct.getnext +nuts.getoffsets=direct.getoffsets +nuts.getprev=direct.getprev +nuts.getsubtype=direct.getsubtype +nuts.getwidth=direct.getwidth +nuts.setattr=direct.setfield +nuts.setboth=direct.setboth +nuts.setchar=direct.setchar +nuts.setcomponents=direct.setcomponents +nuts.setdirection=direct.setdirection +nuts.setdisc=direct.setdisc +nuts.setfield=setfield +nuts.setkern=direct.setkern +nuts.setlink=direct.setlink +nuts.setlist=direct.setlist +nuts.setnext=direct.setnext +nuts.setoffsets=direct.setoffsets +nuts.setprev=direct.setprev +nuts.setsplit=direct.setsplit +nuts.setsubtype=direct.setsubtype +nuts.setwidth=direct.setwidth +nuts.getglyphdata=nuts.getattr +nuts.setglyphdata=nuts.setattr +nuts.ischar=direct.is_char +nuts.isglyph=direct.is_glyph +nuts.copy=direct.copy +nuts.copy_list=direct.copy_list +nuts.copy_node=direct.copy +nuts.delete=direct.delete +nuts.end_of_math=direct.end_of_math +nuts.flush=direct.flush +nuts.flush_list=direct.flush_list +nuts.flush_node=direct.flush_node +nuts.free=direct.free +nuts.insert_after=direct.insert_after +nuts.insert_before=direct.insert_before +nuts.is_node=direct.is_node +nuts.kerning=direct.kerning +nuts.ligaturing=direct.ligaturing +nuts.new=direct.new +nuts.remove=direct.remove +nuts.tail=direct.tail +nuts.traverse=direct.traverse +nuts.traverse_char=direct.traverse_char +nuts.traverse_glyph=direct.traverse_glyph +nuts.traverse_id=direct.traverse_id +local propertydata=direct.get_properties_table() +nodes.properties={ data=propertydata } +if direct.set_properties_mode then + direct.set_properties_mode(true,true) + function direct.set_properties_mode() end +end +nuts.getprop=function(n,k) + local p=propertydata[n] + if p then + return p[k] + end +end +nuts.setprop=function(n,k,v) + if v then + local p=propertydata[n] + if p then + p[k]=v + else + propertydata[n]={ [k]=v } + end + end +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.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 +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-2019-05-18.lua scope for “basics-nod”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “basics-chr” a8b8316248b40cc9bc1be19050f7074f] --- + + +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, + [1539]=4, + [1540]=4, + [1541]=4, + [1542]=6, + [1543]=6, + [1544]=4, + [1545]=6, + [1546]=6, + [1547]=4, + [1548]=6, + [1549]=6, + [1550]=6, + [1551]=6, + [1552]=5, + [1553]=5, + [1554]=5, + [1555]=5, + [1556]=5, + [1557]=5, + [1558]=5, + [1559]=5, + [1560]=5, + [1561]=5, + [1562]=5, + [1563]=6, + [1564]=6, + [1566]=6, + [1567]=6, + [1568]=2, + [1569]=4, + [1570]=3, + [1571]=3, + [1572]=3, + [1573]=3, + [1574]=2, + [1575]=3, + [1576]=2, + [1577]=3, + [1578]=2, + [1579]=2, + [1580]=2, + [1581]=2, + [1582]=2, + [1583]=3, + [1584]=3, + [1585]=3, + [1586]=3, + [1587]=2, + [1588]=2, + [1589]=2, + [1590]=2, + [1591]=2, + [1592]=2, + [1593]=2, + [1594]=2, + [1595]=2, + [1596]=2, + [1597]=2, + [1598]=2, + [1599]=2, + [1600]=2, + [1601]=2, + [1602]=2, + [1603]=2, + [1604]=2, + [1605]=2, + [1606]=2, + [1607]=2, + [1608]=3, + [1609]=2, + [1610]=2, + [1611]=5, + [1612]=5, + [1613]=5, + [1614]=5, + [1615]=5, + [1616]=5, + [1617]=5, + [1618]=5, + [1619]=5, + [1620]=5, + [1621]=5, + [1622]=5, + [1623]=5, + [1624]=5, + [1625]=5, + [1626]=5, + [1627]=5, + [1628]=5, + [1629]=5, + [1630]=5, + [1631]=5, + [1632]=6, + [1633]=6, + [1634]=6, + [1635]=6, + [1636]=6, + [1637]=6, + [1638]=6, + [1639]=6, + [1640]=6, + [1641]=6, + [1642]=6, + [1643]=6, + [1644]=6, + [1645]=6, + [1646]=2, + [1647]=2, + [1648]=5, + [1649]=3, + [1650]=3, + [1651]=3, + [1652]=4, + [1653]=3, + [1654]=3, + [1655]=3, + [1656]=2, + [1657]=2, + [1658]=2, + [1659]=2, + [1660]=2, + [1661]=2, + [1662]=2, + [1663]=2, + [1664]=2, + [1665]=2, + [1666]=2, + [1667]=2, + [1668]=2, + [1669]=2, + [1670]=2, + [1671]=2, + [1672]=3, + [1673]=3, + [1674]=3, + [1675]=3, + [1676]=3, + [1677]=3, + [1678]=3, + [1679]=3, + [1680]=3, + [1681]=3, + [1682]=3, + [1683]=3, + [1684]=3, + [1685]=3, + [1686]=3, + [1687]=3, + [1688]=3, + [1689]=3, + [1690]=2, + [1691]=2, + [1692]=2, + [1693]=2, + [1694]=2, + [1695]=2, + [1696]=2, + [1697]=2, + [1698]=2, + [1699]=2, + [1700]=2, + [1701]=2, + [1702]=2, + [1703]=2, + [1704]=2, + [1705]=2, + [1706]=2, + [1707]=2, + [1708]=2, + [1709]=2, + [1710]=2, + [1711]=2, + [1712]=2, + [1713]=2, + [1714]=2, + [1715]=2, + [1716]=2, + [1717]=2, + [1718]=2, + [1719]=2, + [1720]=2, + [1721]=2, + [1722]=2, + [1723]=2, + [1724]=2, + [1725]=2, + [1726]=2, + [1727]=2, + [1728]=3, + [1729]=2, + [1730]=2, + [1731]=3, + [1732]=3, + [1733]=3, + [1734]=3, + [1735]=3, + [1736]=3, + [1737]=3, + [1738]=3, + [1739]=3, + [1740]=2, + [1741]=3, + [1742]=2, + [1743]=3, + [1744]=2, + [1745]=2, + [1746]=3, + [1747]=3, + [1748]=6, + [1749]=3, + [1750]=5, + [1751]=5, + [1752]=5, + [1753]=5, + [1754]=5, + [1755]=5, + [1756]=5, + [1757]=4, + [1758]=6, + [1759]=5, + [1760]=5, + [1761]=5, + [1762]=5, + [1763]=5, + [1764]=5, + [1765]=6, + [1766]=6, + [1767]=5, + [1768]=5, + [1769]=6, + [1770]=5, + [1771]=5, + [1772]=5, + [1773]=5, + [1774]=3, + [1775]=3, + [1776]=6, + [1777]=6, + [1778]=6, + [1779]=6, + [1780]=6, + [1781]=6, + [1782]=6, + [1783]=6, + [1784]=6, + [1785]=6, + [1786]=2, + [1787]=2, + [1788]=2, + [1789]=6, + [1790]=6, + [1791]=2, + [1792]=6, + [1793]=6, + [1794]=6, + [1795]=6, + [1796]=6, + [1797]=6, + [1798]=6, + [1799]=6, + [1800]=6, + [1801]=6, + [1802]=6, + [1803]=6, + [1804]=6, + [1805]=6, + [1807]=6, + [1808]=3, + [1809]=5, + [1810]=2, + [1811]=2, + [1812]=2, + [1813]=3, + [1814]=3, + [1815]=3, + [1816]=3, + [1817]=3, + [1818]=2, + [1819]=2, + [1820]=2, + [1821]=2, + [1822]=3, + [1823]=2, + [1824]=2, + [1825]=2, + [1826]=2, + [1827]=2, + [1828]=2, + [1829]=2, + [1830]=2, + [1831]=2, + [1832]=3, + [1833]=2, + [1834]=3, + [1835]=2, + [1836]=3, + [1837]=2, + [1838]=2, + [1839]=3, + [1840]=5, + [1841]=5, + [1842]=5, + [1843]=5, + [1844]=5, + [1845]=5, + [1846]=5, + [1847]=5, + [1848]=5, + [1849]=5, + [1850]=5, + [1851]=5, + [1852]=5, + [1853]=5, + [1854]=5, + [1855]=5, + [1856]=5, + [1857]=5, + [1858]=5, + [1859]=5, + [1860]=5, + [1861]=5, + [1862]=5, + [1863]=5, + [1864]=5, + [1865]=5, + [1866]=5, + [1869]=3, + [1870]=2, + [1871]=2, + [1872]=2, + [1873]=2, + [1874]=2, + [1875]=2, + [1876]=2, + [1877]=2, + [1878]=2, + [1879]=2, + [1880]=2, + [1881]=3, + [1882]=3, + [1883]=3, + [1884]=2, + [1885]=2, + [1886]=2, + [1887]=2, + [1888]=2, + [1889]=2, + [1890]=2, + [1891]=2, + [1892]=2, + [1893]=2, + [1894]=2, + [1895]=2, + [1896]=2, + [1897]=2, + [1898]=2, + [1899]=3, + [1900]=3, + [1901]=2, + [1902]=2, + [1903]=2, + [1904]=2, + [1905]=3, + [1906]=2, + [1907]=3, + [1908]=3, + [1909]=2, + [1910]=2, + [1911]=2, + [1912]=3, + [1913]=3, + [1914]=2, + [1915]=2, + [1916]=2, + [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, + [1987]=6, + [1988]=6, + [1989]=6, + [1990]=6, + [1991]=6, + [1992]=6, + [1993]=6, + [1994]=2, + [1995]=2, + [1996]=2, + [1997]=2, + [1998]=2, + [1999]=2, + [2000]=2, + [2001]=2, + [2002]=2, + [2003]=2, + [2004]=2, + [2005]=2, + [2006]=2, + [2007]=2, + [2008]=2, + [2009]=2, + [2010]=2, + [2011]=2, + [2012]=2, + [2013]=2, + [2014]=2, + [2015]=2, + [2016]=2, + [2017]=2, + [2018]=2, + [2019]=2, + [2020]=2, + [2021]=2, + [2022]=2, + [2023]=2, + [2024]=2, + [2025]=2, + [2026]=2, + [2027]=5, + [2028]=5, + [2029]=5, + [2030]=5, + [2031]=5, + [2032]=5, + [2033]=5, + [2034]=5, + [2035]=5, + [2036]=6, + [2037]=6, + [2038]=6, + [2039]=6, + [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, + [2115]=2, + [2116]=2, + [2117]=2, + [2118]=3, + [2119]=3, + [2120]=2, + [2121]=3, + [2122]=2, + [2123]=2, + [2124]=2, + [2125]=2, + [2126]=2, + [2127]=2, + [2128]=2, + [2129]=2, + [2130]=2, + [2131]=2, + [2132]=3, + [2133]=2, + [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, + [2211]=2, + [2212]=2, + [2213]=2, + [2214]=2, + [2215]=2, + [2216]=2, + [2217]=2, + [2218]=3, + [2219]=3, + [2220]=3, + [2221]=4, + [2222]=3, + [2223]=2, + [2224]=2, + [2225]=3, + [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, + [6178]=2, + [6179]=2, + [6180]=2, + [6181]=2, + [6182]=2, + [6183]=2, + [6184]=2, + [6185]=2, + [6186]=2, + [6187]=2, + [6188]=2, + [6189]=2, + [6190]=2, + [6191]=2, + [6192]=2, + [6193]=2, + [6194]=2, + [6195]=2, + [6196]=2, + [6197]=2, + [6198]=2, + [6199]=2, + [6200]=2, + [6201]=2, + [6202]=2, + [6203]=2, + [6204]=2, + [6205]=2, + [6206]=2, + [6207]=2, + [6208]=2, + [6209]=2, + [6210]=2, + [6211]=2, + [6212]=2, + [6213]=2, + [6214]=2, + [6215]=2, + [6216]=2, + [6217]=2, + [6218]=2, + [6219]=2, + [6220]=2, + [6221]=2, + [6222]=2, + [6223]=2, + [6224]=2, + [6225]=2, + [6226]=2, + [6227]=2, + [6228]=2, + [6229]=2, + [6230]=2, + [6231]=2, + [6232]=2, + [6233]=2, + [6234]=2, + [6235]=2, + [6236]=2, + [6237]=2, + [6238]=2, + [6239]=2, + [6240]=2, + [6241]=2, + [6242]=2, + [6243]=2, + [6244]=2, + [6245]=2, + [6246]=2, + [6247]=2, + [6248]=2, + [6249]=2, + [6250]=2, + [6251]=2, + [6252]=2, + [6253]=2, + [6254]=2, + [6255]=2, + [6256]=2, + [6257]=2, + [6258]=2, + [6259]=2, + [6260]=2, + [6261]=2, + [6262]=2, + [6263]=2, + [6272]=4, + [6273]=4, + [6274]=4, + [6275]=4, + [6276]=4, + [6279]=2, + [6280]=2, + [6281]=2, + [6282]=2, + [6283]=2, + [6284]=2, + [6285]=2, + [6286]=2, + [6287]=2, + [6288]=2, + [6289]=2, + [6290]=2, + [6291]=2, + [6292]=2, + [6293]=2, + [6294]=2, + [6295]=2, + [6296]=2, + [6297]=2, + [6298]=2, + [6299]=2, + [6300]=2, + [6301]=2, + [6302]=2, + [6303]=2, + [6304]=2, + [6305]=2, + [6306]=2, + [6307]=2, + [6308]=2, + [6309]=2, + [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, + [43075]=2, + [43076]=2, + [43077]=2, + [43078]=2, + [43079]=2, + [43080]=2, + [43081]=2, + [43082]=2, + [43083]=2, + [43084]=2, + [43085]=2, + [43086]=2, + [43087]=2, + [43088]=2, + [43089]=2, + [43090]=2, + [43091]=2, + [43092]=2, + [43093]=2, + [43094]=2, + [43095]=2, + [43096]=2, + [43097]=2, + [43098]=2, + [43099]=2, + [43100]=2, + [43101]=2, + [43102]=2, + [43103]=2, + [43104]=2, + [43105]=2, + [43106]=2, + [43107]=2, + [43108]=2, + [43109]=2, + [43110]=2, + [43111]=2, + [43112]=2, + [43113]=2, + [43114]=2, + [43115]=2, + [43116]=2, + [43117]=2, + [43118]=2, + [43119]=2, + [43120]=2, + [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, + [68291]=2, + [68292]=2, + [68293]=3, + [68294]=4, + [68295]=3, + [68296]=4, + [68297]=3, + [68298]=3, + [68299]=4, + [68300]=4, + [68301]=1, + [68302]=3, + [68303]=3, + [68304]=3, + [68305]=3, + [68306]=3, + [68307]=2, + [68308]=2, + [68309]=2, + [68310]=2, + [68311]=1, + [68312]=2, + [68313]=2, + [68314]=2, + [68315]=2, + [68316]=2, + [68317]=3, + [68318]=2, + [68319]=2, + [68320]=2, + [68321]=3, + [68322]=4, + [68323]=4, + [68324]=3, + [68325]=5, + [68326]=5, + [68331]=2, + [68332]=2, + [68333]=2, + [68334]=2, + [68335]=3, + [68480]=2, + [68481]=3, + [68482]=2, + [68483]=3, + [68484]=3, + [68485]=3, + [68486]=2, + [68487]=2, + [68488]=2, + [68489]=3, + [68490]=2, + [68491]=2, + [68492]=3, + [68493]=2, + [68494]=3, + [68495]=3, + [68496]=2, + [68497]=3, + [68521]=3, + [68522]=3, + [68523]=3, + [68524]=3, + [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 --- [luaotfload, fontloader-2019-05-18.lua scope for “basics-chr”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ini” 4299a02110bbd7c0d27e131235c5319d] --- + +if not modules then modules={} end modules ['font-ini']={ + 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 allocate=utilities.storage.allocate +local sortedhash=table.sortedhash +fonts=fonts or {} +local fonts=fonts +local identifiers=allocate() +fonts.hashes=fonts.hashes or { identifiers=identifiers } +fonts.tables=fonts.tables or {} +fonts.helpers=fonts.helpers or {} +fonts.tracers=fonts.tracers or {} +fonts.specifiers=fonts.specifiers or {} +fonts.analyzers={} +fonts.readers={} +fonts.definers={ methods={} } +fonts.loggers={ register=function() end } +if context then + font.originaleach=font.each + function font.each() + return sortedhash(identifiers) + end + fontloader=nil +end +fonts.privateoffsets={ + textbase=0xF0000, + textextrabase=0xFD000, + mathextrabase=0xFE000, + mathbase=0xFF000, + keepnames=false, +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ini”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-mis” bc9eb43c27f63ce9d0fff67e104fe1c6] --- + +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) +function font.each() + return table.sortedhash(fonts.hashes.identifiers) +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-mis”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-con” f7d973760207e820b954a1e478a6a347] --- + +if not modules then modules={} end modules ['font-con']={ + 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,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=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") +local fonts=fonts +local constructors=fonts.constructors or {} +fonts.constructors=constructors +local handlers=fonts.handlers or {} +fonts.handlers=handlers +local allocate=utilities.storage.allocate +local setmetatableindex=table.setmetatableindex +constructors.dontembed=allocate() +constructors.autocleanup=true +constructors.namemode="fullpath" +constructors.version=1.01 +constructors.cache=containers.define("fonts","constructors",constructors.version,false) +constructors.privateoffset=fonts.privateoffsets.textbase or 0xF0000 +constructors.cacheintex=true +constructors.addtounicode=true +local designsizes=allocate() +constructors.designsizes=designsizes +local loadedfonts=allocate() +constructors.loadedfonts=loadedfonts +local factors={ + pt=65536.0, + bp=65781.8, +} +function constructors.setfactor(f) + constructors.factor=factors[f or 'pt'] or factors.pt +end +constructors.setfactor() +function constructors.scaled(scaledpoints,designsize) + if scaledpoints<0 then + local factor=constructors.factor + if designsize then + if designsize>factor then + return (- scaledpoints/1000)*designsize + else + return (- scaledpoints/1000)*designsize*factor + end + else + return (- scaledpoints/1000)*10*factor + end + else + 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 + if v.commands then v.commands=nil end + end + end +end +function constructors.calculatescale(tfmdata,scaledpoints) + local parameters=tfmdata.parameters + if scaledpoints<0 then + scaledpoints=(- scaledpoints/1000)*(tfmdata.designsize or parameters.designsize) + end + return scaledpoints,scaledpoints/(parameters.units or 1000) +end +local unscaled={ + ScriptPercentScaleDown=true, + ScriptScriptPercentScaleDown=true, + RadicalDegreeBottomRaisePercent=true, + NoLimitSupFactor=true, + NoLimitSubFactor=true, +} +function constructors.assignmathparameters(target,original) + local mathparameters=original.mathparameters + if mathparameters and next(mathparameters) then + local targetparameters=target.parameters + local targetproperties=target.properties + local targetmathparameters={} + local factor=targetproperties.math_is_scaled and 1 or targetparameters.factor + for name,value in next,mathparameters do + if unscaled[name] then + targetmathparameters[name]=value + else + targetmathparameters[name]=value*factor + end + end + if not targetmathparameters.FractionDelimiterSize then + targetmathparameters.FractionDelimiterSize=1.01*targetparameters.size + end + if not mathparameters.FractionDelimiterDisplayStyleSize then + targetmathparameters.FractionDelimiterDisplayStyleSize=2.40*targetparameters.size + end + target.mathparameters=targetmathparameters + end +end +function constructors.beforecopyingcharacters(target,original) +end +function constructors.aftercopyingcharacters(target,original) +end +constructors.sharefonts=false +constructors.nofsharedfonts=0 +local sharednames={} +function constructors.trytosharefont(target,tfmdata) + if constructors.sharefonts then + local characters=target.characters + local n=1 + local t={ target.psname } + local u=sortedkeys(characters) + for i=1,#u do + local k=u[i] + n=n+1;t[n]=k + n=n+1;t[n]=characters[k].index or k + end + local h=md5.HEX(concat(t," ")) + local s=sharednames[h] + if s then + if trace_defining then + report_defining("font %a uses backend resources of font %a",target.fullname,s) + end + target.fullname=s + constructors.nofsharedfonts=constructors.nofsharedfonts+1 + target.properties.sharedwith=s + else + sharednames[h]=target.fullname + 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 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={} + for i=1,#v do + local entry=v[i] + local height=entry.height + local kern=entry.kern + k[i]={ + height=height and vdelta*height or 0, + kern=kern and vdelta*kern or 0, + } + end + return k +end +local psfake=0 +local function fixedpsname(psname,fallback) + local usedname=psname + if psname and psname~="" then + if find(psname," ",1,true) then + usedname=gsub(psname,"[%s]+","-") + else + end + elseif not fallback or fallback=="" then + psfake=psfake+1 + psname="fakename-"..psfake + else + psname=fallback + usedname=gsub(psname,"[^a-zA-Z0-9]+","-") + end + return usedname,psname~=usedname +end +function constructors.scale(tfmdata,specification) + local target={} + if tonumber(specification) then + specification={ size=specification } + end + target.specification=specification + local scaledpoints=specification.size + local relativeid=specification.relativeid + local properties=tfmdata.properties or {} + local goodies=tfmdata.goodies or {} + local resources=tfmdata.resources or {} + local descriptions=tfmdata.descriptions or {} + local characters=tfmdata.characters or {} + local changed=tfmdata.changed or {} + local shared=tfmdata.shared or {} + local parameters=tfmdata.parameters or {} + local mathparameters=tfmdata.mathparameters or {} + local targetcharacters={} + local targetdescriptions=derivetable(descriptions) + local targetparameters=derivetable(parameters) + local targetproperties=derivetable(properties) + local targetgoodies=goodies + target.characters=targetcharacters + target.descriptions=targetdescriptions + target.parameters=targetparameters + target.properties=targetproperties + target.goodies=targetgoodies + target.shared=shared + target.resources=resources + 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 extrafactor=tonumber(specification.factor ) or 1 + if (mathsize==2 or forcedsize==2) and parameters.scriptpercentage then + scaledpoints=parameters.scriptpercentage*textsize/100 + elseif (mathsize==3 or forcedsize==3) and parameters.scriptscriptpercentage then + scaledpoints=parameters.scriptscriptpercentage*textsize/100 + elseif forcedsize>1000 then + scaledpoints=forcedsize + else + end + targetparameters.mathsize=mathsize + targetparameters.textsize=textsize + targetparameters.forcedsize=forcedsize + targetparameters.extrafactor=extrafactor + local addtounicode=constructors.addtounicode + local tounicode=fonts.mappings.tounicode + local unknowncode=tounicode(0xFFFD) + local defaultwidth=resources.defaultwidth or 0 + local defaultheight=resources.defaultheight or 0 + local defaultdepth=resources.defaultdepth or 0 + local units=parameters.units or 1000 + targetproperties.language=properties.language or "dflt" + targetproperties.script=properties.script or "dflt" + targetproperties.mode=properties.mode or "base" + local askedscaledpoints=scaledpoints + local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification) + local hdelta=delta + local vdelta=delta + target.designsize=parameters.designsize + target.units=units + target.units_per_em=units + local direction=properties.direction or tfmdata.direction or 0 + target.direction=direction + properties.direction=direction + target.size=scaledpoints + target.encodingbytes=properties.encodingbytes or 1 + target.embedding=properties.embedding or "subset" + target.tounicode=1 + target.cidinfo=properties.cidinfo + target.format=properties.format + target.cache=constructors.cacheintex and "yes" or "renew" + local fontname=properties.fontname or tfmdata.fontname + local fullname=properties.fullname or tfmdata.fullname + local filename=properties.filename or tfmdata.filename + local psname=properties.psname or tfmdata.psname + local name=properties.name or tfmdata.name + local psname,psfixed=fixedpsname(psname,fontname or fullname or file.nameonly(filename)) + target.fontname=fontname + target.fullname=fullname + target.filename=filename + target.psname=psname + target.name=name + properties.fontname=fontname + properties.fullname=fullname + properties.filename=filename + properties.psname=psname + properties.name=name + local expansion=parameters.expansion + if expansion then + target.stretch=expansion.stretch + target.shrink=expansion.shrink + target.step=expansion.step + end + 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 + else + target.extend=1000 + end + local squeezefactor=parameters.squeezefactor or 0 + if squeezefactor~=0 and squeezefactor~=1 then + vdelta=vdelta*squeezefactor + target.squeeze=squeezefactor*1000 + else + 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 + targetparameters.vfactor=vdelta + 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=parameters.expansion or parameters.protrusion + local hasitalics=properties.hasitalics + local autoitalicamount=properties.autoitalicamount + local stackmath=not properties.nostackmath + local haskerns=properties.haskerns or properties.mode=="base" + local hasligatures=properties.hasligatures or properties.mode=="base" + 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 + target.type=isvirtual and "virtual" or "real" + target.writingmode=writingmode=="vertical" and "vertical" or "horizontal" + target.identity=identity=="vertical" and "vertical" or "horizontal" + target.postprocessors=tfmdata.postprocessors + local targetslant=(parameters.slant or parameters[1] or 0)*factors.pt + local targetspace=(parameters.space or parameters[2] or 0)*hdelta + local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta + local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta + local targetx_height=(parameters.x_height or parameters[5] or 0)*vdelta + local targetquad=(parameters.quad or parameters[6] or 0)*hdelta + local targetextra_space=(parameters.extra_space or parameters[7] or 0)*hdelta + targetparameters.slant=targetslant + targetparameters.space=targetspace + targetparameters.space_stretch=targetspace_stretch + targetparameters.space_shrink=targetspace_shrink + targetparameters.x_height=targetx_height + targetparameters.quad=targetquad + targetparameters.extra_space=targetextra_space + local ascender=parameters.ascender + if ascender then + targetparameters.ascender=delta*ascender + end + local descender=parameters.descender + if descender then + targetparameters.descender=delta*descender + end + constructors.enhanceparameters(targetparameters) + local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0 + local scaledwidth=defaultwidth*hdelta + local scaledheight=defaultheight*vdelta + local scaleddepth=defaultdepth*vdelta + local hasmath=(properties.hasmath or next(mathparameters)) and true + if hasmath then + constructors.assignmathparameters(target,tfmdata) + properties.hasmath=true + target.nomath=false + target.MathConstants=target.mathparameters + else + properties.hasmath=false + target.nomath=true + target.mathparameters=nil + end + if hasmath then + local mathitalics=properties.mathitalics + if mathitalics==false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics=false + autoitalicamount=false + end + else + local textitalics=properties.textitalics + if textitalics==false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics=false + autoitalicamount=false + end + end + if trace_defining then + report_defining("defining tfm, name %a, fullname %a, filename %a, %spsname %a, hscale %a, vscale %a, math %a, italics %a", + name,fullname,filename,psfixed and "(fixed) " or "",psname,hdelta,vdelta, + hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") + end + constructors.beforecopyingcharacters(target,tfmdata) + local sharedkerns={} + for unicode,character in next,characters do + local chr,description,index + if changed then + local c=changed[unicode] + 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 + end + else + description=descriptions[unicode] or character + index=description.index or unicode + end + local width=description.width + local height=description.height + local depth=description.depth + local isunicode=description.unicode + if realdimensions then + if not height or height==0 then + local bb=description.boundingbox + local ht=bb[4] + if ht~=0 then + height=ht + end + if not depth or depth==0 then + local dp=-bb[2] + if dp~=0 then + depth=dp + end + end + elseif not depth or depth==0 then + local dp=-description.boundingbox[2] + if dp~=0 then + depth=dp + end + end + end + if width then width=hdelta*width else width=scaledwidth end + if height then height=vdelta*height else height=scaledheight end + if depth and depth~=0 then + depth=delta*depth + if isunicode then + chr={ + index=index, + height=height, + depth=depth, + width=width, + unicode=isunicode, + } + else + chr={ + index=index, + height=height, + depth=depth, + width=width, + } + end + else + if isunicode then + chr={ + index=index, + height=height, + width=width, + unicode=isunicode, + } + else + chr={ + index=index, + height=height, + width=width, + } + end + end + if addtounicode then + chr.tounicode=isunicode and tounicode(isunicode) or unknowncode + end + if hasquality then + local ve=character.expansion_factor + if ve then + chr.expansion_factor=ve*1000 + end + local vl=character.left_protruding + if vl then + chr.left_protruding=protrusionfactor*width*vl + end + local vr=character.right_protruding + if vr then + chr.right_protruding=protrusionfactor*width*vr + end + end + if hasmath then + local vn=character.next + if vn then + chr.next=vn + else + local vv=character.vert_variants + if vv then + local t={} + for i=1,#vv do + local vvi=vv[i] + 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"], + } + end + chr.vert_variants=t + else + local hv=character.horiz_variants + if hv then + local t={} + for i=1,#hv do + local hvi=hv[i] + 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"], + } + end + chr.horiz_variants=t + end + end + end + local vi=character.vert_italic + if vi and vi~=0 then + chr.vert_italic=vi*hdelta + end + local va=character.accent + if va then + chr.top_accent=vdelta*va + end + if stackmath then + local mk=character.mathkerns + if mk then + local tr=mk.topright + local tl=mk.topleft + local br=mk.bottomright + local bl=mk.bottomleft + chr.mathkern={ + top_right=tr and mathkerns(tr,vdelta) or nil, + top_left=tl and mathkerns(tl,vdelta) or nil, + bottom_right=br and mathkerns(br,vdelta) or nil, + bottom_left=bl and mathkerns(bl,vdelta) or nil, + } + end + end + if hasitalics then + local vi=character.italic + if vi and vi~=0 then + chr.italic=vi*hdelta + end + end + elseif autoitalicamount then + local vi=description.italic + if not vi then + local bb=description.boundingbox + if bb then + local vi=bb[3]-description.width+autoitalicamount + if vi>0 then + chr.italic=vi*hdelta + end + else + end + elseif vi~=0 then + chr.italic=vi*hdelta + end + elseif hasitalics then + local vi=character.italic + if vi and vi~=0 then + chr.italic=vi*hdelta + end + end + if haskerns then + local vk=character.kerns + if vk then + local s=sharedkerns[vk] + if not s then + s={} + for k,v in next,vk do s[k]=v*hdelta end + sharedkerns[vk]=s + end + chr.kerns=s + end + end + if hasligatures then + local vl=character.ligatures + if vl then + if true then + chr.ligatures=vl + else + local tt={} + for i,l in next,vl do + tt[i]=l + end + chr.ligatures=tt + end + end + end + if isvirtual then + local vc=character.commands + if vc then + local ok=false + for i=1,#vc do + local key=vc[i][1] + if key=="right" or key=="down" or key=="rule" then + ok=true + break + end + end + if ok then + local tt={} + for i=1,#vc do + local ivc=vc[i] + local key=ivc[1] + if key=="right" then + tt[i]={ key,ivc[2]*hdelta } + elseif key=="down" then + tt[i]={ key,ivc[2]*vdelta } + elseif key=="rule" then + tt[i]={ key,ivc[2]*vdelta,ivc[3]*hdelta } + else + tt[i]=ivc + end + end + chr.commands=tt + else + chr.commands=vc + end + end + end + targetcharacters[unicode]=chr + end + 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) + if tfmdata.properties and tfmdata.properties.finalized then + return + end + if not tfmdata.characters then + return nil + end + if not tfmdata.goodies then + tfmdata.goodies={} + end + local parameters=tfmdata.parameters + if not parameters then + return nil + end + if not parameters.expansion then + parameters.expansion={ + 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.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 + parameters.maxsize=tfmdata.maxsize or designsize + else + designsize=factors.pt*10 + parameters.designsize=designsize + parameters.minsize=designsize + parameters.maxsize=designsize + end + parameters.minsize=tfmdata.minsize or parameters.designsize + parameters.maxsize=tfmdata.maxsize or parameters.designsize + if not parameters.units then + parameters.units=tfmdata.units or tfmdata.units_per_em or 1000 + end + if not tfmdata.descriptions then + local descriptions={} + setmetatableindex(descriptions,function(t,k) local v={} t[k]=v return v end) + tfmdata.descriptions=descriptions + end + local properties=tfmdata.properties + if not properties then + properties={} + tfmdata.properties=properties + end + if not properties.virtualized then + properties.virtualized=tfmdata.type=="virtual" + end + properties.fontname=properties.fontname or tfmdata.fontname + properties.filename=properties.filename or tfmdata.filename + properties.fullname=properties.fullname or tfmdata.fullname + properties.name=properties.name or tfmdata.name + properties.psname=properties.psname or tfmdata.psname + properties.encodingbytes=tfmdata.encodingbytes or 1 + properties.embedding=tfmdata.embedding or "subset" + properties.tounicode=tfmdata.tounicode or 1 + properties.cidinfo=tfmdata.cidinfo or nil + properties.format=tfmdata.format or "type1" + properties.direction=tfmdata.direction or 0 + properties.writingmode=tfmdata.writingmode or "horizontal" + properties.identity=tfmdata.identity or "horizontal" + properties.usedbitmap=tfmdata.usedbitmap + if not tfmdata.resources then + tfmdata.resources={} + end + if not tfmdata.shared then + tfmdata.shared={} + end + if not properties.hasmath then + properties.hasmath=not tfmdata.nomath + end + tfmdata.MathConstants=nil + tfmdata.postprocessors=nil + tfmdata.fontname=nil + tfmdata.filename=nil + tfmdata.fullname=nil + tfmdata.name=nil + tfmdata.psname=nil + tfmdata.encodingbytes=nil + tfmdata.embedding=nil + tfmdata.tounicode=nil + tfmdata.cidinfo=nil + tfmdata.format=nil + tfmdata.direction=nil + tfmdata.type=nil + tfmdata.nomath=nil + tfmdata.designsize=nil + tfmdata.size=nil + tfmdata.stretch=nil + tfmdata.shrink=nil + tfmdata.step=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 + properties.finalized=true + return tfmdata +end +local hashmethods={} +constructors.hashmethods=hashmethods +function constructors.hashfeatures(specification) + local features=specification.features + if features then + 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 + n=n+1 + t[n]=category..":"..hash + end + end + end + end + 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 + elseif k=="number" or k=="features" then + else + n=n+1 + 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 + sort(s) + return concat(s,"+") + end +end +function constructors.hashinstance(specification,force) + local hash=specification.hash + local size=specification.size + local fallbacks=specification.fallbacks + if force or not hash then + hash=constructors.hashfeatures(specification) + specification.hash=hash + end + if size<1000 and designsizes[hash] then + size=round(constructors.scaled(size,designsizes[hash])) + else + size=round(size) + end + specification.size=size + if fallbacks then + return hash..' @ '..size..' @ '..fallbacks + else + return hash..' @ '..size + end +end +function constructors.setname(tfmdata,specification) + if constructors.namemode=="specification" then + local specname=specification.specification + if specname then + tfmdata.properties.name=specname + if trace_defining then + report_otf("overloaded fontname %a",specname) + end + end + end +end +function constructors.checkedfilename(data) + local foundfilename=data.foundfilename + if not foundfilename then + local askedfilename=data.filename or "" + if askedfilename~="" then + askedfilename=resolvers.resolve(askedfilename) + foundfilename=resolvers.findbinfile(askedfilename,"") or "" + if foundfilename=="" then + report_defining("source file %a is not found",askedfilename) + foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or "" + if foundfilename~="" then + report_defining("using source file %a due to cache mismatch",foundfilename) + end + end + end + data.foundfilename=foundfilename + end + return foundfilename +end +local formats=allocate() +fonts.formats=formats +setmetatableindex(formats,function(t,k) + local l=lower(k) + if rawget(t,k) then + t[k]=l + return l + end + return rawget(t,file.suffix(l)) +end) +do + local function setindeed(mode,source,target,group,name,position) + local action=source[mode] + if not action then + return + end + local t=target[mode] + if not t then + report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode) + os.exit() + elseif position then + insert(t,position,{ name=name,action=action }) + else + for i=1,#t do + local ti=t[i] + if ti.name==name then + ti.action=action + return + end + end + insert(t,{ name=name,action=action }) + end + end + local function set(group,name,target,source) + target=target[group] + if not target then + report_defining("fatal target error in setting feature %a, group %a",name,group) + os.exit() + end + local source=source[group] + if not source then + report_defining("fatal source error in setting feature %a, group %a",name,group) + os.exit() + end + local position=source.position + setindeed("node",source,target,group,name,position) + setindeed("base",source,target,group,name,position) + setindeed("plug",source,target,group,name,position) + end + local function register(where,specification) + local name=specification.name + if name and name~="" then + local default=specification.default + local description=specification.description + local initializers=specification.initializers + local processors=specification.processors + local manipulators=specification.manipulators + local modechecker=specification.modechecker + if default then + where.defaults[name]=default + end + if description and description~="" then + where.descriptions[name]=description + end + if initializers then + set('initializers',name,where,specification) + end + if processors then + set('processors',name,where,specification) + end + if manipulators then + set('manipulators',name,where,specification) + end + if modechecker then + where.modechecker=modechecker + end + end + end + constructors.registerfeature=register + function constructors.getfeatureaction(what,where,mode,name) + what=handlers[what].features + if what then + where=what[where] + if where then + mode=where[mode] + if mode then + for i=1,#mode do + local m=mode[i] + if m.name==name then + return m.action + end + end + end + end + end + end + local newfeatures={} + constructors.newfeatures=newfeatures + constructors.features=newfeatures + local function setnewfeatures(what) + local handler=handlers[what] + local features=handler.features + if not features then + local tables=handler.tables + local statistics=handler.statistics + features=allocate { + defaults={}, + descriptions=tables and tables.features or {}, + used=statistics and statistics.usedfeatures or {}, + initializers={ base={},node={},plug={} }, + processors={ base={},node={},plug={} }, + manipulators={ base={},node={},plug={} }, + } + features.register=function(specification) return register(features,specification) end + handler.features=features + end + return features + end + setmetatable(newfeatures,{ + __call=function(t,k) local v=t[k] return v end, + __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end, + }) +end +do + local newhandler={} + constructors.handlers=newhandler + constructors.newhandler=newhandler + local function setnewhandler(what) + local handler=handlers[what] + if not handler then + handler={} + handlers[what]=handler + end + return handler + end + setmetatable(newhandler,{ + __call=function(t,k) local v=t[k] return v end, + __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end, + }) +end +do + local newenhancer={} + constructors.enhancers=newenhancer + constructors.newenhancer=newenhancer + local function setnewenhancer(format) + local handler=handlers[format] + local enhancers=handler.enhancers + if not enhancers then + 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") + trackers.register(format..".loading",function(v) trace=v end) + local function enhance(name,data,filename,raw) + local enhancer=actions[name] + if enhancer then + if trace then + report("apply enhancement %a to file %a",name,filename) + ioflush() + end + enhancer(data,filename,raw) + else + end + end + local function apply(data,filename,raw) + local basename=file.basename(lower(filename)) + if trace then + report("%s enhancing file %a","start",filename) + end + ioflush() + for e=1,nofsteps do + local enhancer=order[e] + local b=before[enhancer] + if b then + for pattern,action in next,b do + if find(basename,pattern) then + action(data,filename,raw) + end + end + end + enhance(enhancer,data,filename,raw) + local a=after[enhancer] + if a then + for pattern,action in next,a do + if find(basename,pattern) then + action(data,filename,raw) + end + end + end + ioflush() + end + if trace then + report("%s enhancing file %a","stop",filename) + end + ioflush() + end + local function register(what,action) + if action then + if actions[what] then + else + nofsteps=nofsteps+1 + order[nofsteps]=what + known[what]=nofsteps + end + actions[what]=action + else + report("bad enhancer %a",what) + end + end + local function patch(what,where,pattern,action) + local pw=patches[what] + if pw then + local ww=pw[where] + if ww then + ww[pattern]=action + else + pw[where]={ [pattern]=action } + if not known[where] then + nofsteps=nofsteps+1 + order[nofsteps]=where + known[where]=nofsteps + end + end + end + end + enhancers={ + register=register, + apply=apply, + patch=patch, + report=report, + patches={ + register=patch, + report=report, + }, + } + handler.enhancers=enhancers + end + return enhancers + end + setmetatable(newenhancer,{ + __call=function(t,k) local v=t[k] return v end, + __index=function(t,k) local v=setnewenhancer(k) t[k]=v return v end, + }) +end +function constructors.checkedfeatures(what,features) + local defaults=handlers[what].features.defaults + if features and next(features) then + features=fastcopy(features) + for key,value in next,defaults do + if features[key]==nil then + features[key]=value + end + end + return features + else + return fastcopy(defaults) + end +end +function constructors.initializefeatures(what,tfmdata,features,trace,report) + if features and next(features) then + local properties=tfmdata.properties or {} + local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatmodechecker=whatfeatures.modechecker + local mode=properties.mode or (whatmodechecker and whatmodechecker(tfmdata,features,features.mode)) or features.mode or "base" + properties.mode=mode + features.mode=mode + local done={} + while true do + local redo=false + local initializers=whatfeatures.initializers[mode] + if initializers then + for i=1,#initializers do + local step=initializers[i] + local feature=step.name + local value=features[feature] + if not value then + elseif done[feature] then + else + local action=step.action + if trace then + report("initializing feature %a to %a for mode %a for font %a",feature, + value,mode,tfmdata.properties.fullname) + end + action(tfmdata,value,features) + if mode~=properties.mode or mode~=features.mode then + if whatmodechecker then + properties.mode=whatmodechecker(tfmdata,features,properties.mode) + features.mode=properties.mode + end + if mode~=properties.mode then + mode=properties.mode + redo=true + end + end + done[feature]=true + end + if redo then + break + end + end + if not redo then + break + end + else + break + end + end + properties.mode=mode + return true + else + return false + end +end +function constructors.collectprocessors(what,tfmdata,features,trace,report) + local processes={} + local nofprocesses=0 + if features and next(features) then + local properties=tfmdata.properties + local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatprocessors=whatfeatures.processors + local mode=properties.mode + local processors=whatprocessors[mode] + if processors then + for i=1,#processors do + local step=processors[i] + local feature=step.name + if features[feature] then + local action=step.action + if trace then + report("installing feature processor %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname) + end + if action then + nofprocesses=nofprocesses+1 + processes[nofprocesses]=action + end + end + end + elseif trace then + report("no feature processors for mode %a for font %a",mode,properties.fullname) + end + end + return processes +end +function constructors.applymanipulators(what,tfmdata,features,trace,report) + if features and next(features) then + local properties=tfmdata.properties + local whathandler=handlers[what] + local whatfeatures=whathandler.features + local whatmanipulators=whatfeatures.manipulators + local mode=properties.mode + local manipulators=whatmanipulators[mode] + if manipulators then + for i=1,#manipulators do + local step=manipulators[i] + local feature=step.name + local value=features[feature] + if value then + local action=step.action + if trace then + report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname) + end + if action then + action(tfmdata,feature,value) + end + end + end + end + end +end +function constructors.addcoreunicodes(unicodes) + if not unicodes then + unicodes={} + end + unicodes.space=0x0020 + unicodes.hyphen=0x002D + unicodes.zwj=0x200D + unicodes.zwnj=0x200C + return unicodes +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-con”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-enc” 3e71a54297e8f85a1ac438bb0f20dd79] --- + +if not modules then modules={} end modules ['luatex-font-enc']={ + 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 +local encodings={} +fonts.encodings=encodings +encodings.agl={} +encodings.known={} +setmetatable(encodings.agl,{ __index=function(t,k) + if k=="unicodes" then + logs.report("fonts","loading (extended) adobe glyph list") + local unicodes=dofile(resolvers.findfile("font-age.lua")) + encodings.agl={ unicodes=unicodes } + return unicodes + else + return nil + end +end }) +encodings.cache=containers.define("fonts","enc",encodings.version,true) +function encodings.load(filename) + local name=file.removesuffix(filename) + local data=containers.read(encodings.cache,name) + if data then + return data + end + local vector,tag,hash,unicodes={},"",{},{} + local foundname=resolvers.findfile(filename,'enc') + if foundname and foundname~="" then + local ok,encoding,size=resolvers.loadbinfile(foundname) + if ok and encoding then + encoding=string.gsub(encoding,"%%(.-)\n","") + local unicoding=encodings.agl.unicodes + local tag,vec=string.match(encoding,"/(%w+)%s*%[(.*)%]%s*def") + local i=0 + for ch in string.gmatch(vec,"/([%a%d%.]+)") do + if ch~=".notdef" then + vector[i]=ch + if not hash[ch] then + hash[ch]=i + else + end + local u=unicoding[ch] + if u then + unicodes[u]=i + end + end + i=i+1 + end + end + end + local data={ + name=name, + tag=tag, + vector=vector, + hash=hash, + unicodes=unicodes + } + return containers.write(encodings.cache,name,data) +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-enc”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-cid” 4d87988efa86020a14708ee03c23415f] --- + +if not modules then modules={} end modules ['font-cid']={ + 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 format,match,lower=string.format,string.match,string.lower +local tonumber=tonumber +local P,S,R,C,V,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.match +local fonts,logs,trackers=fonts,logs,trackers +local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) +local report_otf=logs.reporter("fonts","otf loading") +local cid={} +fonts.cid=cid +local cidmap={} +local cidmax=10 +local number=C(R("09","af","AF")^1) +local space=S(" \n\r\t") +local spaces=space^0 +local period=P(".") +local periods=period*period +local name=P("/")*C((1-space)^1) +local unicodes,names={},{} +local function do_one(a,b) + unicodes[tonumber(a)]=tonumber(b,16) +end +local function do_range(a,b,c) + c=tonumber(c,16) + for i=tonumber(a),tonumber(b) do + unicodes[i]=c + c=c+1 + end +end +local function do_name(a,b) + names[tonumber(a)]=b +end +local grammar=P { "start", + start=number*spaces*number*V("series"), + series=(spaces*(V("one")+V("range")+V("named")))^1, + one=(number*spaces*number)/do_one, + range=(number*periods*number*spaces*number)/do_range, + named=(number*spaces*name)/do_name +} +local function loadcidfile(filename) + local data=io.loaddata(filename) + if data then + unicodes,names={},{} + lpegmatch(grammar,data) + local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$") + return { + supplement=supplement, + registry=registry, + ordering=ordering, + filename=filename, + unicodes=unicodes, + names=names, + } + end +end +cid.loadfile=loadcidfile +local template="%s-%s-%s.cidmap" +local function locate(registry,ordering,supplement) + local filename=format(template,registry,ordering,supplement) + local hashname=lower(filename) + local found=cidmap[hashname] + if not found then + if trace_loading then + report_otf("checking cidmap, registry %a, ordering %a, supplement %a, filename %a",registry,ordering,supplement,filename) + end + local fullname=resolvers.findfile(filename,'cid') or "" + if fullname~="" then + found=loadcidfile(fullname) + if found then + if trace_loading then + report_otf("using cidmap file %a",filename) + end + cidmap[hashname]=found + found.usedname=file.basename(filename) + end + end + end + return found +end +function cid.getmap(specification) + if not specification then + report_otf("invalid cidinfo specification, table expected") + return + end + local registry=specification.registry + local ordering=specification.ordering + local supplement=specification.supplement + local filename=format(registry,ordering,supplement) + local lowername=lower(filename) + local found=cidmap[lowername] + if found then + return found + end + if ordering=="Identity" then + local found={ + supplement=supplement, + registry=registry, + ordering=ordering, + filename=filename, + unicodes={}, + names={}, + } + cidmap[lowername]=found + return found + end + if trace_loading then + report_otf("cidmap needed, registry %a, ordering %a, supplement %a",registry,ordering,supplement) + end + found=locate(registry,ordering,supplement) + if not found then + local supnum=tonumber(supplement) + local cidnum=nil + if supnum<cidmax then + for s=supnum+1,cidmax do + local c=locate(registry,ordering,s) + if c then + found,cidnum=c,s + break + end + end + end + if not found and supnum>0 then + for s=supnum-1,0,-1 do + local c=locate(registry,ordering,s) + if c then + found,cidnum=c,s + break + end + end + end + registry=lower(registry) + ordering=lower(ordering) + if found and cidnum>0 then + for s=0,cidnum-1 do + local filename=format(template,registry,ordering,s) + if not cidmap[filename] then + cidmap[filename]=found + end + end + end + end + return found +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-cid”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-map” f486746e90fe972de4b73e208ac7cbb2] --- + +if not modules then modules={} end modules ['font-map']={ + 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 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 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 force_ligatures=false directives.register("fonts.mapping.forceligatures",function(v) force_ligatures=v end) +local fonts=fonts or {} +local mappings=fonts.mappings or {} +fonts.mappings=mappings +local allocate=utilities.storage.allocate +local hex=R("AF","af","09") +local hexfour=(hex*hex*hex^-2)/function(s) return tonumber(s,16) end +local hexsix=(hex*hex*hex^-4)/function(s) return tonumber(s,16) end +local dec=(R("09")^1)/tonumber +local period=P(".") +local unicode=(P("uni")+P("UNI"))*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) +local ucode=(P("u")+P("U") )*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) +local index=P("index")*dec*Cc(false) +local parser=unicode+ucode+index +local parsers={} +local function makenameparser(str) + if not str or str=="" then + return parser + else + local p=parsers[str] + if not p then + p=P(str)*period*dec*Cc(false) + parsers[str]=p + end + return p + end +end +local f_single=formatters["%04X"] +local f_double=formatters["%04X%04X"] +local function tounicode16(unicode) + 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 +local function tounicode16sequence(unicodes) + local t={} + for l=1,#unicodes do + local u=unicodes[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) +end +local unknown=f_single(0xFFFD) +local hash={} +local conc={} +table.setmetatableindex(hash,function(t,k) + if k<0xD7FF or (k>0xDFFF and k<=0xFFFF) then + v=f_single(k) + else + local k=k-0x10000 + v=f_double(rshift(k,10)+0xD800,k%1024+0xDC00) + end + t[k]=v + return v +end) +local function tounicode(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) + elseif k>=0x00E000 and k<=0x00F8FF then + return unknown + elseif k>=0x0F0000 and k<=0x0FFFFF then + return unknown + elseif k>=0x100000 and k<=0x10FFFF then + return unknown + else + return hash[k] + end +end +local function fromunicode16(str) + if #str==4 then + return tonumber(str,16) + else + local l,r=match(str,"(....)(....)") + return 0x10000+(tonumber(l,16)-0xD800)*0x400+tonumber(r,16)-0xDC00 + end +end +mappings.makenameparser=makenameparser +mappings.tounicode=tounicode +mappings.tounicode16=tounicode16 +mappings.tounicode16sequence=tounicode16sequence +mappings.fromunicode16=fromunicode16 +local ligseparator=P("_") +local varseparator=P(".") +local namesplitter=Ct(C((1-ligseparator-varseparator)^1)*(ligseparator*C((1-ligseparator-varseparator)^1))^0) +do + 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 }, + fi={ name="f_i",unicode={ 0x66,0x69 },mess=0xFB01 }, + fl={ name="f_l",unicode={ 0x66,0x6C },mess=0xFB02 }, + ffi={ name="f_f_i",unicode={ 0x66,0x66,0x69 },mess=0xFB03 }, + 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 } }, + } + local o=allocate {} + for k,v in next,overloads do + local name=v.name + local mess=v.mess + if name then + o[name]=v + end + if mess then + o[mess]=v + end + o[k]=v + end + mappings.overloads=o +end +function mappings.addtounicode(data,filename,checklookups,forceligatures) + local resources=data.resources + local unicodes=resources.unicodes + if not unicodes then + if trace_mapping then + report_fonts("no unicode list, quitting tounicode for %a",filename) + end + return + end + local properties=data.properties + local descriptions=data.descriptions + local overloads=mappings.overloads + unicodes['space']=unicodes['space'] or 32 + unicodes['hyphen']=unicodes['hyphen'] or 45 + unicodes['zwj']=unicodes['zwj'] or 0x200D + unicodes['zwnj']=unicodes['zwnj'] or 0x200C + local private=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 + local unicodevector=fonts.encodings.agl.unicodes or {} + local contextvector=fonts.encodings.agl.ctxcodes or {} + local missing={} + local nofmissing=0 + local oparser=nil + local cidnames=nil + local cidcodes=nil + local cidinfo=properties.cidinfo + local usedmap=cidinfo and fonts.cid.getmap(cidinfo) + local uparser=makenameparser() + if usedmap then + oparser=usedmap and makenameparser(cidinfo.ordering) + cidnames=usedmap.names + cidcodes=usedmap.unicodes + end + local ns=0 + local nl=0 + local dlist=sortedkeys(descriptions) + for i=1,#dlist do + local du=dlist[i] + local glyph=descriptions[du] + local name=glyph.name + if name then + local overload=overloads[name] or overloads[du] + if overload then + glyph.unicode=overload.unicode + else + local gu=glyph.unicode + if not gu or gu==-1 or du>=private or (du>=0xE000 and du<=0xF8FF) or du==0xFFFE or du==0xFFFF then + local unicode=unicodevector[name] or contextvector[name] + if unicode then + glyph.unicode=unicode + ns=ns+1 + end + if (not unicode) and usedmap then + local foundindex=lpegmatch(oparser,name) + if foundindex then + unicode=cidcodes[foundindex] + if unicode then + glyph.unicode=unicode + ns=ns+1 + else + local reference=cidnames[foundindex] + if reference then + local foundindex=lpegmatch(oparser,reference) + if foundindex then + unicode=cidcodes[foundindex] + if unicode then + glyph.unicode=unicode + ns=ns+1 + end + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,reference) + if foundcodes then + glyph.unicode=foundcodes + if multiple then + nl=nl+1 + unicode=true + else + ns=ns+1 + unicode=foundcodes + end + end + end + end + end + end + end + if not unicode or unicode=="" then + local split=lpegmatch(namesplitter,name) + local nsplit=split and #split or 0 + if nsplit==0 then + elseif nsplit==1 then + local base=split[1] + local u=unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + elseif type(u)=="table" then + if u[1]<private then + unicode=u + glyph.unicode=unicode + end + elseif u<private then + unicode=u + glyph.unicode=unicode + end + else + local t={} + local n=0 + for l=1,nsplit do + local base=split[l] + local u=unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + break + elseif type(u)=="table" then + if u[1]>=private then + break + end + n=n+1 + t[n]=u[1] + else + if u>=private then + break + end + n=n+1 + t[n]=u + end + end + if n>0 then + if n==1 then + unicode=t[1] + else + unicode=t + end + glyph.unicode=unicode + end + end + nl=nl+1 + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,name) + if foundcodes then + glyph.unicode=foundcodes + if multiple then + nl=nl+1 + unicode=true + else + ns=ns+1 + unicode=foundcodes + end + end + end + local r=overloads[unicode] + if r then + unicode=r.unicode + glyph.unicode=unicode + end + if not unicode then + missing[du]=true + nofmissing=nofmissing+1 + end + else + end + end + else + local overload=overloads[du] + if overload then + glyph.unicode=overload.unicode + elseif not glyph.unicode then + missing[du]=true + nofmissing=nofmissing+1 + end + end + end + if type(checklookups)=="function" then + checklookups(data,missing,nofmissing) + end + local unicoded=0 + 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 + 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 + 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 + end + end + end + end + if trace_mapping and unicoded>0 then + report_fonts("%n ligature tounicode mappings deduced from gsub ligature features",unicoded) + end + if trace_mapping then + for i=1,#dlist do + local du=dlist[i] + local glyph=descriptions[du] + local name=glyph.name or "-" + local index=glyph.index or 0 + local unicode=glyph.unicode + if unicode then + if type(unicode)=="table" then + local unicodes={} + for i=1,#unicode do + unicodes[i]=formatters("%U",unicode[i]) + end + report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,du,unicodes) + else + report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,du,unicode) + end + else + report_fonts("internal slot %U, name %a, unicode %U",index,name,du) + end + end + end + if trace_loading and (ns>0 or nl>0) then + report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns) + end +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-map”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-vfc” 94937140f2c909e9c831ba021f1ab303] --- + +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,type=select,type +local insert=table.insert +local fonts=fonts +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 +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 +function helpers.prependcommandtable(commands,t) + insert(commands,1,push) + for i=#t,1,-1 do + local s=t[i] + if s then + insert(commands,1,s) + end + end + insert(commands,pop) + return commands +end +function helpers.appendcommandtable(commands,t) + insert(commands,1,push) + insert(commands,pop) + for i=1,#t do + local s=t[i] + if s then + insert(commands,s) + end + end + return commands +end +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, +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-vfc”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otr” 340999eb6c53879787a7560bc1a30360] --- + +if not modules then modules={} end modules ['font-otr']={ + 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,type,tonumber=next,type,tonumber +local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub +local fullstrip=string.fullstrip +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 sortedkeys=table.sortedkeys +local sortedhash=table.sortedhash +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 +local otf=handlers.otf or {} +handlers.otf=otf +local readers=otf.readers or {} +otf.readers=readers +local streamreader=utilities.files +local streamwriter=utilities.files +readers.streamreader=streamreader +readers.streamwriter=streamwriter +local openfile=streamreader.open +local closefile=streamreader.close +local setposition=streamreader.setposition +local skipshort=streamreader.skipshort +local readbytes=streamreader.readbytes +local readstring=streamreader.readstring +local readbyte=streamreader.readcardinal1 +local readushort=streamreader.readcardinal2 +local readuint=streamreader.readcardinal3 +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 readcardinaltable=streamreader.readcardinaltable +local readintegertable=streamreader.readintegertable +function streamreader.readtag(f) + 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 reservednames={ [0]="copyright", + "family", + "subfamily", + "uniqueid", + "fullname", + "version", + "postscriptname", + "trademark", + "manufacturer", + "designer", + "description", + "vendorurl", + "designerurl", + "license", + "licenseurl", + "reserved", + "typographicfamily", + "typographicsubfamily", + "compatiblefullname", + "sampletext", + "cidfindfontname", + "wwsfamily", + "wwssubfamily", + "lightbackgroundpalette", + "darkbackgroundpalette", + "variationspostscriptnameprefix", +} +local platforms={ [0]="unicode", + "macintosh", + "iso", + "windows", + "custom", +} +local encodings={ + unicode={ [0]="unicode 1.0 semantics", + "unicode 1.1 semantics", + "iso/iec 10646", + "unicode 2.0 bmp", + "unicode 2.0 full", + "unicode variation sequences", + "unicode full repertoire", + }, + macintosh={ [0]="roman","japanese","chinese (traditional)","korean","arabic","hebrew","greek","russian", + "rsymbol","devanagari","gurmukhi","gujarati","oriya","bengali","tamil","telugu","kannada", + "malayalam","sinhalese","burmese","khmer","thai","laotian","georgian","armenian", + "chinese (simplified)","tibetan","mongolian","geez","slavic","vietnamese","sindhi", + "uninterpreted", + }, + iso={ [0]="7-bit ascii", + "iso 10646", + "iso 8859-1", + }, + windows={ [0]="symbol", + "unicode bmp", + "shiftjis", + "prc", + "big5", + "wansung", + "johab", + "reserved 7", + "reserved 8", + "reserved 9", + "unicode ucs-4", + }, + custom={ + } +} +local decoders={ + unicode={}, + macintosh={}, + iso={}, + windows={ + ["unicode semantics"]=utf16_to_utf8_be, + ["unicode bmp"]=utf16_to_utf8_be, + ["unicode full"]=utf16_to_utf8_be, + ["unicode 1.0 semantics"]=utf16_to_utf8_be, + ["unicode 1.1 semantics"]=utf16_to_utf8_be, + ["unicode 2.0 bmp"]=utf16_to_utf8_be, + ["unicode 2.0 full"]=utf16_to_utf8_be, + ["unicode variation sequences"]=utf16_to_utf8_be, + ["unicode full repertoire"]=utf16_to_utf8_be, + }, + custom={}, +} +local languages={ + unicode={ + [ 0]="english", + }, + macintosh={ + [ 0]="english", + }, + iso={}, + windows={ + [0x0409]="english - united states", + }, + custom={}, +} +local standardromanencoding={ [0]= + "notdef",".null","nonmarkingreturn","space","exclam","quotedbl", + "numbersign","dollar","percent","ampersand","quotesingle","parenleft", + "parenright","asterisk","plus","comma","hyphen","period","slash", + "zero","one","two","three","four","five","six","seven","eight", + "nine","colon","semicolon","less","equal","greater","question","at", + "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O", + "P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft", + "backslash","bracketright","asciicircum","underscore","grave","a","b", + "c","d","e","f","g","h","i","j","k","l","m","n","o","p","q", + "r","s","t","u","v","w","x","y","z","braceleft","bar", + "braceright","asciitilde","Adieresis","Aring","Ccedilla","Eacute", + "Ntilde","Odieresis","Udieresis","aacute","agrave","acircumflex", + "adieresis","atilde","aring","ccedilla","eacute","egrave", + "ecircumflex","edieresis","iacute","igrave","icircumflex","idieresis", + "ntilde","oacute","ograve","ocircumflex","odieresis","otilde","uacute", + "ugrave","ucircumflex","udieresis","dagger","degree","cent","sterling", + "section","bullet","paragraph","germandbls","registered","copyright", + "trademark","acute","dieresis","notequal","AE","Oslash","infinity", + "plusminus","lessequal","greaterequal","yen","mu","partialdiff", + "summation","product","pi","integral","ordfeminine","ordmasculine", + "Omega","ae","oslash","questiondown","exclamdown","logicalnot", + "radical","florin","approxequal","Delta","guillemotleft", + "guillemotright","ellipsis","nonbreakingspace","Agrave","Atilde", + "Otilde","OE","oe","endash","emdash","quotedblleft","quotedblright", + "quoteleft","quoteright","divide","lozenge","ydieresis","Ydieresis", + "fraction","currency","guilsinglleft","guilsinglright","fi","fl", + "daggerdbl","periodcentered","quotesinglbase","quotedblbase", + "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave", + "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex", + "apple","Ograve","Uacute","Ucircumflex","Ugrave","dotlessi", + "circumflex","tilde","macron","breve","dotaccent","ring","cedilla", + "hungarumlaut","ogonek","caron","Lslash","lslash","Scaron","scaron", + "Zcaron","zcaron","brokenbar","Eth","eth","Yacute","yacute","Thorn", + "thorn","minus","multiply","onesuperior","twosuperior","threesuperior", + "onehalf","onequarter","threequarters","franc","Gbreve","gbreve", + "Idotaccent","Scedilla","scedilla","Cacute","cacute","Ccaron","ccaron", + "dcroat", +} +local weights={ + [100]="thin", + [200]="extralight", + [300]="light", + [400]="normal", + [500]="medium", + [600]="semibold", + [700]="bold", + [800]="extrabold", + [900]="black", +} +local widths={ + [1]="ultracondensed", + [2]="extracondensed", + [3]="condensed", + [4]="semicondensed", + [5]="normal", + [6]="semiexpanded", + [7]="expanded", + [8]="extraexpanded", + [9]="ultraexpanded", +} +setmetatableindex(weights,function(t,k) + local r=floor((k+50)/100)*100 + local v=(r>900 and "black") or rawget(t,r) or "normal" + return v +end) +setmetatableindex(widths,function(t,k) + return "normal" +end) +local panoseweights={ + [ 0]="normal", + [ 1]="normal", + [ 2]="verylight", + [ 3]="light", + [ 4]="thin", + [ 5]="book", + [ 6]="medium", + [ 7]="demi", + [ 8]="bold", + [ 9]="heavy", + [10]="black", +} +local panosewidths={ + [ 0]="normal", + [ 1]="normal", + [ 2]="normal", + [ 3]="normal", + [ 4]="normal", + [ 5]="expanded", + [ 6]="condensed", + [ 7]="veryexpanded", + [ 8]="verycondensed", + [ 9]="monospaced", +} +local helpers={} +readers.helpers=helpers +local function gotodatatable(f,fontdata,tag,criterium) + if criterium and f then + local tables=fontdata.tables + if tables then + local datatable=tables[tag] + if datatable then + local tableoffset=datatable.offset + setposition(f,tableoffset) + return tableoffset + end + else + report("no tables") + end + end +end +local function reportskippedtable(f,fontdata,tag,criterium) + if criterium and f then + local tables=fontdata.tables + if tables then + local datatable=tables[tag] + if datatable then + report("loading of table %a skipped",tag) + end + else + report("no tables") + 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, + family=true, + subfamily=true, + typographicfamily=true, + typographicsubfamily=true, + compatiblefullname=true, +} +local platformextras={ + uniqueid=true, + version=true, + copyright=true, + license=true, + licenseurl=true, + manufacturer=true, + vendorurl=true, +} +function readers.name(f,fontdata,specification) + local tableoffset=gotodatatable(f,fontdata,"name",true) + if tableoffset then + local format=readushort(f) + local nofnames=readushort(f) + local offset=readushort(f) + local start=tableoffset+offset + local namelists={ + unicode={}, + windows={}, + macintosh={}, + } + for i=1,nofnames do + local platform=platforms[readushort(f)] + if platform then + local namelist=namelists[platform] + if namelist then + local encoding=readushort(f) + local language=readushort(f) + local encodings=encodings[platform] + local languages=languages[platform] + if encodings and languages then + local encoding=encodings[encoding] + local language=languages[language] + if encoding and language then + 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 + else + skipshort(f,3) + end + else + skipshort(f,5) + end + else + skipshort(f,5) + end + end + local names={} + local done={} + local extras={} + local function decoded(platform,encoding,content) + local decoder=decoders[platform] + if decoder then + decoder=decoder[encoding] + end + if decoder then + return decoder(content) + else + return content + end + end + local function filter(platform,e,l) + local namelist=namelists[platform] + for i=1,#namelist do + local name=namelist[i] + local nametag=name.name + 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 + setposition(f,name.offset) + local content=decoded(platform,encoding,readstring(f,name.length)) + 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 + end + filter("windows","unicode bmp","english - united states") + filter("macintosh","roman","english") + filter("windows") + filter("macintosh") + filter("unicode") + fontdata.names=names + fontdata.extras=extras + if specification.platformnames then + local collected={} + local platformextras=specification.platformextras and platformextras + for platform,namelist in next,namelists do + local filtered=false + for i=1,#namelist do + local entry=namelist[i] + local name=entry.name + if platformnames[name] or (platformextras and platformextras[name]) then + setposition(f,entry.offset) + local content=decoded(platform,entry.encoding,readstring(f,entry.length)) + if filtered then + filtered[name]=content + else + filtered={ [name]=content } + end + end + end + if filtered then + collected[platform]=filtered + end + end + fontdata.platformnames=collected + end + else + fontdata.names={} + end +end +local validutf=lpeg.patterns.validutf8 +local function getname(fontdata,key) + local names=fontdata.names + if names then + local value=names[key] + if value then + local content=value.content + return lpegmatch(validutf,content) and content or nil + end + end +end +readers["os/2"]=function(f,fontdata) + local tableoffset=gotodatatable(f,fontdata,"os/2",true) + if tableoffset then + local version=readushort(f) + local windowsmetrics={ + version=version, + averagewidth=readshort(f), + weightclass=readushort(f), + widthclass=readushort(f), + fstype=readushort(f), + subscriptxsize=readshort(f), + subscriptysize=readshort(f), + subscriptxoffset=readshort(f), + subscriptyoffset=readshort(f), + superscriptxsize=readshort(f), + superscriptysize=readshort(f), + superscriptxoffset=readshort(f), + superscriptyoffset=readshort(f), + strikeoutsize=readshort(f), + strikeoutpos=readshort(f), + familyclass=readshort(f), + panose={ readbytes(f,10) }, + unicoderanges={ readulong(f),readulong(f),readulong(f),readulong(f) }, + vendor=readstring(f,4), + fsselection=readushort(f), + firstcharindex=readushort(f), + lastcharindex=readushort(f), + typoascender=readshort(f), + typodescender=readshort(f), + typolinegap=readshort(f), + winascent=readushort(f), + windescent=readushort(f), + } + if version>=1 then + windowsmetrics.codepageranges={ readulong(f),readulong(f) } + end + if version>=2 then + windowsmetrics.xheight=readshort(f) + windowsmetrics.capheight=readshort(f) + windowsmetrics.defaultchar=readushort(f) + windowsmetrics.breakchar=readushort(f) + end + windowsmetrics.weight=windowsmetrics.weightclass and weights[windowsmetrics.weightclass] + windowsmetrics.width=windowsmetrics.widthclass and widths [windowsmetrics.widthclass] + windowsmetrics.panoseweight=panoseweights[windowsmetrics.panose[3]] + windowsmetrics.panosewidth=panosewidths [windowsmetrics.panose[4]] + fontdata.windowsmetrics=windowsmetrics + else + fontdata.windowsmetrics={} + end +end +readers.head=function(f,fontdata) + local tableoffset=gotodatatable(f,fontdata,"head",true) + if tableoffset then + local version=readulong(f) + local fontversion=readulong(f) + local fontheader={ + version=version, + fontversion=number.to16dot16(fontversion), + fontversionnumber=fontversion, + checksum=readushort(f)*0x10000+readushort(f), + magic=readulong(f), + flags=readushort(f), + units=readushort(f), + created=readlongdatetime(f), + modified=readlongdatetime(f), + xmin=readshort(f), + ymin=readshort(f), + xmax=readshort(f), + ymax=readshort(f), + macstyle=readushort(f), + smallpixels=readushort(f), + directionhint=readshort(f), + indextolocformat=readshort(f), + glyphformat=readshort(f), + } + fontdata.fontheader=fontheader + else + fontdata.fontheader={} + end + fontdata.nofglyphs=0 +end +readers.hhea=function(f,fontdata,specification) + local tableoffset=gotodatatable(f,fontdata,"hhea",specification.details) + if tableoffset then + fontdata.horizontalheader={ + version=readulong(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) + local tableoffset=gotodatatable(f,fontdata,"vhea",specification.details) + if tableoffset then + fontdata.verticalheader={ + version=readulong(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=readulong(f) + local nofglyphs=readushort(f) + fontdata.nofglyphs=nofglyphs + if version==0x00005000 then + fontdata.maximumprofile={ + version=version, + nofglyphs=nofglyphs, + } + elseif version==0x00010000 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 + end +end +readers.hmtx=function(f,fontdata,specification) + 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 + 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) + 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 + 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) + reportskippedtable(f,fontdata,"vorg",specification.glyphs) +end +readers.post=function(f,fontdata,specification) + local tableoffset=gotodatatable(f,fontdata,"post",true) + if tableoffset then + local version=readulong(f) + fontdata.postscript={ + version=version, + italicangle=round(1000*readfixed(f))/1000, + underlineposition=readfword(f), + underlinethickness=readfword(f), + monospaced=readulong(f), + minmemtype42=readulong(f), + maxmemtype42=readulong(f), + minmemtype1=readulong(f), + maxmemtype1=readulong(f), + } + if not specification.glyphs then + elseif version==0x00010000 then + for index=0,#standardromanencoding do + glyphs[index].name=standardromanencoding[index] + end + elseif version==0x00020000 then + local glyphs=fontdata.glyphs + local nofglyphs=readushort(f) + local indices={} + local names={} + local maxnames=0 + for i=0,nofglyphs-1 do + local nameindex=readushort(f) + if nameindex>=258 then + maxnames=maxnames+1 + nameindex=nameindex-257 + indices[nameindex]=i + else + glyphs[i].name=standardromanencoding[nameindex] + end + end + for i=1,maxnames do + local mapping=indices[i] + if not mapping then + report("quit post name fetching at %a of %a: %s",i,maxnames,"no index") + break + else + local length=readbyte(f) + if length>0 then + glyphs[mapping].name=readstring(f,length) + else + report("quit post name fetching at %a of %a: %s",i,maxnames,"overflow") + break + end + end + end + end + else + fontdata.postscript={} + end +end +readers.cff=function(f,fontdata,specification) + reportskippedtable(f,fontdata,"cff",specification.glyphs) +end +local formatreaders={} +local duplicatestoo=true +local sequence={ + { 3,1,4 }, + { 3,10,12 }, + { 0,3,4 }, + { 0,1,4 }, + { 0,0,6 }, + { 3,0,6 }, + { 0,5,14 }, +{ 0,4,12 }, + { 3,10,13 }, +} +local supported={} +for i=1,#sequence do + local si=sequence[i] + local sp,se,sf=si[1],si[2],si[3] + local p=supported[sp] + if not p then + p={} + supported[sp]=p + end + local e=p[se] + if not e then + e={} + p[se]=e + end + e[sf]=true +end +formatreaders[4]=function(f,fontdata,offset) + setposition(f,offset+2) + local length=readushort(f) + local language=readushort(f) + local nofsegments=readushort(f)/2 + skipshort(f,3) + local mapping=fontdata.mapping + local glyphs=fontdata.glyphs + local duplicates=fontdata.duplicates + local nofdone=0 + local endchars=readcardinaltable(f,nofsegments,ushort) + local reserved=readushort(f) + 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] + local offset=offsets[segment] + local delta=deltas[segment] + if startchar==0xFFFF and endchar==0xFFFF then + elseif startchar==0xFFFF and offset==0 then + elseif offset==0xFFFF then + elseif offset==0 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 + local index=(unicode+delta)%65536 + if index and index>0 then + local glyph=glyphs[index] + if glyph then + local gu=glyph.unicode + if not gu then + glyph.unicode=unicode + nofdone=nofdone+1 + elseif gu~=unicode then + if duplicatestoo then + local d=duplicates[gu] + if d then + d[unicode]=true + else + duplicates[gu]={ [unicode]=true } + end + else + report("duplicate case 1: %C %04i %s",unicode,index,glyphs[index].name) + end + end + if not mapping[index] then + mapping[index]=unicode + end + end + end + end + else + local shift=(segment-nofsegments+offset/2)-startchar + 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 + local slot=shift+unicode + local index=indices[slot] + if index and index>0 then + index=(index+delta)%65536 + local glyph=glyphs[index] + if glyph then + local gu=glyph.unicode + if not gu then + glyph.unicode=unicode + nofdone=nofdone+1 + elseif gu~=unicode then + if duplicatestoo then + local d=duplicates[gu] + if d then + d[unicode]=true + else + duplicates[gu]={ [unicode]=true } + end + else + report("duplicate case 2: %C %04i %s",unicode,index,glyphs[index].name) + end + end + if not mapping[index] then + mapping[index]=unicode + end + end + end + end + end + end + return nofdone +end +formatreaders[6]=function(f,fontdata,offset) + setposition(f,offset) + local format=readushort(f) + local length=readushort(f) + local language=readushort(f) + local mapping=fontdata.mapping + local glyphs=fontdata.glyphs + local duplicates=fontdata.duplicates + local start=readushort(f) + local count=readushort(f) + local stop=start+count-1 + local nofdone=0 + if trace_cmap_detail then + report("format 6 from %C to %C",2,start,stop) + end + for unicode=start,stop do + local index=readushort(f) + if index>0 then + local glyph=glyphs[index] + if glyph then + local gu=glyph.unicode + if not gu then + glyph.unicode=unicode + nofdone=nofdone+1 + elseif gu~=unicode then + end + if not mapping[index] then + mapping[index]=unicode + end + end + end + end + return nofdone +end +formatreaders[12]=function(f,fontdata,offset) + setposition(f,offset+2+2+4+4) + local mapping=fontdata.mapping + local glyphs=fontdata.glyphs + local duplicates=fontdata.duplicates + local nofgroups=readulong(f) + local nofdone=0 + for i=1,nofgroups do + local first=readulong(f) + local last=readulong(f) + local index=readulong(f) + 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 + local glyph=glyphs[index] + if glyph then + local gu=glyph.unicode + if not gu then + glyph.unicode=unicode + nofdone=nofdone+1 + elseif gu~=unicode then + local d=duplicates[gu] + if d then + d[unicode]=true + else + duplicates[gu]={ [unicode]=true } + end + end + if not mapping[index] then + mapping[index]=unicode + end + end + index=index+1 + end + end + return nofdone +end +formatreaders[13]=function(f,fontdata,offset) + setposition(f,offset+2+2+4+4) + local mapping=fontdata.mapping + local glyphs=fontdata.glyphs + local duplicates=fontdata.duplicates + local nofgroups=readulong(f) + local nofdone=0 + for i=1,nofgroups do + local first=readulong(f) + local last=readulong(f) + local index=readulong(f) + if first<privateoffset then + if trace_cmap_detail then + report("format 13 from %C to %C get index %i",first,last,index) + end + local glyph=glyphs[index] + local unicode=glyph.unicode + if not unicode then + unicode=first + glyph.unicode=unicode + first=first+1 + end + local list=duplicates[unicode] + mapping[index]=unicode + if not list then + list={} + duplicates[unicode]=list + end + if last>=privateoffset then + local limit=privateoffset-1 + report("format 13 from %C to %C pruned to %C",first,last,limit) + last=limit + end + for unicode=first,last do + list[unicode]=true + end + nofdone=nofdone+last-first+1 + else + report("format 13 from %C to %C ignored",first,last) + end + end + return nofdone +end +formatreaders[14]=function(f,fontdata,offset) + if offset and offset~=0 then + setposition(f,offset) + local format=readushort(f) + local length=readulong(f) + local nofrecords=readulong(f) + local records={} + local variants={} + local nofdone=0 + fontdata.variants=variants + for i=1,nofrecords do + records[i]={ + selector=readuint(f), + default=readulong(f), + other=readulong(f), + } + end + for i=1,nofrecords do + local record=records[i] + local selector=record.selector + local default=record.default + local other=record.other + local other=record.other + if other~=0 then + setposition(f,offset+other) + local mapping={} + local count=readulong(f) + for i=1,count do + mapping[readuint(f)]=readushort(f) + end + nofdone=nofdone+count + variants[selector]=mapping + end + end + return nofdone + else + return 0 + end +end +local function checkcmap(f,fontdata,records,platform,encoding,format) + local data=records[platform] + if not data then + return 0 + end + data=data[encoding] + if not data then + return 0 + end + data=data[format] + if not data then + return 0 + end + local reader=formatreaders[format] + if not reader then + return 0 + end + local p=platforms[platform] + local e=encodings[p] + local n=reader(f,fontdata,data) or 0 + 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) + 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 offsets=subtables.offsets + offsets[#offsets+1]=offset + end + end + end + if trace_cmap then + report("found cmaps:") + 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 + 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 + 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 + list[i]=list[i].." (unsupported)" + end + end + report(" formats: % t",list) + end + end + 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 + 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) + reportskippedtable(f,fontdata,"loca",specification.glyphs) +end +function readers.glyf(f,fontdata,specification) + reportskippedtable(f,fontdata,"glyf",specification.glyphs) +end +function readers.colr(f,fontdata,specification) + reportskippedtable(f,fontdata,"colr",specification.glyphs) +end +function readers.cpal(f,fontdata,specification) + reportskippedtable(f,fontdata,"cpal",specification.glyphs) +end +function readers.svg(f,fontdata,specification) + 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) + 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) + 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 + end + elseif format==2 then + report("todo: kern classes") + else + report("todo: kerns") + end + end + end +end +function readers.gdef(f,fontdata,specification) + reportskippedtable(f,fontdata,"gdef",specification.details) +end +function readers.gsub(f,fontdata,specification) + reportskippedtable(f,fontdata,"gsub",specification.details) +end +function readers.gpos(f,fontdata,specification) + reportskippedtable(f,fontdata,"gpos",specification.details) +end +function readers.math(f,fontdata,specification) + reportskippedtable(f,fontdata,"math",specification.details) +end +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 + if names then + local metrics=fontdata.windowsmetrics or {} + local postscript=fontdata.postscript or {} + local fontheader=fontdata.fontheader or {} + local cffinfo=fontdata.cffinfo or {} + local filename=fontdata.filename + local weight=getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight) + local width=getname(fontdata,"width") or (cffinfo and cffinfo.width ) or (metrics and metrics.width ) + local fontname=getname(fontdata,"postscriptname") + local fullname=getname(fontdata,"fullname") + local family=getname(fontdata,"family") + local subfamily=getname(fontdata,"subfamily") + local familyname=getname(fontdata,"typographicfamily") + local subfamilyname=getname(fontdata,"typographicsubfamily") + local compatiblename=getname(fontdata,"compatiblefullname") + if rawfamilynames then + else + 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"), + fontname=fontname, + fullname=fullname, + family=family, + subfamily=subfamily, + familyname=familyname, + subfamilyname=subfamilyname, + compatiblename=compatiblename, + weight=weight and lower(weight), + width=width and lower(width), + pfmweight=metrics.weightclass or 400, + pfmwidth=metrics.widthclass or 5, + panosewidth=metrics.panosewidth, + panoseweight=metrics.panoseweight, + italicangle=postscript.italicangle or 0, + units=fontheader.units or 0, + designsize=fontdata.designsize, + minsize=fontdata.minsize, + maxsize=fontdata.maxsize, + boundingbox=fontheader and { fontheader.xmin or 0,fontheader.ymin or 0,fontheader.xmax or 0,fontheader.ymax or 0 } or nil, + monospaced=(tonumber(postscript.monospaced or 0)>0) or metrics.panosewidth=="monospaced", + averagewidth=metrics.averagewidth, + xheight=metrics.xheight, + capheight=metrics.capheight or fontdata.maxy, + ascender=metrics.typoascender, + descender=metrics.typodescender, + platformnames=platformnames or nil, + instancenames=instancenames or nil, + tableoffsets=fontdata.tableoffsets, + } + if metricstoo then + local keys={ + "version", + "ascender","descender","linegap", + "maxadvancewidth","maxadvanceheight","maxextent", + "minbottomsidebearing","mintopsidebearing", + } + local h=fontdata.horizontalheader or {} + local v=fontdata.verticalheader or {} + if h then + local th={} + local tv={} + for i=1,#keys do + local key=keys[i] + th[key]=h[key] or 0 + tv[key]=v[key] or 0 + end + info.horizontalmetrics=th + info.verticalmetrics=tv + end + end + elseif n then + info={ + filename=fontdata.filename, + comment="there is no info for subfont "..n, + } + else + info={ + filename=fontdata.filename, + comment="there is no info", + } + end + return info +end +local function loadtables(f,specification,offset) + if offset then + setposition(f,offset) + end + local tables={} + local basename=file.basename(specification.filename) + local filesize=specification.filesize + local filetime=specification.filetime + local fontdata={ + filename=basename, + filesize=filesize, + filetime=filetime, + version=readstring(f,4), + noftables=readushort(f), + searchrange=readushort(f), + entryselector=readushort(f), + rangeshift=readushort(f), + tables=tables, + foundtables=false, + } + for i=1,fontdata.noftables do + local tag=lower(stripstring(readstring(f,4))) + local checksum=readushort(f)*0x10000+readushort(f) + local offset=readulong(f) + local length=readulong(f) + if offset+length>filesize then + report("bad %a table in file %a",tag,basename) + end + tables[tag]={ + checksum=checksum, + offset=offset, + length=length, + } + end + fontdata.foundtables=sortedkeys(tables) + if tables.cff or tables.cff2 then + fontdata.format="opentype" + else + fontdata.format="truetype" + end + return fontdata,tables +end +local function prepareglyps(fontdata) + local glyphs=setmetatableindex(function(t,k) + local v={ + index=k, + } + t[k]=v + return v + end) + 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,tables=loadtables(f,specification,offset) + if specification.glyphs then + prepareglyps(fontdata) + end + 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 "" + local cleanname=gsub(askedname,"[^a-zA-Z0-9]","") + local foundname=gsub(fullname,"[^a-zA-Z0-9]","") + if lower(cleanname)~=lower(foundname) then + return + end + end + 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.cidmaps=nil + fontdata.dictionaries=nil + if specification.tableoffsets then + fontdata.tableoffsets=tables + setmetatableindex(tables,{ + version=fontdata.version, + noftables=fontdata.noftables, + searchrange=fontdata.searchrange, + entryselector=fontdata.entryselector, + rangeshift=fontdata.rangeshift, + }) + end + return fontdata +end +local function loadfontdata(specification) + local filename=specification.filename + local fileattr=lfs.attributes(filename) + local filesize=fileattr and fileattr.size or 0 + local filetime=fileattr and fileattr.modification or 0 + local f=openfile(filename,true) + if not f then + report("unable to open %a",filename) + elseif filesize==0 then + report("empty file %a",filename) + closefile(f) + else + specification.filesize=filesize + specification.filetime=filetime + local version=readstring(f,4) + local fontdata=nil + if version=="OTTO" or version=="true" or version=="\0\1\0\0" then + fontdata=readdata(f,0,specification) + elseif version=="ttcf" then + local subfont=tonumber(specification.subfont) + local ttcversion=readulong(f) + local nofsubfonts=readulong(f) + local offsets=readcardinaltable(f,nofsubfonts,ulong) + if subfont then + if subfont>=1 and subfont<=nofsubfonts then + fontdata=readdata(f,offsets[subfont],specification) + else + report("no subfont %a in file %a",subfont,filename) + end + else + subfont=specification.subfont + if type(subfont)=="string" and subfont~="" then + specification.askedname=subfont + for i=1,nofsubfonts do + fontdata=readdata(f,offsets[i],specification) + if fontdata then + fontdata.subfontindex=i + report("subfont named %a has index %a",subfont,i) + break + end + end + if not fontdata then + report("no subfont named %a",subfont) + end + else + local subfonts={} + fontdata={ + filename=filename, + filesize=filesize, + filetime=filetime, + version=version, + subfonts=subfonts, + ttcversion=ttcversion, + nofsubfonts=nofsubfonts, + } + for i=1,nofsubfonts do + subfonts[i]=readdata(f,offsets[i],specification) + end + end + end + else + report("unknown version %a in file %a",version,filename) + end + closefile(f) + return fontdata or {} + end +end +local function loadfont(specification,n,instance) + if type(specification)=="string" then + specification={ + filename=specification, + info=true, + details=true, + 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 + specification.glyphs=true + end + if specification.glyphs then + specification.details=true + end + if specification.details then + specification.info=true + end + 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 and debug.traceback()) + end + local ok,result=xpcall(loadfontdata,message,specification) + if ok then + return result + end +end +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 + v.class=nil + v.index=nil + v.math=nil + end + local names=fontdata.names + if names then + for k,v in next,names do + names[k]=fullstrip(v.content) + end + end + end + return fontdata and { + filename=filename, + format=fontdata.format, + glyphs=fontdata.glyphs, + units=fontdata.fontheader.units, + cffinfo=fontdata.cffinfo, + fontheader=fontdata.fontheader, + horizontalheader=fontdata.horizontalheader, + verticalheader=fontdata.verticalheader, + maximumprofile=fontdata.maximumprofile, + names=fontdata.names, + postscript=fontdata.postscript, + } or { + filename=filename, + format="unknown", + glyphs={}, + units=0, + } +end +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 { + tableversion=tableversion, + creator="context mkiv", + size=fontdata.filesize, + time=fontdata.filetime, + glyphs=fontdata.glyphs, + descriptions=fontdata.descriptions, + format=fontdata.format, + goodies={}, + 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, + private=privateoffset, + duplicates=fontdata.duplicates or {}, + features=fontdata.features or {}, + sublookups=fontdata.sublookups or {}, + marks=fontdata.marks or {}, + markclasses=fontdata.markclasses or {}, + marksets=fontdata.marksets or {}, + sequences=fontdata.sequences or {}, + variants=fontdata.variants, + version=getname(fontdata,"version"), + cidinfo=fontdata.cidinfo, + mathconstants=fontdata.mathconstants, + colorpalettes=fontdata.colorpalettes, + svgshapes=fontdata.svgshapes, + pngshapes=fontdata.pngshapes, + variabledata=fontdata.variabledata, + foundtables=fontdata.foundtables, + }, + } + end +end +function readers.getinfo(filename,specification) + local subfont=nil + local platformnames=false + local rawfamilynames=false + local instancenames=true + local tableoffsets=false + if type(specification)=="table" then + subfont=tonumber(specification.subfont) + platformnames=specification.platformnames + rawfamilynames=specification.rawfamilynames + tableoffsets=specification.tableoffsets + else + subfont=tonumber(specification) + end + local fontdata=loadfont { + filename=filename, + details=true, + platformnames=platformnames, + instancenames=true, + tableoffsets=tableoffsets, + } + if fontdata then + local subfonts=fontdata.subfonts + if not subfonts then + 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,false,instancenames) + end + return info + elseif subfont>=1 and subfont<=#subfonts then + return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames) + else + return { + filename=filename, + comment="there is no subfont "..subfont.." in this file" + } + end + else + return { + filename=filename, + comment="the file cannot be opened for reading", + } + end +end +function readers.rehash(fontdata,hashmethod) + report("the %a helper is not yet implemented","rehash") +end +function readers.checkhash(fontdata) + report("the %a helper is not yet implemented","checkhash") +end +function readers.pack(fontdata,hashmethod) + report("the %a helper is not yet implemented","pack") +end +function readers.unpack(fontdata) + report("the %a helper is not yet implemented","unpack") +end +function readers.expand(fontdata) + report("the %a helper is not yet implemented","unpack") +end +function readers.compact(fontdata) + report("the %a helper is not yet implemented","compact") +end +local extenders={} +function readers.registerextender(extender) + extenders[#extenders+1]=extender +end +function readers.extend(fontdata) + for i=1,#extenders do + local extender=extenders[i] + local name=extender.name or "unknown" + local action=extender.action + if action then + action(fontdata) + end + end +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otr”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-oti” dbae7722baae24d917a17176553825cf] --- + +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-2019-05-18.lua scope for “font-oti”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ott” a8b78a27cbb22d4f697a8dd801a73eea] --- + +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", + ["kjz" ]="bumthangkha", + ["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", + ["mfa" ]="pattani malay", + ["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", + ["tsj" ]="tshangla", + ["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", + ["xkf" ]="khengkha", + ["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,wrap) + 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 + if wrap and find(value,",") then + uv="{"..lower(value).."}" + else + uv=lower(value) + end + 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-2019-05-18.lua scope for “font-ott”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-cff” 7ff1a757f6a26f57f635014cc8a174fe] --- + +if not modules then modules={} end modules ['font-cff']={ + 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,type,tonumber,rawget=next,type,tonumber,rawget +local byte,char,gmatch=string.byte,string.char,string.gmatch +local concat,remove,unpack=table.concat,table.remove,table.unpack +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 idiv=number.idiv +local rshift,band,extract=bit32.rshift,bit32.band,bit32.extract +local readers=fonts.handlers.otf.readers +local streamreader=readers.streamreader +local readstring=streamreader.readstring +local readbyte=streamreader.readcardinal1 +local readushort=streamreader.readcardinal2 +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") +local parsedictionaries +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", + "comma","hyphen","period","slash","zero","one","two","three","four", + "five","six","seven","eight","nine","colon","semicolon","less", + "equal","greater","question","at","A","B","C","D","E","F","G","H", + "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W", + "X","Y","Z","bracketleft","backslash","bracketright","asciicircum", + "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j", + "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y", + "z","braceleft","bar","braceright","asciitilde","exclamdown","cent", + "sterling","fraction","yen","florin","section","currency", + "quotesingle","quotedblleft","guillemotleft","guilsinglleft", + "guilsinglright","fi","fl","endash","dagger","daggerdbl", + "periodcentered","paragraph","bullet","quotesinglbase","quotedblbase", + "quotedblright","guillemotright","ellipsis","perthousand","questiondown", + "grave","acute","circumflex","tilde","macron","breve","dotaccent", + "dieresis","ring","cedilla","hungarumlaut","ogonek","caron","emdash", + "AE","ordfeminine","Lslash","Oslash","OE","ordmasculine","ae", + "dotlessi","lslash","oslash","oe","germandbls","onesuperior", + "logicalnot","mu","trademark","Eth","onehalf","plusminus","Thorn", + "onequarter","divide","brokenbar","degree","thorn","threequarters", + "twosuperior","registered","minus","eth","multiply","threesuperior", + "copyright","Aacute","Acircumflex","Adieresis","Agrave","Aring", + "Atilde","Ccedilla","Eacute","Ecircumflex","Edieresis","Egrave", + "Iacute","Icircumflex","Idieresis","Igrave","Ntilde","Oacute", + "Ocircumflex","Odieresis","Ograve","Otilde","Scaron","Uacute", + "Ucircumflex","Udieresis","Ugrave","Yacute","Ydieresis","Zcaron", + "aacute","acircumflex","adieresis","agrave","aring","atilde", + "ccedilla","eacute","ecircumflex","edieresis","egrave","iacute", + "icircumflex","idieresis","igrave","ntilde","oacute","ocircumflex", + "odieresis","ograve","otilde","scaron","uacute","ucircumflex", + "udieresis","ugrave","yacute","ydieresis","zcaron","exclamsmall", + "Hungarumlautsmall","dollaroldstyle","dollarsuperior","ampersandsmall", + "Acutesmall","parenleftsuperior","parenrightsuperior","twodotenleader", + "onedotenleader","zerooldstyle","oneoldstyle","twooldstyle", + "threeoldstyle","fouroldstyle","fiveoldstyle","sixoldstyle", + "sevenoldstyle","eightoldstyle","nineoldstyle","commasuperior", + "threequartersemdash","periodsuperior","questionsmall","asuperior", + "bsuperior","centsuperior","dsuperior","esuperior","isuperior", + "lsuperior","msuperior","nsuperior","osuperior","rsuperior","ssuperior", + "tsuperior","ff","ffi","ffl","parenleftinferior","parenrightinferior", + "Circumflexsmall","hyphensuperior","Gravesmall","Asmall","Bsmall", + "Csmall","Dsmall","Esmall","Fsmall","Gsmall","Hsmall","Ismall", + "Jsmall","Ksmall","Lsmall","Msmall","Nsmall","Osmall","Psmall", + "Qsmall","Rsmall","Ssmall","Tsmall","Usmall","Vsmall","Wsmall", + "Xsmall","Ysmall","Zsmall","colonmonetary","onefitted","rupiah", + "Tildesmall","exclamdownsmall","centoldstyle","Lslashsmall", + "Scaronsmall","Zcaronsmall","Dieresissmall","Brevesmall","Caronsmall", + "Dotaccentsmall","Macronsmall","figuredash","hypheninferior", + "Ogoneksmall","Ringsmall","Cedillasmall","questiondownsmall","oneeighth", + "threeeighths","fiveeighths","seveneighths","onethird","twothirds", + "zerosuperior","foursuperior","fivesuperior","sixsuperior", + "sevensuperior","eightsuperior","ninesuperior","zeroinferior", + "oneinferior","twoinferior","threeinferior","fourinferior", + "fiveinferior","sixinferior","seveninferior","eightinferior", + "nineinferior","centinferior","dollarinferior","periodinferior", + "commainferior","Agravesmall","Aacutesmall","Acircumflexsmall", + "Atildesmall","Adieresissmall","Aringsmall","AEsmall","Ccedillasmall", + "Egravesmall","Eacutesmall","Ecircumflexsmall","Edieresissmall", + "Igravesmall","Iacutesmall","Icircumflexsmall","Idieresissmall", + "Ethsmall","Ntildesmall","Ogravesmall","Oacutesmall","Ocircumflexsmall", + "Otildesmall","Odieresissmall","OEsmall","Oslashsmall","Ugravesmall", + "Uacutesmall","Ucircumflexsmall","Udieresissmall","Yacutesmall", + "Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003", + "Black","Bold","Book","Light","Medium","Regular","Roman","Semibold", +} +local cffreaders={ + readbyte, + readushort, + readuint, + readulong, +} +local function readheader(f) + local offset=getposition(f) + local major=readbyte(f) + local header={ + offset=offset, + major=major, + minor=readbyte(f), + size=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,longcount) + local count=longcount and readulong(f) or readushort(f) + if count==0 then + return {} + end + local osize=readbyte(f) + local read=cffreaders[osize] + if not read then + report("bad offset size: %i",osize) + return {} + end + local lengths={} + local previous=read(f) + for i=1,count do + local offset=read(f) + local length=offset-previous + if length<0 then + report("bad offset: %i",length) + length=0 + end + lengths[i]=length + previous=offset + end + return lengths +end +local function readfontnames(f) + local names=readlengths(f) + for i=1,#names do + names[i]=readstring(f,names[i]) + end + return names +end +local function readtopdictionaries(f) + local dictionaries=readlengths(f) + for i=1,#dictionaries do + dictionaries[i]=readstring(f,dictionaries[i]) + end + return dictionaries +end +local function readstrings(f) + local lengths=readlengths(f) + local strings=setmetatableindex({},defaultstrings) + local index=#defaultstrings + for i=1,#lengths do + index=index+1 + strings[index]=readstring(f,lengths[i]) + end + return strings +end +do + local stack={} + local top=0 + local result={} + local strings={} + local p_single=P("\00")/function() + result.version=strings[stack[top]] or "unset" + top=0 + end+P("\01")/function() + result.notice=strings[stack[top]] or "unset" + top=0 + end+P("\02")/function() + result.fullname=strings[stack[top]] or "unset" + top=0 + end+P("\03")/function() + result.familyname=strings[stack[top]] or "unset" + top=0 + end+P("\04")/function() + result.weight=strings[stack[top]] or "unset" + top=0 + end+P("\05")/function() + result.fontbbox={ unpack(stack,1,4) } + top=0 + end+P("\06")/function() + result.bluevalues={ unpack(stack,1,top) } + top=0 + end+P("\07")/function() + result.otherblues={ unpack(stack,1,top) } + top=0 + end+P("\08")/function() + result.familyblues={ unpack(stack,1,top) } + top=0 + end+P("\09")/function() + result.familyotherblues={ unpack(stack,1,top) } + top=0 + end+P("\10")/function() + result.strhw=stack[top] + top=0 + end+P("\11")/function() + result.strvw=stack[top] + top=0 + end+P("\13")/function() + result.uniqueid=stack[top] + top=0 + end+P("\14")/function() + result.xuid=concat(stack,"",1,top) + top=0 + end+P("\15")/function() + result.charset=stack[top] + top=0 + end+P("\16")/function() + result.encoding=stack[top] + top=0 + end+P("\17")/function() + result.charstrings=stack[top] + top=0 + end+P("\18")/function() + result.private={ + size=stack[top-1], + offset=stack[top], + } + 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() + result.copyright=stack[top] + top=0 + end+P("\01")/function() + result.monospaced=stack[top]==1 and true or false + top=0 + end+P("\02")/function() + result.italicangle=stack[top] + top=0 + end+P("\03")/function() + result.underlineposition=stack[top] + top=0 + end+P("\04")/function() + result.underlinethickness=stack[top] + top=0 + end+P("\05")/function() + result.painttype=stack[top] + top=0 + end+P("\06")/function() + result.charstringtype=stack[top] + top=0 + end+P("\07")/function() + result.fontmatrix={ unpack(stack,1,6) } + top=0 + end+P("\08")/function() + result.strokewidth=stack[top] + top=0 + end+P("\09")/function() + result.bluescale=stack[top] + top=0 + end+P("\10")/function() + result.bluesnap=stack[top] + top=0 + end+P("\11")/function() + result.bluefuzz=stack[top] + top=0 + end+P("\12")/function() + result.stemsnaph={ unpack(stack,1,top) } + top=0 + end+P("\13")/function() + result.stemsnapv={ unpack(stack,1,top) } + top=0 + end+P("\20")/function() + result.syntheticbase=stack[top] + top=0 + end+P("\21")/function() + result.postscript=strings[stack[top]] or "unset" + top=0 + end+P("\22")/function() + result.basefontname=strings[stack[top]] or "unset" + top=0 + end+P("\21")/function() + result.basefontblend=stack[top] + top=0 + end+P("\30")/function() + result.cid.registry=strings[stack[top-2]] or "unset" + result.cid.ordering=strings[stack[top-1]] or "unset" + result.cid.supplement=stack[top] + top=0 + end+P("\31")/function() + result.cid.fontversion=stack[top] + top=0 + end+P("\32")/function() + result.cid.fontrevision=stack[top] + top=0 + end+P("\33")/function() + result.cid.fonttype=stack[top] + top=0 + end+P("\34")/function() + result.cid.count=stack[top] + top=0 + end+P("\35")/function() + result.cid.uidbase=stack[top] + top=0 + end+P("\36")/function() + result.cid.fdarray=stack[top] + top=0 + end+P("\37")/function() + result.cid.fdselect=stack[top] + top=0 + end+P("\38")/function() + result.cid.fontname=strings[stack[top]] or "unset" + top=0 + end + ) + local remap={ + ["\x00"]="00",["\x01"]="01",["\x02"]="02",["\x03"]="03",["\x04"]="04",["\x05"]="05",["\x06"]="06",["\x07"]="07",["\x08"]="08",["\x09"]="09",["\x0A"]="0.",["\x0B"]="0E",["\x0C"]="0E-",["\x0D"]="0",["\x0E"]="0-",["\x0F"]="0", + ["\x10"]="10",["\x11"]="11",["\x12"]="12",["\x13"]="13",["\x14"]="14",["\x15"]="15",["\x16"]="16",["\x17"]="17",["\x18"]="18",["\x19"]="19",["\x1A"]="1.",["\x1B"]="1E",["\x1C"]="1E-",["\x1D"]="1",["\x1E"]="1-",["\x1F"]="1", + ["\x20"]="20",["\x21"]="21",["\x22"]="22",["\x23"]="23",["\x24"]="24",["\x25"]="25",["\x26"]="26",["\x27"]="27",["\x28"]="28",["\x29"]="29",["\x2A"]="2.",["\x2B"]="2E",["\x2C"]="2E-",["\x2D"]="2",["\x2E"]="2-",["\x2F"]="2", + ["\x30"]="30",["\x31"]="31",["\x32"]="32",["\x33"]="33",["\x34"]="34",["\x35"]="35",["\x36"]="36",["\x37"]="37",["\x38"]="38",["\x39"]="39",["\x3A"]="3.",["\x3B"]="3E",["\x3C"]="3E-",["\x3D"]="3",["\x3E"]="3-",["\x3F"]="3", + ["\x40"]="40",["\x41"]="41",["\x42"]="42",["\x43"]="43",["\x44"]="44",["\x45"]="45",["\x46"]="46",["\x47"]="47",["\x48"]="48",["\x49"]="49",["\x4A"]="4.",["\x4B"]="4E",["\x4C"]="4E-",["\x4D"]="4",["\x4E"]="4-",["\x4F"]="4", + ["\x50"]="50",["\x51"]="51",["\x52"]="52",["\x53"]="53",["\x54"]="54",["\x55"]="55",["\x56"]="56",["\x57"]="57",["\x58"]="58",["\x59"]="59",["\x5A"]="5.",["\x5B"]="5E",["\x5C"]="5E-",["\x5D"]="5",["\x5E"]="5-",["\x5F"]="5", + ["\x60"]="60",["\x61"]="61",["\x62"]="62",["\x63"]="63",["\x64"]="64",["\x65"]="65",["\x66"]="66",["\x67"]="67",["\x68"]="68",["\x69"]="69",["\x6A"]="6.",["\x6B"]="6E",["\x6C"]="6E-",["\x6D"]="6",["\x6E"]="6-",["\x6F"]="6", + ["\x70"]="70",["\x71"]="71",["\x72"]="72",["\x73"]="73",["\x74"]="74",["\x75"]="75",["\x76"]="76",["\x77"]="77",["\x78"]="78",["\x79"]="79",["\x7A"]="7.",["\x7B"]="7E",["\x7C"]="7E-",["\x7D"]="7",["\x7E"]="7-",["\x7F"]="7", + ["\x80"]="80",["\x81"]="81",["\x82"]="82",["\x83"]="83",["\x84"]="84",["\x85"]="85",["\x86"]="86",["\x87"]="87",["\x88"]="88",["\x89"]="89",["\x8A"]="8.",["\x8B"]="8E",["\x8C"]="8E-",["\x8D"]="8",["\x8E"]="8-",["\x8F"]="8", + ["\x90"]="90",["\x91"]="91",["\x92"]="92",["\x93"]="93",["\x94"]="94",["\x95"]="95",["\x96"]="96",["\x97"]="97",["\x98"]="98",["\x99"]="99",["\x9A"]="9.",["\x9B"]="9E",["\x9C"]="9E-",["\x9D"]="9",["\x9E"]="9-",["\x9F"]="9", + ["\xA0"]=".0",["\xA1"]=".1",["\xA2"]=".2",["\xA3"]=".3",["\xA4"]=".4",["\xA5"]=".5",["\xA6"]=".6",["\xA7"]=".7",["\xA8"]=".8",["\xA9"]=".9",["\xAA"]="..",["\xAB"]=".E",["\xAC"]=".E-",["\xAD"]=".",["\xAE"]=".-",["\xAF"]=".", + ["\xB0"]="E0",["\xB1"]="E1",["\xB2"]="E2",["\xB3"]="E3",["\xB4"]="E4",["\xB5"]="E5",["\xB6"]="E6",["\xB7"]="E7",["\xB8"]="E8",["\xB9"]="E9",["\xBA"]="E.",["\xBB"]="EE",["\xBC"]="EE-",["\xBD"]="E",["\xBE"]="E-",["\xBF"]="E", + ["\xC0"]="E-0",["\xC1"]="E-1",["\xC2"]="E-2",["\xC3"]="E-3",["\xC4"]="E-4",["\xC5"]="E-5",["\xC6"]="E-6",["\xC7"]="E-7",["\xC8"]="E-8",["\xC9"]="E-9",["\xCA"]="E-.",["\xCB"]="E-E",["\xCC"]="E-E-",["\xCD"]="E-",["\xCE"]="E--",["\xCF"]="E-", + ["\xD0"]="-0",["\xD1"]="-1",["\xD2"]="-2",["\xD3"]="-3",["\xD4"]="-4",["\xD5"]="-5",["\xD6"]="-6",["\xD7"]="-7",["\xD8"]="-8",["\xD9"]="-9",["\xDA"]="-.",["\xDB"]="-E",["\xDC"]="-E-",["\xDD"]="-",["\xDE"]="--",["\xDF"]="-", + } + local p_last=S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")+R("\xF0\xFF") + local p_nibbles=P("\30")*Cs(((1-p_last)/remap)^0*(P(1)/remap))/function(n) + top=top+1 + stack[top]=tonumber(n) or 0 + end + local p_byte=C(R("\32\246"))/function(b0) + top=top+1 + stack[top]=byte(b0)-139 + end + local p_positive=C(R("\247\250"))*C(1)/function(b0,b1) + top=top+1 + stack[top]=(byte(b0)-247)*256+byte(b1)+108 + end + local p_negative=C(R("\251\254"))*C(1)/function(b0,b1) + top=top+1 + stack[top]=-(byte(b0)-251)*256-byte(b1)-108 + end + local p_short=P("\28")*C(1)*C(1)/function(b1,b2) + top=top+1 + local n=0x100*byte(b1)+byte(b2) + if n>=0x8000 then + stack[top]=n-0xFFFF-1 + else + stack[top]=n + end + end + local p_long=P("\29")*C(1)*C(1)*C(1)*C(1)/function(b1,b2,b3,b4) + top=top+1 + local n=0x1000000*byte(b1)+0x10000*byte(b2)+0x100*byte(b3)+byte(b4) + if n>=0x8000000 then + stack[top]=n-0xFFFFFFFF-1 + else + stack[top]=n + end + end + local p_unsupported=P(1)/function(detail) + top=0 + end + 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,what) + stack={} + strings=data.strings + for i=1,#dictionaries do + top=0 + result=what=="cff" and { + monospaced=false, + italicangle=0, + underlineposition=-100, + underlinethickness=50, + painttype=0, + charstringtype=2, + fontmatrix={ 0.001,0,0,0.001,0,0 }, + fontbbox={ 0,0,0,0 }, + strokewidth=0, + charset=0, + encoding=0, + cid={ + fontversion=0, + fontrevision=0, + fonttype=0, + count=8720, + } + } or { + charstringtype=2, + charset=0, + vstore=0, + cid={ + }, + } + lpegmatch(p_dictionary,dictionaries[i]) + dictionaries[i]=result + end + result={} + top=0 + stack={} + end + parseprivates=function(data,dictionaries) + stack={} + strings=data.strings + for i=1,#dictionaries do + local private=dictionaries[i].private + if private and private.data then + top=0 + result={ + forcebold=false, + languagegroup=0, + expansionfactor=0.06, + initialrandomseed=0, + subroutines=0, + defaultwidthx=0, + nominalwidthx=0, + cid={ + }, + } + lpegmatch(p_dictionary,private.data) + private.data=result + end + end + result={} + top=0 + stack={} + end + 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) + end + local function showvalue(where,value,showstack) + if showstack then + report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top) + else + report("%w%-10s : %s",depth*2,where,tostring(value)) + end + end + local function xymoveto() + if keepcurve then + r=r+1 + result[r]={ x,y,"m" } + end + if checked then + 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 + xmax=x + ymax=y + checked=true + end + end + 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>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 + xmax=x + ymax=y + checked=true + end + end + 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>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 + xmax=x1 + ymax=y1 + checked=true + 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 not width then + if top>2 then + width=stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width=true + end + end + if trace_charstrings then + showstate("rmoveto") + end + x=x+stack[top-1] + y=y+stack[top] + top=0 + xymoveto() + end + local function hmoveto() + if not width then + if top>1 then + width=stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width=true + end + end + if trace_charstrings then + showstate("hmoveto") + end + x=x+stack[top] + top=0 + xmoveto() + end + local function vmoveto() + if not width then + if top>1 then + width=stack[1] + if trace_charstrings then + showvalue("backtrack width",width) + end + else + width=true + end + end + if trace_charstrings then + showstate("vmoveto") + end + y=y+stack[top] + top=0 + ymoveto() + end + local function rlineto() + if trace_charstrings then + showstate("rlineto") + end + for i=1,top,2 do + x=x+stack[i] + y=y+stack[i+1] + xylineto() + end + top=0 + end + local function hlineto() + if trace_charstrings then + showstate("hlineto") + end + 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 + 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 + showstate("rrcurveto") + end + for i=1,top,6 do + local ax=x+stack[i] + 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] + xycurveto(ax,ay,bx,by,x,y) + end + top=0 + end + local function hhcurveto() + if trace_charstrings then + showstate("hhcurveto") + end + local s=1 + if top%2~=0 then + y=y+stack[1] + s=2 + end + for i=s,top,4 do + 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] + y=by + xycurveto(ax,ay,bx,by,x,y) + end + top=0 + end + local function vvcurveto() + if trace_charstrings then + showstate("vvcurveto") + end + local s=1 + local d=0 + if top%2~=0 then + d=stack[1] + s=2 + end + for i=s,top,4 do + local ax=x+d + local ay=y+stack[i] + local bx=ax+stack[i+1] + local by=ay+stack[i+2] + x=bx + y=by+stack[i+3] + 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 hvcurveto() + if trace_charstrings then + showstate("hvcurveto") + end + xxcurveto(true) + end + local function vhcurveto() + if trace_charstrings then + showstate("vhcurveto") + end + xxcurveto(false) + end + local function rcurveline() + if trace_charstrings then + showstate("rcurveline") + end + for i=1,top-2,6 do + local ax=x+stack[i] + 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] + xycurveto(ax,ay,bx,by,x,y) + end + x=x+stack[top-1] + y=y+stack[top] + xylineto() + top=0 + end + local function rlinecurve() + if trace_charstrings then + showstate("rlinecurve") + end + if top>6 then + for i=1,top-6,2 do + x=x+stack[i] + y=y+stack[i+1] + xylineto() + end + end + local ax=x+stack[top-5] + local ay=y+stack[top-4] + local bx=ax+stack[top-3] + local by=ay+stack[top-2] + x=bx+stack[top-1] + y=by+stack[top] + xycurveto(ax,ay,bx,by,x,y) + top=0 + end + local function flex() + if trace_charstrings then + showstate("flex") + end + local ax=x+stack[1] + local ay=y+stack[2] + local bx=ax+stack[3] + local by=ay+stack[4] + local cx=bx+stack[5] + local cy=by+stack[6] + 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] + 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 ay=y + local bx=ax+stack[2] + local by=ay+stack[3] + local cx=bx+stack[4] + local cy=by + 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] + xycurveto(dx,dy,ex,ey,x,y) + top=0 + end + local function hflex1() + if trace_charstrings then + showstate("hflex1") + end + local ax=x+stack[1] + local ay=y+stack[2] + local bx=ax+stack[3] + local by=ay+stack[4] + local cx=bx+stack[5] + local cy=by + 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] + xycurveto(dx,dy,ex,ey,x,y) + top=0 + end + local function flex1() + if trace_charstrings then + showstate("flex1") + end + local ax=x+stack[1] + local ay=y+stack[2] + local bx=ax+stack[3] + local by=ay+stack[4] + local cx=bx+stack[5] + local cy=by+stack[6] + 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] + if abs(ex-x)>abs(ey-y) then + x=ex+stack[11] + else + y=ey+stack[11] + end + xycurveto(dx,dy,ex,ey,x,y) + top=0 + end + local function getstem() + if top==0 then + elseif top%2~=0 then + if width then + remove(stack,1) + else + width=remove(stack,1) + if trace_charstrings then + showvalue("width",width) + end + end + top=top-1 + end + if trace_charstrings then + showstate("stem") + end + stems=stems+idiv(top,2) + top=0 + end + local function getmask() + if top==0 then + elseif top%2~=0 then + if width then + remove(stack,1) + else + width=remove(stack,1) + if trace_charstrings then + showvalue("width",width) + end + end + top=top-1 + end + if trace_charstrings then + showstate(operator==19 and "hintmark" or "cntrmask") + end + stems=stems+idiv(top,2) + top=0 + if stems==0 then + elseif stems<=8 then + return 1 + else + return idiv(stems+7,8) + end + end + local function unsupported(t) + if trace_charstrings then + showstate("unsupported "..t) + end + top=0 + end + local function unsupportedsub(t) + if trace_charstrings then + showstate("unsupported sub "..t) + end + top=0 + end + local function getstem3() + if trace_charstrings then + showstate("stem3") + end + top=0 + end + local function divide() + if version==1 then + local d=stack[top] + top=top-1 + stack[top]=stack[top]/d + end + end + local function closepath() + if version==1 then + if trace_charstrings then + showstate("closepath") + end + end + top=0 + end + local function hsbw() + if version==1 then + if trace_charstrings then + showstate("hsbw") + end + width=stack[top] + end + top=0 + end + local function seac() + if version==1 then + if trace_charstrings then + showstate("seac") + end + end + top=0 + end + local function sbw() + if version==1 then + if trace_charstrings then + showstate("sbw") + end + width=stack[top-1] + end + top=0 + end + local function callothersubr() + if version==1 then + if trace_charstrings then + showstate("callothersubr (unsupported)") + end + end + top=0 + end + local function pop() + if version==1 then + if trace_charstrings then + showstate("pop (unsupported)") + end + top=top+1 + stack[top]=0 + else + top=0 + end + end + local function setcurrentpoint() + if version==1 then + if trace_charstrings then + showstate("pop (unsupported)") + end + x=x+stack[top-1] + y=y+stack[top] + 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, + getstem, + vmoveto, + rlineto, + hlineto, + vlineto, + rrcurveto, + unsupported, + unsupported, + unsupported, + unsupported, + hsbw, + unsupported, + setvsindex, + blend, + unsupported, + getstem, + getmask, + getmask, + rmoveto, + hmoveto, + getstem, + rcurveline, + rlinecurve, + vvcurveto, + hhcurveto, + unsupported, + unsupported, + vhcurveto, + hvcurveto, + } + local subactions={ + [000]=dotsection, + [001]=getstem3, + [002]=getstem3, + [006]=seac, + [007]=sbw, + [012]=divide, + [016]=callothersubr, + [017]=pop, + [033]=setcurrentpoint, + [034]=hflex, + [035]=flex, + [036]=hflex1, + [037]=flex1, + } + local chars=setmetatableindex(function (t,k) + local v=char(k) + t[k]=v + return v + end) + local c_endchar=chars[14] + local encode={} + setmetatableindex(encode,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]=chars[i+139] + end + for i=108,1131 do + local v=0xF700+i-108 + t[i]=char(extract(v,8,8),extract(v,0,8)) + end + for i=1132,2048 do + t[i]=char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + end + setmetatableindex(encode,function(t,k) + local r=round(k) + local v=rawget(t,r) + if v then + return v + end + local v1=floor(k) + local v2=floor((k-v1)*0x10000) + return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8)) + end) + return t[i] + end) + readers.cffencoder=encode + local function p_setvsindex() + local vsindex=stack[top] + updateregions(vsindex) + top=top-1 + end + local function p_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 + local function p_getstem() + local n=0 + if top%2~=0 then + n=1 + end + if top>n then + stems=stems+idiv(top-n,2) + end + end + local function p_getmask() + local n=0 + if top%2~=0 then + n=1 + end + if top>n then + stems=stems+idiv(top-n,2) + end + if stems==0 then + return 0 + elseif stems<=8 then + return 1 + else + return idiv(stems+7,8) + end + end + local process + local function call(scope,list,bias) + depth=depth+1 + if top==0 then + showstate(formatters["unknown %s call"](scope)) + top=0 + else + local index=stack[top]+bias + top=top-1 + if trace_charstrings then + showvalue(scope,index,true) + end + local tab=list[index] + if tab then + process(tab) + else + showstate(formatters["unknown %s call %i"](scope,index)) + top=0 + end + end + depth=depth-1 + end + local justpass=false + process=function(tab) + local i=1 + local n=#tab + while i<=n do + local t=tab[i] + if t>=32 then + top=top+1 + 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-0x10000 + else + stack[top]=n + end + i=i+3 + elseif t==11 then + if trace_charstrings then + showstate("return") + end + return + elseif t==10 then + call("local",locals,localbias) + i=i+1 + elseif t==14 then + if width then + elseif top>0 then + width=stack[1] + if trace_charstrings then + showvalue("width",width) + end + else + width=true + end + if trace_charstrings then + showstate("endchar") + end + return + elseif t==29 then + call("global",globals,globalbias) + i=i+1 + elseif t==12 then + i=i+1 + local t=tab[i] + if justpass then + if t>=34 or t<=37 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + r=r+1;result[r]=chars[12] + r=r+1;result[r]=chars[t] + top=0 + else + local a=subactions[t] + if a then + a(t) + else + top=0 + end + end + else + local a=subactions[t] + if a then + a(t) + else + if trace_charstrings then + showvalue("<subaction>",t) + end + top=0 + end + end + i=i+1 + elseif justpass then + if t==15 then + p_setvsindex() + i=i+1 + elseif t==16 then + local s=p_blend() or 0 + i=i+s+1 + elseif t==1 or t==3 or t==18 or operation==23 then + p_getstem() +if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] +else + top=0 +end + i=i+1 + elseif t==19 or t==20 then + local s=p_getmask() or 0 +if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] + for j=1,s do + i=i+1 + r=r+1;result[r]=chars[tab[i]] + end +else + i=i+s + top=0 +end + i=i+1 + elseif t==9 then + top=0 + i=i+1 + elseif t==13 then + local s=hsbw() or 0 + i=i+s+1 + else + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] + i=i+1 + end + else + local a=actions[t] + if a then + local s=a(t) + if s then + i=i+s+1 + else + i=i+1 + end + else + if trace_charstrings then + showvalue("<action>",t) + end + top=0 + i=i+1 + end + end + end + end + local function setbias(globals,locals) + local g=#globals + local l=#locals + return + ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, + ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 + end + local function processshape(tab,index) + if not tab then + glyphs[index]={ + boundingbox={ 0,0,0,0 }, + width=0, + name=charset and charset[index] or nil, + } + return + end + tab=bytetable(tab) + 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 + if regions then + updateregions(vsindex) + 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 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 + end + 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("boundingbox: % t",boundingbox) + end + end + 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 + 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) + if charstrings then + startparsing(fontdata,data,streams) + for index=1,#charstrings do + processshape(charstrings[index],index-1) + end + stopparsing(fontdata,data) + else + report("no charstrings") + end + return glyphs + end + parsecharstring=function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams) + 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 {} + justpass=streams==true + 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]=readbytetable(f,routines[i]) + end + data.routines=routines +end +local function readencodings(f,data) + data.encodings={} +end +local function readcharsets(f,data,dictionary) + local header=data.header + local strings=data.strings + local nofglyphs=data.nofglyphs + local charsetoffset=dictionary.charset + if charsetoffset and charsetoffset~=0 then + setposition(f,header.offset+charsetoffset) + local format=readbyte(f) + local charset={ [0]=".notdef" } + dictionary.charset=charset + if format==0 then + for i=1,nofglyphs do + charset[i]=strings[readushort(f)] + end + elseif format==1 or format==2 then + local readcount=format==1 and readbyte or readushort + local i=1 + while i<=nofglyphs do + local sid=readushort(f) + local n=readcount(f) + for s=sid,sid+n do + charset[i]=strings[s] + i=i+1 + if i>nofglyphs then + break + end + end + end + else + report("cff parser: unsupported charset format %a",format) + end + else + dictionary.nocharset=true + dictionary.charset=nil + end +end +local function readprivates(f,data) + local header=data.header + local dictionaries=data.dictionaries + local private=dictionaries[1].private + if private then + setposition(f,header.offset+private.offset) + private.data=readstring(f,private.size) + end +end +local function readlocals(f,data,dictionary) + local header=data.header + local private=dictionary.private + if private then + local subroutineoffset=private.data.subroutines + if subroutineoffset~=0 then + setposition(f,header.offset+private.offset+subroutineoffset) + local subroutines=readlengths(f) + for i=1,#subroutines do + subroutines[i]=readbytetable(f,subroutines[i]) + end + dictionary.subroutines=subroutines + private.data.subroutines=nil + else + dictionary.subroutines={} + end + else + dictionary.subroutines={} + end +end +local function readcharstrings(f,data,what) + local header=data.header + local dictionaries=data.dictionaries + local dictionary=dictionaries[1] + local stringtype=dictionary.charstringtype + local offset=dictionary.charstrings + if type(offset)~="number" then + elseif stringtype==2 then + setposition(f,header.offset+offset) + local charstrings=readlengths(f,what=="cff2") + local nofglyphs=#charstrings + for i=1,nofglyphs do + charstrings[i]=readstring(f,charstrings[i]) + end + data.nofglyphs=nofglyphs + dictionary.charstrings=charstrings + else + report("unsupported charstr type %i",stringtype) + data.nofglyphs=0 + dictionary.charstrings={} + end +end +local function readcidprivates(f,data) + local header=data.header + local dictionaries=data.dictionaries[1].cid.dictionaries + for i=1,#dictionaries do + local dictionary=dictionaries[i] + local private=dictionary.private + if private then + setposition(f,header.offset+private.offset) + private.data=readstring(f,private.size) + end + end + parseprivates(data,dictionaries) +end +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,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) + startparsing(fontdata,data,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) + stopparsing(fontdata,data) +end +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,version) + if version~="cff2" then + readencodings(f,data) + end + local charstrings=dictionary.charstrings + local fdindex={} + local nofglyphs=data.nofglyphs + local maxindex=-1 + setposition(f,header.offset+cidselect) + local format=readbyte(f) + if format==1 then + for i=0,nofglyphs do + local index=readbyte(f) + fdindex[i]=index + if index>maxindex then + maxindex=index + end + end + elseif format==3 then + local nofranges=readushort(f) + local first=readushort(f) + local index=readbyte(f) + while true do + local last=readushort(f) + if index>maxindex then + maxindex=index + end + for i=first,last do + fdindex[i]=index + end + if last>=nofglyphs then + break + else + first=last+1 + index=readbyte(f) + end + end + else + end + if maxindex>=0 then + local cidarray=cid.fdarray + if cidarray then + setposition(f,header.offset+cidarray) + local dictionaries=readlengths(f) + for i=1,#dictionaries do + dictionaries[i]=readstring(f,dictionaries[i]) + end + parsedictionaries(data,dictionaries) + cid.dictionaries=dictionaries + readcidprivates(f,data) + for i=1,#dictionaries do + readlocals(f,data,dictionaries[i]) + end + startparsing(fontdata,data,streams) + for i=1,#charstrings do + parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version,streams) + end + stopparsing(fontdata,data) + else + report("no cid array") + end + end +end +local gotodatatable=readers.helpers.gotodatatable +local function cleanup(data,dictionaries) +end +function readers.cff(f,fontdata,specification) + local tableoffset=gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs) + 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 + local cffinfo={ + familyname=dic.familyname, + fullname=dic.fullname, + boundingbox=dic.boundingbox, + weight=dic.weight, + italicangle=dic.italicangle, + underlineposition=dic.underlineposition, + underlinethickness=dic.underlinethickness, + defaultwidth=dic.defaultwidthx, + nominalwidth=dic.nominalwidthx, + monospaced=dic.monospaced, + } + fontdata.cidinfo=cid and { + registry=cid.registry, + ordering=cid.ordering, + supplement=cid.supplement, + } + fontdata.cffinfo=cffinfo + local all=specification.shapes or specification.streams or false + if specification.glyphs or all then + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams) + else + readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams) + end + end + local private=dic.private + if private then + local data=private.data + if type(data)=="table" then + cffinfo.defaultwidth=data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth=data.nominalwidthx or cffinfo.nominalwidth + cffinfo.bluevalues=data.bluevalues + cffinfo.otherblues=data.otherblues + cffinfo.familyblues=data.familyblues + cffinfo.familyotherblues=data.familyotherblues + cffinfo.bluescale=data.bluescale + cffinfo.blueshift=data.blueshift + cffinfo.bluefuzz=data.bluefuzz + cffinfo.stdhw=data.stdhw + cffinfo.stdvw=data.stdvw + 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 specification.streams 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=0, + } + 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-2019-05-18.lua scope for “font-cff”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ttf” f2d53377b264d59368703e659a7bc228] --- + +if not modules then modules={} end modules ['font-ttf']={ + 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,type,unpack=next,type,unpack +local band,rshift=bit32.band,bit32.rshift +local sqrt,round=math.sqrt,math.round +local char,rep=string.char,string.rep +local concat=table.concat +local idiv=number.idiv +local setmetatableindex=table.setmetatableindex +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 +local readushort=streamreader.readcardinal2 +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,subpoints=merge(subindex,subshape,subcomponents) + end + end + if subpoints then + local matrix=component.matrix + local xscale=matrix[1] + local xrotate=matrix[2] + local yrotate=matrix[3] + local yscale=matrix[4] + local xoffset=matrix[5] + local yoffset=matrix[6] + local count=#subpoints + if xscale==1 and yscale==1 and xrotate==0 and yrotate==0 then + for i=1,count do + local p=subpoints[i] + nofpoints=nofpoints+1 + points[nofpoints]={ + p[1]+xoffset, + p[2]+yoffset, + p[3] + } + end + else + for i=1,count 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 + end + local subcount=#subcontours + if subcount==1 then + nofcontours=nofcontours+1 + contours[nofcontours]=offset+subcontours[1] + else + for i=1,#subcontours do + nofcontours=nofcontours+1 + contours[nofcontours]=offset+subcontours[i] + end + end + offset=offset+count + 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,points + end + for index=0,#glyphs-1 do + local shape=shapes[index] + if shape then + local components=shape.components + if components then + merge(index,shape,components) + end + end + end +end +local function readnothing(f) + return { + type="nothing", + } +end +local function curveto(m_x,m_y,l_x,l_y,r_x,r_y) + 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" +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 quadratic=false +local function contours2outlines_normal(glyphs,shapes) + for index=0,#glyphs-1 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={} + local nofsegments=0 + glyph.segments=segments + if nofcontours>0 then + local px=0 + local py=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 + 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 + 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=first_pt[1] + local y=first_pt[2] + if not done then + xmin=x + ymin=y + xmax=x + ymax=y + done=true + end + nofsegments=nofsegments+1 + segments[nofsegments]={ x,y,"m" } + if not quadratic then + px=x + py=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=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=current_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=false + else + local x2=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=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 + previous_pt=current_pt + end + if first_pt==last_pt then + else + nofsegments=nofsegments+1 + local x2=first_pt[1] + local y2=first_pt[2] + if not control_pt then + segments[nofsegments]={ x2,y2,"l" } + elseif quadratic then + local x1=control_pt[1] + local y1=control_pt[2] + segments[nofsegments]={ x1,y1,x2,y2,"q" } + else + local x1=control_pt[1] + local y1=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 + end + end + end + first=last+1 + end + end + end + end + end +end +local function contours2outlines_shaped(glyphs,shapes,keepcurve) + for index=0,#glyphs-1 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=first_pt[1] + local y=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 + segments[nofsegments]={ x,y,"m" } + end + if not quadratic then + px=x + py=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=current_pt[1] + local y=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=x + py=y + end + else + control_pt=current_pt + end + elseif current_on then + local x1=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=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=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=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=control_pt[1] + local y1=control_pt[2] + local x2=first_pt[1] + local y2=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 + 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 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 + end + end + 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 chars=setmetatableindex(function(t,k) + for i=0,255 do local v=char(i) t[i]=v end return t[k] +end) +local function repackpoints(glyphs,shapes) + local noboundingbox={ 0,0,0,0 } + local result={} + local xpoints={} + local ypoints={} + for index=0,#glyphs-1 do + local shape=shapes[index] + if shape then + local r=0 + local glyph=glyphs[index] + 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 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) + x=x+1 + if dx<-255 or dx>255 then + xpoints[x]=toshort(dx) + elseif dx<0 then + fl=fl+0x02 + xpoints[x]=chars[-dx] + elseif dx>0 then + fl=fl+0x12 + xpoints[x]=chars[dx] + else + fl=fl+0x02 + xpoints[x]=c_zero + end + end + if py==currenty then + fl=fl+0x20 + else + local dy=round(py-currenty) + y=y+1 + if dy<-255 or dy>255 then + ypoints[y]=toshort(dy) + elseif dy<0 then + fl=fl+0x04 + ypoints[y]=chars[-dy] + elseif dy>0 then + fl=fl+0x24 + ypoints[y]=chars[dy] + else + fl=fl+0x04 + 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]=chars[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]=chars[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,"",1,x) + r=r+1 result[r]=concat(ypoints,"",1,y) + end + local stream=concat(result,"",1,r) + local length=#stream + local padding=idiv(length+3,4)*4-length + if padding>0 then + if padding==1 then + padding="\0" + elseif padding==2 then + padding="\0\0" + else + padding="\0\0\0" + end + padding=stream..padding + end + glyph.stream=stream + end + end +end +local flags={} +local function readglyph(f,nofcontours) + local points={} + local contours={} + for i=1,nofcontours do + contours[i]=readshort(f)+1 + end + 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 band(flag,0x08)~=0 then + local n=readbyte(f) + if n==1 then + i=i+1 + flags[i]=flag + else + for j=1,n do + i=i+1 + flags[i]=flag + end + end + end + i=i+1 + end + local x=0 + for i=1,nofpoints do + local flag=flags[i] + if band(flag,0x02)~=0 then + if band(flag,0x10)~=0 then + x=x+readbyte(f) + else + x=x-readbyte(f) + end + elseif band(flag,0x10)~=0 then + else + x=x+readshort(f) + end + points[i]={ x,0,band(flag,0x01)~=0 } + end + local y=0 + for i=1,nofpoints do + local flag=flags[i] + if band(flag,0x04)~=0 then + if band(flag,0x20)~=0 then + y=y+readbyte(f) + else + y=y-readbyte(f) + end + elseif band(flag,0x20)~=0 then + else + y=y+readshort(f) + end + points[i][2]=y + end + return { + type="glyph", + points=points, + contours=contours, + nofpoints=nofpoints, + } +end +local function readcomposite(f) + local components={} + local nofcomponents=0 + local instructions=false + while true do + local flags=readushort(f) + local index=readushort(f) + local f_xyarg=band(flags,0x0002)~=0 + local f_offset=band(flags,0x0800)~=0 + local xscale=1 + local xrotate=0 + local yrotate=0 + local yscale=1 + local xoffset=0 + local yoffset=0 + local base=false + local reference=false + if f_xyarg then + if band(flags,0x0001)~=0 then + xoffset=readshort(f) + yoffset=readshort(f) + else + xoffset=readchar(f) + yoffset=readchar(f) + end + else + if band(flags,0x0001)~=0 then + base=readshort(f) + reference=readshort(f) + else + base=readchar(f) + reference=readchar(f) + end + end + 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 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 band(flags,0x0080)~=0 then + xscale=read2dot14(f) + xrotate=read2dot14(f) + yrotate=read2dot14(f) + yscale=read2dot14(f) + if f_xyarg and f_offset then + xoffset=xoffset*sqrt(xscale^2+xrotate^2) + yoffset=yoffset*sqrt(yrotate^2+yscale^2) + end + end + nofcomponents=nofcomponents+1 + components[nofcomponents]={ + index=index, + usemine=band(flags,0x0200)~=0, + round=band(flags,0x0006)~=0, + base=base, + reference=reference, + matrix={ xscale,xrotate,yrotate,yscale,xoffset,yoffset }, + } + if band(flags,0x0100)~=0 then + instructions=true + end + if band(flags,0x0020)==0 then + break + end + end + return { + type="composite", + components=components, + } +end +function readers.loca(f,fontdata,specification) + if specification.glyphs then + local datatable=fontdata.tables.loca + if datatable then + local offset=fontdata.tables.glyf.offset + local format=fontdata.fontheader.indextolocformat + local profile=fontdata.maximumprofile + local nofglyphs=profile and profile.nofglyphs + local locations={} + setposition(f,datatable.offset) + if format==1 then + if not nofglyphs then + nofglyphs=idiv(datatable.length,4)-1 + end + for i=0,nofglyphs do + locations[i]=offset+readulong(f) + end + fontdata.nofglyphs=nofglyphs + else + if not nofglyphs then + nofglyphs=idiv(datatable.length,2)-1 + end + for i=0,nofglyphs do + locations[i]=offset+readushort(f)*2 + end + end + fontdata.nofglyphs=nofglyphs + fontdata.locations=locations + end + end +end +function readers.glyf(f,fontdata,specification) + 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 or specification.streams + for index=0,nofglyphs-1 do + local location=locations[index] + local length=locations[index+1]-location + 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 length>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) + elseif nofcontours>0 then + shapes[index]=readglyph(f,nofcontours) + else + shapes[index]=readcomposite(f,nofcontours) + end + else + if loadshapes then + shapes[index]=readnothing(f) + 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 + if specification.streams then + repackpoints(glyphs,shapes) + else + contours2outlines_normal(glyphs,shapes) + end + elseif specification.streams then + repackpoints(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 + if index+1>#tuples then + report("error, bad tuple index",index) + end + peak=tuples[index+1] + end + 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 + end + 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-2019-05-18.lua scope for “font-ttf”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-dsp” b5bf2f1c198e027a0d4ededcdf3947b4] --- + +if not modules then modules={} end modules ['font-dsp']={ + 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,type,tonumber=next,type,tonumber +local band=bit32.band +local extract=bit32.extract +local bor=bit32.bor +local lshift=bit32.lshift +local rshift=bit32.rshift +local gsub=string.gsub +local lower=string.lower +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 readuinteger=streamreader.readcardinal1 +local readushort=streamreader.readcardinal2 +local readulong=streamreader.readcardinal4 +local readinteger=streamreader.readinteger1 +local readshort=streamreader.readinteger2 +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 + readuinteger=streamreader.readcardinal1 + 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", + "ligature", + "mark", + "component", +} +local gsubtypes={ + "single", + "multiple", + "alternate", + "ligature", + "context", + "chainedcontext", + "extension", + "reversechainedcontextsingle", +} +local gpostypes={ + "single", + "pair", + "cursive", + "marktobase", + "marktoligature", + "marktomark", + "context", + "chainedcontext", + "extension", +} +local chaindirections={ + context=0, + 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", + multiple="gsub_multiple", + alternate="gsub_alternate", + ligature="gsub_ligature", + context="gsub_context", + chainedcontext="gsub_contextchain", + reversechainedcontextsingle="gsub_reversecontextchain", + }, + gpos={ + single="gpos_single", + pair="gpos_pair", + cursive="gpos_cursive", + marktobase="gpos_mark2base", + marktoligature="gpos_mark2ligature", + marktomark="gpos_mark2mark", + context="gpos_context", + chainedcontext="gpos_contextchain", + } +} +local lookupflags=setmetatableindex(function(t,k) + local v={ + 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) + if coverageformat==1 then + local nofcoverage=readushort(f) + if simple then + 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) + local lastindex=readushort(f) + local coverindex=readushort(f) + if simple then + for i=firstindex,lastindex do + coverage[n]=i + n=n+1 + end + else + for i=firstindex,lastindex do + coverage[i]=n + n=n+1 + end + end + end + return coverage + else + report("unknown coverage format %a ",coverageformat) + return {} + end +end +local function readclassdef(f,offset,preset) + setposition(f,offset) + local classdefformat=readushort(f) + local classdef={} + if type(preset)=="number" then + for k=0,preset-1 do + classdef[k]=1 + end + end + if classdefformat==1 then + local index=readushort(f) + local nofclassdef=readushort(f) + for i=1,nofclassdef do + classdef[index]=readushort(f)+1 + index=index+1 + end + elseif classdefformat==2 then + local nofranges=readushort(f) + local n=0 + for i=1,nofranges do + local firstindex=readushort(f) + local lastindex=readushort(f) + local class=readushort(f)+1 + for i=firstindex,lastindex do + classdef[i]=class + end + end + else + report("unknown classdef format %a ",classdefformat) + end + if type(preset)=="table" then + for k in next,preset do + if not classdef[k] then + classdef[k]=1 + end + end + end + return classdef +end +local function classtocoverage(defs) + if defs then + local list={} + for index,class in next,defs do + local c=list[class] + if c then + c[#c+1]=index + else + list[class]={ index } + end + end + return list + end +end +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 false + end + 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,getdelta) + if not offset or offset==0 then + return nil + end + setposition(f,offset) + 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 +end +local function readfirst(f,offset) + if offset then + setposition(f,offset) + end + return { readushort(f) } +end +function readarray(f,offset) + if offset then + setposition(f,offset) + end + local n=readushort(f) + if n==1 then + return { readushort(f) },1 + elseif n>0 then + return readcardinaltable(f,n,ushort),n + end +end +local function readcoveragearray(f,offset,t,simple) + if not t then + return nil + end + local n=#t + if n==0 then + return nil + end + for i=1,n do + t[i]=readcoverage(f,offset+t[i],simple) + end + return t +end +local function covered(subset,all) + local used,u + for i=1,#subset do + local s=subset[i] + if all[s] then + if used then + u=u+1 + used[u]=s + else + u=1 + used={ s } + end + end + end + return used +end +local function readlookuparray(f,noflookups,nofcurrent) + local lookups={} + if noflookups>0 then + local length=0 + for i=1,noflookups do + local index=readushort(f)+1 + if index>length then + length=index + end + 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 + lookups[index]=false + end + end + end + return lookups +end +local function unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local coverage=readushort(f) + local subclasssets=readarray(f) + local rules={} + if subclasssets then + coverage=readcoverage(f,tableoffset+coverage,true) + for i=1,#subclasssets do + local offset=subclasssets[i] + if offset>0 then + local firstcoverage=coverage[i] + local rulesoffset=tableoffset+offset + local subclassrules=readarray(f,rulesoffset) + for rule=1,#subclassrules do + setposition(f,rulesoffset+subclassrules[rule]) + local nofcurrent=readushort(f) + local noflookups=readushort(f) + local current={ { firstcoverage } } + for i=2,nofcurrent do + current[i]={ readushort(f) } + end + local lookups=readlookuparray(f,noflookups,nofcurrent) + rules[#rules+1]={ + current=current, + lookups=lookups + } + end + end + end + else + report("empty subclassset in %a subtype %i","unchainedcontext",subtype) + end + return { + format="glyphs", + rules=rules, + } + elseif subtype==2 then + local coverage=readushort(f) + local currentclassdef=readushort(f) + local subclasssets=readarray(f) + local rules={} + if subclasssets then + coverage=readcoverage(f,tableoffset+coverage) + currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) + local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) + for class=1,#subclasssets do + local offset=subclasssets[class] + if offset>0 then + local firstcoverage=currentclasses[class] + if firstcoverage then + firstcoverage=covered(firstcoverage,coverage) + if firstcoverage then + local rulesoffset=tableoffset+offset + local subclassrules=readarray(f,rulesoffset) + for rule=1,#subclassrules do + setposition(f,rulesoffset+subclassrules[rule]) + local nofcurrent=readushort(f) + local noflookups=readushort(f) + local current={ firstcoverage } + for i=2,nofcurrent do + current[i]=currentclasses[readushort(f)+1] + end + local lookups=readlookuparray(f,noflookups,nofcurrent) + rules[#rules+1]={ + current=current, + lookups=lookups + } + end + else + report("no coverage") + end + else + report("no coverage class") + end + end + end + else + report("empty subclassset in %a subtype %i","unchainedcontext",subtype) + end + return { + format="class", + rules=rules, + } + elseif subtype==3 then + local nofglyphs=readushort(f) + local noflookups=readushort(f) + local current=readcardinaltable(f,nofglyphs,ushort) + local lookups=readlookuparray(f,noflookups,#current) + current=readcoveragearray(f,tableoffset,current,true) + return { + format="coverage", + rules={ + { + current=current, + lookups=lookups, + } + } + } + else + report("unsupported subtype %a in %a %s",subtype,"unchainedcontext",what) + end +end +local function chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local coverage=readushort(f) + local subclasssets=readarray(f) + local rules={} + if subclasssets then + coverage=readcoverage(f,tableoffset+coverage,true) + for i=1,#subclasssets do + local offset=subclasssets[i] + if offset>0 then + local firstcoverage=coverage[i] + local rulesoffset=tableoffset+offset + local subclassrules=readarray(f,rulesoffset) + for rule=1,#subclassrules do + setposition(f,rulesoffset+subclassrules[rule]) + local nofbefore=readushort(f) + local before + if nofbefore>0 then + before={} + for i=1,nofbefore do + before[i]={ readushort(f) } + end + end + local nofcurrent=readushort(f) + local current={ { firstcoverage } } + for i=2,nofcurrent do + current[i]={ readushort(f) } + end + local nofafter=readushort(f) + local after + if nofafter>0 then + after={} + for i=1,nofafter do + after[i]={ readushort(f) } + end + end + local noflookups=readushort(f) + local lookups=readlookuparray(f,noflookups,nofcurrent) + rules[#rules+1]={ + before=before, + current=current, + after=after, + lookups=lookups, + } + end + end + end + else + report("empty subclassset in %a subtype %i","chainedcontext",subtype) + end + return { + format="glyphs", + rules=rules, + } + elseif subtype==2 then + local coverage=readushort(f) + local beforeclassdef=readushort(f) + local currentclassdef=readushort(f) + local afterclassdef=readushort(f) + local subclasssets=readarray(f) + local rules={} + if subclasssets then + local coverage=readcoverage(f,tableoffset+coverage) + local beforeclassdef=readclassdef(f,tableoffset+beforeclassdef,nofglyphs) + local currentclassdef=readclassdef(f,tableoffset+currentclassdef,coverage) + local afterclassdef=readclassdef(f,tableoffset+afterclassdef,nofglyphs) + local beforeclasses=classtocoverage(beforeclassdef,fontdata.glyphs) + local currentclasses=classtocoverage(currentclassdef,fontdata.glyphs) + local afterclasses=classtocoverage(afterclassdef,fontdata.glyphs) + for class=1,#subclasssets do + local offset=subclasssets[class] + if offset>0 then + local firstcoverage=currentclasses[class] + if firstcoverage then + firstcoverage=covered(firstcoverage,coverage) + if firstcoverage then + local rulesoffset=tableoffset+offset + local subclassrules=readarray(f,rulesoffset) + for rule=1,#subclassrules do + setposition(f,rulesoffset+subclassrules[rule]) + local nofbefore=readushort(f) + local before + if nofbefore>0 then + before={} + for i=1,nofbefore do + before[i]=beforeclasses[readushort(f)+1] + end + end + local nofcurrent=readushort(f) + local current={ firstcoverage } + for i=2,nofcurrent do + current[i]=currentclasses[readushort(f)+1] + end + local nofafter=readushort(f) + local after + if nofafter>0 then + after={} + for i=1,nofafter do + after[i]=afterclasses[readushort(f)+1] + end + end + local noflookups=readushort(f) + local lookups=readlookuparray(f,noflookups,nofcurrent) + rules[#rules+1]={ + before=before, + current=current, + after=after, + lookups=lookups, + } + end + else + report("no coverage") + end + else + report("class is not covered") + end + end + end + else + report("empty subclassset in %a subtype %i","chainedcontext",subtype) + end + return { + format="class", + rules=rules, + } + elseif subtype==3 then + local before=readarray(f) + local current=readarray(f) + local after=readarray(f) + local noflookups=readushort(f) + local lookups=readlookuparray(f,noflookups,#current) + before=readcoveragearray(f,tableoffset,before,true) + current=readcoveragearray(f,tableoffset,current,true) + after=readcoveragearray(f,tableoffset,after,true) + return { + format="coverage", + rules={ + { + before=before, + current=current, + after=after, + lookups=lookups, + } + } + } + else + report("unsupported subtype %a in %a %s",subtype,"chainedcontext",what) + end +end +local function extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,types,handlers,what) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local lookuptype=types[readushort(f)] + local faroffset=readulong(f) + local handler=handlers[lookuptype] + if handler then + return handler(f,fontdata,lookupid,tableoffset+faroffset,0,glyphs,nofglyphs),lookuptype + else + report("no handler for lookuptype %a subtype %a in %s %s",lookuptype,subtype,what,"extension") + end + else + report("unsupported subtype %a in %s %s",subtype,what,"extension") + end +end +function gsubhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local coverage=readushort(f) + local delta=readshort(f) + local coverage=readcoverage(f,tableoffset+coverage) + for index in next,coverage do + local newindex=(index+delta)%65536 + if index>nofglyphs or newindex>nofglyphs then + report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs) + coverage[index]=nil + else + coverage[index]=newindex + end + end + return { + coverage=coverage + } + elseif subtype==2 then + local coverage=readushort(f) + local nofreplacements=readushort(f) + local replacements=readcardinaltable(f,nofreplacements,ushort) + local coverage=readcoverage(f,tableoffset+coverage) + for index,newindex in next,coverage do + newindex=newindex+1 + if index>nofglyphs or newindex>nofglyphs then + report("invalid index in %s format %i: %i -> %i (max %i)","single",subtype,index,newindex,nofglyphs) + coverage[index]=nil + else + coverage[index]=replacements[newindex] + end + end + return { + coverage=coverage + } + else + report("unsupported subtype %a in %a substitution",subtype,"single") + end +end +local function sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,what) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local coverage=readushort(f) + local nofsequence=readushort(f) + local sequences=readcardinaltable(f,nofsequence,ushort) + for i=1,nofsequence do + setposition(f,tableoffset+sequences[i]) + sequences[i]=readcardinaltable(f,readushort(f),ushort) + end + local coverage=readcoverage(f,tableoffset+coverage) + for index,newindex in next,coverage do + newindex=newindex+1 + if index>nofglyphs or newindex>nofglyphs then + report("invalid index in %s format %i: %i -> %i (max %i)",what,subtype,index,newindex,nofglyphs) + coverage[index]=nil + else + coverage[index]=sequences[newindex] + end + end + return { + coverage=coverage + } + else + report("unsupported subtype %a in %a substitution",subtype,what) + end +end +function gsubhandlers.multiple(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"multiple") +end +function gsubhandlers.alternate(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return sethandler(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"alternate") +end +function gsubhandlers.ligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local coverage=readushort(f) + local nofsets=readushort(f) + local ligatures=readcardinaltable(f,nofsets,ushort) + for i=1,nofsets do + local offset=lookupoffset+offset+ligatures[i] + setposition(f,offset) + local n=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 + end + local coverage=readcoverage(f,tableoffset+coverage) + for index,newindex in next,coverage do + local hash={} + local ligatures=ligatures[newindex+1] + for i=1,#ligatures do + local offset=ligatures[i] + setposition(f,offset) + local lig=readushort(f) + local cnt=readushort(f) + local hsh=hash + for i=2,cnt do + local c=readushort(f) + local h=hsh[c] + if not h then + h={} + hsh[c]=h + end + hsh=h + end + hsh.ligature=lig + end + coverage[index]=hash + end + return { + coverage=coverage + } + else + report("unsupported subtype %a in %a substitution",subtype,"ligature") + end +end +function gsubhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"context" +end +function gsubhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"substitution"),"chainedcontext" +end +function gsubhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gsubtypes,gsubhandlers,"substitution") +end +function gsubhandlers.reversechainedcontextsingle(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + local tableoffset=lookupoffset+offset + setposition(f,tableoffset) + local subtype=readushort(f) + if subtype==1 then + local current=readfirst(f) + local before=readarray(f) + local after=readarray(f) + local replacements=readarray(f) + current=readcoveragearray(f,tableoffset,current,true) + before=readcoveragearray(f,tableoffset,before,true) + after=readcoveragearray(f,tableoffset,after,true) + return { + 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,mainoffset,getdelta) + local done={} + for i=1,#sets do + local offset=sets[i] + local reused=done[offset] + if not reused then + offset=tableoffset+offset + setposition(f,offset) + local n=readushort(f) + reused={} + for i=1,n do + reused[i]={ + readushort(f), + readposition(f,format1,offset,getdelta), + readposition(f,format2,offset,getdelta), + } + end + done[offset]=reused + end + sets[i]=reused + end + return sets +end +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,mainoffset,getdelta) + local two=readposition(f,format2,mainoffset,getdelta) + if one or two then + classlist2[j]={ one,two } + else + classlist2[j]=false + end + end + end + return classlist1 +end +function gposhandlers.single(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + 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,tableoffset,getdelta) + local coverage=readcoverage(f,tableoffset+coverage) + for index,newindex in next,coverage do + coverage[index]=value + end + return { + format="single", + coverage=coverage, + } + elseif subtype==2 then + local coverage=readushort(f) + local format=readushort(f) + local nofvalues=readushort(f) + local values={} + for i=1,nofvalues do + 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="single", + coverage=coverage, + } + else + report("unsupported subtype %a in %a positioning",subtype,"single") + end +end +function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + 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,mainoffset,getdelta) + coverage=readcoverage(f,tableoffset+coverage) + local shared={} + for index,newindex in next,coverage do + local set=sets[newindex+1] + local hash={} + for i=1,#set do + local value=set[i] + if value then + local other=value[1] + local share=shared[value] + if share==nil then + local first=value[2] + local second=value[3] + if first or second then + share={ first,second or nil } + else + share=false + end + shared[value]=share + end + hash[other]=share or nil + end + end + coverage[index]=hash + end + return { + shared=shared and true or nil, + format="pair", + coverage=coverage, + } + elseif subtype==2 then + local coverage=readushort(f) + local format1=readushort(f) + local format2=readushort(f) + local classdef1=readushort(f) + local classdef2=readushort(f) + local nofclasses1=readushort(f) + local nofclasses2=readushort(f) + 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) + local usedcoverage={} + local shared={} + for g1,c1 in next,classdef1 do + if coverage[g1] then + local l1=classlist[c1] + if l1 then + local hash={} + for paired,class in next,classdef2 do + local offsets=l1[class] + if offsets then + local first=offsets[1] + local second=offsets[2] + if first or second then + local s1=shared[first] + if s1==nil then + s1={} + shared[first]=s1 + end + local s2=s1[second] + if s2==nil then + s2={ first,second or nil } + s1[second]=s2 + end + hash[paired]=s2 + end + end + end + usedcoverage[g1]=hash + end + end + end + return { + shared=shared and true or nil, + format="pair", + coverage=usedcoverage, + } + elseif subtype==3 then + report("yet unsupported subtype %a in %a positioning",subtype,"pair") + else + report("unsupported subtype %a in %a positioning",subtype,"pair") + end +end +function gposhandlers.cursive(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + 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) + local records={} + for i=1,nofrecords do + local entry=readushort(f) + local exit=readushort(f) + records[i]={ + 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]={ + 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, + } + else + report("unsupported subtype %a in %a positioning",subtype,"cursive") + end +end +local function handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,ligature) + 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) + local nofclasses=readushort(f) + local markoffset=tableoffset+readushort(f) + local baseoffset=tableoffset+readushort(f) + local markcoverage=readcoverage(f,markcoverage) + local basecoverage=readcoverage(f,basecoverage,true) + setposition(f,markoffset) + local markclasses={} + local nofmarkclasses=readushort(f) + local lastanchor=fontdata.lastanchor or 0 + local usedanchors={} + for i=1,nofmarkclasses do + local class=readushort(f)+1 + local offset=readushort(f) + if offset==0 then + markclasses[i]=false + else + markclasses[i]={ class,markoffset+offset } + end + usedanchors[class]=true + end + for i=1,nofmarkclasses do + local mc=markclasses[i] + if mc then + mc[2]=readanchor(f,mc[2],getdelta) + end + end + setposition(f,baseoffset) + local nofbaserecords=readushort(f) + local baserecords={} + if ligature then + for i=1,nofbaserecords do + local offset=readushort(f) + if offset==0 then + baserecords[i]=false + else + baserecords[i]=baseoffset+offset + end + end + for i=1,nofbaserecords do + local recordoffset=baserecords[i] + if recordoffset then + setposition(f,recordoffset) + local nofcomponents=readushort(f) + local components={} + for i=1,nofcomponents do + local classes={} + for i=1,nofclasses do + local offset=readushort(f) + if offset~=0 then + classes[i]=recordoffset+offset + else + classes[i]=false + end + end + components[i]=classes + end + baserecords[i]=components + end + end + local baseclasses={} + for i=1,nofclasses do + baseclasses[i]={} + end + for i=1,nofbaserecords do + local components=baserecords[i] + if components then + local b=basecoverage[i] + for c=1,#components do + local classes=components[c] + if classes then + for i=1,nofclasses do + local anchor=readanchor(f,classes[i],getdelta) + local bclass=baseclasses[i] + local bentry=bclass[b] + if bentry then + bentry[c]=anchor + else + bclass[b]={ [c]=anchor } + end + end + end + end + end + end + for index,newindex in next,markcoverage do + markcoverage[index]=markclasses[newindex+1] or nil + end + return { + format="ligature", + baseclasses=baseclasses, + coverage=markcoverage, + } + else + for i=1,nofbaserecords do + local r={} + for j=1,nofclasses do + local offset=readushort(f) + if offset==0 then + r[j]=false + else + r[j]=baseoffset+offset + end + end + baserecords[i]=r + end + local baseclasses={} + for i=1,nofclasses do + baseclasses[i]={} + end + for i=1,nofbaserecords do + local r=baserecords[i] + local b=basecoverage[i] + for j=1,nofclasses do + baseclasses[j][b]=readanchor(f,r[j],getdelta) + end + end + for index,newindex in next,markcoverage do + markcoverage[index]=markclasses[newindex+1] or nil + end + return { + format="base", + baseclasses=baseclasses, + coverage=markcoverage, + } + end + else + report("unsupported subtype %a in",subtype) + end +end +function gposhandlers.marktobase(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) +end +function gposhandlers.marktoligature(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,true) +end +function gposhandlers.marktomark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return handlemark(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) +end +function gposhandlers.context(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return unchainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"context" +end +function gposhandlers.chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return chainedcontext(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,"positioning"),"chainedcontext" +end +function gposhandlers.extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) + return extension(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs,gpostypes,gposhandlers,"positioning") +end +do + local plugins={} + function plugins.size(f,fontdata,tableoffset,feature) + if fontdata.designsize then + else + local function check(offset) + setposition(f,offset) + local designsize=readushort(f) + if designsize>0 then + 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 + end + if designsize>=minsize and designsize<=maxsize then + return minsize,maxsize,designsize + end + end + end + local minsize,maxsize,designsize=check(tableoffset+feature.offset+feature.parameters) + if not designsize then + minsize,maxsize,designsize=check(tableoffset+feature.parameters) + if designsize then + report("bad size feature in %a, falling back to wrong offset",fontdata.filename or "?") + else + report("bad size feature in %a,",fontdata.filename or "?") + end + end + if designsize then + fontdata.minsize=minsize + fontdata.maxsize=maxsize + fontdata.designsize=designsize + end + end + end + local function reorderfeatures(fontdata,scripts,features) + local scriptlangs={} + local featurehash={} + local featureorder={} + for script,languages in next,scripts do + for language,record in next,languages do + local hash={} + local list=record.featureindices + for k=1,#list do + local index=list[k] + local feature=features[index] + local lookups=feature.lookups + local tag=feature.tag + if tag then + hash[tag]=true + end + if lookups then + for i=1,#lookups do + local lookup=lookups[i] + local o=featureorder[lookup] + if o then + local okay=true + for i=1,#o do + if o[i]==tag then + okay=false + break + end + end + if okay then + o[#o+1]=tag + end + else + featureorder[lookup]={ tag } + end + local f=featurehash[lookup] + if f then + local h=f[tag] + if h then + local s=h[script] + if s then + s[language]=true + else + h[script]={ [language]=true } + end + else + f[tag]={ [script]={ [language]=true } } + end + else + featurehash[lookup]={ [tag]={ [script]={ [language]=true } } } + end + local h=scriptlangs[tag] + if h then + local s=h[script] + if s then + s[language]=true + else + h[script]={ [language]=true } + end + else + scriptlangs[tag]={ [script]={ [language]=true } } + end + end + end + end + end + end + return scriptlangs,featurehash,featureorder + end + local function readscriplan(f,fontdata,scriptoffset) + setposition(f,scriptoffset) + local nofscripts=readushort(f) + local scripts={} + for i=1,nofscripts do + scripts[readtag(f)]=scriptoffset+readushort(f) + end + local languagesystems=setmetatableindex("table") + for script,offset in next,scripts do + setposition(f,offset) + local defaultoffset=readushort(f) + local noflanguages=readushort(f) + local languages={} + if defaultoffset>0 then + languages.dflt=languagesystems[offset+defaultoffset] + end + for i=1,noflanguages do + local language=readtag(f) + local offset=offset+readushort(f) + languages[language]=languagesystems[offset] + end + scripts[script]=languages + end + for offset,usedfeatures in next,languagesystems do + if offset>0 then + setposition(f,offset) + local featureindices={} + usedfeatures.featureindices=featureindices + usedfeatures.lookuporder=readushort(f) + usedfeatures.requiredindex=readushort(f) + local noffeatures=readushort(f) + for i=1,noffeatures do + featureindices[i]=readushort(f)+1 + end + end + end + return scripts + end + local function readfeatures(f,fontdata,featureoffset) + setposition(f,featureoffset) + local features={} + local noffeatures=readushort(f) + for i=1,noffeatures do + features[i]={ + tag=readtag(f), + offset=readushort(f) + } + end + for i=1,noffeatures do + local feature=features[i] + local offset=featureoffset+feature.offset + setposition(f,offset) + local parameters=readushort(f) + local noflookups=readushort(f) + if noflookups>0 then + local lookups=readcardinaltable(f,noflookups,ushort) + feature.lookups=lookups + for j=1,noflookups do + lookups[j]=lookups[j]+1 + end + end + if parameters>0 then + feature.parameters=parameters + local plugin=plugins[feature.tag] + if plugin then + plugin(f,fontdata,featureoffset,feature) + end + end + end + return features + end + local function readlookups(f,lookupoffset,lookuptypes,featurehash,featureorder) + setposition(f,lookupoffset) + local noflookups=readushort(f) + local lookups=readcardinaltable(f,noflookups,ushort) + for lookupid=1,noflookups do + local offset=lookups[lookupid] + setposition(f,lookupoffset+offset) + local subtables={} + local typebits=readushort(f) + local flagbits=readushort(f) + local lookuptype=lookuptypes[typebits] + local lookupflags=lookupflags[flagbits] + local nofsubtables=readushort(f) + for j=1,nofsubtables do + subtables[j]=offset+readushort(f) + end + local markclass=band(flagbits,0x0010)~=0 + if markclass then + markclass=readushort(f) + end + local markset=rshift(flagbits,8) + if markset>0 then + markclass=markset + end + lookups[lookupid]={ + type=lookuptype, + flags=lookupflags, + name=lookupid, + subtables=subtables, + markclass=markclass, + features=featurehash[lookupid], + order=featureorder[lookupid], + } + end + return lookups + end + local f_lookupname=formatters["%s_%s_%s"] + 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 + local nofsublookups=#sublookuplist + local nofsequences=#sequences + local lastsublookup=nofsublookups + local lastsequence=nofsequences + local lookupnames=lookupnames[what] + local sublookuphash={} + local sublookupcheck={} + local glyphs=fontdata.glyphs + 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 + local subtables=lookup.subtables + local features=lookup.features + local handler=lookuphandlers[lookuptype] + if handler then + local nofsubtables=#subtables + local order=lookup.order + local flags=lookup.flags + if flags[1] then flags[1]="mark" end + if flags[2] then flags[2]="ligature" end + if flags[3] then flags[3]="base" end + local markclass=lookup.markclass + if nofsubtables>0 then + local steps={} + local nofsteps=0 + local oldtype=nil + for s=1,nofsubtables do + local step,lt=handler(f,fontdata,lookupid,lookupoffset,subtables[s],glyphs,nofglyphs) + if lt then + lookuptype=lt + if oldtype and lt~=oldtype then + report("messy %s lookup type %a and %a",what,lookuptype,oldtype) + end + oldtype=lookuptype + end + if not step then + report("unsupported %s lookup type %a",what,lookuptype) + else + nofsteps=nofsteps+1 + steps[nofsteps]=step + 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 replacements=rule.replacements + if before then + for i=1,#before do + before[i]=tohash(before[i]) + end + rule.before=reversed(before) + end + if current then + 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 + end + if nofsteps~=nofsubtables then + report("bogus subtables removed in %s lookup type %a",what,lookuptype) + end + lookuptype=lookupnames[lookuptype] or lookuptype + if features then + nofsequences=nofsequences+1 + local l={ + index=nofsequences, + name=f_lookupname(lookupprefix,"s",lookupid+lookupidoffset), + steps=steps, + nofsteps=nofsteps, + type=lookuptype, + markclass=markclass or nil, + flags=flags, + order=order, + features=features, + } + sequences[nofsequences]=l + lookup.done=l + else + nofsublookups=nofsublookups+1 + local l={ + index=nofsublookups, + name=f_lookupname(lookupprefix,"l",lookupid+lookupidoffset), + steps=steps, + nofsteps=nofsteps, + type=lookuptype, + markclass=markclass or nil, + flags=flags, + } + sublookuplist[nofsublookups]=l + sublookuphash[lookupid]=nofsublookups + sublookupcheck[lookupid]=0 + lookup.done=l + end + else + report("no subtables for lookup %a",lookupid) + end + else + 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 + if not reported[name] then + report("rule %i in %s lookup %a has %s lookups",i,what,name,kind) + reported[name]=true + end + end + for i=lastsequence+1,nofsequences do + local sequence=sequences[i] + local steps=sequence.steps + for i=1,#steps do + local step=steps[i] + local rules=step.rules + if rules then + for i=1,#rules do + local rule=rules[i] + local rlookups=rule.lookups + if not rlookups then + report_issue(i,what,sequence,"no") + elseif not next(rlookups) then + rule.lookups=nil + else + local length=#rlookups + for index=1,length do + 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 + sublookupcheck[lookupid]=sublookupcheck[lookupid]+1 + end + if h then + noffound=noffound+1 + found[noffound]=h + end + end + end + rlookups[index]=noffound>0 and found or false + else + rlookups[index]=false + end + end + end + end + end + end + end + for i,n in sortedhash(sublookupcheck) do + local l=lookups[i] + local t=l.type + 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) + end + end + end + 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 + 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 + 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 + 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 + 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) + local datatable=fontdata.tables.kern + if not datatable then + return + end + local features=fontdata.features + local gposfeatures=features and features.gpos + local name + if not gposfeatures or not gposfeatures.kern then + name="kern" + elseif specification.globalkerns then + name="globalkern" + else + report("ignoring global kern table, using gpos kern feature") + return + end + setposition(f,datatable.offset) + local version=readushort(f) + local noftables=readushort(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 + 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", + }, + }, + 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) + if specification.details then + readscripts(f,fontdata,"gsub",gsubtypes,gsubhandlers,specification.lookups) + end + end + function readers.gpos(f,fontdata,specification) + if specification.details then + readscripts(f,fontdata,"gpos",gpostypes,gposhandlers,specification.lookups) + if specification.lookups then + checkkerns(f,fontdata,specification) + end + end + end +end +function readers.gdef(f,fontdata,specification) + 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) + local lastindex=firstindex+readushort(f)-1 + for index=firstindex,lastindex do + local class=classes[readushort(f)] + if class=="mark" then + marks[index]=true + end + glyphs[index].class=class + end + elseif classformat==2 then + local nofranges=readushort(f) + for i=1,nofranges do + local firstindex=readushort(f) + local lastindex=readushort(f) + local class=classes[readushort(f)] + if class then + for index=firstindex,lastindex do + glyphs[index].class=class + if class=="mark" then + marks[index]=true + end + end + end + end + end + end + if markclassoffset~=0 then + setposition(f,tableoffset+markclassoffset) + local classformat=readushort(f) + if classformat==1 then + local firstindex=readushort(f) + local lastindex=firstindex+readushort(f)-1 + for index=firstindex,lastindex do + markclasses[readushort(f)][index]=true + end + elseif classformat==2 then + local nofranges=readushort(f) + for i=1,nofranges do + local firstindex=readushort(f) + local lastindex=readushort(f) + local class=markclasses[readushort(f)] + for index=firstindex,lastindex do + class[index]=true + end + end + end + 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 + end +end +local function readmathvalue(f) + local v=readshort(f) + skipshort(f,1) + return v +end +local function readmathconstants(f,fontdata,offset) + setposition(f,offset) + fontdata.mathconstants={ + ScriptPercentScaleDown=readshort(f), + ScriptScriptPercentScaleDown=readshort(f), + DelimitedSubFormulaMinHeight=readushort(f), + DisplayOperatorMinHeight=readushort(f), + MathLeading=readmathvalue(f), + AxisHeight=readmathvalue(f), + AccentBaseHeight=readmathvalue(f), + FlattenedAccentBaseHeight=readmathvalue(f), + SubscriptShiftDown=readmathvalue(f), + SubscriptTopMax=readmathvalue(f), + SubscriptBaselineDropMin=readmathvalue(f), + SuperscriptShiftUp=readmathvalue(f), + SuperscriptShiftUpCramped=readmathvalue(f), + SuperscriptBottomMin=readmathvalue(f), + SuperscriptBaselineDropMax=readmathvalue(f), + SubSuperscriptGapMin=readmathvalue(f), + SuperscriptBottomMaxWithSubscript=readmathvalue(f), + SpaceAfterScript=readmathvalue(f), + UpperLimitGapMin=readmathvalue(f), + UpperLimitBaselineRiseMin=readmathvalue(f), + LowerLimitGapMin=readmathvalue(f), + LowerLimitBaselineDropMin=readmathvalue(f), + StackTopShiftUp=readmathvalue(f), + StackTopDisplayStyleShiftUp=readmathvalue(f), + StackBottomShiftDown=readmathvalue(f), + StackBottomDisplayStyleShiftDown=readmathvalue(f), + StackGapMin=readmathvalue(f), + StackDisplayStyleGapMin=readmathvalue(f), + StretchStackTopShiftUp=readmathvalue(f), + StretchStackBottomShiftDown=readmathvalue(f), + StretchStackGapAboveMin=readmathvalue(f), + StretchStackGapBelowMin=readmathvalue(f), + FractionNumeratorShiftUp=readmathvalue(f), + FractionNumeratorDisplayStyleShiftUp=readmathvalue(f), + FractionDenominatorShiftDown=readmathvalue(f), + FractionDenominatorDisplayStyleShiftDown=readmathvalue(f), + FractionNumeratorGapMin=readmathvalue(f), + FractionNumeratorDisplayStyleGapMin=readmathvalue(f), + FractionRuleThickness=readmathvalue(f), + FractionDenominatorGapMin=readmathvalue(f), + FractionDenominatorDisplayStyleGapMin=readmathvalue(f), + SkewedFractionHorizontalGap=readmathvalue(f), + SkewedFractionVerticalGap=readmathvalue(f), + OverbarVerticalGap=readmathvalue(f), + OverbarRuleThickness=readmathvalue(f), + OverbarExtraAscender=readmathvalue(f), + UnderbarVerticalGap=readmathvalue(f), + UnderbarRuleThickness=readmathvalue(f), + UnderbarExtraDescender=readmathvalue(f), + RadicalVerticalGap=readmathvalue(f), + RadicalDisplayStyleVerticalGap=readmathvalue(f), + RadicalRuleThickness=readmathvalue(f), + RadicalExtraAscender=readmathvalue(f), + RadicalKernBeforeDegree=readmathvalue(f), + RadicalKernAfterDegree=readmathvalue(f), + RadicalDegreeBottomRaisePercent=readshort(f), + } +end +local function readmathglyphinfo(f,fontdata,offset) + setposition(f,offset) + local italics=readushort(f) + local accents=readushort(f) + local extensions=readushort(f) + local kerns=readushort(f) + local glyphs=fontdata.glyphs + if italics~=0 then + setposition(f,offset+italics) + local coverage=readushort(f) + local nofglyphs=readushort(f) + coverage=readcoverage(f,offset+italics+coverage,true) + setposition(f,offset+italics+4) + for i=1,nofglyphs do + local italic=readmathvalue(f) + if italic~=0 then + local glyph=glyphs[coverage[i]] + local math=glyph.math + if not math then + glyph.math={ italic=italic } + else + math.italic=italic + end + end + end + fontdata.hasitalics=true + end + if accents~=0 then + setposition(f,offset+accents) + local coverage=readushort(f) + local nofglyphs=readushort(f) + coverage=readcoverage(f,offset+accents+coverage,true) + setposition(f,offset+accents+4) + for i=1,nofglyphs do + local accent=readmathvalue(f) + if accent~=0 then + local glyph=glyphs[coverage[i]] + local math=glyph.math + if not math then + glyph.math={ accent=accent } + else + math.accent=accent + end + end + end + end + if extensions~=0 then + setposition(f,offset+extensions) + end + if kerns~=0 then + local kernoffset=offset+kerns + setposition(f,kernoffset) + local coverage=readushort(f) + local nofglyphs=readushort(f) + if nofglyphs>0 then + local function get(offset) + setposition(f,kernoffset+offset) + local n=readushort(f) + if n==0 then + local k=readmathvalue(f) + if k==0 then + else + return { { kern=k } } + end + else + local l={} + for i=1,n do + l[i]={ height=readmathvalue(f) } + end + for i=1,n do + l[i].kern=readmathvalue(f) + end + l[n+1]={ kern=readmathvalue(f) } + return l + end + end + local kernsets={} + for i=1,nofglyphs do + local topright=readushort(f) + local topleft=readushort(f) + local bottomright=readushort(f) + local bottomleft=readushort(f) + kernsets[i]={ + topright=topright~=0 and topright or nil, + topleft=topleft~=0 and topleft or nil, + bottomright=bottomright~=0 and bottomright or nil, + bottomleft=bottomleft~=0 and bottomleft or nil, + } + end + coverage=readcoverage(f,kernoffset+coverage,true) + for i=1,nofglyphs do + local kernset=kernsets[i] + if next(kernset) then + local k=kernset.topright if k then kernset.topright=get(k) end + local k=kernset.topleft if k then kernset.topleft=get(k) end + local k=kernset.bottomright if k then kernset.bottomright=get(k) end + local k=kernset.bottomleft if k then kernset.bottomleft=get(k) end + if next(kernset) then + local glyph=glyphs[coverage[i]] + local math=glyph.math + if math then + math.kerns=kernset + else + glyph.math={ kerns=kernset } + end + end + end + end + end + end +end +local function readmathvariants(f,fontdata,offset) + setposition(f,offset) + local glyphs=fontdata.glyphs + local minoverlap=readushort(f) + local vcoverage=readushort(f) + local hcoverage=readushort(f) + local vnofglyphs=readushort(f) + local hnofglyphs=readushort(f) + 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 + local coverage=readcoverage(f,offset+coverage,true) + for i=1,nofglyphs do + local c=construction[i] + if c~=0 then + local index=coverage[i] + local glyph=glyphs[index] + local math=glyph.math + setposition(f,offset+c) + local assembly=readushort(f) + local nofvariants=readushort(f) + if nofvariants>0 then + local variants,v=nil,0 + for i=1,nofvariants do + local variant=readushort(f) + if variant==index then + elseif variants then + v=v+1 + variants[v]=variant + else + v=1 + variants={ variant } + end + skipshort(f) + end + if not variants then + elseif not math then + math={ [kvariants]=variants } + glyph.math=math + else + math[kvariants]=variants + end + end + if assembly~=0 then + setposition(f,offset+c+assembly) + local italic=readmathvalue(f) + local nofparts=readushort(f) + local parts={} + for i=1,nofparts do + local p={ + glyph=readushort(f), + start=readushort(f), + ["end"]=readushort(f), + advance=readushort(f), + } + local flags=readushort(f) + if band(flags,0x0001)~=0 then + p.extender=1 + end + parts[i]=p + end + if not math then + math={ + [kparts]=parts + } + glyph.math=math + else + math[kparts]=parts + end + if italic and italic~=0 then + math[kitalic]=italic + end + end + end + end + end + end + get(offset,vcoverage,vnofglyphs,vconstruction,"vvariants","vparts","vitalic") + get(offset,hcoverage,hnofglyphs,hconstruction,"hvariants","hparts","hitalic") +end +function readers.math(f,fontdata,specification) + 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 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 t={} + for i=1,noflayers do + t[i]=layerrecords[firstlayer+i] + end + 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) + 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 + 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 + 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 + end + fontdata.pngshapes=shapes + end +end +do + local function getmetrics(f) + return { + ascender=readinteger(f), + descender=readinteger(f), + widthmax=readuinteger(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 function getbigmetrics(f) + return { + height=readuinteger(f), + width=readuinteger(f), + horiBearingX=readinteger(f), + horiBearingY=readinteger(f), + horiAdvance=readuinteger(f), + vertBearingX=readinteger(f), + vertBearingY=readinteger(f), + vertAdvance=readuinteger(f), + } + end + local function getsmallmetrics(f) + return { + height=readuinteger(f), + width=readuinteger(f), + bearingX=readinteger(f), + bearingY=readinteger(f), + advance=readuinteger(f), + } + end + function readers.cblc(f,fontdata,specification) + local ctdttableoffset=gotodatatable(f,fontdata,"cbdt",specification.glyphs) + if not ctdttableoffset then + return + end + local cblctableoffset=gotodatatable(f,fontdata,"cblc",specification.glyphs) + if cblctableoffset then + local majorversion=readushort(f) + local minorversion=readushort(f) + local nofsizetables=readulong(f) + local sizetables={} + local shapes={} + local subtables={} + for i=1,nofsizetables do + sizetables[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(sizetables,function(a,b) + if b.ppemx==a.ppemx then + return b.bitdepth<a.bitdepth + else + return b.ppemx<a.ppemx + end + end) + for i=1,nofsizetables do + local s=sizetables[i] + local d=false + for j=s.firstindex,s.lastindex do + if not shapes[j] then + shapes[j]=i + d=true + end + end + if d then + s.used=true + end + end + for i=1,nofsizetables do + local s=sizetables[i] + if s.used then + local offset=s.subtables + setposition(f,cblctableoffset+offset) + for j=1,s.nofsubtables do + local firstindex=readushort(f) + local lastindex=readushort(f) + local tableoffset=readulong(f)+offset + for k=firstindex,lastindex do + if shapes[k]==i then + local s=subtables[tableoffset] + if not s then + s={ + firstindex=firstindex, + lastindex=lastindex, + } + subtables[tableoffset]=s + end + shapes[k]=s + end + end + end + end + end + for offset,subtable in sortedhash(subtables) do + local tabletype=readushort(f) + subtable.format=readushort(f) + local baseoffset=readulong(f)+ctdttableoffset + local offsets={} + local metrics=nil + if tabletype==1 then + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=readulong(f)+baseoffset + end + skipbytes(f,4) + elseif tabletype==2 then + local size=readulong(f) + local done=baseoffset + metrics=getbigmetrics(f) + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=done + done=done+size + end + elseif tabletype==3 then + local n=subtable.lastindex-subtable.firstindex+2 + for i=subtable.firstindex,subtable.lastindex do + offsets[i]=readushort(f)+baseoffset + end + if math.odd(n) then + skipbytes(f,4) + else + skipbytes(f,2) + end + elseif tabletype==4 then + for i=1,readulong(f) do + offsets[readushort(f)]=readushort(f)+baseoffset + end + elseif tabletype==5 then + local size=readulong(f) + local done=baseoffset + metrics=getbigmetrics(f) + local n=readulong(f) + for i=1,n do + offsets[readushort(f)]=done + done=done+size + end + if math.odd(n) then + skipbytes(f,2) + end + else + return + end + subtable.offsets=offsets + subtable.metrics=metrics + end + local default={ width=0,height=0 } + local glyphs=fontdata.glyphs + for index,subtable in sortedhash(shapes) do + if type(subtable)=="table" then + local data=nil + local metrics=default + local format=subtable.format + local offset=subtable.offsets[index] + setposition(f,offset) + if format==17 then + metrics=getsmallmetrics(f) + data=readstring(f,readulong(f)) + elseif format==18 then + metrics=getbigmetrics(f) + data=readstring(f,readulong(f)) + elseif format==19 then + metrics=subtable.metrics + data=readstring(f,readulong(f)) + else + end + local x=metrics.width + local y=metrics.height + shapes[index]={ + x=x, + y=y, + data=data, + } + local glyph=glyphs[index] + if not glyph.boundingbox then + local width=glyph.width + local height=width*y/x + glyph.boundingbox={ 0,0,width,height } + end + else + shapes[index]={ + x=0, + y=0, + data="", + } + end + end + fontdata.pngshapes=shapes + end + end + function readers.cbdt(f,fontdata,specification) + end +end +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 from=read2dot14(f) + local to=read2dot14(f) + if lastfrom and from<=lastfrom then + elseif lastto and to>=lastto then + else + values[#values+1]={ from,to } + lastfrom,lastto=from,to + 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 version=readulong(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 + 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 + end +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-dsp”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-oup” 669e479e716999edc626a1f045bd76fa] --- + +if not modules then modules={} end modules ['font-oup']={ + 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,type=next,type +local P,R,S=lpeg.P,lpeg.R,lpeg.S +local lpegmatch=lpeg.match +local insert,remove,copy,unpack=table.insert,table.remove,table.copy,table.unpack +local formatters=string.formatters +local sortedkeys=table.sortedkeys +local sortedhash=table.sortedhash +local tohash=table.tohash +local setmetatableindex=table.setmetatableindex +local report_error=logs.reporter("otf reader","error") +local report_markwidth=logs.reporter("otf reader","markwidth") +local report_cleanup=logs.reporter("otf reader","cleanup") +local report_optimizations=logs.reporter("otf reader","merges") +local report_unicodes=logs.reporter("otf reader","unicodes") +local trace_markwidth=false trackers.register("otf.markwidth",function(v) trace_markwidth=v end) +local trace_cleanup=false trackers.register("otf.cleanups",function(v) trace_cleanups=v end) +local trace_optimizations=false trackers.register("otf.optimizations",function(v) trace_optimizations=v end) +local trace_unicodes=false trackers.register("otf.unicodes",function(v) trace_unicodes=v end) +local readers=fonts.handlers.otf.readers +local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 +local f_private=formatters["P%05X"] +local f_unicode=formatters["U%05X"] +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=true +directives.register("otf.checksofthyphen",function(v) + check_soft_hyphen=v +end) +local function replaced(list,index,replacement) + if type(list)=="number" then + return replacement + elseif type(replacement)=="table" then + local t={} + local n=index-1 + for i=1,n do + t[i]=list[i] + end + for i=1,#replacement do + n=n+1 + t[n]=replacement[i] + end + for i=index+1,#list do + n=n+1 + t[n]=list[i] + end + else + list[index]=replacement + return list + end +end +local function unifyresources(fontdata,indices) + local descriptions=fontdata.descriptions + local resources=fontdata.resources + if not descriptions or not resources then + return + end + local nofindices=#indices + local variants=fontdata.resources.variants + if variants then + for selector,unicodes in next,variants do + for unicode,index in next,unicodes do + unicodes[unicode]=indices[index] + end + end + end + local function remark(marks) + if marks then + local newmarks={} + for k,v in next,marks do + local u=indices[k] + if u then + newmarks[u]=v + elseif trace_optimizations then + report_optimizations("discarding mark %i",k) + end + end + return newmarks + end + end + local marks=resources.marks + if marks then + resources.marks=remark(marks) + end + local markclasses=resources.markclasses + if markclasses then + for class,marks in next,markclasses do + markclasses[class]=remark(marks) + end + end + local marksets=resources.marksets + if marksets then + for class,marks in next,marksets do + marksets[class]=remark(marks) + end + end + local done={} + local duplicates=check_duplicates and resources.duplicates + if duplicates and not next(duplicates) then + duplicates=false + end + local function recover(cover) + for i=1,#cover do + local c=cover[i] + if not done[c] then + local t={} + for k,v in next,c do + local ug=indices[k] + if ug then + t[ug]=v + else + report_error("case %i, bad index in unifying %s: %s of %s",1,"coverage",k,nofindices) + end + end + cover[i]=t + done[c]=d + end + end + end + local function recursed(c,kind) + local t={} + for g,d in next,c do + if type(d)=="table" then + local ug=indices[g] + if ug then + t[ug]=recursed(d,kind) + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g,nofindices) + end + else + t[g]=indices[d] + end + end + return t + end + local function unifythem(sequences) + if not sequences then + return + end + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + local features=sequence.features + if steps then + for i=1,#steps do + local step=steps[i] + if kind=="gsub_single" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + if duplicates then + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + local ud1=indices[d1] + if ud1 then + t1[ug1]=ud1 + local dg1=duplicates[ug1] + if dg1 then + for u in next,dg1 do + t1[u]=ud1 + end + end + else + report_error("case %i, bad index in unifying %s: %s of %s",3,kind,d1,nofindices) + end + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) + end + end + else + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=indices[d1] + else + report_error("fuzzy case %i in unifying %s: %i",2,kind,g1) + end + end + end + done[c]=t1 + end + step.coverage=t1 + end + elseif kind=="gpos_pair" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + local t2=done[d1] + if not t2 then + t2={} + for g2,d2 in next,d1 do + local ug2=indices[g2] + if ug2 then + t2[ug2]=d2 + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g2,nofindices,nofindices) + end + end + done[d1]=t2 + end + t1[ug1]=t2 + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) + end + end + done[c]=t1 + end + step.coverage=t1 + end + elseif kind=="gsub_ligature" then + local c=step.coverage + if c then + step.coverage=recursed(c,kind) + end + elseif kind=="gsub_alternate" or kind=="gsub_multiple" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + if duplicates then + for g1,d1 in next,c do + for i=1,#d1 do + local d1i=d1[i] + local d1u=indices[d1i] + if d1u then + d1[i]=d1u + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,i,d1i,nofindices) + end + end + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + local dg1=duplicates[ug1] + if dg1 then + for u in next,dg1 do + t1[u]=copy(d1) + end + end + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) + end + end + else + for g1,d1 in next,c do + for i=1,#d1 do + local d1i=d1[i] + local d1u=indices[d1i] + if d1u then + d1[i]=d1u + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,d1i,nofindices) + end + end + t1[indices[g1]]=d1 + end + end + done[c]=t1 + end + step.coverage=t1 + end + elseif kind=="gpos_single" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + if duplicates then + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + local dg1=duplicates[ug1] + if dg1 then + for u in next,dg1 do + t1[u]=d1 + end + end + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) + end + end + else + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) + end + end + end + done[c]=t1 + end + step.coverage=t1 + end + elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" or kind=="gpos_mark2ligature" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) + end + end + done[c]=t1 + end + step.coverage=t1 + end + local c=step.baseclasses + if c then + local t1=done[c] + if not t1 then + for g1,d1 in next,c do + local t2=done[d1] + if not t2 then + t2={} + for g2,d2 in next,d1 do + local ug2=indices[g2] + if ug2 then + t2[ug2]=d2 + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g2,nofindices) + end + end + done[d1]=t2 + end + c[g1]=t2 + end + done[c]=c + end + end + elseif kind=="gpos_cursive" then + local c=step.coverage + if c then + local t1=done[c] + if not t1 then + t1={} + if duplicates then + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + local dg1=duplicates[ug1] + if dg1 then + for u in next,dg1 do + t1[u]=copy(d1) + end + end + else + report_error("case %i, bad index in unifying %s: %s of %s",1,kind,g1,nofindices) + end + end + else + for g1,d1 in next,c do + local ug1=indices[g1] + if ug1 then + t1[ug1]=d1 + else + report_error("case %i, bad index in unifying %s: %s of %s",2,kind,g1,nofindices) + end + end + end + done[c]=t1 + end + step.coverage=t1 + end + end + local rules=step.rules + if rules then + for i=1,#rules do + local rule=rules[i] + local before=rule.before if before then recover(before) end + local after=rule.after if after then recover(after) end + local current=rule.current if current then recover(current) end + local replacements=rule.replacements + if replacements then + if not done[replacements] then + local r={} + for k,v in next,replacements do + r[indices[k]]=indices[v] + end + rule.replacements=r + done[replacements]=r + end + end + end + end + end + end + end + end + unifythem(resources.sequences) + unifythem(resources.sublookups) +end +local function copyduplicates(fontdata) + if check_duplicates then + local descriptions=fontdata.descriptions + local resources=fontdata.resources + local duplicates=resources.duplicates + if check_soft_hyphen then + local ds=descriptions[0xAD] + if not ds or ds.width==0 then + if ds then + descriptions[0xAD]=nil + if trace_unicodes then + report_unicodes("patching soft hyphen") + end + else + if trace_unicodes then + report_unicodes("adding soft hyphen") + end + end + if not duplicates then + duplicates={} + resources.duplicates=duplicates + end + local dh=duplicates[0x2D] + if dh then + dh[#dh+1]={ [0xAD]=true } + else + duplicates[0x2D]={ [0xAD]=true } + end + end + end + if duplicates then + for u,d in next,duplicates do + local du=descriptions[u] + if du then + local t={ f_character_y(u),"@",f_index(du.index),"->" } + local n=0 + local m=25 + for u in next,d do + if descriptions[u] then + if n<m then + t[n+4]=f_character_n(u) + end + else + local c=copy(du) + c.unicode=u + descriptions[u]=c + if n<m then + t[n+4]=f_character_y(u) + end + end + n=n+1 + end + if trace_unicodes then + if n<=m then + report_unicodes("%i : % t",n,t) + else + report_unicodes("%i : % t ...",n,t) + end + end + else + end + end + end + end +end +local ignore={ + ["notdef"]=true, + [".notdef"]=true, + ["null"]=true, + [".null"]=true, + ["nonmarkingreturn"]=true, +} +local function checklookups(fontdata,missing,nofmissing) + local descriptions=fontdata.descriptions + local resources=fontdata.resources + if missing and nofmissing and nofmissing<=0 then + return + end + local singles={} + local alternates={} + local ligatures={} + if not missing then + missing={} + nofmissing=0 + for u,d in next,descriptions do + if not d.unicode then + nofmissing=nofmissing+1 + missing[u]=true + end + end + end + local function collectthem(sequences) + if not sequences then + return + end + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + if steps then + for i=1,#steps do + local step=steps[i] + if kind=="gsub_single" then + local c=step.coverage + if c then + singles[#singles+1]=c + end + elseif kind=="gsub_alternate" then + local c=step.coverage + if c then + alternates[#alternates+1]=c + end + elseif kind=="gsub_ligature" then + local c=step.coverage + if c then + ligatures[#ligatures+1]=c + end + end + end + end + end + end + collectthem(resources.sequences) + collectthem(resources.sublookups) + local loops=0 + while true do + loops=loops+1 + local old=nofmissing + for i=1,#singles do + local c=singles[i] + for g1,g2 in next,c do + if missing[g1] then + local u2=descriptions[g2].unicode + if u2 then + missing[g1]=false + descriptions[g1].unicode=u2 + nofmissing=nofmissing-1 + end + end + if missing[g2] then + local u1=descriptions[g1].unicode + if u1 then + missing[g2]=false + descriptions[g2].unicode=u1 + nofmissing=nofmissing-1 + end + end + end + end + for i=1,#alternates do + local c=alternates[i] + for g1,d1 in next,c do + if missing[g1] then + for i=1,#d1 do + local g2=d1[i] + local u2=descriptions[g2].unicode + if u2 then + missing[g1]=false + descriptions[g1].unicode=u2 + nofmissing=nofmissing-1 + end + end + end + if not missing[g1] then + for i=1,#d1 do + local g2=d1[i] + if missing[g2] then + local u1=descriptions[g1].unicode + if u1 then + missing[g2]=false + descriptions[g2].unicode=u1 + nofmissing=nofmissing-1 + end + end + end + end + end + end + if nofmissing<=0 then + if trace_unicodes then + report_unicodes("all missings done in %s loops",loops) + end + return + elseif old==nofmissing then + break + end + end + local t,n + local function recursed(c) + for g,d in next,c do + if g~="ligature" then + local u=descriptions[g].unicode + if u then + n=n+1 + t[n]=u + recursed(d) + n=n-1 + end + elseif missing[d] then + local l={} + local m=0 + for i=1,n do + local u=t[i] + if type(u)=="table" then + for i=1,#u do + m=m+1 + l[m]=u[i] + end + else + m=m+1 + l[m]=u + end + end + missing[d]=false + descriptions[d].unicode=l + nofmissing=nofmissing-1 + end + end + end + if nofmissing>0 then + t={} + n=0 + local loops=0 + while true do + loops=loops+1 + local old=nofmissing + for i=1,#ligatures do + recursed(ligatures[i]) + end + if nofmissing<=0 then + if trace_unicodes then + report_unicodes("all missings done in %s loops",loops) + end + return + elseif old==nofmissing then + break + end + end + t=nil + n=0 + end + if trace_unicodes and nofmissing>0 then + local done={} + for i,r in next,missing do + if r then + local data=descriptions[i] + local name=data and data.name or f_index(i) + if not ignore[name] then + done[name]=true + end + end + end + if next(done) then + report_unicodes("not unicoded: % t",sortedkeys(done)) + end + end +end +local function unifymissing(fontdata) + if not fonts.mappings then + require("font-map") + require("font-agl") + end + local unicodes={} + local resources=fontdata.resources + resources.unicodes=unicodes + for unicode,d in next,fontdata.descriptions do + if unicode<privateoffset then + local name=d.name + if name then + unicodes[name]=unicode + end + end + end + fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups) + resources.unicodes=nil +end +local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000 +local puafirst=0xE000 +local pualast=0xF8FF +local function unifyglyphs(fontdata,usenames) + local private=fontdata.private or privateoffset + local glyphs=fontdata.glyphs + local indices={} + local descriptions={} + local names=usenames and {} + local resources=fontdata.resources + local zero=glyphs[0] + local zerocode=zero.unicode + if not zerocode then + zerocode=private + zero.unicode=zerocode + private=private+1 + end + descriptions[zerocode]=zero + if names then + local name=glyphs[0].name or f_private(zerocode) + indices[0]=name + names[name]=zerocode + else + indices[0]=zerocode + end + if names then + for index=1,#glyphs do + local glyph=glyphs[index] + local unicode=glyph.unicode + if not unicode then + unicode=private + local name=glyph.name or f_private(unicode) + indices[index]=name + names[name]=unicode + private=private+1 + elseif unicode>=firstprivate then + unicode=private + local name=glyph.name or f_private(unicode) + indices[index]=name + names[name]=unicode + private=private+1 + elseif unicode>=puafirst and unicode<=pualast then + local name=glyph.name or f_private(unicode) + indices[index]=name + names[name]=unicode + elseif descriptions[unicode] then + unicode=private + local name=glyph.name or f_private(unicode) + indices[index]=name + names[name]=unicode + private=private+1 + else + local name=glyph.name or f_unicode(unicode) + indices[index]=name + names[name]=unicode + end + descriptions[unicode]=glyph + end + elseif trace_unicodes then + for index=1,#glyphs do + local glyph=glyphs[index] + local unicode=glyph.unicode + if not unicode then + unicode=private + indices[index]=unicode + private=private+1 + elseif unicode>=firstprivate then + local name=glyph.name + if name then + report_unicodes("moving glyph %a indexed %05X from private %U to %U ",name,index,unicode,private) + else + report_unicodes("moving glyph indexed %05X from private %U to %U ",index,unicode,private) + end + unicode=private + indices[index]=unicode + private=private+1 + elseif unicode>=puafirst and unicode<=pualast then + local name=glyph.name + if name then + report_unicodes("keeping private unicode %U for glyph %a indexed %05X",unicode,name,index) + else + report_unicodes("keeping private unicode %U for glyph indexed %05X",unicode,index) + end + indices[index]=unicode + elseif descriptions[unicode] then + local name=glyph.name + if name then + report_unicodes("assigning duplicate unicode %U to %U for glyph %a indexed %05X ",unicode,private,name,index) + else + report_unicodes("assigning duplicate unicode %U to %U for glyph indexed %05X ",unicode,private,index) + end + unicode=private + indices[index]=unicode + private=private+1 + else + indices[index]=unicode + end + descriptions[unicode]=glyph + end + else + for index=1,#glyphs do + local glyph=glyphs[index] + local unicode=glyph.unicode + if not unicode then + unicode=private + indices[index]=unicode + private=private+1 + elseif unicode>=firstprivate then + local name=glyph.name + unicode=private + indices[index]=unicode + private=private+1 + elseif unicode>=puafirst and unicode<=pualast then + local name=glyph.name + indices[index]=unicode + elseif descriptions[unicode] then + local name=glyph.name + unicode=private + indices[index]=unicode + private=private+1 + else + indices[index]=unicode + end + descriptions[unicode]=glyph + end + end + for index=1,#glyphs do + local math=glyphs[index].math + if math then + local list=math.vparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.hparts + if list then + for i=1,#list do local l=list[i] l.glyph=indices[l.glyph] end + end + local list=math.vvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end + local list=math.hvariants + if list then + for i=1,#list do list[i]=indices[list[i]] end + end + end + end + local colorpalettes=resources.colorpalettes + if colorpalettes then + for index=1,#glyphs do + local colors=glyphs[index].colors + if colors then + for i=1,#colors do + local c=colors[i] + c.slot=indices[c.slot] + end + end + end + end + fontdata.private=private + fontdata.glyphs=nil + fontdata.names=names + fontdata.descriptions=descriptions + fontdata.hashmethod=hashmethod + return indices,names +end +local p_crappyname do + local p_hex=R("af","AF","09") + local p_digit=R("09") + local p_done=S("._-")^0+P(-1) + local p_alpha=R("az","AZ") + local p_ALPHA=R("AZ") + p_crappyname=( + lpeg.utfchartabletopattern({ "uni","u" },true)*S("Xx_")^0*p_hex^1 ++lpeg.utfchartabletopattern({ "identity","glyph","jamo" },true)*p_hex^1 ++lpeg.utfchartabletopattern({ "index","afii" },true)*p_digit^1 ++p_digit*p_hex^3+p_alpha*p_digit^1 ++P("aj")*p_digit^1+P("eh_")*(p_digit^1+p_ALPHA*p_digit^1)+(1-P("_"))^1*P("_uni")*p_hex^1+P("_")*P(1)^1 + )*p_done +end +local forcekeep=false +directives.register("otf.keepnames",function(v) + report_cleanup("keeping weird glyph names, expect larger files and more memory usage") + forcekeep=v +end) +local function stripredundant(fontdata) + local descriptions=fontdata.descriptions + if descriptions then + local n=0 + local c=0 + if (not context and fonts.privateoffsets.keepnames) or forcekeep then + for unicode,d in next,descriptions do + if d.class=="base" then + d.class=nil + c=c+1 + end + end + else + for unicode,d in next,descriptions do + local name=d.name + if name and lpegmatch(p_crappyname,name) then + d.name=nil + n=n+1 + end + if d.class=="base" then + d.class=nil + c=c+1 + end + end + end + if trace_cleanup then + if n>0 then + report_cleanup("%s bogus names removed (verbose unicode)",n) + end + if c>0 then + report_cleanup("%s base class tags removed (default is base)",c) + end + end + end +end +readers.stripredundant=stripredundant +function readers.getcomponents(fontdata) + local resources=fontdata.resources + if resources then + local sequences=resources.sequences + if sequences then + local collected={} + for i=1,#sequences do + local sequence=sequences[i] + if sequence.type=="gsub_ligature" then + local steps=sequence.steps + if steps then + local l={} + local function traverse(p,k,v) + if k=="ligature" then + collected[v]={ unpack(l) } + else + insert(l,k) + for k,vv in next,v do + traverse(p,k,vv) + end + remove(l) + end + end + for i=1,#steps do + local c=steps[i].coverage + if c then + for k,v in next,c do + traverse(k,k,v) + end + end + end + end + end + end + if next(collected) then + while true do + local done=false + for k,v in next,collected do + for i=1,#v do + local vi=v[i] + if vi==k then + collected[k]=nil + break + else + local c=collected[vi] + if c then + done=true + local t={} + local n=i-1 + for j=1,n do + t[j]=v[j] + end + for j=1,#c do + n=n+1 + t[n]=c[j] + end + for j=i+1,#v do + n=n+1 + t[n]=v[j] + end + collected[k]=t + break + end + end + end + end + if not done then + break + end + end + return collected + end + end + end +end +readers.unifymissing=unifymissing +function readers.rehash(fontdata,hashmethod) + if not (fontdata and fontdata.glyphs) then + return + end + if hashmethod=="indices" then + fontdata.hashmethod="indices" + elseif hashmethod=="names" then + fontdata.hashmethod="names" + local indices=unifyglyphs(fontdata,true) + unifyresources(fontdata,indices) + copyduplicates(fontdata) + unifymissing(fontdata) + else + fontdata.hashmethod="unicodes" + local indices=unifyglyphs(fontdata) + unifyresources(fontdata,indices) + copyduplicates(fontdata) + unifymissing(fontdata) + stripredundant(fontdata) + end +end +function readers.checkhash(fontdata) + local hashmethod=fontdata.hashmethod + if hashmethod=="unicodes" then + fontdata.names=nil + elseif hashmethod=="names" and fontdata.names then + unifyresources(fontdata,fontdata.names) + copyduplicates(fontdata) + fontdata.hashmethod="unicodes" + fontdata.names=nil + else + readers.rehash(fontdata,"unicodes") + end +end +function readers.addunicodetable(fontdata) + local resources=fontdata.resources + local unicodes=resources.unicodes + if not unicodes then + local descriptions=fontdata.descriptions + if descriptions then + unicodes={} + resources.unicodes=unicodes + for u,d in next,descriptions do + local n=d.name + if n then + unicodes[n]=u + end + end + end + end +end +local concat,sort=table.concat,table.sort +local next,type,tostring=next,type,tostring +local criterium=1 +local threshold=0 +local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end) +local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) +local report_otf=logs.reporter("fonts","otf loading") +local function tabstr_normal(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + if type(v)=="table" then + s[n]=k..">"..tabstr_normal(v) + elseif v==true then + s[n]=k.."+" + elseif v then + s[n]=k.."="..v + else + s[n]=k.."-" + end + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else + sort(s) + return concat(s,",") + end +end +local function tabstr_flat(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + s[n]=k.."="..v + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else + sort(s) + return concat(s,",") + end +end +local function tabstr_mixed(t) + local s={} + local n=#t + if n==0 then + return "" + elseif n==1 then + local k=t[1] + if k==true then + return "++" + elseif k==false then + return "--" + else + return tostring(k) + end + else + for i=1,n do + local k=t[i] + if k==true then + s[i]="++" + elseif k==false then + s[i]="--" + else + s[i]=k + end + end + return concat(s,",") + end +end +local function tabstr_boolean(t) + local s={} + local n=0 + for k,v in next,t do + n=n+1 + if v then + s[n]=k.."+" + else + s[n]=k.."-" + end + end + if n==0 then + return "" + elseif n==1 then + return s[1] + else + sort(s) + return concat(s,",") + end +end +function readers.pack(data) + if data then + local h,t,c={},{},{} + local hh,tt,cc={},{},{} + local nt,ntt=0,0 + local function pack_normal(v) + local tag=tabstr_normal(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_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 + c[nt]=1 + return nt + end + end + local function pack_flat(v) + local tag=tabstr_flat(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_indexed(v) + local tag=concat(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_mixed(v) + local tag=tabstr_mixed(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_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] + 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 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 + report_otf("pack quality: nothing to pack") + end + return false + elseif nt>=threshold then + local one=0 + local two=0 + local rest=0 + if pass==1 then + for k,v in next,c do + if v==1 then + one=one+1 + elseif v==2 then + two=two+1 + else + rest=rest+1 + end + end + else + for k,v in next,cc do + if v>20 then + rest=rest+1 + elseif v>10 then + two=two+1 + else + one=one+1 + end + end + data.tables=tt + end + if trace_loading or trace_packing then + report_otf("pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", + stage,pass,one+two+rest,one,two,rest,criterium) + end + return true + else + if trace_loading or trace_packing then + report_otf("pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", + stage,pass,nt,threshold) + end + return false + end + end + local function packers(pass) + if pass==1 then + 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,pack_final_cc + end + end + local resources=data.resources + local sequences=resources.sequences + 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 + 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,pack_normal_cc=packers(pass) + for unicode,description in next,descriptions do + local boundingbox=description.boundingbox + if boundingbox then + description.boundingbox=pack_indexed(boundingbox) + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + for tag,kern in next,kerns do + kerns[tag]=pack_normal(kern) + end + end + end + end + local function packthem(sequences) + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + local order=sequence.order + local features=sequence.features + local flags=sequence.flags + 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~="pair" then + for g1,d1 in next,c do + c[g1]=pack_normal(d1) + end + elseif step.shared then + local shared={} + for g1,d1 in next,c do + for g2,d2 in next,d1 do + if not shared[d2] then + 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 + shared[d2]=true + end + end + end + if pass==2 then + step.shared=nil + end + else + for g1,d1 in next,c do + 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 + end + end + elseif kind=="gpos_single" then + local c=step.coverage + if c then + if step.format=="single" then + for g1,d1 in next,c do + 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 + local c=step.coverage + if c then + for g1,d1 in next,c do + local f=d1[2] if f then d1[2]=pack_indexed(f) end + local s=d1[3] if s then d1[3]=pack_indexed(s) end + end + end + elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" 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_indexed(d2) + end + end + end + local c=step.coverage + if c then + for g1,d1 in next,c do + d1[2]=pack_indexed(d1[2]) + 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 + for g3,d3 in next,d2 do + d2[g3]=pack_indexed(d3) + end + end + end + end + local c=step.coverage + if c then + for g1,d1 in next,c do + d1[2]=pack_indexed(d1[2]) + end + end + end + local rules=step.rules + if rules then + for i=1,#rules do + local rule=rules[i] + 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.replacements if r then rule.replacements=pack_flat (r) end + end + end + end + end + if order then + sequence.order=pack_indexed(order) + end + if features then + for script,feature in next,features do + features[script]=pack_normal(feature) + end + end + if flags then + sequence.flags=pack_normal(flags) + end + end + end + if sequences then + packthem(sequences) + end + if sublookups then + packthem(sublookups) + end + if features then + for k,list in next,features do + for feature,spec in next,list do + list[feature]=pack_normal(spec) + end + end + end + if palettes then + for i=1,#palettes do + local p=palettes[i] + for j=1,#p do + p[j]=pack_indexed(p[j]) + 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 + end + if nt>0 then + for pass=1,2 do + 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,pack_normal_cc=packers(pass) + for unicode,description in next,descriptions do + local math=description.math + if math then + local kerns=math.kerns + if kerns then + math.kerns=pack_normal(kerns) + end + end + end + local function packthem(sequences) + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + local features=sequence.features + 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=="pair" then + for g1,d1 in next,c do + for g2,d2 in next,d1 do + d1[g2]=pack_normal(d2) + end + 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 + for i=1,#rules do + local rule=rules[i] + local r=rule.before if r then rule.before=pack_normal(r) end + local r=rule.after if r then rule.after=pack_normal(r) end + local r=rule.current if r then rule.current=pack_normal(r) end + end + end + end + end + if features then + sequence.features=pack_normal(features) + end + end + end + if sequences then + packthem(sequences) + end + if sublookups then + packthem(sublookups) + end + 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,pack_normal_cc=packers(pass) + local function packthem(sequences) + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + local features=sequence.features + 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=="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 + if sequences then + packthem(sequences) + end + if sublookups then + packthem(sublookups) + end + end + end + end +end +local unpacked_mt={ + __index=function(t,k) + t[k]=false + return k + end +} +function readers.unpack(data) + if data then + local tables=data.tables + if tables then + local resources=data.resources + local descriptions=data.descriptions or data.glyphs + local sequences=resources.sequences + 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 + local tv=tables[description.boundingbox] + if tv then + description.boundingbox=tv + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + local tm=tables[kerns] + if tm then + math.kerns=tm + kerns=unpacked[tm] + end + if kerns then + for k,kern in next,kerns do + local tv=tables[kern] + if tv then + kerns[k]=tv + end + end + end + end + end + end + local function unpackthem(sequences) + for i=1,#sequences do + local sequence=sequences[i] + local kind=sequence.type + local steps=sequence.steps + local order=sequence.order + 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=="pair" then + for g1,d1 in next,c do + local tv=tables[d1] + if tv then + c[g1]=tv + d1=tv + end + for g2,d2 in next,d1 do + local tv=tables[d2] + if tv then + d1[g2]=tv + d2=tv + end + local f=tables[d2[1]] if f then d2[1]=f end + 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=="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 + end + elseif kind=="gpos_mark2base" or kind=="gpos_mark2mark" then + local c=step.baseclasses + if c then + for g1,d1 in next,c do + for g2,d2 in next,d1 do + local tv=tables[d2] + if tv then + d1[g2]=tv + end + end + end + end + local c=step.coverage + if c then + for g1,d1 in next,c do + local tv=tables[d1[2]] + if tv then + d1[2]=tv + 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 + 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 + d2[g3]=tv + end + end + end + end + end + local c=step.coverage + if c then + for g1,d1 in next,c do + local tv=tables[d1[2]] + if tv then + d1[2]=tv + end + end + end + end + local rules=step.rules + if rules then + for i=1,#rules do + local rule=rules[i] + local before=rule.before + if before then + local tv=tables[before] + if tv then + rule.before=tv + before=tv + end + for i=1,#before do + local tv=tables[before[i]] + if tv then + before[i]=tv + end + end + end + local after=rule.after + if after then + local tv=tables[after] + if tv then + rule.after=tv + after=tv + end + for i=1,#after do + local tv=tables[after[i]] + if tv then + after[i]=tv + end + end + end + local current=rule.current + if current then + local tv=tables[current] + if tv then + rule.current=tv + current=tv + end + for i=1,#current do + local tv=tables[current[i]] + if tv then + current[i]=tv + end + end + end + local replacements=rule.replacements + if replacements then + local tv=tables[replacements] + if tv then + rule.replacements=tv + end + end + end + end + end + end + if order then + local tv=tables[order] + if tv then + sequence.order=tv + end + end + if flags then + local tv=tables[flags] + if tv then + sequence.flags=tv + end + end + end + end + if sequences then + unpackthem(sequences) + end + if sublookups then + unpackthem(sublookups) + end + if features then + for k,list in next,features do + for feature,spec in next,list do + local tv=tables[spec] + if tv then + list[feature]=tv + end + end + end + end + if palettes then + for i=1,#palettes do + local p=palettes[i] + for j=1,#p do + local tv=tables[p[j]] + if tv then + p[j]=tv + end + 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 +end +local mt={ + __index=function(t,k) + if k=="height" then + local ht=t.boundingbox[4] + return ht<0 and 0 or ht + elseif k=="depth" then + local dp=-t.boundingbox[2] + return dp<0 and 0 or dp + elseif k=="width" then + return 0 + elseif k=="name" then + return forcenotdef and ".notdef" + end + end +} +local function sameformat(sequence,steps,first,nofsteps,kind) + return true +end +local function mergesteps_1(lookup,strict) + local steps=lookup.steps + local nofsteps=lookup.nofsteps + local first=steps[1] + if strict then + local f=first.format + for i=2,nofsteps do + if steps[i].format~=f then + if trace_optimizations then + report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) + end + return 0 + end + end + end + if trace_optimizations then + report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) + end + local target=first.coverage + for i=2,nofsteps do + 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 + lookup.nofsteps=1 + lookup.merged=true + lookup.steps={ first } + return nofsteps-1 +end +local function mergesteps_2(lookup) + local steps=lookup.steps + local nofsteps=lookup.nofsteps + local first=steps[1] + if strict then + local f=first.format + for i=2,nofsteps do + if steps[i].format~=f then + if trace_optimizations then + report_optimizations("not merging %a steps of %a lookup %a, different formats",nofsteps,lookup.type,lookup.name) + end + return 0 + end + end + end + if trace_optimizations then + report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) + end + local target=first.coverage + 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 + for kk,vv in next,v do + if tk[kk]==nil then + tk[kk]=vv + end + end + else + target[k]=v + end + 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 + if trace_optimizations then + report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) + end + local coverage={} + for i=1,nofsteps do + local c=steps[i].coverage + if c then + for k,v in next,c do + local tk=coverage[k] + if tk then + if trace_optimizations then + report_optimizations("quitting merge due to multiple checks") + end + 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 + 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 +local function nested(old,new) + for k,v in next,old do + if k=="ligature" then + if not new.ligature then + new.ligature=v + end + else + local n=new[k] + if n then + nested(v,n) + else + new[k]=v + end + end + end +end +local function mergesteps_4(lookup) + local steps=lookup.steps + local nofsteps=lookup.nofsteps + local first=steps[1] + if trace_optimizations then + report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) + end + local target=first.coverage + 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 + 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] + if trace_optimizations then + report_optimizations("merging %a steps of %a lookup %a",nofsteps,lookup.type,lookup.name) + end + 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==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 + if trace_optimizations then + report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) + end + local c={} + for g1,d1 in next,coverage do + if d1 and d1~=true then + c[g1]=d1[3] + end + end + 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 + 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 + 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 + if trace_optimizations then + report_optimizations("turning pairs of step %a of %a lookup %a into kerns",i,lookup.type,lookup.name) + end + for g1,d1 in next,coverage do + local d={} + for g2,d2 in next,d1 do + local v=d2[1] + if v==true then + elseif v then + d[g2]=v[3] + end + end + coverage[g1]=d + end + 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 + else + data.compacted=true + end + local resources=data.resources + local merged=0 + local kerned=0 + local allsteps=0 + local function compact(what) + local lookups=resources[what] + if lookups then + 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 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 + if merge_ligatures then + merged=merged+mergesteps_4(lookup) + end + elseif kind=="gpos_single" then + 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 + if merge_pairs then + merged=merged+mergesteps_2(lookup) + end + if compact_pairs then + kerned=kerned+checkpairs(lookup) + end + elseif kind=="gpos_cursive" then + if merge_cursives then + merged=merged+mergesteps_5(lookup) + end + elseif kind=="gpos_mark2mark" or kind=="gpos_mark2base" or kind=="gpos_mark2ligature" then + 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 + elseif trace_optimizations then + report_optimizations("no lookups in %a",what) + end + end + compact("sequences") + compact("sublookups") + if trace_optimizations then + if merged>0 then + report_optimizations("%i steps of %i removed due to merging",merged,allsteps) + end + if kerned>0 then + report_optimizations("%i steps of %i steps turned from pairs into kerns",kerned,allsteps) + end + 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 + else + data.expanded=true + end + local resources=data.resources + local sublookups=resources.sublookups + local sequences=resources.sequences + local markclasses=resources.markclasses + local descriptions=data.descriptions + if descriptions then + local defaultwidth=resources.defaultwidth or 0 + local defaultheight=resources.defaultheight or 0 + local defaultdepth=resources.defaultdepth or 0 + local basename=trace_markwidth and file.basename(resources.filename) + for u,d in next,descriptions do + local bb=d.boundingbox + local wd=d.width + if not wd then + d.width=defaultwidth + elseif trace_markwidth and wd~=0 and d.class=="mark" then + report_markwidth("mark %a with width %b found in %a",d.name or "<noname>",wd,basename) + end + if bb then + local ht=bb[4] + local dp=-bb[2] + if ht==0 or ht<0 then + else + d.height=ht + end + if dp==0 or dp<0 then + else + d.depth=dp + end + end + end + end + local function expandlookups(sequences) + if sequences then + for i=1,#sequences do + 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 + if not markclasses then + report_warning("missing markclasses") + sequence.markclass=false + else + sequence.markclass=markclasses[markclass] + end + end + for i=1,nofsteps do + local step=steps[i] + local baseclasses=step.baseclasses + if baseclasses then + local coverage=step.coverage + for k,v in next,coverage do + v[1]=baseclasses[v[1]] + end + elseif kind=="gpos_cursive" then + local coverage=step.coverage + for k,v in next,coverage do + v[1]=coverage + end + end + local rules=step.rules + if rules then + local rulehash={ n=0 } + local rulesize=0 + local coverage={} + local lookuptype=sequence.type + local nofrules=#rules + step.coverage=coverage + for currentrule=1,nofrules do + local rule=rules[currentrule] + local current=rule.current + local before=rule.before + local after=rule.after + local replacements=rule.replacements or false + local sequence={} + local nofsequences=0 + if before then + for n=1,#before do + nofsequences=nofsequences+1 + sequence[nofsequences]=before[n] + end + end + local start=nofsequences+1 + for n=1,#current do + nofsequences=nofsequences+1 + sequence[nofsequences]=current[n] + end + local stop=nofsequences + if after then + for n=1,#after do + nofsequences=nofsequences+1 + sequence[nofsequences]=after[n] + end + end + local lookups=rule.lookups or false + local subtype=nil + if lookups then + 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 + end + end + end + if sequence[1] then + sequence.n=#sequence + local ruledata={ + currentrule, + lookuptype, + sequence, + start, + stop, + lookups, + replacements, + subtype, + } + 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 + end + expandlookups(sequences) + expandlookups(sublookups) +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-oup”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otl” b041e8512af19d28edbbebc683f7cd51] --- + +if not modules then modules={} end modules ['font-otl']={ + 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 type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack +local abs=math.abs +local derivetable=table.derive +local formatters=string.formatters +local setmetatableindex=table.setmetatableindex +local allocate=utilities.storage.allocate +local registertracker=trackers.register +local registerdirective=directives.register +local starttiming=statistics.starttiming +local stoptiming=statistics.stoptiming +local elapsedtime=statistics.elapsedtime +local findbinfile=resolvers.findbinfile +local trace_loading=false registertracker("otf.loading",function(v) trace_loading=v end) +local trace_features=false registertracker("otf.features",function(v) trace_features=v end) +local trace_defining=false registertracker("fonts.defining",function(v) trace_defining=v end) +local report_otf=logs.reporter("fonts","otf loading") +local fonts=fonts +local otf=fonts.handlers.otf +otf.version=3.108 +otf.cache=containers.define("fonts","otl",otf.version,true) +otf.svgcache=containers.define("fonts","svg",otf.version,true) +otf.pngcache=containers.define("fonts","png",otf.version,true) +otf.pdfcache=containers.define("fonts","pdf",otf.version,true) +otf.svgenabled=false +otf.pngenabled=false +local otfreaders=otf.readers +local hashes=fonts.hashes +local definers=fonts.definers +local readers=fonts.readers +local constructors=fonts.constructors +local otffeatures=constructors.features.otf +local registerotffeature=otffeatures.register +local otfenhancers=constructors.enhancers.otf +local registerotfenhancer=otfenhancers.register +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" +local formats=fonts.formats +formats.otf="opentype" +formats.ttf="truetype" +formats.ttc="truetype" +registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end) +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) +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 attr=lfs.attributes(filename) + local size=attr and attr.size or 0 + local time=attr and attr.modification or 0 + if sub=="" then + sub=false + end + local hash=name + if sub then + hash=hash.."-"..sub + 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 reload then + report_otf("loading %a, hash %a",filename,hash) + starttiming(otfreaders,true) + data=otfreaders.loadfont(filename,sub or 1,instance) + if data then + local used=checkmemory() + local resources=data.resources + local svgshapes=resources.svgshapes + local pngshapes=resources.pngshapes + if cleanup==0 then + checkmemory(used,threshold,tracememory) + end + if svgshapes then + resources.svgshapes=nil + if otf.svgenabled then + local timestamp=os.date() + containers.write(otf.svgcache,hash,{ + svgshapes=svgshapes, + timestamp=timestamp, + }) + data.properties.svg={ + hash=hash, + timestamp=timestamp, + } + end + if cleanup>1 then + collectgarbage("collect") + else + checkmemory(used,threshold,tracememory) + end + end + if pngshapes then + resources.pngshapes=nil + if otf.pngenabled then + local timestamp=os.date() + containers.write(otf.pngcache,hash,{ + pngshapes=pngshapes, + timestamp=timestamp, + }) + data.properties.png={ + 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 + report_otf("loading, optimizing, packing and caching time %s",elapsedtime(otfreaders)) + 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 + stoptiming(otfreaders) + data=nil + report_otf("loading failed due to read error") + end + end + if data then + if trace_defining then + report_otf("loading from cache using hash %a",hash) + end + otfreaders.unpack(data) + otfreaders.expand(data) + otfreaders.addunicodetable(data) + otfenhancers.apply(data,filename,data) + if applyruntimefixes then + 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 +function otf.setfeatures(tfmdata,features) + local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf) + if okay then + return constructors.collectprocessors("otf",tfmdata,features,trace_features,report_otf) + else + return {} + end +end +local function copytotfm(data,cache_id) + if data then + local metadata=data.metadata + local properties=derivetable(data.properties) + local descriptions=derivetable(data.descriptions) + local goodies=derivetable(data.goodies) + local characters={} + local parameters={} + local mathparameters={} + local resources=data.resources + local unicodes=resources.unicodes + local spaceunits=500 + local spacer="space" + local designsize=metadata.designsize or 100 + local minsize=metadata.minsize or designsize + local maxsize=metadata.maxsize or designsize + local mathspecs=metadata.math + if designsize==0 then + designsize=100 + minsize=100 + maxsize=100 + end + if mathspecs then + for name,value in next,mathspecs do + mathparameters[name]=value + end + end + for unicode in next,data.descriptions do + characters[unicode]={} + end + if mathspecs then + for unicode,character in next,characters do + local d=descriptions[unicode] + local m=d.math + if m then + local italic=m.italic + local vitalic=m.vitalic + local variants=m.hvariants + local parts=m.hparts + if variants then + local c=character + for i=1,#variants do + local un=variants[i] + c.next=un + c=characters[un] + end + c.horiz_variants=parts + elseif parts then + character.horiz_variants=parts + italic=m.hitalic + end + local variants=m.vvariants + local parts=m.vparts + if variants then + local c=character + for i=1,#variants do + local un=variants[i] + c.next=un + c=characters[un] + end + c.vert_variants=parts + elseif parts then + character.vert_variants=parts + end + if italic and italic~=0 then + character.italic=italic + end + if vitalic and vitalic~=0 then + character.vert_italic=vitalic + end + local accent=m.accent + if accent then + character.accent=accent + end + local kerns=m.kerns + if kerns then + character.mathkerns=kerns + end + end + end + end + local filename=constructors.checkedfilename(resources) + 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 + metadata.units=1000 + report_otf("changing %a units to %a",0,units) + end + local monospaced=metadata.monospaced + local charwidth=metadata.averagewidth + local charxheight=metadata.xheight + local italicangle=metadata.italicangle + local hasitalics=metadata.hasitalics + properties.monospaced=monospaced + properties.hasitalics=hasitalics + parameters.italicangle=italicangle + parameters.charwidth=charwidth + parameters.charxheight=charxheight + local space=0x0020 + local emdash=0x2014 + if monospaced then + if descriptions[space] then + spaceunits,spacer=descriptions[space].width,"space" + end + if not spaceunits and descriptions[emdash] then + spaceunits,spacer=descriptions[emdash].width,"emdash" + end + if not spaceunits and charwidth then + spaceunits,spacer=charwidth,"charwidth" + end + else + if descriptions[space] then + spaceunits,spacer=descriptions[space].width,"space" + end + if not spaceunits and descriptions[emdash] then + spaceunits,spacer=descriptions[emdash].width/2,"emdash/2" + end + if not spaceunits and charwidth then + spaceunits,spacer=charwidth,"charwidth" + end + end + spaceunits=tonumber(spaceunits) or units/2 + parameters.slant=0 + parameters.space=spaceunits + parameters.space_stretch=1*units/2 + parameters.space_shrink=1*units/3 + parameters.x_height=2*units/5 + parameters.quad=units + if spaceunits<2*units/5 then + end + if italicangle and italicangle~=0 then + parameters.italicangle=italicangle + parameters.italicfactor=math.cos(math.rad(90+italicangle)) + parameters.slant=- math.tan(italicangle*math.pi/180) + end + if monospaced then + parameters.space_stretch=0 + parameters.space_shrink=0 + elseif syncspace then + parameters.space_stretch=spaceunits/2 + parameters.space_shrink=spaceunits/3 + end + parameters.extra_space=parameters.space_shrink + if charxheight then + parameters.x_height=charxheight + else + local x=0x0078 + if x then + local x=descriptions[x] + if x then + parameters.x_height=x.height + end + end + end + parameters.designsize=(designsize/10)*65536 + parameters.minsize=(minsize/10)*65536 + parameters.maxsize=(maxsize/10)*65536 + parameters.ascender=abs(metadata.ascender or 0) + parameters.descender=abs(metadata.descender or 0) + parameters.units=units + properties.space=spacer + properties.encodingbytes=2 + properties.format=data.format or formats.otf + properties.filename=filename + properties.fontname=fontname + 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, + parameters=parameters, + mathparameters=mathparameters, + resources=resources, + properties=properties, + goodies=goodies, + } + end +end +local converters={ + woff={ + cachename="webfonts", + action=otf.readers.woff2otf, + } +} +local function checkconversion(specification) + local filename=specification.filename + local converter=converters[lower(file.suffix(filename))] + if converter then + local base=file.basename(filename) + 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 size>0 then + local cleanname=containers.cleanname(name) + local cachename=caches.setfirstwritablefile(cleanname,converter.cachename) + if not io.exists(cachename) or (time~=lfs.attributes(cachename).modification) then + report_otf("caching font %a in %a",filename,cachename) + converter.action(filename,cachename) + lfs.touch(cachename,time,time) + end + specification.filename=cachename + end + end +end +local function otftotfm(specification) + local cache_id=specification.hash + local tfmdata=containers.read(constructors.cache,cache_id) + if not tfmdata then + checkconversion(specification) + local name=specification.name + local sub=specification.sub + local subindex=specification.subindex + local filename=specification.filename + local features=specification.features.normal + 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={} + tfmdata=copytotfm(rawdata,cache_id) + if tfmdata and next(tfmdata) then + local features=constructors.checkedfeatures("otf",features) + local shared=tfmdata.shared + if not shared then + shared={} + tfmdata.shared=shared + end + shared.rawdata=rawdata + shared.dynamics={} + tfmdata.changed={} + shared.features=features + shared.processes=otf.setfeatures(tfmdata,features) + end + end + containers.write(constructors.cache,cache_id,tfmdata) + end + return tfmdata +end +local function read_from_otf(specification) + local tfmdata=otftotfm(specification) + if tfmdata then + tfmdata.properties.name=specification.name + tfmdata.properties.sub=specification.sub + tfmdata=constructors.scale(tfmdata,specification) + local allfeatures=tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("otf",tfmdata,allfeatures,trace_features,report_otf) + constructors.setname(tfmdata,specification) + fonts.loggers.register(tfmdata,file.suffix(specification.filename),specification) + end + return tfmdata +end +local function checkmathsize(tfmdata,mathsize) + local mathdata=tfmdata.shared.rawdata.metadata.math + local mathsize=tonumber(mathsize) + if mathdata then + local parameters=tfmdata.parameters + parameters.scriptpercentage=mathdata.ScriptPercentScaleDown + parameters.scriptscriptpercentage=mathdata.ScriptScriptPercentScaleDown + parameters.mathsize=mathsize + end +end +registerotffeature { + name="mathsize", + description="apply mathsize specified in the font", + initializers={ + base=checkmathsize, + node=checkmathsize, + } +} +function otf.collectlookups(rawdata,kind,script,language) + if not kind then + return + end + if not script then + script=default + end + if not language then + language=default + end + local lookupcache=rawdata.lookupcache + if not lookupcache then + lookupcache={} + rawdata.lookupcache=lookupcache + end + local kindlookup=lookupcache[kind] + if not kindlookup then + kindlookup={} + lookupcache[kind]=kindlookup + end + local scriptlookup=kindlookup[script] + if not scriptlookup then + scriptlookup={} + kindlookup[script]=scriptlookup + end + local languagelookup=scriptlookup[language] + if not languagelookup then + local sequences=rawdata.resources.sequences + local featuremap={} + local featurelist={} + if sequences then + for s=1,#sequences do + local sequence=sequences[s] + local features=sequence.features + if features then + features=features[kind] + if features then + features=features[script] or features[wildcard] + if features then + features=features[language] or features[wildcard] + if features then + if not featuremap[sequence] then + featuremap[sequence]=true + featurelist[#featurelist+1]=sequence + end + end + end + end + end + end + if #featurelist==0 then + featuremap,featurelist=false,false + end + else + featuremap,featurelist=false,false + end + languagelookup={ featuremap,featurelist } + scriptlookup[language]=languagelookup + end + return unpack(languagelookup) +end +local function getgsub(tfmdata,k,kind,value) + local shared=tfmdata.shared + local rawdata=shared and shared.rawdata + if rawdata then + local sequences=rawdata.resources.sequences + if sequences then + local properties=tfmdata.properties + local validlookups,lookuplist=otf.collectlookups(rawdata,kind,properties.script,properties.language) + if validlookups then + for i=1,#lookuplist do + local lookup=lookuplist[i] + local steps=lookup.steps + local nofsteps=lookup.nofsteps + for i=1,nofsteps do + local coverage=steps[i].coverage + if coverage then + local found=coverage[k] + if found then + return found,lookup.type + end + end + end + end + end + end + end +end +otf.getgsub=getgsub +function otf.getsubstitution(tfmdata,k,kind,value) + local found,kind=getgsub(tfmdata,k,kind,value) + if not found then + elseif kind=="gsub_single" then + return found + elseif kind=="gsub_alternate" then + local choice=tonumber(value) or 1 + return found[choice] or found[1] or k + end + return k +end +otf.getalternate=otf.getsubstitution +function otf.getmultiple(tfmdata,k,kind) + local found,kind=getgsub(tfmdata,k,kind) + if found and kind=="gsub_multiple" then + return found + end + return { k } +end +function otf.getkern(tfmdata,left,right,kind) + local kerns=getgsub(tfmdata,left,kind or "kern",true) + if kerns then + local found=kerns[right] + local kind=type(found) + if kind=="table" then + found=found[1][3] + elseif kind~="number" then + found=false + end + if found then + return found*tfmdata.parameters.factor + end + end + return 0 +end +local function check_otf(forced,specification,suffix) + local name=specification.name + if forced then + name=specification.forcedname + end + local fullname=findbinfile(name,suffix) or "" + if fullname=="" then + fullname=fonts.names.getfilename(name,suffix) or "" + end + if fullname~="" and not fonts.names.ignoredfile(fullname) then + specification.filename=fullname + return read_from_otf(specification) + end +end +local function opentypereader(specification,suffix) + local forced=specification.forced or "" + if formats[forced] then + return check_otf(true,specification,forced) + else + return check_otf(false,specification,suffix) + end +end +readers.opentype=opentypereader +function readers.otf(specification) return opentypereader(specification,"otf") end +function readers.ttf(specification) return opentypereader(specification,"ttf") end +function readers.ttc(specification) return opentypereader(specification,"ttf") end +function readers.woff(specification) + checkconversion(specification) + opentypereader(specification,"") +end +function otf.scriptandlanguage(tfmdata,attr) + local properties=tfmdata.properties + return properties.script or "dflt",properties.language or "dflt" +end +local function justset(coverage,unicode,replacement) + coverage[unicode]=replacement +end +otf.coverup={ + stepkey="steps", + actions={ + chainsubstitution=justset, + chainposition=justset, + substitution=justset, + alternate=justset, + multiple=justset, + kern=justset, + pair=justset, + single=justset, + ligature=function(coverage,unicode,ligature) + local first=ligature[1] + local tree=coverage[first] + if not tree then + tree={} + coverage[first]=tree + end + for i=2,#ligature do + local l=ligature[i] + local t=tree[l] + if not t then + t={} + tree[l]=t + end + tree=t + end + tree.ligature=unicode + end, + }, + register=function(coverage,featuretype,format) + return { + format=format, + coverage=coverage, + } + end +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otl”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-oto” 54ea5c823993e536950b2245e94aee93] --- + +if not modules then modules={} end modules ['font-oto']={ + 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 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 +local type,next,tonumber,tostring,rawget=type,next,tonumber,tostring,rawget +local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end) +local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end) +local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) +local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end) +local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end) +local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end) +local trace_preparing=false trackers.register("otf.preparing",function(v) trace_preparing=v end) +local report_prepare=logs.reporter("fonts","otf prepare") +local fonts=fonts +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 +local f_unicode=formatters["%U"] +local f_uniname=formatters["%U (%s)"] +local f_unilist=formatters["% t (% t)"] +local function gref(descriptions,n) + if type(n)=="number" then + local name=descriptions[n].name + if name then + return f_uniname(n,name) + else + return f_unicode(n) + end + elseif n then + local num={} + local nam={} + local j=0 + for i=1,#n do + local ni=n[i] + if tonumber(ni) then + j=j+1 + local di=descriptions[ni] + num[j]=f_unicode(ni) + nam[j]=di and di.name or "-" + end + end + return f_unilist(num,nam) + else + return "<error in base mode tracing>" + end +end +local function cref(feature,sequence) + return formatters["feature %a, type %a, chain lookup %a"](feature,sequence.type,sequence.name) +end +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_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", + cref(feature,sequence), + gref(descriptions,ligature), + gref(descriptions,unicode)) +end +local function report_kern(feature,sequence,descriptions,unicode,otherunicode,value) + report_prepare("%s: base kern %s + %s => %S", + cref(feature,sequence), + gref(descriptions,unicode), + gref(descriptions,otherunicode), + value) +end +local basehash,basehashes,applied={},1,{} +local function registerbasehash(tfmdata) + local properties=tfmdata.properties + local hash=concat(applied," ") + local base=basehash[hash] + if not base then + basehashes=basehashes+1 + base=basehashes + basehash[hash]=base + end + properties.basehash=base + properties.fullname=(properties.fullname or properties.name).."-"..base + applied={} +end +local function registerbasefeature(feature,value) + applied[#applied+1]=feature.."="..tostring(value) +end +local function makefake(tfmdata,name,present) + local private=getprivate(tfmdata) + local character={ intermediate=true,ligatures={} } + resources.unicodes[name]=private + tfmdata.characters[private]=character + tfmdata.descriptions[private]={ name=name } + present[name]=private + return character +end +local function make_1(present,tree,name) + for k,v in next,tree do + if k=="ligature" then + present[name]=v + else + make_1(present,v,name.."_"..k) + end + end +end +local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done) + for k,v in next,tree do + if k=="ligature" then + local character=characters[preceding] + if not character then + if trace_baseinit then + report_prepare("weird ligature in lookup %a, current %C, preceding %C",sequence.name,v,preceding) + end + character=makefake(tfmdata,name,present) + end + local ligatures=character.ligatures + if ligatures then + ligatures[unicode]={ char=v } + else + character.ligatures={ [unicode]={ char=v } } + end + if done then + local d=done[name] + if not d then + done[name]={ "dummy",v } + else + d[#d+1]=v + end + end + else + local code=present[name] or unicode + local name=name.."_"..k + make_2(present,tfmdata,characters,v,name,code,k,done) + end + end +end +local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local changed=tfmdata.changed + local ligatures={} + local alternate=tonumber(value) or true and 1 + local defaultalt=otf.defaultbasealternate + local trace_singles=trace_baseinit and trace_singles + local trace_alternatives=trace_baseinit and trace_alternatives + local trace_ligatures=trace_baseinit and trace_ligatures + if not changed then + changed={} + tfmdata.changed=changed + end + for i=1,#lookuplist do + local sequence=lookuplist[i] + local steps=sequence.steps + local kind=sequence.type + if kind=="gsub_single" then + for i=1,#steps do + for unicode,data in next,steps[i].coverage do + 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 + local replacement=data[alternate] + if replacement then + if unicode~=replacement then + changed[unicode]=replacement + 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 + 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 + end + elseif kind=="gsub_ligature" then + for i=1,#steps do + for unicode,data in next,steps[i].coverage do + ligatures[#ligatures+1]={ unicode,data,"" } + if trace_ligatures then + report_ligature(feature,sequence,descriptions,unicode,data) + end + end + end + end + end + local nofligatures=#ligatures + if nofligatures>0 then + local characters=tfmdata.characters + local present={} + local done=trace_baseinit and trace_ligatures and {} + for i=1,nofligatures do + local ligature=ligatures[i] + local unicode=ligature[1] + local tree=ligature[2] + make_1(present,tree,"ctx_"..unicode) + end + for i=1,nofligatures do + local ligature=ligatures[i] + local unicode=ligature[1] + local tree=ligature[2] + local lookupname=ligature[3] + make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) + end + end +end +local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) + local characters=tfmdata.characters + local descriptions=tfmdata.descriptions + local resources=tfmdata.resources + local properties=tfmdata.properties + local traceindeed=trace_baseinit and trace_kerns + for i=1,#lookuplist do + local sequence=lookuplist[i] + local steps=sequence.steps + local kind=sequence.type + local format=sequence.format + if kind=="gpos_pair" then + for i=1,#steps do + 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 + if not kerns then + kerns={} + character.kerns=kerns + end + if traceindeed then + for otherunicode,kern in next,data do + if not kerns[otherunicode] and kern~=0 then + kerns[otherunicode]=kern + report_kern(feature,sequence,descriptions,unicode,otherunicode,kern) + end + end + else + for otherunicode,kern in next,data do + if not kerns[otherunicode] and kern~=0 then + kerns[otherunicode]=kern + end + end + end + end + else + for unicode,data in next,steps[i].coverage do + local character=characters[unicode] + local kerns=character.kerns + for otherunicode,kern in next,data do + local other=kern[2] + if other==true or (not other and not (kerns and kerns[otherunicode])) then + local kern=kern[1] + 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 + if kerns then + kerns[otherunicode]=kern + else + kerns={ [otherunicode]=kern } + character.kerns=kerns + end + if traceindeed then + report_kern(feature,sequence,descriptions,unicode,otherunicode,kern) + end + end + end + end + end + end + end + end + end + end +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] + if u and r then + 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 + else + if trace_preparing then + report_prepare("error replacing %C by %U",unicode,replacement) + end + end + end + end + end +end +local function featuresinitializer(tfmdata,value) + if true then + local starttime=trace_preparing and os.clock() + local features=tfmdata.shared.features + local fullname=tfmdata.properties.fullname or "?" + if features then + initializehashes(tfmdata) + local collectlookups=otf.collectlookups + local rawdata=tfmdata.shared.rawdata + local properties=tfmdata.properties + local script=properties.script + local language=properties.language + local rawresources=rawdata.resources + 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 + local sequence=sequences[s] + local sfeatures=sequence.features + if sfeatures then + local order=sequence.order + if order then + for i=1,#order do + local feature=order[i] + local value=features[feature] + if value then + local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) + if not validlookups then + elseif basesubstitutions and basesubstitutions[feature] then + if trace_preparing then + report_prepare("filtering base %s feature %a for %a with value %a","sub",feature,fullname,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 + end + end + end + end + if substitutionsdone then + checkmathreplacements(tfmdata,fullname,features.fixitalics) + end + registerbasehash(tfmdata) + end + if trace_preparing then + report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,fullname) + end + end +end +registerotffeature { + name="features", + description="features", + default=true, + initializers={ + base=featuresinitializer, + } +} +otf.basemodeinitializer=featuresinitializer + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-oto”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otj” bd772fd29bdec537c3c4e9d971b80325] --- + +if not modules then modules={} end modules ['font-otj']={ + version=1.001, + 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", +} +if not nodes.properties then return end +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 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 +local setcolor=tracers and tracers.colors.set +local resetcolor=tracers and tracers.colors.reset +local nodecodes=nodes.nodecodes +local glyph_code=nodecodes.glyph +local disc_code=nodecodes.disc +local kern_code=nodecodes.kern +local glue_code=nodecodes.glue +local nuts=nodes.nuts +local nodepool=nuts.pool +local tonode=nuts.tonode +local tonut=nuts.tonut +local setfield=nuts.setfield +local getnext=nuts.getnext +local getprev=nuts.getprev +local getid=nuts.getid +local getfont=nuts.getfont +local getchar=nuts.getchar +local getoffsets=nuts.getoffsets +local getboth=nuts.getboth +local getdisc=nuts.getdisc +local setdisc=nuts.setdisc +local setoffsets=nuts.setoffsets +local ischar=nuts.ischar +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 +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 nofregisteredpositions=0 +local nofregisteredmarks=0 +local nofregisteredcursives=0 +local keepregisteredcounts=false +function injections.keepcounts() + keepregisteredcounts=true +end +function injections.resetcounts() + nofregisteredkerns=0 + nofregisteredpositions=0 + nofregisteredmarks=0 + nofregisteredcursives=0 + keepregisteredcounts=false +end +function injections.reset(n) + local p=rawget(properties,n) + if p then + p.injections=false + else + properties[n]=false + end +end +function injections.copy(target,source) + local sp=rawget(properties,source) + if sp then + local tp=rawget(properties,target) + local si=sp.injections + if si then + si=fastcopy(si) + if tp then + tp.injections=si + else + properties[target]={ + injections=si, + } + end + elseif tp then + tp.injections=false + else + properties[target]={ injections={} } + end + else + local tp=rawget(properties,target) + if tp then + tp.injections=false + else + properties[target]=false + end + end +end +function injections.setligaindex(n,index) + local p=rawget(properties,n) + if p then + local i=p.injections + if i then + i.ligaindex=index + else + p.injections={ + ligaindex=index + } + end + else + properties[n]={ + injections={ + ligaindex=index + } + } + end +end +function injections.getligaindex(n,default) + local p=rawget(properties,n) + if p then + local i=p.injections + if i then + return i.ligaindex or default + end + end + return default +end +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 + local wn=tfmnext.width + nofregisteredcursives=nofregisteredcursives+1 + if rlmode<0 then + dx=-(dx+wn) + else + dx=dx-ws + end + if dx==0 then + dx=0 + end + local p=rawget(properties,start) + if p then + local i=p.injections + if i then + i.cursiveanchor=true + else + p.injections={ + cursiveanchor=true, + } + end + else + properties[start]={ + injections={ + cursiveanchor=true, + }, + } + end + local p=rawget(properties,nxt) + if p then + local i=p.injections + if i then + i.cursivex=dx + i.cursivey=dy + else + p.injections={ + cursivex=dx, + cursivey=dy, + } + end + else + properties[nxt]={ + injections={ + cursivex=dx, + cursivey=dy, + }, + } + end + return dx,dy,nofregisteredcursives +end +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 + nofregisteredpositions=nofregisteredpositions+1 + if rlmode and rlmode<0 then + leftkern,rightkern=rightkern,leftkern + end + if not injection then + injection="injections" + end + local p=rawget(properties,current) + if p then + local i=p[injection] + if i then + if leftkern~=0 then + i.leftkern=(i.leftkern or 0)+leftkern + end + if rightkern~=0 then + i.rightkern=(i.rightkern or 0)+rightkern + end + if yoffset~=0 then + i.yoffset=(i.yoffset or 0)+yoffset + end + elseif leftkern~=0 or rightkern~=0 then + p[injection]={ + leftkern=leftkern, + rightkern=rightkern, + yoffset=yoffset, + } + else + p[injection]={ + yoffset=yoffset, + } + end + elseif leftkern~=0 or rightkern~=0 then + properties[current]={ + [injection]={ + leftkern=leftkern, + rightkern=rightkern, + yoffset=yoffset, + }, + } + else + properties[current]={ + [injection]={ + yoffset=yoffset, + }, + } + end + return x,y,w,h,nofregisteredpositions + end + end + return x,y,w,h +end +function injections.setkern(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 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 + return dx,nofregisteredkerns + else + 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=factor*(ba[1]-ma[1]) + local dy=factor*(ba[2]-ma[2]) + nofregisteredmarks=nofregisteredmarks+1 + if rlmode>=0 then + dx=tfmbase.width-dx + end + local p=rawget(properties,start) + if p then + local i=p.injections + if i then + if i.markmark then + else + i.markx=dx + i.marky=dy + i.markdir=rlmode or 0 + i.markbase=nofregisteredmarks + i.markbasenode=base + i.markmark=mkmk + i.checkmark=checkmark + end + else + p.injections={ + markx=dx, + marky=dy, + markdir=rlmode or 0, + markbase=nofregisteredmarks, + markbasenode=base, + markmark=mkmk, + checkmark=checkmark, + } + end + else + properties[start]={ + injections={ + markx=dx, + marky=dy, + markdir=rlmode or 0, + markbase=nofregisteredmarks, + markbasenode=base, + markmark=mkmk, + checkmark=checkmark, + }, + } + end + return dx,dy,nofregisteredmarks +end +local function dir(n) + return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" +end +local function showchar(n,nested) + local char=getchar(n) + report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char) +end +local function show(n,what,nested,symbol) + if n then + local p=rawget(properties,n) + if p then + local i=p[what] + if i then + local leftkern=i.leftkern or 0 + local rightkern=i.rightkern or 0 + local yoffset=i.yoffset or 0 + local markx=i.markx or 0 + local marky=i.marky or 0 + local markdir=i.markdir or 0 + local markbase=i.markbase or 0 + local cursivex=i.cursivex or 0 + local cursivey=i.cursivey or 0 + local ligaindex=i.ligaindex or 0 + local cursbase=i.cursiveanchor + local margin=nested and 4 or 2 + if rightkern~=0 or yoffset~=0 then + report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset) + elseif leftkern~=0 then + report_injections("%w%s kern: dx %p",margin,symbol,leftkern) + end + if markx~=0 or marky~=0 or markbase~=0 then + report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no") + end + if cursivex~=0 or cursivey~=0 then + if cursbase then + report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey) + else + report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + end + elseif cursbase then + report_injections("%w%s curs: base",margin,symbol) + end + if ligaindex~=0 then + report_injections("%w%s liga: index %i",margin,symbol,ligaindex) + end + end + end + end +end +local function showsub(n,what,where) + report_injections("begin subrun: %s",where) + 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() + 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) + if id==glyph_code then + showchar(n) + show(n,"injections",false," ") + show(n,"preinjections",false,"<") + show(n,"postinjections",false,">") + show(n,"replaceinjections",false,"=") + show(n,"emptyinjections",false,"*") + elseif id==disc_code then + local pre,post,replace=getdisc(n) + if pre then + showsub(pre,"preinjections","pre") + end + if post then + showsub(post,"postinjections","post") + end + if replace then + showsub(replace,"replaceinjections","replace") + end + show(n,"emptyinjections",false,"*") + end + n=getnext(n) + end + report_injections("end run") +end +local function show_result(head) + local current=head + local skipping=false + while current do + local id=getid(current) + if id==glyph_code then + 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",getkern(current)) + skipping=false + elseif not skipping then + report_injections() + skipping=true + end + current=getnext(current) + end + report_injections() +end +local function inject_kerns_only(head,where) + if trace_injections then + trace(head,"kerns") + end + local current=head + local prev=nil + local next=nil + local prevdisc=nil + local pre=nil + local post=nil + local replace=nil + local pretail=nil + local posttail=nil + local replacetail=nil + while current do + local next=getnext(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 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 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 + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + replace=fontkern(leftkern) + done=true + end + end + end + if done then + setdisc(prevdisc,pre,post,replace) + end + end + end + prevdisc=nil + 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 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 + pre=insert_node_before(pre,n,fontkern(leftkern)) + done=true + end + end + end + end + end + if post then + 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 + post=insert_node_before(post,n,fontkern(leftkern)) + done=true + end + end + end + end + end + if replace then + 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 + replace=insert_node_before(replace,n,fontkern(leftkern)) + done=true + end + end + end + end + end + if done then + setdisc(current,pre,post,replace) + end + prevdisc=current + else + prevdisc=nil + end + prev=current + current=next + end + if keepregisteredcounts then + keepregisteredcounts=false + else + nofregisteredkerns=0 + end + if trace_injections then + show_result(head) + end + return head +end +local function inject_positions_only(head,where) + if trace_injections then + trace(head,"positions") + end + local current=head + local prev=nil + local next=nil + local prevdisc=nil + local prevglyph=nil + local pre=nil + local post=nil + local replace=nil + local pretail=nil + local posttail=nil + local replacetail=nil + while current do + local next=getnext(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 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 + if next and getid(next)==disc_code then + if replace then + else + replace=fontkern(rightkern) + done=true + end + 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 + setlink(posttail,fontkern(leftkern)) + done=true + end + 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 + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + replace=fontkern(leftkern) + done=true + 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 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + end + end + end + end + if post then + 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + end + end + end + end + if replace then + 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + end + end + end + end + if prevglyph then + if pre then + local p=rawget(properties,prevglyph) + if p then + local i=p.preinjections + if i then + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + pre=insert_node_before(pre,pre,fontkern(rightkern)) + done=true + end + end + end + end + if replace then + local p=rawget(properties,prevglyph) + if p then + local i=p.replaceinjections + if i then + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + replace=insert_node_before(replace,replace,fontkern(rightkern)) + done=true + end + end + end + end + end + if done then + setdisc(current,pre,post,replace) + end + prevglyph=nil + prevdisc=current + else + prevglyph=nil + prevdisc=nil + end + prev=current + current=next + end + if keepregisteredcounts then + keepregisteredcounts=false + else + nofregisteredpositions=0 + end + if trace_injections then + show_result(head) + end + return head +end +local function showoffset(n,flag) + local x,y=getoffsets(n) + if x~=0 or y~=0 then + setcolor(n,"darkgray") + end +end +local function inject_everything(head,where) + if trace_injections then + trace(head,"everything") + end + local hascursives=nofregisteredcursives>0 + local hasmarks=nofregisteredmarks>0 + local current=head + local last=nil + local prev=nil + local next=nil + local prevdisc=nil + local prevglyph=nil + local pre=nil + local post=nil + local replace=nil + local pretail=nil + local posttail=nil + local replacetail=nil + local cursiveanchor=nil + local minc=0 + local maxc=0 + local glyphs={} + local marks={} + local nofmarks=0 + local function processmark(p,n,pn) + 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=pp.injections + if pp then + rightkern=pp.rightkern + end + end + local markdir=pn.markdir + if rightkern then + 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=ox-leftkern + end + end + end + else + 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=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,fontkern(-wn)) + insert_node_after(n,n,fontkern(-wn)) + end + end + end + 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 next=getnext(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=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 + 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 + setoffsets(ti,false,ny) + if trace_cursive then + showoffset(ti) + end + end + maxc=0 + end + cursiveanchor=nil + end + 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 + 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 + replace=fontkern(rightkern) + done=true + end + 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 + setlink(posttail,fontkern(leftkern)) + done=true + end + 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 + else + local i=p.emptyinjections + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + replace=fontkern(leftkern) + done=true + end + end + end + if done then + setdisc(prevdisc,pre,post,replace) + end + 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 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + if hasmarks then + local pm=i.markbasenode + if pm then + processmark(pm,n,i) + end + end + end + end + end + end + if post then + 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + if hasmarks then + local pm=i.markbasenode + if pm then + processmark(pm,n,i) + end + end + end + end + end + end + if replace then + 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 + setoffsets(n,false,yoffset) + end + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + 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,fontkern(rightkern)) + done=true + end + if hasmarks then + local pm=i.markbasenode + if pm then + processmark(pm,n,i) + end + end + end + end + end + end + if prevglyph then + if pre then + local p=rawget(properties,prevglyph) + if p then + local i=p.preinjections + if i then + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + pre=insert_node_before(pre,pre,fontkern(rightkern)) + done=true + end + end + end + end + if replace then + local p=rawget(properties,prevglyph) + if p then + local i=p.replaceinjections + if i then + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + replace=insert_node_before(replace,replace,fontkern(rightkern)) + done=true + end + end + end + end + end + if done then + setdisc(current,pre,post,replace) + end + prevglyph=nil + prevdisc=current + else + prevglyph=nil + prevdisc=nil + end + prev=current + current=next + end + if hascursives and maxc>0 then + local nx,ny=getoffsets(last) + 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 + end + if nofmarks>0 then + for i=1,nofmarks do + local m=marks[i] + local p=rawget(properties,m) + local i=p.injections + local b=i.markbasenode + processmark(b,m,i) + end + elseif hasmarks then + end + if keepregisteredcounts then + keepregisteredcounts=false + else + nofregisteredkerns=0 + nofregisteredpositions=0 + nofregisteredmarks=0 + nofregisteredcursives=0 + end + if trace_injections then + show_result(head) + end + return head +end +local triggers=false +function nodes.injections.setspacekerns(font,sequence) + if triggers then + triggers[font]=sequence + else + triggers={ [font]=sequence } + end +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 +else + injections.threshold=0 + getthreshold=function(font) + local p=fontdata[font].parameters + local f=p.factor + local s=p.spacing + local t=injections.threshold*(s and s.width or p.space or 0)-2 + return t>0 and t or 0,f + end +end +injections.getthreshold=getthreshold +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 + end + local lastfont=nil + local spacekerns=nil + local leftkerns=nil + local rightkerns=nil + local factor=0 + local threshold=0 + local leftkern=false + local rightkern=false + local function updatefont(font,trig) + leftkerns=trig.left + rightkerns=trig.right + lastfont=font + threshold, + factor=getthreshold(font) + end + 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] + if trig then + if lastfont~=font then + updatefont(font,trig) + end + if rightkerns then + rightkern=rightkerns[nextchar] + end + end + end + if prevchar then + local font=getfont(prev) + local trig=triggers[font] + if trig then + if lastfont~=font then + updatefont(font,trig) + end + if leftkerns then + leftkern=leftkerns[prevchar] + end + end + end + if leftkern then + local old=getwidth(n) + if old>threshold then + if rightkern then + 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 + rightkern=false + else + 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 + end + end + leftkern=false + elseif rightkern then + local old=getwidth(n) + if old>threshold then + 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 + end + rightkern=false + end + end + triggers=false + return head +end +function injections.handler(head,where) + if triggers then + head=injectspaces(head) + end + if nofregisteredmarks>0 or nofregisteredcursives>0 then + if trace_injections then + report_injections("injection variant %a","everything") + end + return inject_everything(head,where) + elseif nofregisteredpositions>0 then + if trace_injections then + report_injections("injection variant %a","positions") + end + 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 + end +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otj”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ota” d6dfb94563d6a52675e274b2e673e4a6] --- + +if not modules then modules={} end modules ['font-ota']={ + 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=type +if not trackers then trackers={ register=function() end } end +local fonts,nodes,node=fonts,nodes,node +local allocate=utilities.storage.allocate +local otf=fonts.handlers.otf +local analyzers=fonts.analyzers +local initializers=allocate() +local methods=allocate() +analyzers.initializers=initializers +analyzers.methods=methods +local a_state=attributes.private('state') +local nuts=nodes.nuts +local tonut=nuts.tonut +local getnext=nuts.getnext +local getprev=nuts.getprev +local getprev=nuts.getprev +local getprop=nuts.getprop +local setprop=nuts.setprop +local getsubtype=nuts.getsubtype +local getchar=nuts.getchar +local ischar=nuts.ischar +local end_of_math=nuts.end_of_math +local nodecodes=nodes.nodecodes +local disc_code=nodecodes.disc +local math_code=nodecodes.math +local fontdata=fonts.hashes.identifiers +local categories=characters and characters.categories or {} +local chardata=characters and characters.data +local otffeatures=fonts.constructors.features.otf +local registerotffeature=otffeatures.register +local s_init=1 local s_rphf=7 +local s_medi=2 local s_half=8 +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=allocate { + init=s_init, + medi=s_medi, + med2=s_medi, + fina=s_fina, + fin2=s_fina, + fin3=s_fina, + isol=s_isol, + mark=s_mark, + rest=s_rest, + rphf=s_rphf, + half=s_half, + pref=s_pref, + blwf=s_blwf, + pstf=s_pstf, +} +local features=allocate { + init=s_init, + medi=s_medi, + med2=s_medi, + fina=s_fina, + fin2=s_fina, + fin3=s_fina, + isol=s_isol, + rphf=s_rphf, + half=s_half, + pref=s_pref, + blwf=s_blwf, + pstf=s_pstf, +} +analyzers.states=states +analyzers.features=features +analyzers.useunicodemarks=false +function analyzers.setstate(head,font) + local useunicodemarks=analyzers.useunicodemarks + local tfmdata=fontdata[font] + local descriptions=tfmdata.descriptions + local first,last,current,n,done=nil,nil,head,0,false + current=tonut(current) + while current do + local char,id=ischar(current,font) + if char and not getprop(current,a_state) then + done=true + local d=descriptions[char] + if d then + if d.class=="mark" then + done=true + setprop(current,a_state,s_mark) + elseif useunicodemarks and categories[char]=="mn" then + done=true + setprop(current,a_state,s_mark) + elseif n==0 then + first,last,n=current,current,1 + setprop(current,a_state,s_init) + else + last,n=current,n+1 + setprop(current,a_state,s_medi) + end + else + if first and first==last then + setprop(last,a_state,s_isol) + elseif last then + setprop(last,a_state,s_fina) + end + first,last,n=nil,nil,0 + end + elseif char==false then + if first and first==last then + setprop(last,a_state,s_isol) + elseif last then + setprop(last,a_state,s_fina) + end + first,last,n=nil,nil,0 + if id==math_code then + current=end_of_math(current) + end + elseif id==disc_code then + setprop(current,a_state,s_medi) + last=current + else + if first and first==last then + setprop(last,a_state,s_isol) + elseif last then + setprop(last,a_state,s_fina) + end + first,last,n=nil,nil,0 + if id==math_code then + current=end_of_math(current) + end + end + current=getnext(current) + end + if first and first==last then + setprop(last,a_state,s_isol) + elseif last then + setprop(last,a_state,s_fina) + end + return head,done +end +local function analyzeinitializer(tfmdata,value) + local script,language=otf.scriptandlanguage(tfmdata) + local action=initializers[script] + if not action then + elseif type(action)=="function" then + return action(tfmdata,value) + else + local action=action[language] + if action then + return action(tfmdata,value) + end + end +end +local function analyzeprocessor(head,font,attr) + local tfmdata=fontdata[font] + local script,language=otf.scriptandlanguage(tfmdata,attr) + local action=methods[script] + if not action then + elseif type(action)=="function" then + return action(head,font,attr) + else + action=action[language] + if action then + return action(head,font,attr) + end + end + return head,false +end +registerotffeature { + name="analyze", + description="analysis of character classes", + default=true, + initializers={ + node=analyzeinitializer, + }, + processors={ + position=1, + node=analyzeprocessor, + } +} +methods.latn=analyzers.setstate +local arab_warned={} +local function warning(current,what) + local char=getchar(current) + if not arab_warned[char] then + log.report("analyze","arab: character %C has no %a class",char,what) + arab_warned[char]=true + end +end +local mappers=allocate { + l=s_init, + d=s_medi, + c=s_medi, + r=s_fina, + u=s_isol, +} +local classifiers=characters.classifiers +if not classifiers then + local f_arabic,l_arabic=characters.blockrange("arabic") + local f_syriac,l_syriac=characters.blockrange("syriac") + local f_mandiac,l_mandiac=characters.blockrange("mandiac") + local f_nko,l_nko=characters.blockrange("nko") + local f_ext_a,l_ext_a=characters.blockrange("arabicextendeda") + classifiers=table.setmetatableindex(function(t,k) + if type(k)=="number" then + local c=chardata[k] + local v=false + if c then + local arabic=c.arabic + if arabic then + v=mappers[arabic] + if not v then + log.report("analyze","error in mapping arabic %C",k) + v=false + end + elseif (k>=f_arabic and k<=l_arabic) or + (k>=f_syriac and k<=l_syriac) or + (k>=f_mandiac and k<=l_mandiac) or + (k>=f_nko and k<=l_nko) or + (k>=f_ext_a and k<=l_ext_a) then + if categories[k]=="mn" then + v=s_mark + else + v=s_rest + end + end + end + t[k]=v + return v + end + end) + characters.classifiers=classifiers +end +function methods.arab(head,font,attr) + local first,last,c_first,c_last + local current=head + local done=false + current=tonut(current) + while current do + local char,id=ischar(current,font) + if char and not getprop(current,a_state) then + done=true + local classifier=classifiers[char] + if not classifier then + if last then + if c_last==s_medi or c_last==s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first,last=nil,nil + elseif first then + if c_first==s_medi or c_first==s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first=nil + end + elseif classifier==s_mark then + setprop(current,a_state,s_mark) + elseif classifier==s_isol then + if last then + if c_last==s_medi or c_last==s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first,last=nil,nil + elseif first then + if c_first==s_medi or c_first==s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first=nil + end + setprop(current,a_state,s_isol) + elseif classifier==s_medi then + if first then + last=current + c_last=classifier + setprop(current,a_state,s_medi) + else + setprop(current,a_state,s_init) + first=current + c_first=classifier + end + elseif classifier==s_fina then + if last then + if getprop(last,a_state)~=s_init then + setprop(last,a_state,s_medi) + end + setprop(current,a_state,s_fina) + first,last=nil,nil + elseif first then + setprop(current,a_state,s_fina) + first=nil + else + setprop(current,a_state,s_isol) + end + else + setprop(current,a_state,s_rest) + if last then + if c_last==s_medi or c_last==s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first,last=nil,nil + elseif first then + if c_first==s_medi or c_first==s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first=nil + end + end + else + if last then + if c_last==s_medi or c_last==s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + first,last=nil,nil + elseif first then + if c_first==s_medi or c_first==s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + first=nil + end + if id==math_code then + current=end_of_math(current) + end + end + current=getnext(current) + end + if last then + if c_last==s_medi or c_last==s_fina then + setprop(last,a_state,s_fina) + else + warning(last,"fina") + setprop(last,a_state,s_error) + end + elseif first then + if c_first==s_medi or c_first==s_fina then + setprop(first,a_state,s_isol) + else + warning(first,"isol") + setprop(first,a_state,s_error) + end + end + return head,done +end +methods.syrc=methods.arab +methods.mand=methods.arab +methods.nko=methods.arab +directives.register("otf.analyze.useunicodemarks",function(v) + analyzers.useunicodemarks=v +end) + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ota”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ots” 0da86e8e56e342169221ec66c4f05318] --- + +if not modules then modules={} end modules ['font-ots']={ + 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=type,next,tonumber +local random=math.random +local formatters=string.formatters +local insert=table.insert +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) +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 +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 getfield=nuts.getfield +local getnext=nuts.getnext +local setnext=nuts.setnext +local getprev=nuts.getprev +local setprev=nuts.setprev +local getboth=nuts.getboth +local setboth=nuts.setboth +local getid=nuts.getid +local getprop=nuts.getprop +local setprop=nuts.setprop +local getsubtype=nuts.getsubtype +local setsubtype=nuts.setsubtype +local getchar=nuts.getchar +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 getwidth=nuts.getwidth +local getattr=nuts.getattr +local getglyphdata=nuts.getglyphdata +local ischar=nuts.ischar +local isglyph=nuts.isglyph +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 setmetatable=setmetatable +local setmetatableindex=table.setmetatableindex +local nextnode=nuts.traversers.node +local nodecodes=nodes.nodecodes +local glyphcodes=nodes.glyphcodes +local disccodes=nodes.disccodes +local glyph_code=nodecodes.glyph +local glue_code=nodecodes.glue +local disc_code=nodecodes.disc +local math_code=nodecodes.math +local dir_code=nodecodes.dir +local localpar_code=nodecodes.localpar +local discretionarydisc_code=disccodes.discretionary +local ligatureglyph_code=glyphcodes.ligature +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 setmove=injections.setmove +local setposition=injections.setposition +local resetinjection=injections.reset +local copyinjection=injections.copy +local setligaindex=injections.setligaindex +local getligaindex=injections.getligaindex +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 +local getrandom=utilities and utilities.randomizer and utilities.randomizer.get +otf.defaultnodealternate="none" +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 sweephead={} +local notmatchpre={} +local notmatchpost={} +local notmatchreplace={} +local handlers={} +local isspace=injections.isspace +local getthreshold=injections.getthreshold +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 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 + end +end +local function cref(dataset,sequence,index) + if not dataset then + return "no valid dataset" + 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, %schain lookup %a"]( + dataset[4],sequence.type,merged,sequence.name) + end +end +local function pref(dataset,sequence) + 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 "l2r" + else + return "r2l" + end +end +local function flattendisk(head,disc) + local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) + local prev,next=getboth(disc) + local ishead=head==disc + setdisc(disc) + flush_node(disc) + if pre then + flush_node_list(pre) + end + if post then + flush_node_list(post) + end + if ishead then + if replace then + if next then + setlink(replacetail,next) + end + return replace,replace + elseif next then + return next,next + else + end + else + if replace then + if next then + setlink(replacetail,next) + end + setlink(prev,replace) + return head,replace + else + setlink(prev,next) + return head,next + end + end +end +local function appenddisc(disc,list) + local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) + local posthead=list + local replacehead=copy_node_list(list) + if post then + setlink(posttail,posthead) + else + post=posthead + end + if replace then + setlink(replacetail,replacehead) + else + replace=replacehead + end + setdisc(disc,pre,post,replace) +end +local copy_no_components=nuts.copy_no_components +local copy_only_glyphs=nuts.copy_only_glyphs +local set_components=setcomponents +local take_components=getcomponents +local function count_components(start,marks) + local char=isglyph(start) + if char then + if getsubtype(start)==ligatureglyph_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[char] then + return 1 + end + end + return 0 +end +local function markstoligature(head,start,stop,char) + if start==stop and getchar(start)==char then + return head,start + else + local prev=getprev(start) + local next=getnext(stop) + setprev(start) + setnext(stop) + local base=copy_no_components(start,copyinjection) + if head==start then + head=base + end + resetinjection(base) + setchar(base,char) + setsubtype(base,ligatureglyph_code) + set_components(base,start) + setlink(prev,base,next) + return head,base + end +end +local function toligature(head,start,stop,char,dataset,sequence,skiphash,discfound,hasmarks) + if getattr(start,a_noligature)==1 then + return head,start + end + if start==stop and getchar(start)==char then + resetinjection(start) + setchar(start,char) + return head,start + end + local prev=getprev(start) + local next=getnext(stop) + local comp=start + setprev(start) + setnext(stop) + local base=copy_no_components(start,copyinjection) + if start==head then + head=base + end + resetinjection(base) + setchar(base,char) + setsubtype(base,ligatureglyph_code) + set_components(base,comp) + setlink(prev,base,next) + if not discfound then + local deletemarks=not skiphash or hasmarks + local components=start + local baseindex=0 + local componentindex=0 + local head=base + local current=base + while start do + local char=getchar(start) + if not marks[char] then + baseindex=baseindex+componentindex + 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) + head,current=insert_node_after(head,current,n) + elseif trace_marks then + logwarning("%s: delete mark %s",pref(dataset,sequence),gref(char)) + end + start=getnext(start) + end + local start=getnext(current) + while start do + local char=ischar(start) + if char then + if marks[char] then + setligaindex(start,baseindex+getligaindex(start,componentindex)) + if trace_marks then + logwarning("%s: set mark %s, gets index %s",pref(dataset,sequence),gref(char),getligaindex(start)) + end + start=getnext(start) + else + break + end + else + break + end + end + else + local discprev,discnext=getboth(discfound) + if discprev and discnext then + local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true) + 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) + end + pre=comp + if post then + setlink(posttail,discnext) + setprev(post) + else + post=discnext + setprev(discnext) + end + setlink(prev,discfound,next) + setboth(base) + set_components(base,copied) + replace=base + if forcediscretionaries then + setdisc(discfound,pre,post,replace,discretionarydisc_code) + else + setdisc(discfound,pre,post,replace) + end + base=prev + end + end + end + return head,base +end +local function multiple_glyphs(head,start,multiple,skiphash,what,stop) + local nofmultiples=#multiple + if nofmultiples>0 then + resetinjection(start) + setchar(start,multiple[1]) + if nofmultiples>1 then + local sn=getnext(start) + for k=2,nofmultiples do + local n=copy_node(start) + resetinjection(n) + setchar(n,multiple[k]) + insert_node_after(head,start,n) + start=n + end + if what==true then + elseif what>1 then + local m=multiple[nofmultiples] + for i=2,what do + local n=copy_node(start) + resetinjection(n) + setchar(n,m) + insert_node_after(head,start,n) + start=n + end + end + end + return head,start,true + else + if trace_multiples then + logprocess("no multiple for %s",gref(getchar(start))) + end + return head,start,false + end +end +local function get_alternative_glyph(start,alternatives,value) + local n=#alternatives + 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 + return alternatives[1],trace_alternatives and formatters["value %a, taking %a"](value,1) + elseif value=="last" then + return alternatives[n],trace_alternatives and formatters["value %a, taking %a"](value,n) + end + value=value==true and 1 or tonumber(value) + if type(value)~="number" then + return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,1) + end + if value>n then + local defaultalt=otf.defaultnodealternate + if defaultalt=="first" then + return alternatives[n],trace_alternatives and formatters["invalid value %s, taking %a"](value,1) + elseif defaultalt=="last" then + return alternatives[1],trace_alternatives and formatters["invalid value %s, taking %a"](value,n) + else + return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range") + end + elseif value==0 then + return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change") + elseif value<1 then + return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1) + else + return alternatives[value],trace_alternatives and formatters["value %a, taking %a"](value,value) + end +end +function handlers.gsub_single(head,start,dataset,sequence,replacement) + if trace_singles then + logprocess("%s: replacing %s by single %s",pref(dataset,sequence),gref(getchar(start)),gref(replacement)) + end + resetinjection(start) + setchar(start,replacement) + return head,start,true +end +function handlers.gsub_alternate(head,start,dataset,sequence,alternative) + local kind=dataset[4] + local what=dataset[1] + local value=what==true and tfmdata.shared.features[kind] or what + local choice,comment=get_alternative_glyph(start,alternative,value) + if choice then + if trace_alternatives then + logprocess("%s: replacing %s by alternative %a to %s, %s",pref(dataset,sequence),gref(getchar(start)),gref(choice),comment) + end + resetinjection(start) + setchar(start,choice) + else + if trace_alternatives then + logwarning("%s: no variant %a for %s, %s",pref(dataset,sequence),value,gref(getchar(start)),comment) + end + end + return head,start,true +end +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,skiphash,dataset[1]) +end +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 skiphash and skiphash[startchar] then + while current do + local char=ischar(current,currentfont) + if char then + local lg=ligature[char] + if lg then + stop=current + ligature=lg + current=getnext(current) + else + break + end + else + break + end + end + if stop then + local lig=ligature.ligature + if lig then + if trace_ligatures then + local stopchar=getchar(stop) + head,start=markstoligature(head,start,stop,lig) + logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(dataset,sequence),gref(startchar),gref(stopchar),gref(getchar(start))) + else + head,start=markstoligature(head,start,stop,lig) + end + return head,start,true,false + else + end + end + else + local discfound=false + local hasmarks=marks[startchar] + while current do + local char,id=ischar(current,currentfont) + if char then + if skiphash and skiphash[char] then + current=getnext(current) + else + local lg=ligature[char] + if lg then + if marks[char] then + hasmarks=true + end + stop=current + ligature=lg + current=getnext(current) + else + break + end + end + elseif char==false then + break + elseif id==disc_code then + discfound=current + break + else + break + end + end + if discfound then + local pre,post,replace=getdisc(discfound) + local match + if replace then + local char=ischar(replace,currentfont) + if char and ligature[char] then + match=true + end + end + if not match and pre then + local char=ischar(pre,currentfont) + if char and ligature[char] then + match=true + end + end + if not match and not pre or not replace then + local n=getnext(discfound) + local char=ischar(n,currentfont) + if char and ligature[char] then + match=true + end + end + if match then + local ishead=head==start + local prev=getprev(start) + if stop then + setnext(stop) + local copy=copy_node_list(start) + local tail=stop + local liat=find_node_tail(copy) + if pre then + setlink(liat,pre) + end + if replace then + setlink(tail,replace) + end + pre=copy + replace=start + else + setnext(start) + local copy=copy_node(start) + if pre then + setlink(copy,pre) + end + if replace then + setlink(start,replace) + end + pre=copy + replace=start + end + setdisc(discfound,pre,post,replace) + if prev then + setlink(prev,discfound) + else + setprev(discfound) + head=discfound + end + start=discfound + return head,start,true,true + end + end + local lig=ligature.ligature + if lig then + if stop then + if trace_ligatures then + local stopchar=getchar(stop) + head,start=toligature(head,start,stop,lig,dataset,sequence,skiphash,false,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,skiphash,false,hasmarks) + end + else + resetinjection(start) + setchar(start,lig) + if trace_ligatures then + logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(dataset,sequence),gref(startchar),gref(lig)) + end + end + return head,start,true,false + else + end + end + return head,start,false,false +end +function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,skiphash,step,injection) + local startchar=getchar(start) + 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 %s xy (%p,%p) and wh (%p,%p)",pref(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",pref(dataset,sequence),gref(startchar),format,k) + end + end + return head,start,true +end +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 + while snext do + local nextchar=ischar(snext,currentfont) + if nextchar then + if skiphash and skiphash[nextchar] then + prev=snext + snext=getnext(snext) + else + local krn=kerns[nextchar] + if not krn then + break + end + local format=step.format + if format=="pair" then + local a=krn[1] + local b=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 + 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 + end + 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 + 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 + 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 + end + else + break + end + end + return head,start,false + end +end +function handlers.gpos_mark2base(head,start,dataset,sequence,markanchors,rlmode,skiphash) + local markchar=getchar(start) + if marks[markchar] 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 + 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),2) + end + return head,start,false + end + end + end + local ba=markanchors[1][basechar] + if ba then + 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, 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) + end + elseif trace_bugs then + logwarning("%s: nothing preceding, case %i",pref(dataset,sequence),2) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) + end + return head,start,false +end +function handlers.gpos_mark2ligature(head,start,dataset,sequence,markanchors,rlmode,skiphash) + local markchar=getchar(start) + if marks[markchar] 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 + 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),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, 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 + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(dataset,sequence),gref(markchar),gref(basechar),index) + end + end + end + elseif trace_bugs then + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) + end + elseif trace_bugs then + logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),1) + end + elseif trace_bugs then + logwarning("%s: prev node is no char, case %i",pref(dataset,sequence),2) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) + end + return head,start,false +end +function handlers.gpos_mark2mark(head,start,dataset,sequence,markanchors,rlmode,skiphash) + local markchar=getchar(start) + if marks[markchar] 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 + if base then + local basechar=ischar(base,currentfont) + if basechar then + local ba=markanchors[1][basechar] + if ba then + 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, 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 + end + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(dataset,sequence),gref(markchar)) + end + return head,start,false +end +function handlers.gpos_cursive(head,start,dataset,sequence,exitanchors,rlmode,skiphash,step) + local startchar=getchar(start) + 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 + 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 + end + end + break + end + end + end + 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 +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,skiphash) + local char=getchar(start) + local replacement=replacements[char] + if replacement then + if trace_singles then + logprocess("%s: single reverse replacement of %s by %s",cref(dataset,sequence),gref(char),gref(replacement)) + end + resetinjection(start) + setchar(start,replacement) + return head,start,true + else + return head,start,false + 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 +local function getmapping(dataset,sequence,currentlookup) + local steps=currentlookup.steps + local nofsteps=currentlookup.nofsteps + 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 +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 + current=getnext(current) + end + end + end + return head,start,false +end +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 + 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 + end + return head,start,false +end +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 + else + 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,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 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 schar=getchar(current) + if skiphash and skiphash[schar] then + current=getnext(current) + else + 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 + 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 + 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 + end + return head,start,false,0,false +end +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 + 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,skiphash,chainindex) + local mapping=currentlookup.mapping + if mapping==nil then + mapping=getmapping(dataset,sequence,currentlookup) + end + 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=krn[1] + local b=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: inserting %s %p between %s and %s",cref(dataset,sequence),format,k,gref(getchar(prev)),gref(nextchar)) + end + return head,start,true + else + break + end + end + end + end + end + end + return head,start,false +end +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),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, 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 + 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),2) + end + elseif trace_bugs then + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) + end + end + return head,start,false +end +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,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, 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 + 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),2) + end + elseif trace_bugs then + logwarning("%s, mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + end + elseif trace_bugs then + logwarning("%s, mark %s is no mark",cref(dataset,sequence),gref(markchar)) + end + end + return head,start,false +end +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 + 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 + 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),2) + end + elseif trace_bugs then + logwarning("%s: mark %s has no anchors",cref(dataset,sequence),gref(markchar)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",cref(dataset,sequence),gref(markchar)) + end + end + return head,start,false +end +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 + 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 + 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 + end + elseif trace_bugs then + onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) + end + break + end + end + end + elseif trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(dataset,sequence),gref(getchar(start)),alreadydone) + end + 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 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=userkern(getwidth(current)) + if head==current then + local next=getnext(current) + if next then + setlink(kern,next) + end + flush_node(current) + head=kern + current=next + else + local prev,next=getboth(current) + setlink(prev,kern,next) + flush_node(current) + current=next + end + else + current=getnext(current) + end + end + return head +end +local function setdiscchecked(d,pre,post,replace) + if pre then pre=checked(pre) end + if post then post=checked(post) end + if replace then replace=checked(replace) end + setdisc(d,pre,post,replace) +end +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 + local startishead=start==head + local seq=ck[3] + local f=ck[4] + local l=ck[5] + local s=#seq + local done=false + local sweepnode=sweepnode + local sweeptype=sweeptype + local sweepoverflow=false + local keepdisc=not sweepnode + local lookaheaddisc=nil + local backtrackdisc=nil + local current=start + local last=start + local prev=getprev(start) + local hasglue=false + local i=f + while i<=l do + local id=getid(current) + if id==glyph_code then + i=i+1 + last=current + current=getnext(current) + elseif id==glue_code then + i=i+1 + last=current + current=getnext(current) + hasglue=true + elseif id==disc_code then + if keepdisc then + keepdisc=false + lookaheaddisc=current + local replace=getfield(current,"replace") + 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 + current=getnext(replace) + end + last=current + else + head,current=flattendisk(head,current) + end + else + last=current + current=getnext(current) + end + if current then + elseif sweepoverflow then + break + elseif sweeptype=="post" or sweeptype=="replace" then + current=getnext(sweepnode) + if current then + sweeptype=nil + sweepoverflow=true + else + break + end + else + break + end + end + if sweepoverflow then + local prev=current and getprev(current) + if not current or prev~=sweepnode then + local head=getnext(sweepnode) + local tail=nil + if prev then + tail=prev + setprev(current,sweepnode) + else + tail=find_node_tail(head) + end + setnext(sweepnode,current) + setprev(head) + setnext(tail) + appenddisc(sweepnode,head) + end + end + if l<s then + local i=l + local t=sweeptype=="post" or sweeptype=="replace" + while current and i<s do + local id=getid(current) + if id==glyph_code then + i=i+1 + current=getnext(current) + elseif id==glue_code then + i=i+1 + current=getnext(current) + hasglue=true + elseif id==disc_code then + if keepdisc then + keepdisc=false + if notmatchpre[current]~=notmatchreplace[current] then + lookaheaddisc=current + end + local replace=getfield(current,"replace") + while replace and i<s do + if getid(replace)==glyph_code then + i=i+1 + end + replace=getnext(replace) + end + current=getnext(current) + elseif notmatchpre[current]~=notmatchreplace[current] then + head,current=flattendisk(head,current) + else + current=getnext(current) + end + else + current=getnext(current) + end + if not current and t then + current=getnext(sweepnode) + if current then + sweeptype=nil + end + end + end + end + if f>1 then + local current=prev + local i=f + local t=sweeptype=="pre" or sweeptype=="replace" + if not current and t and current==checkdisk then + current=getprev(sweepnode) + end + while current and i>1 do + local id=getid(current) + if id==glyph_code then + i=i-1 + elseif id==glue_code then + i=i-1 + hasglue=true + elseif id==disc_code then + if keepdisc then + keepdisc=false + if notmatchpost[current]~=notmatchreplace[current] then + backtrackdisc=current + end + local replace=getfield(current,"replace") + while replace and i>1 do + if getid(replace)==glyph_code then + i=i-1 + end + replace=getnext(replace) + end + elseif notmatchpost[current]~=notmatchreplace[current] then + head,current=flattendisk(head,current) + end + end + current=getprev(current) + if t and current==checkdisk then + current=getprev(sweepnode) + end + end + end + local done=false + if lookaheaddisc then + local cf=start + local cl=getprev(lookaheaddisc) + local cprev=getprev(start) + local insertedmarks=0 + while cprev do + local char=ischar(cf,currentfont) + if char and marks[char] then + insertedmarks=insertedmarks+1 + cf=cprev + startishead=cf==head + cprev=getprev(cprev) + else + break + end + 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 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 + 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 + 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) + else + setdisc(lookaheaddisc,cf,post,new) + end + start=getprev(lookaheaddisc) + sweephead[cf]=getnext(clast) or false + sweephead[new]=getnext(cl) or false + elseif backtrackdisc then + local cf=getnext(backtrackdisc) + local cl=start + local cnext=getnext(start) + local insertedmarks=0 + while cnext do + local char=ischar(cnext,currentfont) + if char and marks[char] then + insertedmarks=insertedmarks+1 + cl=cnext + cnext=getnext(cnext) + else + break + end + end + setlink(backtrackdisc,cnext) + setprev(cf) + setnext(cl) + local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true) + local new=copy_node_list(cf) + local cnew=find_node_tail(new) + for i=1,insertedmarks do + cnew=getprev(cnew) + end + local clast=cnew + for i=f,l do + clast=getnext(clast) + end + if not notmatchpost[backtrackdisc] then + 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 + 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) + else + post=cf + end + if replace then + setlink(replacetail,new) + else + replace=new + end + if hasglue then + setdiscchecked(backtrackdisc,pre,post,replace) + else + setdisc(backtrackdisc,pre,post,replace) + end + start=getprev(backtrackdisc) + sweephead[post]=getnext(clast) or false + sweephead[replace]=getnext(last) or false + else + 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,done +end +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 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 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 + break + end + else + goto next + end + elseif char==false then + if discfound then + notmatchreplace[discfound]=true + if notmatchpre[discfound] then + goto next + else + break + end + 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 + pre=getnext(pre) + else + notmatchpre[last]=true + break + end + 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 + break + end + end + end + if notmatchpre[last] then + goto next + end + end + last=getnext(last) + else + goto next + end + else + goto next + end + end + end + if f>1 then + if startprev then + local prev=startprev + if prereplace and prev==checkdisc then + prev=getprev(sweepnode) + end + if prev then + 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 + break + end + else + goto next + end + elseif char==false then + if discfound then + notmatchreplace[discfound]=true + if notmatchpost[discfound] then + goto next + end + 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 + else + notmatchpost[prev]=true + break + end + end + if n>=1 then + notmatchpost[prev]=true + 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 + break + end + end + end + else + end + 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 + goto next + end + elseif seq[n][0xFFFC] then + n=n-1 + prev=getprev(prev) + else + goto next + end + else + goto next + end + end + else + goto next + end + else + goto next + 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 + break + end + else + goto next + end + elseif char==false then + if discfound then + notmatchreplace[discfound]=true + if notmatchpre[discfound] then + goto next + else + break + end + 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 + else + notmatchpre[current]=true + break + end + end + if n<=s then + notmatchpre[current]=true + end + 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) + end + else + notmatchreplace[current]=true + if notmatchpre[current] then + goto next + else + break + end + end + end + else + 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 + goto next + end + elseif seq[n][0xFFFC] then + n=n+1 + current=getnext(current) + else + goto next + end + else + goto next + end + end + else + 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 discseen then + notmatchpre={} + notmatchpost={} + notmatchreplace={} + end + return head,start,done +end +handlers.gsub_context=handle_contextchain +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,skiphash) + local steps=currentlookup.steps + local nofsteps=currentlookup.nofsteps + if nofsteps>1 then + reportmoresteps(dataset,sequence) + end + 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 +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 sequencelists=setmetatableindex(function(t,font) + local sequences=fontdata[font].resources.sequences + if not sequences or not next(sequences) then + sequences=false + end + t[font]=sequences + return sequences +end) +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 + 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 + end + end + end + end + return rl + end +end +local function report_disc(what,n) + report_run("%s: %s > %s",what,n,languages.serializediscretionary(n)) +end +local function kernrun(disc,k_run,font,attr,...) + if trace_kernruns then + report_disc("kern",disc) + end + local prev,next=getboth(disc) + local nextstart=next + local done=false + local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) + local prevmarks=prev + while prevmarks do + local char=ischar(prevmarks,font) + if char and marks[char] then + prevmarks=getprev(prevmarks) + else + break + end + end + if prev and not ischar(prev,font) then + prev=false + end + if next and not ischar(next,font) then + next=false + end + if pre then + if k_run(pre,"injections",nil,font,attr,...) then + done=true + end + if prev then + setlink(prev,pre) + if k_run(prevmarks,"preinjections",pre,font,attr,...) then + done=true + end + setprev(pre) + setlink(prev,disc) + end + end + if post then + if k_run(post,"injections",nil,font,attr,...) then + done=true + end + if next then + setlink(posttail,next) + if k_run(posttail,"postinjections",next,font,attr,...) then + done=true + end + setnext(posttail) + setlink(disc,next) + end + end + if replace then + if k_run(replace,"injections",nil,font,attr,...) then + done=true + end + if prev then + setlink(prev,replace) + if k_run(prevmarks,"replaceinjections",replace,font,attr,...) then + done=true + end + setprev(replace) + setlink(prev,disc) + end + if next then + setlink(replacetail,next) + if k_run(replacetail,"replaceinjections",next,font,attr,...) then + done=true + end + setnext(replacetail) + 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,next) + end + if done and trace_testruns then + report_disc("done",disc) + end + return nextstart,done +end +local function comprun(disc,c_run,...) + if trace_compruns then + report_disc("comp",disc) + end + local pre,post,replace=getdisc(disc) + local renewed=false + if pre then + sweepnode=disc + sweeptype="pre" + local new,done=c_run(pre,...) + if done then + pre=new + renewed=true + end + end + if post then + sweepnode=disc + sweeptype="post" + local new,done=c_run(post,...) + if done then + post=new + renewed=true + end + end + if replace then + sweepnode=disc + sweeptype="replace" + local new,done=c_run(replace,...) + if done then + replace=new + renewed=true + end + end + 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 +local function testrun(disc,t_run,c_run,...) + if trace_testruns then + report_disc("test",disc) + end + local prev,next=getboth(disc) + if not next then + return + end + local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) + 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) + local tail=head + for i=2,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 + if pre then + sweepnode=disc + sweeptype="pre" + local new,ok=c_run(pre,...) + if ok then + pre=new + renewed=true + end + end + if post then + sweepnode=disc + sweeptype="post" + local new,ok=c_run(post,...) + if ok then + post=new + renewed=true + end + end + if replace then + sweepnode=disc + sweeptype="replace" + local new,ok=c_run(replace,...) + if ok then + replace=new + renewed=true + end + end + sweepnode=nil + sweeptype=nil + if renewed then + setdisc(disc,pre,post,replace) + 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,skiphash,handler) + local done=false + local sweep=sweephead[head] + if sweep then + start=sweep + sweephead[head]=false + else + start=head + end + while start do + local char,id=ischar(start,font) + if char then + local a + if attr then + a=getglyphdata(start) + 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,skiphash,step) + if ok then + done=true + end + end + if start then + start=getnext(start) + end + else + start=getnext(start) + end + elseif char==false then + return head,done + elseif sweep then + return head,done + else + start=getnext(start) + end + end + 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 + if attr then + a=getglyphdata(start) + end + local startnext=getnext(start) + if not a or (a==attr) then + 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,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 + lastd=d + end + else + end + else + end + 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,skiphash,handler) + local a + if attr then + a=getglyphdata(sub) + end + if not a or (a==attr) then + for n in nextnode,sub do + if n==last then + break + end + local char=ischar(n) + if char then + 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 + end + end + end + end +end +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]=false + else + start=head + end + while start do + local char=ischar(start,font) + if char then + local a + if attr then + a=getglyphdata(start) + end + if not a or (a==attr) then + for i=1,nofsteps 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 + done=true + break + elseif not start then + break + end + end + end + if start then + start=getnext(start) + end + else + start=getnext(start) + end + elseif char==false then + return head,done + elseif sweep then + return head,done + else + start=getnext(start) + end + end + 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 + if attr then + a=getglyphdata(start) + 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 + 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 + else + break + end + end + if l and l.ligature then + lastd=d + end + end + end + else + end + 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,skiphash,handler) + local a + if attr then + a=getglyphdata(sub) + end + if not a or (a==attr) then + for n in nextnode,sub do + if n==last then + break + end + local char=ischar(n) + if char then + for i=1,nofsteps do + local step=steps[i] + local lookupcache=step.coverage + 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 + end + end + end + end + end +end +local txtdirstate,pardirstate do + local getdirection=nuts.getdirection + local lefttoright=0 + local righttoleft=1 + txtdirstate=function(start,stack,top,rlparmode) + local dir,pop=getdirection(start) + if pop then + if top==1 then + return 0,rlparmode + else + top=top-1 + if stack[top]==righttoleft then + return top,-1 + else + return top,1 + end + end + elseif dir==lefttoright then + top=top+1 + stack[top]=lefttoright + return top,1 + elseif dir==righttoleft then + top=top+1 + stack[top]=righttoleft + return top,-1 + else + return top,rlparmode + end + end + pardirstate=function(start) + local dir=getdirection(start) + if dir==lefttoright then + return 1,1 + elseif dir==righttoleft then + return -1,-1 + elseif dir=="TLT" then + return 1,1 + elseif dir=="TRT" then + return -1,-1 + else + return 0,0 + end + end +end +otf.helpers=otf.helpers or {} +otf.helpers.txtdirstate=txtdirstate +otf.helpers.pardirstate=pardirstate +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=0 + if getid(head)==localpar_code and getsubtype(head)==0 then + initialrl=pardirstate(head) + elseif direction==1 or direction=="TRT" then + initialrl=-1 + end + 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 + 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=getglyphdata(start) + 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 + start=getprev(start) + end + else + start=getprev(start) + end + else + start=getprev(start) + end + end + 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 + if skiphash and skiphash[char] then + start=getnext(start) + else + local lookupmatch=lookupcache[char] + if lookupmatch then + local a + if attr then + if getglyphdata(start)==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 + local ok,df + head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if df then + elseif start then + start=getnext(start) + end + else + start=getnext(start) + end + else + start=getnext(start) + end + end + 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_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,skiphash,handler) + end + else + start=getnext(start) + end + elseif id==math_code then + start=getnext(end_of_math(start)) + elseif id==dir_code then + topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) + start=getnext(start) + else + start=getnext(start) + end + end + 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 getglyphdata(start)==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 + local ok,df + for i=m[1],m[2] do + local step=steps[i] + local lookupcache=step.coverage + local lookupmatch=lookupcache[char] + if lookupmatch then + head,start,ok,df=handler(head,start,dataset,sequence,lookupmatch,rlmode,skiphash,step) + if df then + break + elseif ok then + break + elseif not start then + break + end + end + end + if df then + elseif start then + start=getnext(start) + end + else + start=getnext(start) + end + else + start=getnext(start) + end + end + 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 + topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) + start=getnext(start) + else + start=getnext(start) + end + 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==1 or 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) + 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 + end + if start then + start=getnext(start) + end + 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 + topstack,rlmode=txtdirstate(start,dirstack,topstack,rlparmode) + start=getnext(start) + else + start=getnext(start) + end + end + return head + end +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 +function otf.plugininitializer(tfmdata,value) + if type(value)=="string" then + tfmdata.shared.plugin=plugins[value] + end +end +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,attr,direction) + else + return head,false + end +end +function otf.featuresinitializer(tfmdata,value) +end +registerotffeature { + name="features", + description="features", + default=true, + initializers={ + position=1, + node=otf.featuresinitializer, + plug=otf.plugininitializer, + }, + processors={ + node=otf.featuresprocessor, + plug=otf.pluginprocessor, + } +} +otf.handlers=handlers +local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end +local tag="kern" +if fontfeatures then + function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr) + local features=fontfeatures[font] + local enabled=features and features.spacekern and features[tag] + if enabled then + setspacekerns(font,sequence) + end + return head,enabled + end +else + 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[tag] + if enabled then + setspacekerns(font,sequence) + end + return head,enabled + end +end +local function hasspacekerns(data) + 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 + end + end + end + return false +end +otf.readers.registerextender { + name="spacekerns", + action=function(data) + data.properties.hasspacekerns=hasspacekerns(data) + end +} +local function spaceinitializer(tfmdata,value) + local resources=tfmdata.resources + local spacekerns=resources and resources.spacekerns + 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 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 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 + 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={ [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 + end + end + resources.spacekerns=spacekerns + end + return spacekerns +end +registerotffeature { + name="spacekern", + description="space kern injection", + default=true, + initializers={ + node=spaceinitializer, + }, +} +local function markinitializer(tfmdata,value) + local properties=tfmdata.properties + properties.checkmarks=value +end +registerotffeature { + name="checkmarks", + description="check mark widths", + default=true, + initializers={ + node=markinitializer, + }, +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ots”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-osd” e8111d24e652a181bf2bbd5149fb66d4] --- + +if not modules then modules={} end modules ['font-osd']={ + version=1.001, + comment="companion to font-ini.mkiv", + author="Kai Eigner, TAT Zetwerk / Hans Hagen, PRAGMA ADE", + copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +local insert,imerge,copy=table.insert,table.imerge,table.copy +local next,type=next,type +local report=logs.reporter("otf","devanagari") +fonts=fonts or {} +fonts.analyzers=fonts.analyzers or {} +fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } } +local otf=fonts.handlers.otf +local handlers=otf.handlers +local methods=fonts.analyzers.methods +local otffeatures=fonts.constructors.features.otf +local registerotffeature=otffeatures.register +local nuts=nodes.nuts +local getnext=nuts.getnext +local getprev=nuts.getprev +local getboth=nuts.getboth +local getid=nuts.getid +local getchar=nuts.getchar +local getfont=nuts.getfont +local getsubtype=nuts.getsubtype +local setlink=nuts.setlink +local setnext=nuts.setnext +local setprev=nuts.setprev +local setchar=nuts.setchar +local getprop=nuts.getprop +local setprop=nuts.setprop +local ischar=nuts.ischar +local insert_node_after=nuts.insert_after +local copy_node=nuts.copy +local remove_node=nuts.remove +local flush_list=nuts.flush_list +local flush_node=nuts.flush_node +local copyinjection=nodes.injections.copy +local unsetvalue=attributes.unsetvalue +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 +local s_pref=states.pref +local s_blwf=states.blwf +local s_pstf=states.pstf +local replace_all_nbsp=nil +replace_all_nbsp=function(head) + replace_all_nbsp=typesetters and typesetters.characters and typesetters.characters.replacenbspaces or function(head) + return head + end + return replace_all_nbsp(head) +end +local processcharacters=nil +if context then + 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 + 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={ + [c_zwnj]=true, + [c_zwj ]=true, +} +local dflt_true={ + dflt=true +} +local two_defaults={ + dev2=dflt_true, +} +local one_defaults={ + dev2=dflt_true, + deva=dflt_true, +} +local false_flags={ false,false,false,false } +local sequence_reorder_matras={ + features={ dv01=two_defaults }, + flags=false_flags, + name="dv01_reorder_matras", + order={ "dv01" }, + type="devanagari_reorder_matras", + nofsteps=1, + steps={ + { + coverage=pre_mark, + } + } +} +local sequence_reorder_reph={ + features={ dv02=two_defaults }, + flags=false_flags, + name="dv02_reorder_reph", + order={ "dv02" }, + type="devanagari_reorder_reph", + nofsteps=1, + steps={ + { + coverage={}, + } + } +} +local sequence_reorder_pre_base_reordering_consonants={ + features={ dv03=two_defaults }, + flags=false_flags, + name="dv03_reorder_pre_base_reordering_consonants", + order={ "dv03" }, + type="devanagari_reorder_pre_base_reordering_consonants", + nofsteps=1, + steps={ + { + coverage={}, + } + } +} +local sequence_remove_joiners={ + features={ dv04=one_defaults }, + flags=false_flags, + name="dv04_remove_joiners", + order={ "dv04" }, + type="devanagari_remove_joiners", + nofsteps=1, + steps={ + { + coverage=zw_char, + }, + } +} +local basic_shaping_forms={ + akhn=true, + blwf=true, + cjct=true, + half=true, + nukt=true, + pref=true, + pstf=true, + rkrf=true, + rphf=true, + vatu=true, +} +local valid={ + abvs=true, + akhn=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 scripts[script] then + local resources=tfmdata.resources + local devanagari=resources.devanagari + if not devanagari then + report("adding devanagari features to font") + local gsubfeatures=resources.features.gsub + local sequences=resources.sequences + local sharedfeatures=tfmdata.shared.features + local lastmatch=0 + for s=1,#sequences do + local features=sequences[s].features + if features then + for k,v in next,features do + if basic_shaping_forms[k] then + lastmatch=s + end + end + end + end + local insertindex=lastmatch+1 + 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) + local remove_joiners=copy(sequence_remove_joiners) + insert(sequences,insertindex,reorder_pre_base_reordering_consonants) + insert(sequences,insertindex,reorder_reph) + insert(sequences,insertindex,reorder_matras) + insert(sequences,insertindex,remove_joiners) + local blwfcache={} + local seqsubset={} + local rephstep={ + coverage={} + } + local devanagari={ + reph=false, + vattu=false, + blwfcache=blwfcache, + seqsubset=seqsubset, + reorderreph=rephstep, + } + reorder_reph.steps={ rephstep } + local pre_base_reordering_consonants={} + reorder_pre_base_reordering_consonants.steps[1].coverage=pre_base_reordering_consonants + resources.devanagari=devanagari + for s=1,#sequences do + local sequence=sequences[s] + local steps=sequence.steps + local nofsteps=sequence.nofsteps + local features=sequence.features + local has_rphf=features.rphf + local has_blwf=features.blwf + if has_rphf and has_rphf.deva then + devanagari.reph=true + elseif has_blwf and has_blwf.deva then + devanagari.vattu=true + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + for k,v in next,coverage do + if not blwfcache[k] then + blwfcache[k]=v + end + end + end + end + end + 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 + 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 + end + end + seqsubset[#seqsubset+1]={ kind,coverage,reph } + end + end + end + if kind=="pref" then + local steps=sequence.steps + local nofsteps=sequence.nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + for k,v in next,halant do + local h=coverage[k] + if h then + local found=false + for k,v in next,h do + found=v and v.ligature + if found then + pre_base_reordering_consonants[k]=found + break + end + end + if found then + break + end + end + end + end + end + end + end + end + if script=="deva" then + sharedfeatures["dv04"]=true + elseif script=="dev2" then + sharedfeatures["dv01"]=true + sharedfeatures["dv02"]=true + sharedfeatures["dv03"]=true + sharedfeatures["dv04"]=true + elseif script=="mlym" then + sharedfeatures["pstf"]=true + elseif script=="mlm2" then + sharedfeatures["pstf"]=true + sharedfeatures["pref"]=true + sharedfeatures["dv03"]=true + 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 +end +registerotffeature { + name="devanagari", + description="inject additional features", + default=true, + initializers={ + node=initializedevanagi, + }, +} +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 + if not devanagaridata then + devanagaridata={ + reph=false, + vattu=false, + blwfcache={}, + } + datasets.devanagari=devanagaridata + local resources=tfmdata.resources + local devanagari=resources.devanagari + for s=1,#datasets do + local dataset=datasets[s] + if dataset and dataset[1] then + local kind=dataset[4] + if kind=="rphf" then + devanagaridata.reph=true + elseif kind=="blwf" then + devanagaridata.vattu=true + devanagaridata.blwfcache=devanagari.blwfcache + end + end + end + end + return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache +end +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 + local firstcons=nil + local lastcons=nil + local basefound=false + if reph and ra[getchar(start)] and halant[getchar(n)] then + if n==stop then + return head,stop,nbspaces + end + if getchar(getnext(n))==c_zwj then + current=start + else + current=getnext(n) + setprop(start,a_state,s_rphf) + end + end + if getchar(current)==c_nbsp then + if current==stop then + stop=getprev(stop) + head=remove_node(head,current) + flush_node(current) + return head,stop,nbspaces + else + nbspaces=nbspaces+1 + base=current + firstcons=current + lastcons=current + current=getnext(current) + if current~=stop then + local char=getchar(current) + if nukta[char] then + current=getnext(current) + char=getchar(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 + end + end + end + end + while not basefound do + local char=getchar(current) + if consonant[char] then + setprop(current,a_state,s_half) + if not firstcons then + firstcons=current + end + lastcons=current + if not base then + base=current + elseif blwfcache[char] then + setprop(current,a_state,s_blwf) + else + base=current + end + end + basefound=current==stop + current=getnext(current) + end + if base~=lastcons then + local np=base + local n=getnext(base) + local ch=getchar(n) + if nukta[ch] then + np=n + n=getnext(n) + ch=getchar(n) + end + if halant[ch] then + if lastcons~=stop then + local ln=getnext(lastcons) + if nukta[getchar(ln)] then + lastcons=ln + end + end + local nn=getnext(n) + local ln=getnext(lastcons) + setlink(np,nn) + setnext(lastcons,n) + if ln then + setprev(ln,n) + end + setnext(n,ln) + setprev(n,lastcons) + if lastcons==stop then + stop=n + end + end + end + n=getnext(start) + if n~=stop and ra[getchar(start)] and halant[getchar(n)] and not zw_char[getchar(getnext(n))] then + local matra=base + if base~=stop then + local next=getnext(base) + if dependent_vowel[getchar(next)] then + matra=next + end + end + local sp=getprev(start) + local nn=getnext(n) + local mn=getnext(matra) + setlink(sp,nn) + setlink(matra,start) + setlink(n,mn) + if head==start then + head=nn + end + start=nn + if matra==stop then + stop=n + end + end + local current=start + while current~=stop do + local next=getnext(current) + if next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwnj then + setprop(current,a_state,unsetvalue) + end + current=next + end + if base~=stop and getprop(base,a_state) then + local next=getnext(base) + if halant[getchar(next)] and not (next~=stop and getchar(getnext(next))==c_zwj) then + setprop(base,a_state,unsetvalue) + end + end + local current,allreordered,moved=start,false,{ [base]=true } + local a,b,p,bn=base,base,base,getnext(base) + if base~=stop and nukta[getchar(bn)] then + a,b,p=bn,bn,bn + end + while not allreordered do + local c=current + local n=getnext(current) + local l=nil + if c~=stop then + local ch=getchar(n) + if nukta[ch] then + c=n + n=getnext(n) + ch=getchar(n) + end + if c~=stop then + if halant[ch] then + c=n + n=getnext(n) + ch=getchar(n) + end + while c~=stop and dependent_vowel[ch] do + c=n + n=getnext(n) + ch=getchar(n) + end + if c~=stop then + if vowel_modifier[ch] then + c=n + n=getnext(n) + ch=getchar(n) + end + if c~=stop and stress_tone_mark[ch] then + c=n + n=getnext(n) + end + end + end + end + local bp=getprev(firstcons) + local cn=getnext(current) + local last=getnext(c) + while cn~=last do + if pre_mark[getchar(cn)] then + if bp then + setnext(bp,cn) + end + local prev,next=getboth(cn) + if next then + setprev(next,prev) + end + setnext(prev,next) + if cn==stop then + stop=prev + end + setprev(cn,bp) + setlink(cn,firstcons) + if firstcons==start then + if head==start then + head=cn + end + start=cn + end + break + end + cn=getnext(cn) + end + allreordered=c==stop + current=getnext(c) + end + if reph or vattu then + local current,cns=start,nil + while current~=stop do + local c=current + local n=getnext(current) + if ra[getchar(current)] and halant[getchar(n)] then + c=n + n=getnext(n) + local b,bn=base,base + while bn~=stop do + local next=getnext(bn) + if dependent_vowel[getchar(next)] then + b=next + end + bn=next + end + if getprop(current,a_state)==s_rphf then + if b~=current then + if current==start then + if head==start then + head=n + end + start=n + end + if b==stop then + stop=c + end + local prev=getprev(current) + setlink(prev,n) + local next=getnext(b) + setlink(c,next) + setlink(b,current) + end + elseif cns and getnext(cns)~=current then + local cp=getprev(current) + local cnsn=getnext(cns) + setlink(cp,n) + setlink(cns,current) + setlink(c,cnsn) + if c==stop then + stop=cp + break + end + current=getprev(n) + end + else + local char=getchar(current) + if consonant[char] then + cns=current + local next=getnext(cns) + if halant[getchar(next)] then + cns=next + end + elseif char==c_nbsp then + nbspaces=nbspaces+1 + cns=current + local next=getnext(cns) + if halant[getchar(next)] then + cns=next + end + end + end + current=getnext(current) + end + end + if getchar(base)==c_nbsp then + nbspaces=nbspaces-1 + head=remove_node(head,base) + flush_node(base) + end + return head,stop,nbspaces +end +function handlers.devanagari_reorder_matras(head,start) + local current=start + local startfont=getfont(start) + local startattr=getprop(start,a_syllabe) + while current do + local char=ischar(current,startfont) + local next=getnext(current) + if char and getprop(current,a_syllabe)==startattr then + if halant[char] and not getprop(current,a_state) then + if next then + local char=ischar(next,startfont) + if char and zw_char[char] and getprop(next,a_syllabe)==startattr then + current=next + next=getnext(current) + end + end + local startnext=getnext(start) + head=remove_node(head,start) + setlink(start,next) + setlink(current,start) + start=startnext + break + end + else + break + end + current=next + end + return head,start,true +end +function handlers.devanagari_reorder_reph(head,start) + local current=getnext(start) + local startnext=nil + 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 halant[char] and not getprop(current,a_state) then + local next=getnext(current) + if next then + local nextchar=ischar(next,startfont) + if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then + current=next + next=getnext(current) + end + end + startnext=getnext(start) + head=remove_node(head,start) + setlink(start,next) + setlink(current,start) + start=startnext + startattr=getprop(start,a_syllabe) + break + end + current=getnext(current) + else + 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 getprop(current,a_state)==s_pstf then + startnext=getnext(start) + head=remove_node(head,start) + setlink(getprev(current),start) + setlink(start,current) + start=startnext + startattr=getprop(start,a_syllabe) + break + end + current=getnext(current) + else + break + 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 not after_subscript[char] then + c=current + end + current=getnext(current) + else + break + end + end + if c then + startnext=getnext(start) + head=remove_node(head,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 + current=next + next=getnext(current) + else + break + end + end + if start~=current then + startnext=getnext(start) + head=remove_node(head,start) + setlink(start,getnext(current)) + setlink(current,start) + start=startnext + end + end + return head,start,true +end +function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) + local current=start + local startnext=nil + local startprev=nil + local startfont=getfont(start) + local startattr=getprop(start,a_syllabe) + while current do + local char=ischar(current,startfont) + if char and getprop(current,a_syllabe)==startattr then + local next=getnext(current) + if halant[char] and not getprop(current,a_state) then + if next then + local nextchar=ischar(next,startfont) + if nextchar and getprop(next,a_syllabe)==startattr then + if nextchar==c_zwnj or nextchar==c_zwj then + current=next + next=getnext(current) + end + end + end + startnext=getnext(start) + removenode(start,start) + setlink(start,next) + setlink(current,start) + start=startnext + break + end + current=next + else + break + end + end + if not startnext then + current=getnext(start) + startattr=getprop(start,a_syllabe) + while current do + local char=ischar(current,startfont) + if char and getprop(current,a_syllabe)==startattr then + if not consonant[char] and getprop(current,a_state) then + startnext=getnext(start) + removenode(start,start) + setlink(getprev(current),start) + setlink(start,current) + start=startnext + break + end + current=getnext(current) + else + break + end + end + end + return head,start,true +end +function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) + local stop=getnext(start) + local font=getfont(start) + local last=start + while stop do + local char=ischar(stop,font) + if char and (char==c_zwnj or char==c_zwj) then + last=stop + stop=getnext(stop) + else + break + end + end + local prev=getprev(start) + if stop then + setnext(last) + setlink(prev,stop) + elseif prev then + setnext(prev) + end + if head==start then + head=stop + end + flush_list(start) + return head,stop,true +end +local function initialize_two(font,attr) + local devanagari=fontdata[font].resources.devanagari + if devanagari then + return devanagari.seqsubset or {},devanagari.reorderreph or {} + else + return {},{} + end +end +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 + local subpos=nil + local postpos=nil + local locl={} + for i=1,#seqsubset do + local subset=seqsubset[i] + local kind=subset[1] + local lookupcache=subset[2] + if kind=="rphf" then + reph=subset[3] + local current=start + local last=getnext(stop) + while current~=last do + if current~=stop then + local c=locl[current] or getchar(current) + local found=lookupcache[c] + if found then + local next=getnext(current) + local n=locl[next] or getchar(next) + if found[n] then + local afternext=next~=stop and getnext(next) + if afternext and zw_char[getchar(afternext)] then + current=afternext + elseif current==start then + setprop(current,a_state,s_rphf) + current=next + else + current=next + end + end + end + end + current=getnext(current) + end + elseif kind=="pref" then + local current=start + local last=getnext(stop) + while current~=last do + if current~=stop then + local c=locl[current] or getchar(current) + local found=lookupcache[c] + if found then + local next=getnext(current) + local n=locl[next] or getchar(next) + if found[n] then + setprop(current,a_state,s_pref) + setprop(next,a_state,s_pref) + current=next + end + end + end + current=getnext(current) + end + elseif kind=="half" then + local current=start + local last=getnext(stop) + while current~=last do + if current~=stop then + local c=locl[current] or getchar(current) + local found=lookupcache[c] + if found then + local next=getnext(current) + local n=locl[next] or getchar(next) + if found[n] then + if next~=stop and getchar(getnext(next))==c_zwnj then + current=next + else + setprop(current,a_state,s_half) + if not halfpos then + halfpos=current + end + end + current=getnext(current) + end + end + end + current=getnext(current) + end + elseif kind=="blwf" then + local current=start + local last=getnext(stop) + while current~=last do + if current~=stop then + local c=locl[current] or getchar(current) + local found=lookupcache[c] + if found then + local next=getnext(current) + local n=locl[next] or getchar(next) + if found[n] then + setprop(current,a_state,s_blwf) + setprop(next,a_state,s_blwf) + current=next + subpos=current + end + end + end + current=getnext(current) + end + elseif kind=="pstf" then + local current=start + local last=getnext(stop) + while current~=last do + if current~=stop then + local c=locl[current] or getchar(current) + local found=lookupcache[c] + if found then + local next=getnext(current) + local n=locl[next] or getchar(next) + if found[n] then + setprop(current,a_state,s_pstf) + setprop(next,a_state,s_pstf) + current=next + postpos=current + end + end + end + current=getnext(current) + end + end + end + reorderreph.coverage={ [reph]=true } + local current,base,firstcons=start,nil,nil + if getprop(start,a_state)==s_rphf then + current=getnext(getnext(start)) + end + if current~=getnext(stop) and getchar(current)==c_nbsp then + if current==stop then + stop=getprev(stop) + head=remove_node(head,current) + flush_node(current) + return head,stop,nbspaces + else + nbspaces=nbspaces+1 + base=current + current=getnext(current) + if current~=stop then + local char=getchar(current) + if nukta[char] then + current=getnext(current) + char=getchar(current) + end + if char==c_zwj then + local next=getnext(current) + if current~=stop and next~=stop and halant[getchar(next)] then + current=next + next=getnext(current) + local tmp=getnext(next) + local changestop=next==stop + setnext(next) + setprop(current,a_state,s_pref) + current=processcharacters(current,font) + setprop(current,a_state,s_blwf) + current=processcharacters(current,font) + setprop(current,a_state,s_pstf) + current=processcharacters(current,font) + setprop(current,a_state,unsetvalue) + if halant[getchar(current)] then + setnext(getnext(current),tmp) + if show_syntax_errors then + head,current=inject_syntax_error(head,current,char) + end + else + setnext(current,tmp) + if changestop then + stop=current + end + end + end + end + end + end + else + local last=getnext(stop) + while current~=last do + local next=getnext(current) + if consonant[getchar(current)] then + if not (current~=stop and next~=stop and halant[getchar(next)] and getchar(getnext(next))==c_zwj) then + if not firstcons then + firstcons=current + end + local a=getprop(current,a_state) + if not (a==s_pref or a==s_blwf or a==s_pstf) then + base=current + end + end + end + current=next + end + if not base then + base=firstcons + end + end + if not base then + if getprop(start,a_state)==s_rphf then + setprop(start,a_state,unsetvalue) + end + return head,stop,nbspaces + else + if getprop(base,a_state) then + setprop(base,a_state,unsetvalue) + end + basepos=base + end + if not halfpos then + halfpos=base + end + if not subpos then + subpos=base + end + if not postpos then + postpos=subpos or base + end + local moved={} + local current=start + local last=getnext(stop) + while current~=last do + local char,target,cn=locl[current] or getchar(current),nil,getnext(current) + local tpm=twopart_mark[char] + if tpm then + local extra=copy_node(current) + copyinjection(extra,current) + char=tpm[1] + setchar(current,char) + setchar(extra,tpm[2]) + head=insert_node_after(head,current,extra) + end + if not moved[current] and dependent_vowel[char] then + if pre_mark[char] then + moved[current]=true + local prev,next=getboth(current) + setlink(prev,next) + if current==stop then + stop=getprev(current) + end + if halfpos==start then + if head==start then + head=current + end + start=current + end + setlink(getprev(halfpos),current) + setlink(current,halfpos) + halfpos=current + elseif above_mark[char] then + target=basepos + if subpos==basepos then + subpos=current + end + if postpos==basepos then + postpos=current + end + basepos=current + elseif below_mark[char] then + target=subpos + if postpos==subpos then + postpos=current + end + subpos=current + elseif post_mark[char] then + target=postpos + postpos=current + end + if mark_above_below_post[char] then + local prev=getprev(current) + if prev~=target then + local next=getnext(current) + setlink(prev,next) + if current==stop then + stop=prev + end + setlink(current,getnext(target)) + setlink(target,current) + end + end + end + current=cn + end + local current,c=start,nil + while current~=stop do + local char=getchar(current) + if halant[char] or stress_tone_mark[char] then + if not c then + c=current + end + else + c=nil + end + local next=getnext(current) + if c and nukta[getchar(next)] then + if head==c then + head=next + end + if stop==next then + stop=current + end + setlink(getprev(c),next) + local nextnext=getnext(next) + setnext(current,nextnext) + local nextnextnext=getnext(nextnext) + if nextnextnext then + setprev(nextnextnext,current) + end + setlink(nextnext,c) + end + if stop==current then break end + current=getnext(current) + end + if getchar(base)==c_nbsp then + if base==stop then + stop=getprev(stop) + end + nbspaces=nbspaces-1 + head=remove_node(head,base) + flush_node(base) + end + return head,stop,nbspaces +end +local separator={} +imerge(separator,consonant) +imerge(separator,independent_vowel) +imerge(separator,dependent_vowel) +imerge(separator,vowel_modifier) +imerge(separator,stress_tone_mark) +for k,v in next,nukta do separator[k]=true end +for k,v in next,halant do separator[k]=true end +local function analyze_next_chars_one(c,font,variant) + local n=getnext(c) + if not n then + return c + end + if variant==1 then + local v=ischar(n,font) + if v and nukta[v] then + n=getnext(n) + if n then + v=ischar(n,font) + end + end + if n and v then + local nn=getnext(n) + if nn then + local vv=ischar(nn,font) + if vv then + local nnn=getnext(nn) + if nnn then + local vvv=ischar(nnn,font) + if vvv then + if vv==c_zwj and consonant[vvv] then + c=nnn + elseif (vv==c_zwnj or vv==c_zwj) and halant[vvv] then + local nnnn=getnext(nnn) + if nnnn then + local vvvv=ischar(nnnn,font) + if vvvv and consonant[vvvv] then + c=nnnn + end + end + end + end + end + end + end + end + elseif variant==2 then + local v=ischar(n,font) + if v and nukta[v] then + c=n + end + n=getnext(c) + if n then + v=ischar(n,font) + if v then + local nn=getnext(n) + if nn then + local vv=ischar(nn,font) + if vv and zw_char[v] then + n=nn + v=vv + nn=getnext(nn) + vv=nn and ischar(nn,font) + end + if vv and halant[v] and consonant[vv] then + c=nn + end + end + end + end + end + local n=getnext(c) + if not n then + return c + end + local v=ischar(n,font) + if not v then + return c + end + if dependent_vowel[v] then + c=getnext(c) + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if nukta[v] then + c=getnext(c) + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if halant[v] then + c=getnext(c) + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if vowel_modifier[v] then + c=getnext(c) + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if stress_tone_mark[v] then + c=getnext(c) + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if stress_tone_mark[v] then + return n + else + return c + end +end +local function analyze_next_chars_two(c,font) + local n=getnext(c) + if not n then + return c + end + local v=ischar(n,font) + if v and nukta[v] then + c=n + end + n=c + while true do + local nn=getnext(n) + if nn then + local vv=ischar(nn,font) + if vv then + if halant[vv] then + n=nn + local nnn=getnext(nn) + if nnn then + local vvv=ischar(nnn,font) + if vvv and zw_char[vvv] then + n=nnn + end + end + elseif vv==c_zwnj or vv==c_zwj then + local nnn=getnext(nn) + if nnn then + local vvv=ischar(nnn,font) + if vvv and halant[vvv] then + n=nnn + end + end + else + break + end + local nn=getnext(n) + if nn then + local vv=ischar(nn,font) + if vv and consonant[vv] then + n=nn + local nnn=getnext(nn) + if nnn then + local vvv=ischar(nnn,font) + if vvv and nukta[vvv] then + n=nnn + end + end + c=n + else + break + end + else + break + end + else + break + end + else + break + end + end + if not c then + return + end + local n=getnext(c) + if not n then + return c + end + local v=ischar(n,font) + if not v then + return c + end + if anudatta[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if halant[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + if v==c_zwnj or v==c_zwj then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + else + if dependent_vowel[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if nukta[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if halant[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + end + if vowel_modifier[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if stress_tone_mark[v] then + c=n + n=getnext(c) + if not n then + return c + end + v=ischar(n,font) + if not v then + return c + end + end + if stress_tone_mark[v] then + return n + else + return c + end +end +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) + if char then + done=true + local syllablestart=current + local syllableend=nil + local c=current + local n=getnext(c) + local first=char + if n and ra[first] then + local second=ischar(n,font) + if second and halant[second] then + local n=getnext(n) + if n then + local third=ischar(n,font) + if third then + c=n + first=third + end + end + end + end + local standalone=first==c_nbsp + if standalone then + local prev=getprev(current) + if prev then + local prevchar=ischar(prev,font) + if not prevchar then + elseif not separator[prevchar] then + else + standalone=false + end + else + end + end + if standalone then + local syllableend=analyze_next_chars_one(c,font,2) + current=getnext(syllableend) + if syllablestart~=syllableend then + head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces) + current=getnext(current) + end + else + if consonant[char] then + local prevc=true + while prevc do + prevc=false + local n=getnext(current) + if not n then + break + end + local v=ischar(n,font) + if not v then + break + end + if nukta[v] then + n=getnext(n) + if not n then + break + end + v=ischar(n,font) + if not v then + break + end + end + if halant[v] then + n=getnext(n) + if not n then + break + end + v=ischar(n,font) + if not v then + break + end + if v==c_zwnj or v==c_zwj then + n=getnext(n) + if not n then + break + end + v=ischar(n,font) + if not v then + break + end + end + if consonant[v] then + prevc=true + current=n + end + end + end + local n=getnext(current) + if n then + local v=ischar(n,font) + if v and nukta[v] then + current=n + n=getnext(current) + end + end + syllableend=current + current=n + if current then + local v=ischar(current,font) + if not v then + elseif halant[v] then + local n=getnext(current) + if n then + local v=ischar(n,font) + if v and zw_char[v] then + syllableend=n + current=getnext(n) + else + syllableend=current + current=n + end + else + syllableend=current + current=n + end + else + if dependent_vowel[v] then + syllableend=current + current=getnext(current) + v=ischar(current,font) + end + if v and vowel_modifier[v] then + syllableend=current + current=getnext(current) + v=ischar(current,font) + end + if v and stress_tone_mark[v] then + syllableend=current + current=getnext(current) + end + end + end + if syllablestart~=syllableend then + head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces) + current=getnext(current) + end + elseif independent_vowel[char] then + syllableend=current + current=getnext(current) + if current then + local v=ischar(current,font) + if v then + if vowel_modifier[v] then + syllableend=current + current=getnext(current) + v=ischar(current,font) + end + if v and stress_tone_mark[v] then + syllableend=current + current=getnext(current) + end + end + end + else + 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 + end + else + current=getnext(current) + end + start=false + end + if nbspaces>0 then + head=replace_all_nbsp(head) + end + return head,done +end +local function method_two(head,font,attr) + local current=head + local start=true + local done=false + local syllabe=0 + local nbspaces=0 + while current do + local syllablestart=nil + local syllableend=nil + local char=ischar(current,font) + if char then + done=true + syllablestart=current + local c=current + local n=getnext(current) + if n and ra[char] then + local nextchar=ischar(n,font) + if nextchar and halant[nextchar] then + local n=getnext(n) + if n then + local nextnextchar=ischar(n,font) + if nextnextchar then + c=n + char=nextnextchar + end + end + end + end + if independent_vowel[char] then + current=analyze_next_chars_one(c,font,1) + syllableend=current + else + local standalone=char==c_nbsp + if standalone then + nbspaces=nbspaces+1 + local p=getprev(current) + if not p then + elseif ischar(p,font) then + elseif not separator[getchar(p)] then + else + standalone=false + end + end + if standalone then + current=analyze_next_chars_one(c,font,2) + syllableend=current + elseif consonant[getchar(current)] then + current=analyze_next_chars_two(current,font) + syllableend=current + end + end + end + if syllableend then + syllabe=syllabe+1 + local c=syllablestart + local n=getnext(syllableend) + while c~=n do + setprop(c,a_syllabe,syllabe) + c=getnext(c) + end + end + if syllableend and syllablestart~=syllableend then + head,current,nbspaces=reorder_two(head,syllablestart,syllableend,font,attr,nbspaces) + end + 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,char) + end + end + end + start=false + current=getnext(current) + end + if nbspaces>0 then + head=replace_all_nbsp(head) + end + return head,done +end +for i=1,nofscripts do + methods[scripts_one[i]]=method_one + methods[scripts_two[i]]=method_two +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-osd”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ocl” 280ad7888c7c386010598e9fdb83f466] --- + +if not modules then modules={} end modules ['font-ocl']={ + 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 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["%.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 +else + local tounicode=fonts.mappings.tounicode16 + function otf.getactualtext(s) + return + "/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 colors=attributes.list[attributes.private('color')] or {} + local transparencies=attributes.list[attributes.private('transparency')] or {} + function otf.registerpalette(name,values) + sharedpalettes[name]=values + local color=lpdf.color + local transparency=lpdf.transparency + local register=colors.register + for i=1,#values do + local v=values[i] + if v=="textcolor" then + values[i]=false + else + local c=nil + local t=nil + if type(v)=="table" then + c=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 + c=colors[v] + t=transparencies[v] + end + if c and t then + values[i]=hash[color(1,c).." "..transparency(t)] + elseif c then + values[i]=hash[color(1,c)] + elseif t then + values[i]=hash[color(1,t)] + end + end + end + end +else + function otf.registerpalette(name,values) + sharedpalettes[name]=values + for i=1,#values do + local v=values[i] + if v then + 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 +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" } +local function initialize(tfmdata,kind,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] + local default=false + if colorvalues then + default=colorvalues[#colorvalues] + else + colorvalues=converted[palettes[tonumber(value) or 1] or palettes[1]] or {} + end + 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 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 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={ + start, + not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) } + } + local n=2 + local l=nil + local f=false + for i=1,s do + local entry=colorlist[i] + 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 + else + if f then + n=n+1 t[n]=pop + end + f=false + l=nil + 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 + if f then + n=n+1 t[n]=pop + end + n=n+1 t[n]=actuale + character.commands=t + end + end + end + end + end +end +fonts.handlers.otf.features.register { + name="colr", + description="color glyphs", + manipulators={ + base=initialize, + node=initialize, + } +} +do + 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 + done=f_used(n) + hashed[pdf]=done + end + return done + 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 done + end + end +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 } + local vfimage=lpdf and lpdf.vfimage or function(wd,ht,dp,data,name) + local name=storepdfdata(data) + return { "image",{ filename=name,width=wd,height=ht,depth=dp } } + end + 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 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], + vfimage(wd,ht,dp,data,name), + actuale, + } + character[kind]=true + end + 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 + local savedata=io.savedata + local remove=os.remove + if context and xml.convert then + local xmlconvert=xml.convert + local xmlfirst=xml.first + function otfsvg.filterglyph(entry,index) + local svg=xmlconvert(entry.data) + local root=svg and xmlfirst(svg,"/svg[@id='glyph"..index.."']") + local data=root and tostring(root) + return data + end + else + function otfsvg.filterglyph(entry,index) + 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 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 + 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 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 + local svgfile=containers.read(otf.svgcache,hash) + local svgshapes=svgfile and svgfile.svgshapes + pdfshapes=svgshapes and otfsvg.topdf(svgshapes) or {} + containers.write(otf.pdfcache,hash,{ + pdfshapes=pdfshapes, + timestamp=timestamp, + }) + end + pdftovirtual(tfmdata,pdfshapes,"svg") + end +end +fonts.handlers.otf.features.register { + name="svg", + description="svg glyphs", + manipulators={ + base=initializesvg, + node=initializesvg, + } +} +local otfpng=otf.png or {} +otf.png=otfpng +otf.pngenabled=true +do + local report_png=logs.reporter("fonts","png conversion") + local loaddata=io.loaddata + local savedata=io.savedata + local remove=os.remove + local runner=sandbox and sandbox.registerrunner { + name="otfpng", + program="gm", + template="convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log", + } + if not runner then + runner=function() + return os.execute("gm convert -quality 100 temp-otf-png-shape.png temp-otf-png-shape.pdf > temp-otf-svg-shape.log") + end + end + function otfpng.topdf(pngshapes) + local pdfshapes={} + local pngfile="temp-otf-png-shape.png" + local pdffile="temp-otf-png-shape.pdf" + local nofdone=0 + local indices=sortedkeys(pngshapes) + local nofindices=#indices + report_png("processing %i png containers",nofindices) + statistics.starttiming() + for i=1,nofindices do + local index=indices[i] + local entry=pngshapes[index] + local data=entry.data + local x=entry.x + local y=entry.y + savedata(pngfile,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_png("%i shapes processed",nofdone) + end + end + report_png("processing %i pdf results",nofindices) + remove(pngfile) + remove(pdffile) + statistics.stoptiming() + if statistics.elapsedseconds then + report_png("png conversion time %s",statistics.elapsedseconds() or "-") + end + return pdfshapes + end +end +local function initializepng(tfmdata,kind,value) + if value and otf.pngenabled then + local png=tfmdata.properties.png + local hash=png and png.hash + local timestamp=png and png.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 pngfile=containers.read(otf.pngcache,hash) + local pngshapes=pngfile and pngfile.pngshapes + pdfshapes=pngshapes and otfpng.topdf(pngshapes) or {} + containers.write(otf.pdfcache,hash,{ + pdfshapes=pdfshapes, + timestamp=timestamp, + }) + end + pdftovirtual(tfmdata,pdfshapes,"png") + end +end +fonts.handlers.otf.features.register { + name="sbix", + description="sbix glyphs", + manipulators={ + base=initializepng, + node=initializepng, + } +} +fonts.handlers.otf.features.register { + name="cblc", + description="cblc glyphs", + manipulators={ + base=initializepng, + node=initializepng, + } +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-ocl”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otc” 95a4ff28ba4afb55a978a4aecfd688bf] --- + +if not modules then modules={} end modules ['font-otc']={ + 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 insert,sortedkeys,sortedhash,tohash=table.insert,table.sortedkeys,table.sortedhash,table.tohash +local type,next,tonumber=type,next,tonumber +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", + ligature="ligature", + alternate="alternate", + multiple="multiple", + kern="kern", + pair="pair", + single="single", + chainsubstitution="chainsubstitution", + chainposition="chainposition", +} +local types={ + substitution="gsub_single", + ligature="gsub_ligature", + alternate="gsub_alternate", + multiple="gsub_multiple", + kern="gpos_pair", + pair="gpos_pair", + single="gpos_single", + chainsubstitution="gsub_contextchain", + chainposition="gpos_contextchain", +} +local names={ + gsub_single="gsub", + gsub_multiple="gsub", + gsub_alternate="gsub", + gsub_ligature="gsub", + gsub_context="gsub", + gsub_contextchain="gsub", + gsub_reversecontextchain="gsub", + gpos_single="gpos", + gpos_pair="gpos", + gpos_cursive="gpos", + gpos_mark2base="gpos", + gpos_mark2ligature="gpos", + gpos_mark2mark="gpos", + gpos_context="gpos", + gpos_contextchain="gpos", +} +setmetatableindex(types,function(t,k) t[k]=k return k end) +local everywhere={ ["*"]={ ["*"]=true } } +local noflags={ false,false,false,false } +local function getrange(sequences,category) + local count=#sequences + local first=nil + local last=nil + for i=1,count do + local t=sequences[i].type + if t and names[t]==category then + if not first then + first=i + end + last=i + end + end + return first or 1,last or count +end +local function validspecification(specification,name) + local dataset=specification.dataset + if dataset then + elseif specification[1] then + dataset=specification + specification={ dataset=dataset } + else + dataset={ { data=specification.data } } + specification.data=nil + specification.dataset=dataset + end + local first=dataset[1] + if first then + first=first.data + end + if not first then + report_otf("invalid feature specification, no dataset") + return + end + if type(name)~="string" then + name=specification.name or first.name + end + if type(name)~="string" then + report_otf("invalid feature specification, no name") + return + end + local n=#dataset + if n>0 then + for i=1,n do + setmetatableindex(dataset[i],specification) + end + return specification,name + end +end +local function addfeature(data,feature,specifications) + if not specifications then + report_otf("missing specification") + return + end + local descriptions=data.descriptions + local resources=data.resources + local features=resources.features + local sequences=resources.sequences + if not features or not sequences then + report_otf("missing specification") + return + end + local alreadydone=resources.alreadydone + if not alreadydone then + alreadydone={} + resources.alreadydone=alreadydone + end + if alreadydone[specifications] then + return + else + alreadydone[specifications]=true + end + local fontfeatures=resources.features or everywhere + local unicodes=resources.unicodes + local splitter=lpeg.splitter(" ",unicodes) + local done=0 + local skip=0 + local aglunicodes=false + local specifications=validspecification(specifications,feature) + if not specifications then + return + end + local p=lpeg.P("P")*(lpeg.patterns.hexdigit^1/function(s) return tonumber(s,16) end)*lpeg.P(-1) + local function tounicode(code) + if not code then + return + end + if type(code)=="number" then + return code + end + local u=unicodes[code] + if u then + return u + end + if utflen(code)==1 then + u=utfbyte(code) + if u then + return u + end + end + local u=lpegmatch(p,code) + if u then + return u + end + if not aglunicodes then + aglunicodes=fonts.encodings.agl.unicodes + end + local u=aglunicodes[code] + if u then + return u + end + end + local coverup=otf.coverup + local coveractions=coverup.actions + local stepkey=coverup.stepkey + local register=coverup.register + 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 not nocheck and not description then + skip=skip+1 + else + if type(replacement)=="table" then + replacement=replacement[1] + end + replacement=tounicode(replacement) + if replacement and descriptions[replacement] then + cover(coverage,unicode,replacement) + done=done+1 + else + skip=skip+1 + end + end + end + return coverage + end + 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 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]=(nocheck or descriptions[u]) and u or unicode + end + cover(coverage,unicode,r) + done=done+1 + else + local u=tounicode(replacement) + if u then + cover(coverage,unicode,{ u }) + done=done+1 + else + skip=skip+1 + end + end + end + return coverage + end + 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 nocheck and not description then + skip=skip+1 + elseif type(replacement)=="table" then + local r={} + local n=0 + for i=1,#replacement do + local u=tounicode(replacement[i]) + if nocheck or descriptions[u] then + n=n+1 + r[n]=u + end + end + if n>0 then + cover(coverage,unicode,r) + done=done+1 + else + skip=skip+1 + end + else + local u=tounicode(replacement) + if u then + cover(coverage,unicode,{ u }) + done=done+1 + else + skip=skip+1 + end + end + end + return coverage + end + 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 not nocheck and not description then + skip=skip+1 + else + if type(ligature)=="string" then + ligature={ lpegmatch(splitter,ligature) } + end + local present=true + for i=1,#ligature do + local l=ligature[i] + local u=tounicode(l) + if nocheck or descriptions[u] then + ligature[i]=u + else + present=false + break + end + end + if present then + cover(coverage,unicode,ligature) + done=done+1 + else + skip=skip+1 + end + 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] + if description and type(replacement)=="table" then + local r={} + for k,v in next,replacement do + 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 + else + skip=skip+1 + end + end + if isspace then + resetspacekerns() + end + return coverage + end + local function prepare_pair(list,featuretype) + local coverage={} + local cover=coveractions[featuretype] + if cover then + for code,replacement in next,list do + local unicode=tounicode(code) + local description=descriptions[unicode] + if description and type(replacement)=="table" then + local r={} + for k,v in next,replacement do + 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 + else + 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 lookuptype=types[featuretype] + for nofrules=1,#rules do + local rule=rules[nofrules] + local current=rule.current + local before=rule.before + local after=rule.after + local replacements=rule.replacements or false + local sequence={} + local nofsequences=0 + if before then + for n=1,#before do + nofsequences=nofsequences+1 + sequence[nofsequences]=before[n] + end + end + local start=nofsequences+1 + for n=1,#current do + nofsequences=nofsequences+1 + sequence[nofsequences]=current[n] + end + local stop=nofsequences + if after then + for n=1,#after do + nofsequences=nofsequences+1 + sequence[nofsequences]=after[n] + end + end + local lookups=rule.lookups or false + local subtype=nil + if lookups and sublookups then + 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 + if nofsequences>0 then + local hashed={} + for i=1,nofsequences do + local t={} + local s=sequence[i] + for i=1,#s do + local u=tounicode(s[i]) + if u then + t[u]=true + end + end + hashed[i]=t + end + sequence=hashed + rulesize=rulesize+1 + rulehash[rulesize]={ + nofrules, + lookuptype, + sequence, + start, + stop, + lookups, + replacements, + subtype, + } + 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 + local dataset=specifications.dataset + local function report(name,category,position,first,last,sequences) + report_otf("injecting name %a of category %a at position %i in [%i,%i] of [%i,%i]", + name,category,position,first,last,1,#sequences) + end + local function inject(specification,sequences,sequence,first,last,category,name) + local position=specification.position or false + if not position then + position=specification.prepend + if position==true then + if trace_loading then + report(name,category,first,first,last,sequences) + end + insert(sequences,first,sequence) + return + end + end + if not position then + position=specification.append + if position==true then + if trace_loading then + report(name,category,last+1,first,last,sequences) + end + insert(sequences,last+1,sequence) + return + end + end + local kind=type(position) + if kind=="string" then + local index=false + for i=first,last do + local s=sequences[i] + local f=s.features + if f then + for k in sortedhash(f) do + if k==position then + index=i + break + end + end + if index then + break + end + end + end + if index then + position=index + else + position=last+1 + end + elseif kind=="number" then + if position<0 then + position=last-position+1 + end + if position>last then + position=last+1 + elseif position<first then + position=first + end + else + position=last+1 + end + if trace_loading then + report(name,category,position,first,last,sequences) + end + insert(sequences,position,sequence) + end + for s=1,#dataset do + local specification=dataset[s] + local valid=specification.valid + local feature=specification.name or feature + if not feature or feature=="" then + report_otf("no valid name given for extra feature") + elseif not valid or valid(data,specification,feature) then + local initialize=specification.initialize + if initialize then + specification.initialize=initialize(specification,data) and initialize or nil + end + local askedfeatures=specification.features or everywhere + 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 + local specification=sublookups[i] + 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 nofsteps=0 + local steps={} + for i=1,#askedsteps do + local list=askedsteps[i] + local coverage=nil + local format=nil + if featuretype=="substitution" then + coverage=prepare_substitution(list,featuretype,nocheck) + elseif featuretype=="ligature" then + coverage=prepare_ligature(list,featuretype,nocheck) + elseif featuretype=="alternate" then + coverage=prepare_alternate(list,featuretype,nocheck) + elseif featuretype=="multiple" then + 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 + sublookups=s + end + for i=1,#askedsteps do + local list=askedsteps[i] + local coverage=nil + local format=nil + if featuretype=="substitution" then + category="gsub" + coverage=prepare_substitution(list,featuretype,nocheck) + elseif featuretype=="ligature" then + category="gsub" + coverage=prepare_ligature(list,featuretype,nocheck) + elseif featuretype=="alternate" then + category="gsub" + coverage=prepare_alternate(list,featuretype,nocheck) + elseif featuretype=="multiple" then + category="gsub" + coverage=prepare_multiple(list,featuretype,nocheck) + elseif featuretype=="kern" or featuretype=="move" then + category="gpos" + 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) + elseif featuretype=="chainposition" then + category="gpos" + coverage=prepare_chain(list,featuretype,sublookups) + else + report_otf("not registering feature %a, unknown category",feature) + return + end + if coverage and next(coverage) then + nofsteps=nofsteps+1 + steps[nofsteps]=register(coverage,featuretype,format,feature,nofsteps,descriptions,resources) + end + end + if nofsteps>0 then + for k,v in next,askedfeatures do + if v[1] then + 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 + local steptype=types[featuretype] + local sequence={ + chain=featurechain, + features={ [feature]=askedfeatures }, + flags=featureflags, + name=feature, + order=featureorder, + [stepkey]=steps, + 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] + if not features then + features={} + fontfeatures[category]=features + end + local k=features[feature] + if not k then + k={} + features[feature]=k + end + for script,languages in next,askedfeatures do + local kk=k[script] + if not kk then + kk={} + k[script]=kk + end + for language,value in next,languages do + kk[language]=value + end + end + end + end + end + if trace_loading then + report_otf("registering feature %a, affected glyphs %a, skipped glyphs %a",feature,done,skip) + end +end +otf.enhancers.addfeature=addfeature +local extrafeatures={} +local knownfeatures={} +function otf.addfeature(name,specification) + if type(name)=="table" then + specification=name + end + if type(specification)~="table" then + report_otf("invalid feature specification, no valid table") + return + end + specification,name=validspecification(specification,name) + if name and specification then + local slot=knownfeatures[name] + 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 + end +end +local function enhance(data,filename,raw) + for slot=1,#extrafeatures do + local specification=extrafeatures[slot] + addfeature(data,specification.name,specification) + end +end +otf.enhancers.enhance=enhance +otf.enhancers.register("check extra features",enhance) + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-otc”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-onr” 20b0d2753f58ff91180947ce4078571e] --- + +if not modules then modules={} end modules ['font-onr']={ + 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 fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers +local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset +local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find +local char,byte,sub=string.char,string.byte,string.sub +local abs=math.abs +local bxor,rshift=bit32.bxor,bit32.rshift +local P,S,R,V,Cmt,C,Ct,Cs,Carg,Cf,Cg,Cc=lpeg.P,lpeg.S,lpeg.R,lpeg.V,lpeg.Cmt,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cf,lpeg.Cg,lpeg.Cc +local lpegmatch,patterns=lpeg.match,lpeg.patterns +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) +local report_afm=logs.reporter("fonts","afm loading") +local report_pfb=logs.reporter("fonts","pfb loading") +local handlers=fonts.handlers +local afm=handlers.afm or {} +handlers.afm=afm +local readers=afm.readers or {} +afm.readers=readers +afm.version=1.513 +local get_indexes,get_shapes +do + local decrypt + do + local r,c1,c2,n=0,0,0,0 + local function step(c) + local cipher=byte(c) + local plain=bxor(cipher,rshift(r,8)) + r=((cipher+r)*c1+c2)%65536 + return char(plain) + end + decrypt=function(binary,initial,seed) + r,c1,c2,n=initial,52845,22719,seed + binary=gsub(binary,".",step) + return sub(binary,n+1) + end + end + local charstrings=P("/CharStrings") + local subroutines=P("/Subrs") + local encoding=P("/Encoding") + local dup=P("dup") + local put=P("put") + local array=P("array") + local name=P("/")*C((R("az","AZ","09")+S("-_."))^1) + local digits=R("09")^1 + local cardinal=digits/tonumber + local spaces=P(" ")^1 + local spacing=patterns.whitespace^0 + local routines,vector,chars,n,m + local initialize=function(str,position,size) + n=0 + m=size + return position+1 + end + local setroutine=function(str,position,index,size,filename) + if routines[index] then + return false + end + local forward=position+size + local stream=decrypt(sub(str,position+1,forward),4330,4) + routines[index]={ byte(stream,1,#stream) } + n=n+1 + if n>=m then + return #str + end + return forward+1 + end + 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 + return forward + else + return #str + end + end + 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) + return forward + else + return #str + end + end + local p_rd=spacing*(P("RD")+P("-|")) + 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*Carg(1),setroutine)*p_np+(1-p_nd))^1 + local p_filtershapes= + (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*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 +,rawset) + local key=spacing*P("/")*R("az","AZ") + local str=spacing*Cs { (P("(")/"")*((1-P("\\(")-P("\\)")-S("()"))+V(1))^0*(P(")")/"") } + local num=spacing*(R("09")+S("+-."))^1/tonumber + local arr=spacing*Ct (S("[{")*(num)^0*spacing*S("]}")) + local boo=spacing*(P("true")*Cc(true)+P("false")*Cc(false)) + local nam=spacing*P("/")*Cs(R("az","AZ")^1) + local p_filtermetadata=( + P("/")*Carg(1)*(( + C("version")*str+C("Copyright")*str+C("Notice")*str+C("FullName")*str+C("FamilyName")*str+C("Weight")*str+C("ItalicAngle")*num+C("isFixedPitch")*boo+C("UnderlinePosition")*num+C("UnderlineThickness")*num+C("FontName")*nam+C("FontMatrix")*arr+C("FontBBox")*arr + ) )/function(t,k,v) t[lower(k)]=v end+P(1) + )^0*Carg(1) + local function loadpfbvector(filename,shapestoo,streams) + local data=io.loaddata(resolvers.findfile(filename)) + if not data then + report_pfb("no data in %a",filename) + return + end + if not (find(data,"!PS-AdobeFont-",1,true) or find(data,"%!FontType1",1,true)) then + report_pfb("no font in %a",filename) + return + end + local ascii,binary=match(data,"(.*)eexec%s+......(.*)") + if not binary then + report_pfb("no binary data in %a",filename) + return + end + binary=decrypt(binary,55665,4) + local names={} + local encoding=lpegmatch(p_filterencoding,ascii) + local metadata=lpegmatch(p_filtermetadata,ascii,1,{}) + local glyphs={} + routines,vector,chars={},{},{} + if shapestoo or streams then + lpegmatch(p_filterroutines,binary,1,filename) + lpegmatch(p_filtershapes,binary,1,filename) + local data={ + dictionaries={ + { + charstrings=chars, + charset=vector, + subroutines=routines, + } + }, + } + fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams) + else + lpegmatch(p_filternames,binary,1,filename) + end + names=vector + routines,vector,chars=nil,nil,nil + return names,encoding,glyphs,metadata + end + local pfb=handlers.pfb or {} + handlers.pfb=pfb + pfb.loadvector=loadpfbvector + get_indexes=function(data,pfbname) + local vector=loadpfbvector(pfbname) + if vector then + local characters=data.characters + if trace_loading then + report_afm("getting index data from %a",pfbname) + end + for index=0,#vector do + local name=vector[index] + local char=characters[name] + if char then + if trace_indexing then + 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 + end + get_shapes=function(pfbname) + local vector,encoding,glyphs=loadpfbvector(pfbname,true) + return glyphs + end +end +local spacer=patterns.spacer +local whitespace=patterns.whitespace +local lineend=patterns.newline +local spacing=spacer^0 +local number=spacing*S("+-")^-1*(R("09")+S("."))^1/tonumber +local name=spacing*C((1-whitespace)^1) +local words=spacing*((1-lineend)^1/strip) +local rest=(1-lineend)^0 +local fontdata=Carg(1) +local semicolon=spacing*P(";") +local plus=spacing*P("plus")*number +local minus=spacing*P("minus")*number +local function addkernpair(data,one,two,value) + local chr=data.characters[one] + if chr then + local kerns=chr.kerns + if kerns then + kerns[two]=tonumber(value) + else + chr.kerns={ [two]=tonumber(value) } + end + end +end +local p_kernpair=(fontdata*P("KPX")*name*name*number)/addkernpair +local chr=false +local ind=0 +local function start(data,version) + data.metadata.afmversion=version + ind=0 + chr={} +end +local function stop() + ind=0 + chr=false +end +local function setindex(i) + if i<0 then + ind=ind+1 + else + ind=i + end + chr={ + index=ind + } +end +local function setwidth(width) + chr.width=width +end +local function setname(data,name) + data.characters[name]=chr +end +local function setboundingbox(boundingbox) + chr.boundingbox=boundingbox +end +local function setligature(plus,becomes) + local ligatures=chr.ligatures + if ligatures then + ligatures[plus]=becomes + else + chr.ligatures={ [plus]=becomes } + end +end +local p_charmetric=(( + P("C")*number/setindex+P("WX")*number/setwidth+P("N")*fontdata*name/setname+P("B")*Ct((number)^4)/setboundingbox+P("L")*(name)^2/setligature + )*semicolon )^1 +local p_charmetrics=P("StartCharMetrics")*number*(p_charmetric+(1-P("EndCharMetrics")))^0*P("EndCharMetrics") +local p_kernpairs=P("StartKernPairs")*number*(p_kernpair+(1-P("EndKernPairs" )))^0*P("EndKernPairs" ) +local function set_1(data,key,a) data.metadata[lower(key)]=a end +local function set_2(data,key,a,b) data.metadata[lower(key)]={ a,b } end +local function set_3(data,key,a,b,c) data.metadata[lower(key)]={ a,b,c } end +local p_parameters=P(false)+fontdata*((P("FontName")+P("FullName")+P("FamilyName"))/lower)*words/function(data,key,value) + data.metadata[key]=value + end+fontdata*((P("Weight")+P("Version"))/lower)*name/function(data,key,value) + data.metadata[key]=value + end+fontdata*P("IsFixedPitch")*name/function(data,pitch) + data.metadata.monospaced=toboolean(pitch,true) + end+fontdata*P("FontBBox")*Ct(number^4)/function(data,boundingbox) + data.metadata.boundingbox=boundingbox + end+fontdata*((P("CharWidth")+P("CapHeight")+P("XHeight")+P("Descender")+P("Ascender")+P("ItalicAngle"))/lower)*number/function(data,key,value) + data.metadata[key]=value + end+P("Comment")*spacing*(P(false)+(fontdata*C("DESIGNSIZE")*number*rest)/set_1 ++(fontdata*C("TFM designsize")*number*rest)/set_1+(fontdata*C("DesignSize")*number*rest)/set_1+(fontdata*C("CODINGSCHEME")*words*rest)/set_1 ++(fontdata*C("CHECKSUM")*number*words*rest)/set_1 ++(fontdata*C("SPACE")*number*plus*minus*rest)/set_3 ++(fontdata*C("QUAD")*number*rest)/set_1 ++(fontdata*C("EXTRASPACE")*number*rest)/set_1 ++(fontdata*C("NUM")*number*number*number*rest)/set_3 ++(fontdata*C("DENOM")*number*number*rest)/set_2 ++(fontdata*C("SUP")*number*number*number*rest)/set_3 ++(fontdata*C("SUB")*number*number*rest)/set_2 ++(fontdata*C("SUPDROP")*number*rest)/set_1 ++(fontdata*C("SUBDROP")*number*rest)/set_1 ++(fontdata*C("DELIM")*number*number*rest)/set_2 ++(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 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) + if afmblob then + local data={ + resources={ + filename=resolvers.unresolve(filename), + version=afm.version, + creator="context mkiv", + }, + properties={ + hasitalics=false, + }, + goodies={}, + metadata={ + filename=file.removesuffix(file.basename(filename)) + }, + characters={ + }, + descriptions={ + }, + } + if trace_loading then + report_afm("parsing afm file %a",filename) + end + lpegmatch(parser,afmblob,1,data) + return data + else + if trace_loading then + report_afm("no valid afm file %a",filename) + end + return nil + end +end +function readers.loadfont(afmname,pfbname) + local data=read(resolvers.findfile(afmname),fullparser) + if data then + if not pfbname or pfbname=="" then + 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) + return data + else + report_afm("no pfb file for %a",afmname) + end + end +end +function readers.loadshapes(filename) + local fullname=resolvers.findfile(filename) or "" + if fullname=="" then + return { + filename="not found: "..filename, + glyphs={} + } + else + return { + filename=fullname, + format="opentype", + glyphs=get_shapes(fullname) or {}, + units=1000, + } + end +end +function readers.getinfo(filename) + local data=read(resolvers.findfile(filename),infoparser) + if data then + return data.metadata + end +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-onr”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-one” 987c5c5ed3754ad2feab80985067d59e] --- + +if not modules then modules={} end modules ['font-one']={ + 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 fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers +local next,type,tonumber,rawget=next,type,tonumber,rawget +local match,gsub=string.match,string.gsub +local abs=math.abs +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) +local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) +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 +local afm=constructors.handlers.afm +local pfb=constructors.handlers.pfb +local otf=fonts.handlers.otf +local otfreaders=otf.readers +local otfenhancers=otf.enhancers +local afmfeatures=constructors.features.afm +local registerafmfeature=afmfeatures.register +local afmenhancers=constructors.enhancers.afm +local registerafmenhancer=afmenhancers.register +afm.version=1.513 +afm.cache=containers.define("fonts","one",afm.version,true) +afm.autoprefixed=true +afm.helpdata={} +afm.syncspace=true +local overloads=fonts.mappings.overloads +local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes +function afm.load(filename) + filename=resolvers.findfile(filename,'afm') or "" + if filename~="" and not fonts.names.ignoredfile(filename) then + local name=file.removesuffix(file.basename(filename)) + local data=containers.read(afm.cache,name) + local attr=lfs.attributes(filename) + local size=attr and attr.size or 0 + local time=attr and attr.modification or 0 + local pfbfile=file.replacesuffix(name,"pfb") + local pfbname=resolvers.findfile(pfbfile,"pfb") or "" + if pfbname=="" then + pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or "" + end + local pfbsize=0 + local pfbtime=0 + if pfbname~="" then + local attr=lfs.attributes(pfbname) + pfbsize=attr.size or 0 + pfbtime=attr.modification or 0 + end + if not data or data.size~=size or data.time~=time or data.pfbsize~=pfbsize or data.pfbtime~=pfbtime then + report_afm("reading %a",filename) + data=afm.readers.loadfont(filename,pfbname) + if data then + afmenhancers.apply(data,filename) + fonts.mappings.addtounicode(data,filename) + otfreaders.stripredundant(data) + otfreaders.pack(data) + data.size=size + data.time=time + data.pfbsize=pfbsize + data.pfbtime=pfbtime + report_afm("saving %a in cache",name) + data=containers.write(afm.cache,name,data) + data=containers.read(afm.cache,name) + end + end + if data then + otfreaders.unpack(data) + otfreaders.expand(data) + otfreaders.addunicodetable(data) + otfenhancers.apply(data,filename,data) + if applyruntimefixes then + applyruntimefixes(filename,data) + end + end + return data + end +end +local uparser=fonts.mappings.makenameparser() +local function enhance_unify_names(data,filename) + local unicodevector=fonts.encodings.agl.unicodes + local unicodes={} + local names={} + local private=data.private or privateoffset + local descriptions=data.descriptions + for name,blob in sortedhash(data.characters) do + local code=unicodevector[name] + if not code then + code=lpegmatch(uparser,name) + if type(code)~="number" then + code=private + private=private+1 + report_afm("assigning private slot %U for unknown glyph name %a",code,name) + end + end + local index=blob.index + unicodes[name]=code + names[name]=index + blob.name=name + descriptions[code]={ + boundingbox=blob.boundingbox, + width=blob.width, + kerns=blob.kerns, + index=index, + name=name, + } + end + for unicode,description in next,descriptions do + local kerns=description.kerns + if kerns then + local krn={} + for name,kern in next,kerns do + local unicode=unicodes[name] + if unicode then + krn[unicode]=kern + else + end + end + description.kerns=krn + 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={} +end +local everywhere={ ["*"]={ ["*"]=true } } +local noflags={ false,false,false,false } +local function enhance_normalize_features(data) + local ligatures=setmetatableindex("table") + local kerns=setmetatableindex("table") + local extrakerns=setmetatableindex("table") + for u,c in next,data.descriptions do + local l=c.ligatures + local k=c.kerns + local e=c.extrakerns + if l then + ligatures[u]=l + for u,v in next,l do + l[u]={ ligature=v } + end + c.ligatures=nil + end + if k then + kerns[u]=k + for u,v in next,k do + k[u]=v + end + c.kerns=nil + end + if e then + extrakerns[u]=e + for u,v in next,e do + e[u]=v + end + c.extrakerns=nil + end + end + local features={ + gpos={}, + gsub={}, + } + local sequences={ + } + if next(ligatures) then + features.gsub.liga=everywhere + data.properties.hasligatures=true + sequences[#sequences+1]={ + features={ + liga=everywhere, + }, + flags=noflags, + name="s_s_0", + nofsteps=1, + order={ "liga" }, + type="gsub_ligature", + steps={ + { + coverage=ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern=everywhere + data.properties.haskerns=true + sequences[#sequences+1]={ + features={ + kern=everywhere, + }, + flags=noflags, + name="p_s_0", + nofsteps=1, + order={ "kern" }, + type="gpos_pair", + steps={ + { + format="kern", + coverage=kerns, + }, + }, + } + end + if next(extrakerns) then + features.gpos.extrakerns=everywhere + data.properties.haskerns=true + sequences[#sequences+1]={ + features={ + extrakerns=everywhere, + }, + flags=noflags, + name="p_s_1", + nofsteps=1, + order={ "extrakerns" }, + type="gpos_pair", + steps={ + { + format="kern", + coverage=extrakerns, + }, + }, + } + end + data.resources.features=features + data.resources.sequences=sequences +end +local function enhance_fix_names(data) + for k,v in next,data.descriptions do + local n=v.name + local r=overloads[n] + if r then + local name=r.name + if trace_indexing then + report_afm("renaming characters %a to %a",n,name) + end + v.name=name + v.unicode=r.unicode + end + end +end +local addthem=function(rawdata,ligatures) + if ligatures then + local descriptions=rawdata.descriptions + local resources=rawdata.resources + local unicodes=resources.unicodes + for ligname,ligdata in next,ligatures do + local one=descriptions[unicodes[ligname]] + if one then + for _,pair in next,ligdata do + local two=unicodes[pair[1]] + local three=unicodes[pair[2]] + if two and three then + local ol=one.ligatures + if ol then + if not ol[two] then + ol[two]=three + end + else + one.ligatures={ [two]=three } + end + end + end + end + end + end +end +local function enhance_add_ligatures(rawdata) + addthem(rawdata,afm.helpdata.ligatures) +end +local function enhance_add_extra_kerns(rawdata) + local descriptions=rawdata.descriptions + local resources=rawdata.resources + local unicodes=resources.unicodes + local function do_it_left(what) + if what then + for unicode,description in next,descriptions do + local kerns=description.kerns + if kerns then + local extrakerns + for complex,simple in next,what do + complex=unicodes[complex] + simple=unicodes[simple] + if complex and simple then + local ks=kerns[simple] + if ks and not kerns[complex] then + if extrakerns then + extrakerns[complex]=ks + else + extrakerns={ [complex]=ks } + end + end + end + end + if extrakerns then + description.extrakerns=extrakerns + end + end + end + end + end + local function do_it_copy(what) + if what then + for complex,simple in next,what do + complex=unicodes[complex] + simple=unicodes[simple] + if complex and simple then + local complexdescription=descriptions[complex] + if complexdescription then + local simpledescription=descriptions[complex] + if simpledescription then + local extrakerns + local kerns=simpledescription.kerns + if kerns then + for unicode,kern in next,kerns do + if extrakerns then + extrakerns[unicode]=kern + else + extrakerns={ [unicode]=kern } + end + end + end + local extrakerns=simpledescription.extrakerns + if extrakerns then + for unicode,kern in next,extrakerns do + if extrakerns then + extrakerns[unicode]=kern + else + extrakerns={ [unicode]=kern } + end + end + end + if extrakerns then + complexdescription.extrakerns=extrakerns + end + end + end + end + end + end + end + do_it_left(afm.helpdata.leftkerned) + do_it_left(afm.helpdata.bothkerned) + do_it_copy(afm.helpdata.bothkerned) + do_it_copy(afm.helpdata.rightkerned) +end +local function adddimensions(data) + if data then + for unicode,description in next,data.descriptions do + local bb=description.boundingbox + if bb then + local ht=bb[4] + local dp=-bb[2] + if ht==0 or ht<0 then + else + description.height=ht + end + if dp==0 or dp<0 then + else + description.depth=dp + end + end + end + end +end +local function copytotfm(data) + if data and data.descriptions then + local metadata=data.metadata + local resources=data.resources + local properties=derivetable(data.properties) + local descriptions=derivetable(data.descriptions) + local goodies=derivetable(data.goodies) + local characters={} + local parameters={} + local unicodes=resources.unicodes + for unicode,description in next,data.descriptions do + characters[unicode]={} + end + local filename=constructors.checkedfilename(resources) + local fontname=metadata.fontname or metadata.fullname + local fullname=metadata.fullname or metadata.fontname + local endash=0x2013 + local emdash=0x2014 + local space=0x0020 + local spacer="space" + local spaceunits=500 + local monospaced=metadata.monospaced + local charwidth=metadata.charwidth + local italicangle=metadata.italicangle + local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight + properties.monospaced=monospaced + parameters.italicangle=italicangle + parameters.charwidth=charwidth + parameters.charxheight=charxheight + local d_endash=descriptions[endash] + local d_emdash=descriptions[emdash] + local d_space=descriptions[space] + if not d_space or d_space==0 then + d_space=d_endash + end + if d_space then + spaceunits,spacer=d_space.width or 0,"space" + end + if properties.monospaced then + if spaceunits==0 and d_emdash then + spaceunits,spacer=d_emdash.width or 0,"emdash" + end + else + if spaceunits==0 and d_endash then + spaceunits,spacer=d_emdash.width or 0,"endash" + end + end + if spaceunits==0 and charwidth then + spaceunits,spacer=charwidth or 0,"charwidth" + end + if spaceunits==0 then + spaceunits=tonumber(spaceunits) or 500 + end + if spaceunits==0 then + spaceunits=500 + end + parameters.slant=0 + parameters.space=spaceunits + parameters.space_stretch=500 + parameters.space_shrink=333 + parameters.x_height=400 + parameters.quad=1000 + if italicangle and italicangle~=0 then + parameters.italicangle=italicangle + parameters.italicfactor=math.cos(math.rad(90+italicangle)) + parameters.slant=- math.tan(italicangle*math.pi/180) + end + if monospaced then + parameters.space_stretch=0 + parameters.space_shrink=0 + elseif afm.syncspace then + parameters.space_stretch=spaceunits/2 + parameters.space_shrink=spaceunits/3 + end + parameters.extra_space=parameters.space_shrink + if charxheight then + parameters.x_height=charxheight + else + local x=0x0078 + if x then + local x=descriptions[x] + if x then + parameters.x_height=x.height + end + end + end + if metadata.sup then + local dummy={ 0,0,0 } + parameters[ 1]=metadata.designsize or 0 + parameters[ 2]=metadata.checksum or 0 + parameters[ 3], + parameters[ 4], + parameters[ 5]=unpack(metadata.space or dummy) + parameters[ 6]=metadata.quad or 0 + parameters[ 7]=metadata.extraspace or 0 + parameters[ 8], + parameters[ 9], + parameters[10]=unpack(metadata.num or dummy) + parameters[11], + parameters[12]=unpack(metadata.denom or dummy) + parameters[13], + parameters[14], + parameters[15]=unpack(metadata.sup or dummy) + parameters[16], + parameters[17]=unpack(metadata.sub or dummy) + parameters[18]=metadata.supdrop or 0 + parameters[19]=metadata.subdrop or 0 + parameters[20], + parameters[21]=unpack(metadata.delim or dummy) + parameters[22]=metadata.axisheight or 0 + end + parameters.designsize=(metadata.designsize or 10)*65536 + parameters.ascender=abs(metadata.ascender or 0) + parameters.descender=abs(metadata.descender or 0) + parameters.units=1000 + properties.spacer=spacer + properties.encodingbytes=2 + properties.format=fonts.formats[filename] or "type1" + properties.filename=filename + properties.fontname=fontname + 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, + descriptions=descriptions, + parameters=parameters, + resources=resources, + properties=properties, + goodies=goodies, + } + end + end + return nil +end +function afm.setfeatures(tfmdata,features) + local okay=constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm) + if okay then + return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm) + else + return {} + end +end +local function addtables(data) + local resources=data.resources + local lookuptags=resources.lookuptags + local unicodes=resources.unicodes + if not lookuptags then + lookuptags={} + resources.lookuptags=lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v=type(k)=="number" and ("lookup "..k) or k + t[k]=v + return v + end) + if not unicodes then + unicodes={} + resources.unicodes=unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u,d in next,data.descriptions do + local n=d.name + if n then + t[n]=u + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) +end +local function afmtotfm(specification) + local afmname=specification.filename or specification.name + if specification.forced=="afm" or specification.format=="afm" then + if trace_loading then + report_afm("forcing afm format for %a",afmname) + end + else + local tfmname=findbinfile(afmname,"ofm") or "" + if tfmname~="" then + if trace_loading then + report_afm("fallback from afm to tfm for %a",afmname) + end + return + end + end + if afmname~="" then + local features=constructors.checkedfeatures("afm",specification.features.normal) + specification.features.normal=features + constructors.hashinstance(specification,true) + specification=definers.resolve(specification) + local cache_id=specification.hash + local tfmdata=containers.read(constructors.cache,cache_id) + if not tfmdata then + local rawdata=afm.load(afmname) + if rawdata and next(rawdata) then + addtables(rawdata) + adddimensions(rawdata) + tfmdata=copytotfm(rawdata) + if tfmdata and next(tfmdata) then + local shared=tfmdata.shared + if not shared then + shared={} + tfmdata.shared=shared + end + shared.rawdata=rawdata + shared.dynamics={} + tfmdata.changed={} + shared.features=features + shared.processes=afm.setfeatures(tfmdata,features) + end + elseif trace_loading then + report_afm("no (valid) afm file found with name %a",afmname) + end + tfmdata=containers.write(constructors.cache,cache_id,tfmdata) + end + return tfmdata + end +end +local function read_from_afm(specification) + local tfmdata=afmtotfm(specification) + if tfmdata then + tfmdata.properties.name=specification.name + tfmdata=constructors.scale(tfmdata,specification) + local allfeatures=tfmdata.shared.features or specification.features.normal + constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm) + fonts.loggers.register(tfmdata,'afm',specification) + end + return tfmdata +end +registerafmfeature { + name="mode", + description="mode", + initializers={ + base=otf.modeinitializer, + node=otf.modeinitializer, + } +} +registerafmfeature { + name="features", + description="features", + default=true, + initializers={ + node=otf.nodemodeinitializer, + base=otf.basemodeinitializer, + }, + processors={ + node=otf.featuresprocessor, + } +} +fonts.formats.afm="type1" +fonts.formats.pfb="type1" +local function check_afm(specification,fullname) + local foundname=findbinfile(fullname,'afm') or "" + if foundname=="" then + foundname=fonts.names.getfilename(fullname,"afm") or "" + end + if fullname and foundname=="" and afm.autoprefixed then + local encoding,shortname=match(fullname,"^(.-)%-(.*)$") + if encoding and shortname and fonts.encodings.known[encoding] then + shortname=findbinfile(shortname,'afm') or "" + if shortname~="" then + foundname=shortname + if trace_defining then + report_afm("stripping encoding prefix from filename %a",afmname) + end + end + end + end + if foundname~="" then + specification.filename=foundname + specification.format="afm" + return read_from_afm(specification) + end +end +function readers.afm(specification,method) + local fullname=specification.filename or "" + local tfmdata=nil + if fullname=="" then + local forced=specification.forced or "" + if forced~="" then + tfmdata=check_afm(specification,specification.name.."."..forced) + end + if not tfmdata then + local check_tfm=readers.check_tfm + method=(check_tfm and (method or definers.method or "afm or tfm")) or "afm" + if method=="tfm" then + tfmdata=check_tfm(specification,specification.name) + elseif method=="afm" then + tfmdata=check_afm(specification,specification.name) + elseif method=="tfm or afm" then + tfmdata=check_tfm(specification,specification.name) or check_afm(specification,specification.name) + else + tfmdata=check_afm(specification,specification.name) or check_tfm(specification,specification.name) + end + end + else + tfmdata=check_afm(specification,fullname) + end + return tfmdata +end +function readers.pfb(specification,method) + local original=specification.specification + if trace_defining then + report_afm("using afm reader for %a",original) + end + specification.forced="afm" + local function swap(name) + local value=specification[swap] + if value then + specification[swap]=gsub("%.pfb",".afm",1) + end + end + swap("filename") + swap("fullname") + swap("forcedname") + swap("specification") + return readers.afm(specification,method) +end +registerafmenhancer("unify names",enhance_unify_names) +registerafmenhancer("add ligatures",enhance_add_ligatures) +registerafmenhancer("add extra kerns",enhance_add_extra_kerns) +registerafmenhancer("normalize features",enhance_normalize_features) +registerafmenhancer("check extra features",otfenhancers.enhance) +registerafmenhancer("fix names",enhance_fix_names) + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-one”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-afk” 54d554530e75c57c56ee76234724e26d] --- + +if not modules then modules={} end modules ['font-afk']={ + version=1.001, + 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", + dataonly=true, +} +local allocate=utilities.storage.allocate +fonts.handlers.afm.helpdata={ + ligatures=allocate { + ['f']={ + { 'f','ff' }, + { 'i','fi' }, + { 'l','fl' }, + }, + ['ff']={ + { 'i','ffi' } + }, + ['fi']={ + { 'i','fii' } + }, + ['fl']={ + { 'i','fli' } + }, + ['s']={ + { 't','st' } + }, + ['i']={ + { 'j','ij' } + }, + }, + texligatures=allocate { + ['quoteleft']={ + { 'quoteleft','quotedblleft' } + }, + ['quoteright']={ + { 'quoteright','quotedblright' } + }, + ['hyphen']={ + { 'hyphen','endash' } + }, + ['endash']={ + { 'hyphen','emdash' } + } + }, + leftkerned=allocate { + AEligature="A",aeligature="a", + OEligature="O",oeligature="o", + IJligature="I",ijligature="i", + AE="A",ae="a", + OE="O",oe="o", + IJ="I",ij="i", + Ssharp="S",ssharp="s", + }, + rightkerned=allocate { + AEligature="E",aeligature="e", + OEligature="E",oeligature="e", + IJligature="J",ijligature="j", + AE="E",ae="e", + OE="E",oe="e", + IJ="J",ij="j", + Ssharp="S",ssharp="s", + }, + bothkerned=allocate { + Acircumflex="A",acircumflex="a", + Ccircumflex="C",ccircumflex="c", + Ecircumflex="E",ecircumflex="e", + Gcircumflex="G",gcircumflex="g", + Hcircumflex="H",hcircumflex="h", + Icircumflex="I",icircumflex="i", + Jcircumflex="J",jcircumflex="j", + Ocircumflex="O",ocircumflex="o", + Scircumflex="S",scircumflex="s", + Ucircumflex="U",ucircumflex="u", + Wcircumflex="W",wcircumflex="w", + Ycircumflex="Y",ycircumflex="y", + Agrave="A",agrave="a", + Egrave="E",egrave="e", + Igrave="I",igrave="i", + Ograve="O",ograve="o", + Ugrave="U",ugrave="u", + Ygrave="Y",ygrave="y", + Atilde="A",atilde="a", + Itilde="I",itilde="i", + Otilde="O",otilde="o", + Utilde="U",utilde="u", + Ntilde="N",ntilde="n", + Adiaeresis="A",adiaeresis="a",Adieresis="A",adieresis="a", + Ediaeresis="E",ediaeresis="e",Edieresis="E",edieresis="e", + Idiaeresis="I",idiaeresis="i",Idieresis="I",idieresis="i", + Odiaeresis="O",odiaeresis="o",Odieresis="O",odieresis="o", + Udiaeresis="U",udiaeresis="u",Udieresis="U",udieresis="u", + Ydiaeresis="Y",ydiaeresis="y",Ydieresis="Y",ydieresis="y", + Aacute="A",aacute="a", + Cacute="C",cacute="c", + Eacute="E",eacute="e", + Iacute="I",iacute="i", + Lacute="L",lacute="l", + Nacute="N",nacute="n", + Oacute="O",oacute="o", + Racute="R",racute="r", + Sacute="S",sacute="s", + Uacute="U",uacute="u", + Yacute="Y",yacute="y", + Zacute="Z",zacute="z", + Dstroke="D",dstroke="d", + Hstroke="H",hstroke="h", + Tstroke="T",tstroke="t", + Cdotaccent="C",cdotaccent="c", + Edotaccent="E",edotaccent="e", + Gdotaccent="G",gdotaccent="g", + Idotaccent="I",idotaccent="i", + Zdotaccent="Z",zdotaccent="z", + Amacron="A",amacron="a", + Emacron="E",emacron="e", + Imacron="I",imacron="i", + Omacron="O",omacron="o", + Umacron="U",umacron="u", + Ccedilla="C",ccedilla="c", + Kcedilla="K",kcedilla="k", + Lcedilla="L",lcedilla="l", + Ncedilla="N",ncedilla="n", + Rcedilla="R",rcedilla="r", + Scedilla="S",scedilla="s", + Tcedilla="T",tcedilla="t", + Ohungarumlaut="O",ohungarumlaut="o", + Uhungarumlaut="U",uhungarumlaut="u", + Aogonek="A",aogonek="a", + Eogonek="E",eogonek="e", + Iogonek="I",iogonek="i", + Uogonek="U",uogonek="u", + Aring="A",aring="a", + Uring="U",uring="u", + Abreve="A",abreve="a", + Ebreve="E",ebreve="e", + Gbreve="G",gbreve="g", + Ibreve="I",ibreve="i", + Obreve="O",obreve="o", + Ubreve="U",ubreve="u", + Ccaron="C",ccaron="c", + Dcaron="D",dcaron="d", + Ecaron="E",ecaron="e", + Lcaron="L",lcaron="l", + Ncaron="N",ncaron="n", + Rcaron="R",rcaron="r", + Scaron="S",scaron="s", + Tcaron="T",tcaron="t", + Zcaron="Z",zcaron="z", + dotlessI="I",dotlessi="i", + dotlessJ="J",dotlessj="j", + AEligature="AE",aeligature="ae",AE="AE",ae="ae", + OEligature="OE",oeligature="oe",OE="OE",oe="oe", + IJligature="IJ",ijligature="ij",IJ="IJ",ij="ij", + Lstroke="L",lstroke="l",Lslash="L",lslash="l", + Ostroke="O",ostroke="o",Oslash="O",oslash="o", + Ssharp="SS",ssharp="ss", + Aumlaut="A",aumlaut="a", + Eumlaut="E",eumlaut="e", + Iumlaut="I",iumlaut="i", + Oumlaut="O",oumlaut="o", + Uumlaut="U",uumlaut="u", + } +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-afk”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-tfm” 3bbba3214fd0b8c6f35ad85592fc2917] --- + +if not modules then modules={} end modules ['luatex-fonts-tfm']={ + 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,type=next,type +local match,format=string.match,string.format +local concat,sortedhash=table.concat,table.sortedhash +local idiv=number.idiv +local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) +local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end) +local report_defining=logs.reporter("fonts","defining") +local report_tfm=logs.reporter("fonts","tfm loading") +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 +local tfm=constructors.handlers.tfm +tfm.version=1.000 +tfm.maxnestingdepth=5 +tfm.maxnestingsize=65536*1024 +local otf=fonts.handlers.otf +local otfenhancers=otf.enhancers +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" +function tfm.setfeatures(tfmdata,features) + local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) + if okay then + return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm) + else + return {} + end +end +local depth={} +local loadtfm=font.read_tfm +local loadvf=font.read_vf +local function read_from_tfm(specification) + local filename=specification.filename + local size=specification.size + depth[filename]=(depth[filename] or 0)+1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata=loadtfm(filename,size) + if tfmdata then + local features=specification.features and specification.features.normal or {} + local features=constructors.checkedfeatures("tfm",features) + specification.features.normal=features + local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata=newtfmdata + end + local resources=tfmdata.resources or {} + local properties=tfmdata.properties or {} + local parameters=tfmdata.parameters or {} + local shared=tfmdata.shared or {} + shared.features=features + shared.resources=resources + properties.name=tfmdata.name + properties.fontname=tfmdata.fontname + properties.psname=tfmdata.psname + properties.fullname=tfmdata.fullname + properties.filename=specification.filename + properties.format=tfmdata.format or fonts.formats.tfm + properties.usedbitmap=tfmdata.usedbitmap + tfmdata.properties=properties + tfmdata.resources=resources + tfmdata.parameters=parameters + tfmdata.shared=shared + shared.rawdata={ resources=resources } + shared.features=features + if newtfmdata then + if not resources.marks then + resources.marks={} + end + if not resources.sequences then + resources.sequences={} + end + if not resources.features then + resources.features={ + gsub={}, + gpos={}, + } + end + if not tfmdata.changed then + tfmdata.changed={} + end + if not tfmdata.descriptions then + tfmdata.descriptions=tfmdata.characters + end + otf.readers.addunicodetable(tfmdata) + tfmenhancers.apply(tfmdata,filename) + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + otf.readers.unifymissing(tfmdata) + fonts.mappings.addtounicode(tfmdata,filename) + tfmdata.tounicode=1 + local tounicode=fonts.mappings.tounicode + for unicode,v in next,tfmdata.characters do + local u=v.unicode + if u then + v.tounicode=tounicode(u) + end + end + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil + if size<0 then + size=idiv(65536*-size,100) + end + parameters.factor=1 + parameters.units=1000 + parameters.size=size + parameters.slant=parameters.slant or parameters[1] or 0 + parameters.space=parameters.space or parameters[2] or 0 + parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 + parameters.x_height=parameters.x_height or parameters[5] or 0 + 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) + local vfname=findbinfile(specification.name,'ovf') + if vfname and vfname~="" then + local vfdata=loadvf(vfname,size) + if vfdata then + local chars=tfmdata.characters + for k,v in next,vfdata.characters do + chars[k].commands=v.commands + end + properties.virtualized=true + tfmdata.fonts=vfdata.fonts + tfmdata.type="virtual" + local fontlist=vfdata.fonts + local name=file.nameonly(filename) + for i=1,#fontlist do + local n=fontlist[i].name + local s=fontlist[i].size + local d=depth[filename] + s=constructors.scaled(s,vfdata.designsize) + if d>tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i]={ id=0 } + elseif (d>1) and (s>tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i]={ id=0 } + else + local t,id=constructors.readanddefine(n,s) + fontlist[i]={ id=id } + end + end + end + end + end + properties.haskerns=true + properties.hasligatures=true + properties.hasitalics=true + resources.unicodes={} + resources.lookuptags={} + depth[filename]=depth[filename]-1 + return tfmdata + else + depth[filename]=depth[filename]-1 + end +end +local function check_tfm(specification,fullname) + local foundname=findbinfile(fullname,'tfm') or "" + if foundname=="" then + foundname=findbinfile(fullname,'ofm') or "" + end + if foundname=="" then + foundname=fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname~="" then + specification.filename=foundname + specification.format="ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) + end +end +readers.check_tfm=check_tfm +function readers.tfm(specification) + local fullname=specification.filename or "" + if fullname=="" then + local forced=specification.forced or "" + if forced~="" then + fullname=specification.name.."."..forced + else + fullname=specification.name + end + end + return check_tfm(specification,fullname) +end +readers.ofm=readers.tfm +do + local outfiles={} + local tfmcache=table.setmetatableindex(function(t,tfmdata) + local id=font.define(tfmdata) + t[tfmdata]=id + return id + end) + local encdone=table.setmetatableindex("table") + function tfm.reencode(tfmdata,specification) + local features=specification.features + if not features then + return + end + local features=features.normal + if not features then + return + end + local tfmfile=file.basename(tfmdata.name) + local encfile=features.reencode + local pfbfile=features.pfbfile + local bitmap=features.bitmap + if not encfile then + return + end + local pfbfile=outfiles[tfmfile] + if pfbfile==nil then + if bitmap then + pfbfile=false + elseif type(pfbfile)~="string" then + pfbfile=tfmfile + end + if type(pfbfile)=="string" then + pfbfile=file.addsuffix(pfbfile,"pfb") + report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile) + else + report_tfm("using bitmap shapes for %a",tfmfile) + pfbfile=false + end + outfiles[tfmfile]=pfbfile + end + local encoding=false + local vector=false + if type(pfbfile)=="string" then + local pfb=constructors.handlers.pfb + if pfb and pfb.loadvector then + local v,e=pfb.loadvector(pfbfile) + if v then + vector=v + end + if e then + encoding=e + end + end + end + if type(encfile)=="string" and encfile~="auto" then + encoding=fonts.encodings.load(file.addsuffix(encfile,"enc")) + if encoding then + encoding=encoding.vector + end + end + if not encoding then + report_tfm("bad encoding for %a, quitting",tfmfile) + return + end + local unicoding=fonts.encodings.agl and fonts.encodings.agl.unicodes + local virtualid=tfmcache[tfmdata] + local tfmdata=table.copy(tfmdata) + local characters={} + local originals=tfmdata.characters + local indices={} + local parentfont={ "font",1 } + local private=tfmdata.privateoffset or constructors.privateoffset + local reported=encdone[tfmfile][encfile] + local backmap=vector and table.swapped(vector) + local done={} + for index,name in sortedhash(encoding) do + local unicode=unicoding[name] + local original=originals[index] + if original then + if unicode then + original.unicode=unicode + else + unicode=private + private=private+1 + if not reported then + report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode) + end + end + characters[unicode]=original + indices[index]=unicode + original.name=name + if backmap then + original.index=backmap[name] + else + original.commands={ parentfont,charcommand[index] } + original.oindex=index + end + done[name]=true + elseif not done[name] then + report_tfm("bad index %a in font %a with name %a",index,tfmfile,name) + end + end + encdone[tfmfile][encfile]=true + for k,v in next,characters do + local kerns=v.kerns + if kerns then + local t={} + for k,v in next,kerns do + local i=indices[k] + if i then + t[i]=v + end + end + v.kerns=next(t) and t or nil + end + local ligatures=v.ligatures + if ligatures then + local t={} + for k,v in next,ligatures do + local i=indices[k] + if i then + t[i]=v + v.char=indices[v.char] + end + end + v.ligatures=next(t) and t or nil + end + end + tfmdata.fonts={ { id=virtualid } } + tfmdata.characters=characters + tfmdata.fullname=tfmdata.fullname or tfmdata.name + tfmdata.psname=file.nameonly(pfbfile or tfmdata.name) + tfmdata.filename=pfbfile + tfmdata.encodingbytes=2 + tfmdata.format="type1" + tfmdata.tounicode=1 + tfmdata.embedding="subset" + tfmdata.usedbitmap=bitmap and virtualid + tfmdata.private=private + return tfmdata + end +end +do + local template=[[ +/CIDInit /ProcSet findresource begin + 12 dict begin + begincmap + /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def + /CMapName /TeX-bitmap-%s def + /CMapType 2 def + 1 begincodespacerange + <00> <FF> + endcodespacerange + %s beginbfchar +%s + endbfchar + endcmap +CMapName currentdict /CMap defineresource pop end +end +end +]] + local flushstreamobject=lpdf and lpdf.flushstreamobject + local setfontattributes=lpdf and lpdf.setfontattributes + if not flushstreamobject then + flushstreamobject=function(data) + return pdf.obj { immediate=true,type="stream",string=data } + end + end + if not setfontattributes then + setfontattributes=function(id,data) + return pdf.setfontattributes(id,data) + end + end + function tfm.addtounicode(tfmdata) + local id=tfmdata.usedbitmap + local map={} + local char={} + for k,v in next,tfmdata.characters do + local index=v.oindex + local tounicode=v.tounicode + if index and tounicode then + map[index]=tounicode + end + end + for k,v in sortedhash(map) do + char[#char+1]=format("<%02X> <%s>",k,v) + end + char=concat(char,"\n") + local stream=format(template,id,id,#char,char) + local reference=flushstreamobject(stream,nil,true) + setfontattributes(id,format("/ToUnicode %i 0 R",reference)) + end +end +do + local everywhere={ ["*"]={ ["*"]=true } } + local noflags={ false,false,false,false } + local function enhance_normalize_features(data) + local ligatures=setmetatableindex("table") + local kerns=setmetatableindex("table") + local characters=data.characters + for u,c in next,characters do + local l=c.ligatures + local k=c.kerns + if l then + ligatures[u]=l + for u,v in next,l do + l[u]={ ligature=v.char } + end + c.ligatures=nil + end + if k then + kerns[u]=k + for u,v in next,k do + k[u]=v + end + c.kerns=nil + end + end + for u,l in next,ligatures do + for k,v in next,l do + local vl=v.ligature + local dl=ligatures[vl] + if dl then + for kk,vv in next,dl do + v[kk]=vv + end + end + end + end + local features={ + gpos={}, + gsub={}, + } + local sequences={ + } + if next(ligatures) then + features.gsub.liga=everywhere + data.properties.hasligatures=true + sequences[#sequences+1]={ + features={ + liga=everywhere, + }, + flags=noflags, + name="s_s_0", + nofsteps=1, + order={ "liga" }, + type="gsub_ligature", + steps={ + { + coverage=ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern=everywhere + data.properties.haskerns=true + sequences[#sequences+1]={ + features={ + kern=everywhere, + }, + flags=noflags, + name="p_s_0", + nofsteps=1, + order={ "kern" }, + type="gpos_pair", + steps={ + { + format="kern", + coverage=kerns, + }, + }, + } + end + data.resources.features=features + data.resources.sequences=sequences + data.shared.resources=data.shared.resources or resources + end + registertfmenhancer("normalize features",enhance_normalize_features) + registertfmenhancer("check extra features",otfenhancers.enhance) +end +registertfmfeature { + name="mode", + description="mode", + initializers={ + base=otf.modeinitializer, + node=otf.modeinitializer, + } +} +registertfmfeature { + name="features", + description="features", + default=true, + initializers={ + base=otf.basemodeinitializer, + node=otf.nodemodeinitializer, + }, + processors={ + node=otf.featuresprocessor, + } +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-tfm”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-lua” 55b281fb98f7bd848fc19928f376f647] --- + +if not modules then modules={} end modules ['font-lua']={ + 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 trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) +local report_lua=logs.reporter("fonts","lua loading") +local fonts=fonts +local readers=fonts.readers +fonts.formats.lua="lua" +local function check_lua(specification,fullname) + local fullname=resolvers.findfile(fullname) or "" + if fullname~="" then + local loader=loadfile(fullname) + loader=loader and loader() + return loader and loader(specification) + end +end +readers.check_lua=check_lua +function readers.lua(specification) + local original=specification.specification + if trace_defining then + report_lua("using lua reader for %a",original) + end + local fullname=specification.filename or "" + if fullname=="" then + local forced=specification.forced or "" + if forced~="" then + fullname=specification.name.."."..forced + else + fullname=specification.name + end + end + return check_lua(specification,fullname) +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-lua”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-def” f66c365dae4499f982d8bf16e5d37de3] --- + +if not modules then modules={} end modules ['font-def']={ + 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,gsub=string.lower,string.gsub +local tostring,next=tostring,next +local lpegmatch=lpeg.match +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") +local report_defining=logs.reporter("fonts","defining") +local fonts=fonts +local fontdata=fonts.hashes.identifiers +local readers=fonts.readers +local definers=fonts.definers +local specifiers=fonts.specifiers +local constructors=fonts.constructors +local fontgoodies=fonts.goodies +readers.sequence=allocate { 'otf','ttf','afm','tfm','lua' } +local variants=allocate() +specifiers.variants=variants +definers.methods=definers.methods or {} +local internalized=allocate() +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 function makespecification(specification,lookup,name,sub,method,detail,size) + size=size or 655360 + if not lookup or lookup=="" then + lookup=definers.defaultlookup + end + if trace_defining then + report_defining("specification %a, lookup %a, name %a, sub %a, method %a, detail %a", + specification,lookup,name,sub,method,detail) + end + local t={ + lookup=lookup, + specification=specification, + size=size, + name=name, + sub=sub, + method=method, + detail=detail, + resolved="", + forced="", + features={}, + } + return t +end +definers.makespecification=makespecification +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 +function resolvers.file(specification) + local name=resolvefile(specification.name) + local suffix=lower(suffixonly(name)) + if fonts.formats[suffix] then + specification.forced=suffix + specification.forcedname=name + specification.name=removesuffix(name) + else + specification.name=name + end +end +function resolvers.name(specification) + local resolve=fonts.names.resolve + if resolve then + 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 + end + local suffix=lower(suffixonly(resolved)) + if fonts.formats[suffix] then + specification.forced=suffix + specification.forcedname=resolved + specification.name=removesuffix(resolved) + else + specification.name=resolved + end + end + else + resolvers.file(specification) + end +end +function resolvers.spec(specification) + local resolvespec=fonts.names.resolvespec + if resolvespec then + local resolved,sub,subindex=resolvespec(specification.name,specification.sub,specification) + if resolved then + specification.resolved=resolved + specification.sub=sub + specification.subindex=subindex + specification.forced=lower(suffixonly(resolved)) + specification.forcedname=resolved + specification.name=removesuffix(resolved) + end + else + resolvers.name(specification) + end +end +function definers.resolve(specification) + if not specification.resolved or specification.resolved=="" then + local r=resolvers[specification.lookup] + if r then + r(specification) + end + end + if specification.forced=="" then + specification.forced=nil + specification.forcedname=nil + end + specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification)) + if specification.sub and specification.sub~="" then + specification.hash=specification.sub..' @ '..specification.hash + end + return specification +end +function definers.applypostprocessors(tfmdata) + local postprocessors=tfmdata.postprocessors + if postprocessors then + local properties=tfmdata.properties + for i=1,#postprocessors do + local extrahash=postprocessors[i](tfmdata) + if type(extrahash)=="string" and extrahash~="" then + extrahash=gsub(lower(extrahash),"[^a-z]","-") + properties.fullname=formatters["%s-%s"](properties.fullname,extrahash) + end + end + end + return tfmdata +end +local function checkembedding(tfmdata) + local properties=tfmdata.properties + local embedding + if directive_embedall then + embedding="full" + elseif properties and properties.filename and constructors.dontembed[properties.filename] then + embedding="no" + else + embedding="subset" + end + if properties then + properties.embedding=embedding + else + tfmdata.properties={ embedding=embedding } + 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 context and 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 context and 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] + if not tfmdata then + local forced=specification.forced or "" + if forced~="" then + local reader=readers[lower(forced)] + tfmdata=reader and reader(specification) + if not tfmdata then + report_defining("forced type %a of %a not found",forced,specification.name) + end + else + local sequence=readers.sequence + for s=1,#sequence do + local reader=sequence[s] + if readers[reader] then + if trace_defining then + report_defining("trying (reader sequence driven) type %a for %a with file %a",reader,specification.name,specification.filename) + end + tfmdata=readers[reader](specification) + if tfmdata then + break + else + specification.filename=nil + end + end + end + end + if tfmdata then + tfmdata=definers.applypostprocessors(tfmdata) + checkembedding(tfmdata) + loadedfonts[hash]=tfmdata + designsizes[specification.hash]=tfmdata.parameters.designsize + checkfeatures(tfmdata) + end + end + if not tfmdata then + report_defining("font with asked name %a is not found using lookup %a",specification.name,specification.lookup) + end + return tfmdata +end +function constructors.readanddefine(name,size) + local specification=definers.analyze(name,size) + local method=specification.method + if method and variants[method] then + specification=variants[method](specification) + end + specification=definers.resolve(specification) + local hash=constructors.hashinstance(specification) + local id=definers.registered(hash) + if not id then + local tfmdata=definers.loadfont(specification) + if tfmdata then + tfmdata.properties.hash=hash + id=font.define(tfmdata) + definers.register(tfmdata,id) + else + id=0 + end + end + return fontdata[id],id +end +function definers.current() + return lastdefined +end +function definers.registered(hash) + local id=internalized[hash] + return id,id and fontdata[id] +end +function definers.register(tfmdata,id) + if tfmdata and id then + local hash=tfmdata.properties.hash + if not hash then + report_defining("registering font, id %a, name %a, invalid hash",id,tfmdata.properties.filename or "?") + elseif not internalized[hash] then + internalized[hash]=id + if trace_defining then + report_defining("registering font, id %s, hash %a",id,hash) + end + fontdata[id]=tfmdata + end + end +end +function definers.read(specification,size,id) + statistics.starttiming(fonts) + if type(specification)=="string" then + specification=definers.analyze(specification,size) + end + local method=specification.method + if method and variants[method] then + specification=variants[method](specification) + end + specification=definers.resolve(specification) + local hash=constructors.hashinstance(specification) + local tfmdata=definers.registered(hash) + if tfmdata then + if trace_defining then + report_defining("already hashed: %s",hash) + end + else + tfmdata=definers.loadfont(specification) + if tfmdata then + if trace_defining then + report_defining("loaded and hashed: %s",hash) + end + tfmdata.properties.hash=hash + if id then + definers.register(tfmdata,id) + end + else + if trace_defining then + report_defining("not loaded and hashed: %s",hash) + end + end + end + lastdefined=tfmdata or id + if not tfmdata then + report_defining("unknown font %a, loading aborted",specification.name) + elseif trace_defining and type(tfmdata)=="table" then + 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 or "-",properties.name,parameters.size,properties.encodingbytes, + properties.encodingname,properties.fullname,basename(properties.filename)) + end + statistics.stoptiming(fonts) + return tfmdata +end +function font.getfont(id) + return fontdata[id] +end +callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “font-def”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-def” 5ad79120ebc5e60f4d322fb3ee13bffe] --- + +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 +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 +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 + return tfmdata +end + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-def”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-ext” 01015ab3758cdc2af29394e6d502a91a] --- + +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" +} +if context then + os.exit() +end +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] + if setup then + local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1 + local emwidth=tfmdata.parameters.quad + tfmdata.parameters.protrusion={ + auto=true, + } + for i,chr in next,tfmdata.characters do + local v,pl,pr=setup[i],nil,nil + if v then + pl,pr=v[1],v[2] + end + if pl and pl~=0 then chr.left_protruding=left*pl*factor end + if pr and pr~=0 then chr.right_protruding=right*pr*factor end + end + end + end +end +local specification={ + name="protrusion", + description="shift characters into the left and or right margin", + initializers={ + base=initializeprotrusion, + 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] + if setup then + local factor=setup.factor or 1 + tfmdata.parameters.expansion={ + stretch=10*(setup.stretch or 0), + shrink=10*(setup.shrink or 0), + step=10*(setup.step or 0), + auto=true, + } + for i,chr in next,tfmdata.characters do + local v=setup[i] + if v and v~=0 then + chr.expansion_factor=v*factor + else + chr.expansion_factor=factor + end + end + end + end +end +local specification={ + name="expansion", + description="apply hz optimization", + initializers={ + base=initializeexpansion, + node=initializeexpansion, + } +} +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 +end +function fonts.helpers.nametoslot(name) + local t=type(name) + if t=="string" then + local tfmdata=fonts.hashes.identifiers[currentfont()] + local shared=tfmdata and tfmdata.shared + local fntdata=shared and shared.rawdata + return fntdata and fntdata.resources.unicodes[name] + elseif t=="number" then + return n + end +end +fonts.encodings=fonts.encodings or {} +local reencodings={} +fonts.encodings.reencodings=reencodings +local function specialreencode(tfmdata,value) + local encoding=value and reencodings[value] + if encoding then + local temp={} + local char=tfmdata.characters + for k,v in next,encoding do + temp[k]=char[v] + end + for k,v in next,temp do + char[k]=temp[k] + end + return string.format("reencoded:%s",value) + end +end +local function initialize(tfmdata,value) + tfmdata.postprocessors=tfmdata.postprocessors or {} + table.insert(tfmdata.postprocessors, + function(tfmdata) + return specialreencode(tfmdata,value) + end + ) +end +registerotffeature { + name="reencode", + description="reencode characters", + manipulators={ + base=initialize, + node=initialize, + } +} +local function initialize(tfmdata,key,value) + if value then + tfmdata.mathparameters=nil + end +end +registerotffeature { + name="ignoremathconstants", + description="ignore math constants table", + initializers={ + base=initialize, + node=initialize, + } +} + +end --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-ext”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-imp-tex” 77c374b0ef00c2fb12188ec42beb4257] --- + +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-2019-05-18.lua scope for “font-imp-tex”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-imp-ligatures” 043daa4fcccf2560868da359d71d3a4a] --- + +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-2019-05-18.lua scope for “font-imp-ligatures”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-imp-italics” fe1ca80fb5ea4a2f8d2d5c484e7ba913] --- + +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-2019-05-18.lua scope for “font-imp-italics”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “font-imp-effects” 73a660359a0ec71e44cc2b7225a715ac] --- + +if not modules then modules={} end modules ['font-imp-effects']={ + 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,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-2019-05-18.lua scope for “font-imp-effects”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-lig” b9dbe77ce747d4c35bb2a20ffbe5aa51] --- + + +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-2019-05-18.lua scope for “fonts-lig”] --- + + +do --- [luaotfload, fontloader-2019-05-18.lua scope for “fonts-gbn” d25472d54c4841db43a745764a63533e] --- + +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", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +if context then + os.exit() +end +local next=next +local fonts=fonts +local nodes=nodes +local nuts=nodes.nuts +local traverse_id=nuts.traverse_id +local flush_node=nuts.flush_node +local glyph_code=nodes.nodecodes.glyph +local disc_code=nodes.nodecodes.disc +local tonode=nuts.tonode +local tonut=nuts.tonut +local getfont=nuts.getfont +local getchar=nuts.getchar +local getid=nuts.getid +local getboth=nuts.getboth +local getprev=nuts.getprev +local getnext=nuts.getnext +local getdisc=nuts.getdisc +local setchar=nuts.setchar +local setlink=nuts.setlink +local setprev=nuts.setprev +local n_ligaturing=node.ligaturing +local n_kerning=node.kerning +local d_ligaturing=nuts.ligaturing +local d_kerning=nuts.kerning +local basemodepass=true +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() + end + return n_ligaturing(...) +end +function node.kerning(...) + if basemodepass and k_warning then + k_warning() + 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 +local function nodepass(head,groupcode,size,packtype,direction) + local fontdata=fonts.hashes.identifiers + if fontdata then + local usedfonts={} + local basefonts={} + local prevfont=nil + local basefont=nil + local variants=nil + local redundant=nil + local nofused=0 + for n in traverse_id(glyph_code,head) do + local font=getfont(n) + if font~=prevfont then + if basefont then + basefont[2]=getprev(n) + end + prevfont=font + local used=usedfonts[font] + if not used then + local tfmdata=fontdata[font] + if tfmdata then + local shared=tfmdata.shared + if shared then + 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 + end + end + local resources=tfmdata.resources + variants=resources and resources.variants + variants=variants and next(variants) and variants or false + end + else + local tfmdata=fontdata[prevfont] + if tfmdata then + local resources=tfmdata.resources + variants=resources and resources.variants + variants=variants and next(variants) and variants or false + end + end + end + if variants then + local char=getchar(n) + if (char>=0xFE00 and char<=0xFE0F) or (char>=0xE0100 and char<=0xE01EF) then + local hash=variants[char] + if hash then + local p=getprev(n) + if p and getid(p)==glyph_code then + local variant=hash[getchar(p)] + if variant then + setchar(p,variant) + end + end + end + if not redundant then + redundant={ n } + else + redundant[#redundant+1]=n + end + end + end + end + local nofbasefonts=#basefonts + if redundant then + for i=1,#redundant do + local r=redundant[i] + local p,n=getboth(r) + if r==head then + head=n + setprev(n) + else + setlink(p,n) + end + if nofbasefonts>0 then + for i=1,nofbasefonts do + local bi=basefonts[i] + if r==bi[1] then + bi[1]=n + end + if r==bi[2] then + bi[2]=n + end + end + end + flush_node(r) + end + end + 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 + local font=getfont(n) + if font~=prevfont then + prevfont=font + local used=usedfonts[font] + if not used then + local tfmdata=fontdata[font] + if tfmdata then + local shared=tfmdata.shared + if shared then + local processors=shared.processes + if processors and #processors>0 then + usedfonts[font]=processors + nofused=nofused+1 + end + end + end + end + end + end + end + end + if next(usedfonts) then + for font,processors in next,usedfonts do + for i=1,#processors do + head=processors[i](head,font,0,direction,nofused) or head + end + end + end + if basemodepass and nofbasefonts>0 then + for i=1,nofbasefonts do + local range=basefonts[i] + local start=range[1] + local stop=range[2] + if start then + local front=head==start + local prev,next + if stop then + 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 next then + setlink(stop,next) + end + if front and head~=start then + head=start + end + end + end + end + 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 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) + head=tonode(head) + end + return head +end + +end --- [luaotfload, fontloader-2019-05-18.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-nod.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua index e22f170ef90..2b996829e4c 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-basics-nod.lua @@ -70,87 +70,84 @@ nodes.nodecodes = nodecodes nodes.glyphcodes = glyphcodes nodes.disccodes = disccodes -local flush_node = node.flush_node -local remove_node = node.remove -local traverse_id = node.traverse_id - nodes.handlers.protectglyphs = node.protect_glyphs -- beware: nodes! nodes.handlers.unprotectglyphs = node.unprotect_glyphs -- beware: nodes! -function nodes.remove(head, current, free_too) - local t = current - head, current = remove_node(head,current) - if t then - if free_too then - flush_node(t) - t = nil - else - t.next, t.prev = nil, nil - end - end - return head, current, t -end - -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end - -local getfield = node.getfield -local setfield = node.setfield - -nodes.getfield = getfield -nodes.setfield = setfield - -nodes.getattr = getfield -nodes.setattr = setfield - --- being lazy ... just copy a bunch ... not all needed in generic but we assume --- nodes to be kind of private anyway - -nodes.tostring = node.tostring or tostring -nodes.copy = node.copy -nodes.copy_node = node.copy -nodes.copy_list = node.copy_list -nodes.delete = node.delete -nodes.dimensions = node.dimensions -nodes.end_of_math = node.end_of_math -nodes.flush_list = node.flush_list -nodes.flush_node = node.flush_node -nodes.flush = node.flush_node -nodes.free = node.free -nodes.insert_after = node.insert_after -nodes.insert_before = node.insert_before -nodes.hpack = node.hpack -nodes.new = node.new -nodes.tail = node.tail -nodes.traverse = node.traverse -nodes.traverse_id = node.traverse_id -nodes.slide = node.slide -nodes.vpack = node.vpack - -nodes.first_glyph = node.first_glyph -nodes.has_glyph = node.has_glyph or node.first_glyph - -nodes.current_attr = node.current_attr -nodes.has_field = node.has_field -nodes.last_node = node.last_node -nodes.usedlist = node.usedlist -nodes.protrusion_skippable = node.protrusion_skippable -nodes.write = node.write - -nodes.has_attribute = node.has_attribute -nodes.set_attribute = node.set_attribute -nodes.unset_attribute = node.unset_attribute - -nodes.protect_glyphs = node.protect_glyphs -nodes.unprotect_glyphs = node.unprotect_glyphs -nodes.mlist_to_hlist = node.mlist_to_hlist +-- These are now gone in generic as they are context specific. + +-- local flush_node = node.flush_node +-- local remove_node = node.remove +-- local traverse_id = node.traverse_id +-- +-- function nodes.remove(head, current, free_too) +-- local t = current +-- head, current = remove_node(head,current) +-- if t then +-- if free_too then +-- flush_node(t) +-- t = nil +-- else +-- t.next, t.prev = nil, nil +-- end +-- end +-- return head, current, t +-- end +-- +-- function nodes.delete(head,current) +-- return nodes.remove(head,current,true) +-- end + +----- getfield = node.getfield +----- setfield = node.setfield + +-----.getfield = getfield +-----.setfield = setfield +-----.getattr = getfield +-----.setattr = setfield + +-----.tostring = node.tostring or tostring +-----.copy = node.copy +-----.copy_node = node.copy +-----.copy_list = node.copy_list +-----.delete = node.delete +-----.dimensions = node.dimensions +-----.end_of_math = node.end_of_math +-----.flush_list = node.flush_list +-----.flush_node = node.flush_node +-----.flush = node.flush_node +-----.free = node.free +-----.insert_after = node.insert_after +-----.insert_before = node.insert_before +-----.hpack = node.hpack +-----.new = node.new +-----.tail = node.tail +-----.traverse = node.traverse +-----.traverse_id = node.traverse_id +-----.slide = node.slide +-----.vpack = node.vpack + +-----.first_glyph = node.first_glyph +-----.has_glyph = node.has_glyph or node.first_glyph +-----.current_attr = node.current_attr +-----.has_field = node.has_field +-----.usedlist = node.usedlist +-----.protrusion_skippable = node.protrusion_skippable +-----.write = node.write + +-----.has_attribute = node.has_attribute +-----.set_attribute = node.set_attribute +-----.unset_attribute = node.unset_attribute + +-----.protect_glyphs = node.protect_glyphs +-----.unprotect_glyphs = node.unprotect_glyphs +-----.mlist_to_hlist = node.mlist_to_hlist -- in generic code, at least for some time, we stay nodes, while in context -- 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 +-- much of this will go away .. it's part of the context interface and not +-- officially in luatex-*.lua local direct = node.direct local nuts = { } @@ -190,7 +187,7 @@ nuts.setboth = direct.setboth nuts.setchar = direct.setchar nuts.setcomponents = direct.setcomponents ----.setdepth = direct.setdepth -nuts.setdir = direct.setdir +----.setdir = direct.setdir nuts.setdirection = direct.setdirection nuts.setdisc = direct.setdisc nuts.setfield = setfield @@ -207,8 +204,9 @@ nuts.setsplit = direct.setsplit nuts.setsubtype = direct.setsubtype nuts.setwidth = direct.setwidth -nuts.is_char = direct.is_char -nuts.is_glyph = direct.is_glyph +nuts.getglyphdata = nuts.getattr +nuts.setglyphdata = nuts.setattr + nuts.ischar = direct.is_char nuts.isglyph = direct.is_glyph @@ -234,26 +232,6 @@ nuts.traverse_char = direct.traverse_char nuts.traverse_glyph = direct.traverse_glyph nuts.traverse_id = direct.traverse_id --- for now - -if not nuts.getdirection then - - local getdir = direct.getdir - - function nuts.getdirection(n) - local d = getdir(n) - if d == "TLT" then return 0 - elseif d == "TRT" then return 1 - elseif d == "+TLT" then return 0, false - elseif d == "+TRT" then return 1, false - elseif d == "-TLT" then return 0, true - elseif d == "-TRT" then return 1, true - else return 0 - end - end - -end - -- properties as used in the (new) injector: local propertydata = direct.get_properties_table() 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 75486624b1b..86ae448cc22 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua @@ -1950,7 +1950,8 @@ end -- 1, -- 1 -- else - local g, l = #globals, #locals + local g = #globals + local l = #locals return ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1, ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1 @@ -2427,8 +2428,8 @@ function readers.cff(f,fontdata,specification) if private then local data = private.data if type(data) == "table" then - cffinfo.defaultwidth = data.defaultwidth or cffinfo.defaultwidth - cffinfo.nominalwidth = data.nominalwidth or cffinfo.nominalwidth + cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth cffinfo.bluevalues = data.bluevalues cffinfo.otherblues = data.otherblues cffinfo.familyblues = data.familyblues 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 9f85ee20839..9def52ef02c 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-con.lua @@ -547,7 +547,6 @@ function constructors.scale(tfmdata,specification) local hasitalics = properties.hasitalics local autoitalicamount = properties.autoitalicamount local stackmath = not properties.nostackmath - local nonames = properties.noglyphnames local haskerns = properties.haskerns or properties.mode == "base" -- we can have afm in node mode local hasligatures = properties.hasligatures or properties.mode == "base" -- we can have afm in node mode local realdimensions = properties.realdimensions @@ -596,7 +595,6 @@ function constructors.scale(tfmdata,specification) targetparameters.descender = delta * descender end -- --- inspect(targetparameters) constructors.enhanceparameters(targetparameters) -- official copies for us, now virtual -- local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0 @@ -677,9 +675,10 @@ function constructors.scale(tfmdata,specification) description = descriptions[unicode] or character index = description.index or unicode end - local width = description.width - local height = description.height - local depth = description.depth + local width = description.width + local height = description.height + local depth = description.depth + local isunicode = description.unicode if realdimensions then -- this is mostly for checking issues if not height or height == 0 then @@ -706,16 +705,16 @@ function constructors.scale(tfmdata,specification) -- if depth then depth = vdelta*depth else depth = scaleddepth end if depth and depth ~= 0 then depth = delta*depth - if nonames then + if isunicode then chr = { - index = index, - height = height, - depth = depth, - width = width, + index = index, + height = height, + depth = depth, + width = width, + unicode = isunicode, } else chr = { - name = description.name, index = index, height = height, depth = depth, @@ -723,36 +722,23 @@ function constructors.scale(tfmdata,specification) } end else - -- this saves a little bit of memory time and memory, esp for big cjk fonts - if nonames then + if isunicode then chr = { - index = index, - height = height, - width = width, + index = index, + height = height, + width = width, + unicode = isunicode, } else chr = { - name = description.name, index = index, height = height, width = width, } end end - local isunicode = description.unicode if addtounicode then - if isunicode then - chr.unicode = isunicode - chr.tounicode = tounicode(isunicode) - -- in luatex > 0.85 we can do this: - -- chr.tounicode = isunicode - else - chr.tounicode = unknowncode - end - else - if isunicode then - chr.unicode = isunicode - end + chr.tounicode = isunicode and tounicode(isunicode) or unknowncode end if hasquality then -- we could move these calculations elsewhere (saves calculations) @@ -827,7 +813,10 @@ function constructors.scale(tfmdata,specification) if stackmath then local mk = character.mathkerns if mk then - local tr, tl, br, bl = mk.topright, mk.topleft, mk.bottomright, mk.bottomleft + local tr = mk.topright + local tl = mk.topleft + local br = mk.bottomright + local bl = mk.bottomleft chr.mathkern = { -- singular -> should be patched in luatex ! top_right = tr and mathkerns(tr,vdelta) or nil, top_left = tl and mathkerns(tl,vdelta) or nil, @@ -1037,11 +1026,11 @@ function constructors.finalize(tfmdata) properties.virtualized = tfmdata.type == "virtual" end -- - properties.fontname = tfmdata.fontname - properties.filename = tfmdata.filename - properties.fullname = tfmdata.fullname - properties.name = tfmdata.name - properties.psname = tfmdata.psname + properties.fontname = properties.fontname or tfmdata.fontname + properties.filename = properties.filename or tfmdata.filename + properties.fullname = properties.fullname or tfmdata.fullname + properties.name = properties.name or tfmdata.name + properties.psname = properties.psname or tfmdata.psname -- properties.encodingbytes = tfmdata.encodingbytes or 1 properties.embedding = tfmdata.embedding or "subset" @@ -1174,7 +1163,9 @@ loose our testcases for <l n='luatex'/>.</p> --ldx]]-- function constructors.hashinstance(specification,force) - local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks + local hash = specification.hash + local size = specification.size + local fallbacks = specification.fallbacks if force or not hash then hash = constructors.hashfeatures(specification) specification.hash = hash @@ -1612,7 +1603,8 @@ end -- while typesetting function constructors.collectprocessors(what,tfmdata,features,trace,report) - local processes, nofprocesses = { }, 0 + local processes = { } + local nofprocesses = 0 if features and next(features) then local properties = tfmdata.properties local whathandler = handlers[what] 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 c5fb14d465a..79749741c34 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-dsp.lua @@ -1473,6 +1473,123 @@ 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. +-- local simple = { +-- [true] = { [true] = { true, true }, [false] = { true } }, +-- [false] = { [true] = { false, true }, [false] = { false } }, +-- } + +-- function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) +-- 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,mainoffset,getdelta) +-- coverage = readcoverage(f,tableoffset + coverage) +-- local shared = { } -- partial sparse, when set also needs to be handled in the packer +-- for index, newindex in next, coverage do +-- local set = sets[newindex+1] +-- local hash = { } +-- for i=1,#set do +-- local value = set[i] +-- if value then +-- local other = value[1] +-- if shared then +-- local s = shared[value] +-- if s == nil then +-- local first = value[2] +-- local second = value[3] +-- if first or second then +-- s = { first, second or nil } -- needs checking +-- else +-- s = false +-- end +-- shared[value] = s +-- end +-- hash[other] = s or nil +-- else +-- local first = value[2] +-- local second = value[3] +-- if first or second then +-- hash[other] = { first, second or nil } -- needs checking +-- else +-- hash[other] = nil -- what if set, maybe warning +-- end +-- end +-- end +-- end +-- coverage[index] = hash +-- end +-- return { +-- shared = shared and true or nil, +-- format = "pair", +-- coverage = coverage, +-- } +-- elseif subtype == 2 then +-- local coverage = readushort(f) +-- local format1 = readushort(f) +-- local format2 = readushort(f) +-- local classdef1 = readushort(f) +-- 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,tableoffset,getdelta) +-- coverage = readcoverage(f,tableoffset+coverage) +-- classdef1 = readclassdef(f,tableoffset+classdef1,coverage) +-- classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs) +-- local usedcoverage = { } +-- local shared = { } -- partial sparse, when set also needs to be handled in the packer +-- for g1, c1 in next, classdef1 do +-- if coverage[g1] then +-- local l1 = classlist[c1] +-- if l1 then +-- local hash = { } +-- for paired, class in next, classdef2 do +-- local offsets = l1[class] +-- if offsets then +-- local first = offsets[1] +-- local second = offsets[2] +-- if first or second then +-- if shared then +-- local s1 = shared[first] +-- if s1 == nil then +-- s1 = { } +-- shared[first] = s1 +-- end +-- local s2 = s1[second] +-- if s2 == nil then +-- s2 = { first, second or nil } +-- s1[second] = s2 +-- end +-- hash[paired] = s2 +-- else +-- hash[paired] = { first, second or nil } +-- end +-- else +-- -- upto the next lookup for this combination +-- end +-- end +-- end +-- usedcoverage[g1] = hash +-- end +-- end +-- end +-- return { +-- shared = shared and true or nil, +-- format = "pair", +-- coverage = usedcoverage, +-- } +-- elseif subtype == 3 then +-- report("yet unsupported subtype %a in %a positioning",subtype,"pair") +-- else +-- report("unsupported subtype %a in %a positioning",subtype,"pair") +-- end +-- end + function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofglyphs) local tableoffset = lookupoffset + offset setposition(f,tableoffset) @@ -1485,25 +1602,32 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local sets = readarray(f) sets = readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta) coverage = readcoverage(f,tableoffset + coverage) + local shared = { } -- partial sparse, when set also needs to be handled in the packer for index, newindex in next, coverage do local set = sets[newindex+1] local hash = { } for i=1,#set do local value = set[i] if value then - local other = value[1] - local first = value[2] - local second = value[3] - if first or second then - hash[other] = { first, second or nil } -- needs checking - else - hash[other] = nil -- what if set, maybe warning + local other = value[1] + local share = shared[value] + if share == nil then + local first = value[2] + local second = value[3] + if first or second then + share = { first, second or nil } -- needs checking + else + share = false + end + shared[value] = share end + hash[other] = share or nil -- really overload ? end end coverage[index] = hash end return { + shared = shared and true or nil, format = "pair", coverage = coverage, } @@ -1520,6 +1644,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly classdef1 = readclassdef(f,tableoffset+classdef1,coverage) classdef2 = readclassdef(f,tableoffset+classdef2,nofglyphs) local usedcoverage = { } + local shared = { } -- partial sparse, when set also needs to be handled in the packer for g1, c1 in next, classdef1 do if coverage[g1] then local l1 = classlist[c1] @@ -1531,9 +1656,17 @@ 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 or nil } - else - -- upto the next lookup for this combination + local s1 = shared[first] + if s1 == nil then + s1 = { } + shared[first] = s1 + end + local s2 = s1[second] + if s2 == nil then + s2 = { first, second or nil } + s1[second] = s2 + end + hash[paired] = s2 end end end @@ -1542,6 +1675,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly end end return { + shared = shared and true or nil, format = "pair", coverage = usedcoverage, } @@ -3502,14 +3636,15 @@ function readers.avar(f,fontdata,specification) local lastfrom = false local lastto = false for i=1,nofvalues do - local f, t = read2dot14(f), read2dot14(f) - if lastfrom and f <= lastfrom then + local from = read2dot14(f) + local to = read2dot14(f) + if lastfrom and from <= lastfrom then -- ignore - elseif lastto and t >= lastto then + elseif lastto and to >= lastto then -- ignore else - values[#values+1] = { f, t } - lastfrom, lastto = f, t + values[#values+1] = { from, to } + lastfrom, lastto = from, to end end nofvalues = #values 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 7dd53885876..d931b822e55 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-map.lua @@ -523,7 +523,8 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) glyph.unicode = unicode end else - local t, n = { }, 0 + local t = { } + local n = 0 for l=1,nsplit do local base = split[l] local u = unicodes[base] or unicodevector[base] or contextvector[name] 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 48bf117feb8..5387516b4d5 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-one.lua @@ -86,14 +86,16 @@ 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 and attr.size or 0, attr and attr.modification or 0 + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 -- local pfbfile = file.replacesuffix(name,"pfb") local pfbname = resolvers.findfile(pfbfile,"pfb") or "" if pfbname == "" then pfbname = resolvers.findfile(file.basename(pfbfile),"pfb") or "" end - local pfbsize, pfbtime = 0, 0 + local pfbsize = 0 + local pfbtime = 0 if pfbname ~= "" then local attr = lfs.attributes(pfbname) pfbsize = attr.size or 0 @@ -324,7 +326,8 @@ local addthem = function(rawdata,ligatures) local one = descriptions[unicodes[ligname]] if one then for _, pair in next, ligdata do - local two, three = unicodes[pair[1]], unicodes[pair[2]] + local two = unicodes[pair[1]] + local three = unicodes[pair[2]] if two and three then local ol = one.ligatures if ol then @@ -392,7 +395,7 @@ local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust h if what then for complex, simple in next, what do complex = unicodes[complex] - simple = unicodes[simple] + simple = unicodes[simple] if complex and simple then local complexdescription = descriptions[complex] if complexdescription then -- optional @@ -445,7 +448,8 @@ local function adddimensions(data) -- we need to normalize afm to otf i.e. index for unicode, description in next, data.descriptions do local bb = description.boundingbox if bb then - local ht, dp = bb[4], -bb[2] + local ht = bb[4] + local dp = -bb[2] if ht == 0 or ht < 0 then -- no need to set it and no negative heights, nil == 0 else @@ -479,8 +483,9 @@ local function copytotfm(data) local filename = constructors.checkedfilename(resources) local fontname = metadata.fontname or metadata.fullname local fullname = metadata.fullname or metadata.fontname - local endash = 0x0020 -- space + local endash = 0x2013 local emdash = 0x2014 + local space = 0x0020 -- space local spacer = "space" local spaceunits = 500 -- @@ -492,28 +497,33 @@ local function copytotfm(data) parameters.italicangle = italicangle parameters.charwidth = charwidth parameters.charxheight = charxheight - -- same as otf + -- nearly the same as otf, catches + local d_endash = descriptions[endash] + local d_emdash = descriptions[emdash] + local d_space = descriptions[space] + if not d_space or d_space == 0 then + d_space = d_endash + end + if d_space then + spaceunits, spacer = d_space.width or 0, "space" + end if properties.monospaced then - if descriptions[endash] then - spaceunits, spacer = descriptions[endash].width, "space" - end - if not spaceunits and descriptions[emdash] then - spaceunits, spacer = descriptions[emdash].width, "emdash" - end - if not spaceunits and charwidth then - spaceunits, spacer = charwidth, "charwidth" + if spaceunits == 0 and d_emdash then + spaceunits, spacer = d_emdash.width or 0, "emdash" end else - if descriptions[endash] then - spaceunits, spacer = descriptions[endash].width, "space" - end - if not spaceunits and charwidth then - spaceunits, spacer = charwidth, "charwidth" + if spaceunits == 0 and d_endash then + spaceunits, spacer = d_emdash.width or 0, "endash" end end - spaceunits = tonumber(spaceunits) - if spaceunits < 200 then - -- todo: warning + if spaceunits == 0 and charwidth then + spaceunits, spacer = charwidth or 0, "charwidth" + end + if spaceunits == 0 then + spaceunits = tonumber(spaceunits) or 500 + end + if spaceunits == 0 then + spaceunits = 500 end -- parameters.slant = 0 @@ -757,7 +767,7 @@ local function check_afm(specification,fullname) if foundname == "" then foundname = fonts.names.getfilename(fullname,"afm") or "" end - if foundname == "" and afm.autoprefixed then + if fullname and foundname == "" and afm.autoprefixed then local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.* if encoding and shortname and fonts.encodings.known[encoding] then shortname = findbinfile(shortname,'afm') or "" -- just to be sure 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 32d791b48e9..91cf1522c4c 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-osd.lua @@ -114,7 +114,7 @@ local setchar = nuts.setchar local getprop = nuts.getprop local setprop = nuts.setprop -local ischar = nuts.is_char +local ischar = nuts.ischar local insert_node_after = nuts.insert_after local copy_node = nuts.copy @@ -615,6 +615,8 @@ local function initializedevanagi(tfmdata) end end -- + -- needs checking: this might be needed per instance ? + -- if script == "deva" then sharedfeatures["dv04"] = true -- dv04_remove_joiners elseif script == "dev2" then @@ -689,7 +691,7 @@ local function initialize_one(font,attr) -- we need a proper hook into the datas if not devanagaridata then - devanagaridata = { + devanagaridata = { reph = false, vattu = false, blwfcache = { }, @@ -1329,7 +1331,7 @@ end function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) local stop = getnext(start) - local font = getfont(start) + local font = getfont(start) -- hm local last = start while stop do local char = ischar(stop,font) 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 a0bf616e78c..3d217b3f4d0 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ota.lua @@ -39,7 +39,7 @@ local getprop = nuts.getprop local setprop = nuts.setprop local getsubtype = nuts.getsubtype local getchar = nuts.getchar -local ischar = nuts.is_char +local ischar = nuts.ischar local end_of_math = nuts.end_of_math @@ -302,9 +302,9 @@ if not classifiers then end function methods.arab(head,font,attr) - local first, last = nil, nil - local c_first, c_last = nil, nil - local current, done = head, false + local first, last, c_first, c_last + local current = head + local done = false current = tonut(current) while current do local char, id = ischar(current,font) 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 595778e34d1..a774a81c2c9 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otc.lua @@ -278,7 +278,8 @@ local function addfeature(data,feature,specifications) if not nocheck and not description then skip = skip + 1 elseif type(replacement) == "table" then - local r, n = { }, 0 + local r = { } + local n = 0 for i=1,#replacement do local u = tounicode(replacement[i]) if nocheck or descriptions[u] then 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 df9756f4e92..b8be2ec7565 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otj.lua @@ -90,7 +90,7 @@ local getboth = nuts.getboth local getdisc = nuts.getdisc local setdisc = nuts.setdisc local setoffsets = nuts.setoffsets -local ischar = nuts.is_char +local ischar = nuts.ischar local getkern = nuts.getkern local setkern = nuts.setkern local setlink = nuts.setlink @@ -456,7 +456,8 @@ function injections.setmove(current,factor,rlmode,x,injection) 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]) + local dx = factor*(ba[1]-ma[1]) + local dy = factor*(ba[2]-ma[2]) nofregisteredmarks = nofregisteredmarks + 1 if rlmode >= 0 then dx = tfmbase.width - dx -- see later commented ox 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 df83dc96825..bba7bcb64a4 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otl.lua @@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading") local fonts = fonts local otf = fonts.handlers.otf -otf.version = 3.107 -- beware: also sync font-mis.lua and in mtx-fonts +otf.version = 3.108 -- 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.pngcache = containers.define("fonts", "png", otf.version, true) @@ -495,7 +495,6 @@ local function copytotfm(data,cache_id) properties.space = spacer properties.encodingbytes = 2 properties.format = data.format or formats.otf - properties.noglyphnames = true properties.filename = filename properties.fontname = fontname properties.fullname = fullname 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 c32a7af25a9..6f6d89d434a 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oto.lua @@ -49,7 +49,9 @@ local function gref(descriptions,n) return f_unicode(n) end elseif n then - local num, nam, j = { }, { }, 0 + local num = { } + local nam = { } + local j = 0 for i=1,#n do local ni = n[i] if tonumber(ni) then -- first is likely a key @@ -121,8 +123,8 @@ local basehash, basehashes, applied = { }, 1, { } local function registerbasehash(tfmdata) local properties = tfmdata.properties - local hash = concat(applied," ") - local base = basehash[hash] + local hash = concat(applied," ") + local base = basehash[hash] if not base then basehashes = basehashes + 1 base = basehashes @@ -310,13 +312,16 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,nofligatures do local ligature = ligatures[i] - local unicode, tree = ligature[1], ligature[2] + local unicode = ligature[1] + local tree = ligature[2] make_1(present,tree,"ctx_"..unicode) end for i=1,nofligatures do - local ligature = ligatures[i] - local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3] + local ligature = ligatures[i] + local unicode = ligature[1] + local tree = ligature[2] + local lookupname = ligature[3] make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) end 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 c7ff6b72689..4ac73769720 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-otr.lua @@ -74,7 +74,6 @@ 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.nospaces @@ -2074,9 +2073,7 @@ 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 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 4d011a93471..24a8688875f 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ots.lua @@ -185,8 +185,6 @@ local setprev = nuts.setprev local getboth = nuts.getboth local setboth = nuts.setboth local getid = nuts.getid -local getattr = nuts.getattr -local setattr = nuts.setattr local getprop = nuts.getprop local setprop = nuts.setprop local getsubtype = nuts.getsubtype @@ -199,8 +197,11 @@ 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 getwidth = nuts.getwidth +local getattr = nuts.getattr + +local getglyphdata = nuts.getglyphdata -local ischar = nuts.is_char +local ischar = nuts.ischar local isglyph = nuts.isglyph local usesfont = nuts.uses_font @@ -829,7 +830,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip end end if not match and not pre or not replace then - local n = getnext(discfound) + local n = getnext(discfound) local char = ischar(n,currentfont) if char and ligature[char] then match = true @@ -841,8 +842,8 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev = getprev(start) if stop then setnext(stop) - local tail = getprev(stop) local copy = copy_node_list(start) + local tail = stop -- was: getprev(stop) -- Kai: needs checking on your samples local liat = find_node_tail(copy) if pre then setlink(liat,pre) @@ -939,7 +940,8 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end local format = step.format if format == "pair" then - local a, b = krn[1], krn[2] + local a = krn[1] + local b = krn[2] if a == true then -- zero elseif a then -- #a > 0 @@ -1559,7 +1561,8 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm end local format = currentlookup.format if format == "pair" then - local a, b = krn[1], krn[2] + local a = krn[1] + local b = krn[2] if a == true then -- zero elseif a then @@ -3192,7 +3195,7 @@ local function testrun(disc,t_run,c_run,...) local d = d_replace > d_post and d_replace or d_post local head = getnext(disc) -- is: next local tail = head - for i=2,d do -- must start at 2 according to Kai + for i=2,d do -- must start at 2 according to Kai local nx = getnext(tail) local id = getid(nx) if id == disc_code then @@ -3289,7 +3292,7 @@ end -- discretionaries (maybe we need to tag those some day). So, at least for now, we don't -- have the following test in the sub runs: -- --- -- local a = getattr(start,0) +-- -- local a = getglyhpdata(start) -- -- if a then -- -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) -- -- else @@ -3299,7 +3302,7 @@ end -- -- but use this instead: -- --- -- local a = getattr(start,0) +-- -- local a = getglyphdata(start) -- -- if not a or (a == attr) then -- -- and even that one is probably not needed. However, we can handle interesting @@ -3325,7 +3328,7 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm if char then local a -- happens often so no assignment is faster if attr then - a = getattr(start,0) + a = getglyphdata(start) end if not a or (a == attr) then local lookupmatch = lookupcache[char] @@ -3365,7 +3368,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) if char then local a -- happens often so no assignment is faster if attr then - a = getattr(start,0) + a = getglyphdata(start) end local startnext = getnext(start) if not a or (a == attr) then @@ -3449,7 +3452,7 @@ end 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) + a = getglyphdata(sub) end if not a or (a == attr) then for n in nextnode, sub do -- only gpos @@ -3485,7 +3488,7 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm if char then local a -- happens often so no assignment is faster if attr then - a = getattr(start,0) + a = getglyphdata(start) end if not a or (a == attr) then for i=1,nofsteps do @@ -3533,7 +3536,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) if char then local a -- happens often so no assignment is faster if attr then - a = getattr(start,0) + a = getglyphdata(start) end local startnext = getnext(start) if not a or (a == attr) then @@ -3614,7 +3617,7 @@ end 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) + a = getglyphdata(sub) end if not a or (a == attr) then for n in nextnode, sub do -- only gpos @@ -3707,7 +3710,7 @@ do -- reference: -- - -- local a = attr and getattr(start,0) + -- local a = attr and getglyphdata(start) -- if a then -- a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) -- else @@ -3718,7 +3721,7 @@ do -- -- 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 + -- if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then -- a = true -- end -- elseif not attribute or getprop(start,a_state) == attribute then @@ -3858,7 +3861,7 @@ do if m then local a -- happens often so no assignment is faster if attr then - a = getattr(start,0) + a = getglyphdata(start) end if not a or (a == attr) then for i=m[1],m[2] do @@ -3905,7 +3908,7 @@ do if lookupmatch 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 + if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then a = true end elseif not attribute or getprop(start,a_state) == attribute then @@ -3972,7 +3975,7 @@ do 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 + if getglyphdata(start) == attr and (not attribute or getprop(start,a_state) == attribute) then a = true end elseif not attribute or getprop(start,a_state) == attribute then 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 e7f483642e5..51b1c248f87 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-oup.lua @@ -1466,7 +1466,9 @@ function readers.pack(data) end return false elseif nt >= threshold then - local one, two, rest = 0, 0, 0 + local one = 0 + local two = 0 + local rest = 0 if pass == 1 then for k,v in next, c do if v == 1 then @@ -1571,16 +1573,34 @@ function readers.pack(data) if kind == "gpos_pair" then local c = step.coverage if c then - if step.format == "pair" then + if step.format ~= "pair" then + for g1, d1 in next, c do + c[g1] = pack_normal(d1) + end + elseif step.shared then + -- This branch results from classes. We already share at the reader end. Maybe + -- the sharing should be moved there altogether but it becomes kind of messy + -- then. Here we're still wasting time because in the second pass we serialize + -- and hash. So we compromise. We could merge the two passes ... + local shared = { } for g1, d1 in next, c do 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 + if not shared[d2] then + 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 + shared[d2] = true + end end end + if pass == 2 then + step.shared = nil -- weird, so dups + end else 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 end end 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 58e999e260d..d2fe0917c53 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-ttf.lua @@ -319,7 +319,8 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox 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 px = 0 + local py = 0 local first = 1 for i=1,nofcontours do local last = contours[i] @@ -347,15 +348,20 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox end control_pt = first_pt end - local x, y = first_pt[1], first_pt[2] + local x = first_pt[1] + local y = first_pt[2] if not done then - xmin, ymin, xmax, ymax = x, y, x, y + xmin = x + ymin = y + xmax = x + ymax = y done = true end nofsegments = nofsegments + 1 segments[nofsegments] = { x, y, "m" } -- "moveto" if not quadratic then - px, py = x, y + px = x + py = y end local previous_pt = first_pt for i=first,last do @@ -375,8 +381,10 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox 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] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = current_pt[2] nofsegments = nofsegments + 1 if quadratic then segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" @@ -386,8 +394,10 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox 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] + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = control_pt[2] nofsegments = nofsegments + 1 if quadratic then segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" @@ -403,14 +413,17 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox -- we're already done, probably a simple curve else nofsegments = nofsegments + 1 - local x2, y2 = first_pt[1], first_pt[2] + local x2 = first_pt[1] + local y2 = 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] + local x1 = control_pt[1] + local y1 = control_pt[2] segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" else - local x1, y1 = control_pt[1], control_pt[2] + local x1 = control_pt[1] + local y1 = 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 @@ -474,7 +487,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt = first_pt end - local x, y = first_pt[1], first_pt[2] + local x = first_pt[1] + local y = first_pt[2] if not done then xmin, ymin, xmax, ymax = x, y, x, y done = true @@ -487,7 +501,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments] = { x, y, "m" } -- "moveto" end if not quadratic then - px, py = x, y + px = x + py = y end local previous_pt = first_pt for i=first,last do @@ -497,7 +512,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) if previous_on then if current_on then -- both normal points - local x, y = current_pt[1], current_pt[2] + local x = current_pt[1] + local y = 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 @@ -505,14 +521,17 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments] = { x, y, "l" } -- "lineto" end if not quadratic then - px, py = x, y + px = x + py = 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] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = 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 @@ -535,8 +554,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) 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] + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = 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 @@ -569,8 +590,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) 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] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = first_pt[1] + local y2 = 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 diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-tfm.lua index 6e4f8698052..0b6e09a8f95 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-tfm.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-fonts-tfm.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['font-tfm'] = { +if not modules then modules = { } end modules ['luatex-fonts-tfm'] = { version = 1.001, comment = "companion to font-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['font-tfm'] = { license = "see context related readme files" } +-- This is the generic tfm/vf loader. There are no fundamental differences with +-- the one used in ConTeXt but we save some byte(codes) this way. + local next, type = next, type local match, format = string.match, string.format local concat, sortedhash = table.concat, table.sortedhash @@ -48,30 +51,6 @@ constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua fonts.formats.tfm = "type1" -- we need to have at least a value here fonts.formats.ofm = "type1" -- we need to have at least a value here ---[[ldx-- -<p>The next function encapsulates the standard <l n='tfm'/> loader as -supplied by <l n='luatex'/>.</p> ---ldx]]-- - --- this might change: not scaling and then apply features and do scaling in the --- usual way with dummy descriptions but on the other hand .. we no longer use --- tfm so why bother - --- ofm directive blocks local path search unless set; btw, in context we --- don't support ofm files anyway as this format is obsolete - --- we need to deal with nested virtual fonts, but because we load in the --- frontend we also need to make sure we don't nest too deep (esp when sizes --- get large) --- --- (VTITLE Example of a recursion) --- (MAPFONT D 0 (FONTNAME recurse)(FONTAT D 2)) --- (CHARACTER C A (CHARWD D 1)(CHARHT D 1)(MAP (SETRULE D 1 D 1))) --- (CHARACTER C B (CHARWD D 2)(CHARHT D 2)(MAP (SETCHAR C A))) --- (CHARACTER C C (CHARWD D 4)(CHARHT D 4)(MAP (SETCHAR C B))) --- --- we added the same checks as below to the luatex engine - function tfm.setfeatures(tfmdata,features) local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) if okay then @@ -83,301 +62,214 @@ end local depth = { } -- table.setmetatableindex("number") --- Normally we just load the tfm data and go on. However there was some demand for --- loading good old tfm /pfb files where afm files were lacking and even enc files --- of dubious quality so we now support loading such (often messy) setups too. --- --- Because such fonts also use (ugly) tweaks achieve some purpose (like swapping --- accents) we need to delay the unicoding actions till after the features have been --- applied. --- --- It must be noted that in ConTeXt we don't expect this to be used at all. Here is --- example: --- --- tfm metrics + pfb vector for index + pfb file for shapes --- --- \font\foo=file:csr10.tfm:reencode=auto;mode=node;liga=yes;kern=yes --- --- tfm metrics + pfb vector for index + enc file for tfm mapping + pfb file for shapes --- --- \font\foo=file:csr10.tfm:reencode=csr.enc;mode=node;liga=yes;kern=yes --- --- tfm metrics + enc file for mapping to tfm + bitmaps shapes --- --- \font\foo=file:csr10.tfm:reencode=csr.enc;bitmap=yes;mode=node;liga=yes;kern=yes --- --- One can add features: --- --- fonts.handlers.otf.addfeature { --- name = "czechdqcheat", --- type = "substitution", --- data = { --- quotedblright = "csquotedblright", --- }, --- } --- --- So "czechdqcheat=yes" is then a valid feature. And yes, it's a cheat. - -local read_from_tfm, check_tfm do - - local tfmreaders = context and tfm.readers - local loadtfmvf = tfmreaders and tfmreaders.loadtfmvf - local loadtfm = font.read_tfm - local loadvf = font.read_vf - - directives.register("fonts.tfm.builtin",function(v) - loadtfmvf = tfmreaders and tfmreaders.loadtfmvf - if v and loadtfm then - loadtfmvf = false - end - end) +local loadtfm = font.read_tfm +local loadvf = font.read_vf - read_from_tfm = function(specification) - local filename = specification.filename - local size = specification.size - depth[filename] = (depth[filename] or 0) + 1 - if trace_defining then - report_defining("loading tfm file %a at size %s",filename,size) - end - local tfmdata -- not cached, fast enough - if loadtfmvf then - tfmdata = loadtfmvf(filename,size) - else - tfmdata = loadtfm(filename,size) - end - if tfmdata then +local function read_from_tfm(specification) + local filename = specification.filename + local size = specification.size + depth[filename] = (depth[filename] or 0) + 1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata = loadtfm(filename,size) + if tfmdata then - local features = specification.features and specification.features.normal or { } - local features = constructors.checkedfeatures("tfm",features) - specification.features.normal = features + local features = specification.features and specification.features.normal or { } + local features = constructors.checkedfeatures("tfm",features) + specification.features.normal = features - -- If reencode returns a new table, we assume that we're doing something - -- special. An 'auto' reencode picks up its vector from the pfb file. + -- If reencode returns a new table, we assume that we're doing something + -- special. An 'auto' reencode picks up its vector from the pfb file. - local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata = newtfmdata - end + local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata = newtfmdata + end - local resources = tfmdata.resources or { } - local properties = tfmdata.properties or { } - local parameters = tfmdata.parameters or { } - local shared = tfmdata.shared or { } + local resources = tfmdata.resources or { } + local properties = tfmdata.properties or { } + local parameters = tfmdata.parameters or { } + local shared = tfmdata.shared or { } + -- + shared.features = features + shared.resources = resources + -- + properties.name = tfmdata.name -- todo: fallback + properties.fontname = tfmdata.fontname -- todo: fallback + properties.psname = tfmdata.psname -- todo: fallback + properties.fullname = tfmdata.fullname -- todo: fallback + properties.filename = specification.filename -- todo: fallback + properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing + properties.usedbitmap = tfmdata.usedbitmap + -- + tfmdata.properties = properties + tfmdata.resources = resources + tfmdata.parameters = parameters + tfmdata.shared = shared + -- + shared.rawdata = { resources = resources } + shared.features = features + -- + -- The next branch is only entered when we have a proper encoded file i.e. + -- unicodes and such. It really nakes no sense to do feature juggling when + -- we have no names and unicodes. + -- + if newtfmdata then + -- + -- Some opentype processing assumes these to be present: + -- + if not resources.marks then + resources.marks = { } + end + if not resources.sequences then + resources.sequences = { } + end + if not resources.features then + resources.features = { + gsub = { }, + gpos = { }, + } + end + if not tfmdata.changed then + tfmdata.changed = { } + end + if not tfmdata.descriptions then + tfmdata.descriptions = tfmdata.characters + end -- - shared.features = features - shared.resources = resources + -- It might be handy to have this: -- - properties.name = tfmdata.name -- todo: fallback - properties.fontname = tfmdata.fontname -- todo: fallback - properties.psname = tfmdata.psname -- todo: fallback - properties.fullname = tfmdata.fullname -- todo: fallback - properties.filename = specification.filename -- todo: fallback - properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing - properties.usedbitmap = tfmdata.usedbitmap + otf.readers.addunicodetable(tfmdata) -- - tfmdata.properties = properties - tfmdata.resources = resources - tfmdata.parameters = parameters - tfmdata.shared = shared + -- We make a pseudo opentype font, e.g. kerns and ligatures etc: -- - shared.rawdata = { resources = resources } - shared.features = features + tfmenhancers.apply(tfmdata,filename) -- - -- The next branch is only entered when we have a proper encoded file i.e. - -- unicodes and such. It really nakes no sense to do feature juggling when - -- we have no names and unicodes. + -- Now user stuff can kick in. -- - if newtfmdata then - -- - -- Some opentype processing assumes these to be present: - -- - if not resources.marks then - resources.marks = { } - end - if not resources.sequences then - resources.sequences = { } - end - if not resources.features then - resources.features = { - gsub = { }, - gpos = { }, - } - end - if not tfmdata.changed then - tfmdata.changed = { } - end - if not tfmdata.descriptions then - tfmdata.descriptions = tfmdata.characters - end - -- - -- It might be handy to have this: - -- - otf.readers.addunicodetable(tfmdata) - -- - -- We make a pseudo opentype font, e.g. kerns and ligatures etc: - -- - tfmenhancers.apply(tfmdata,filename) - -- - -- Now user stuff can kick in. - -- - constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) - -- - -- As that can also mess with names and such, we are now ready for finalizing - -- the unicode information. This is a different order that for instance type one - -- (afm) files. First we try to deduce unicodes from already present information. - -- - otf.readers.unifymissing(tfmdata) - -- - -- Next we fill in the gaps, based on names from teh agl. Probably not much will - -- happen here. - -- - fonts.mappings.addtounicode(tfmdata,filename) - -- - -- The tounicode data is passed to the backend that constructs the vectors for us. - -- - tfmdata.tounicode = 1 - local tounicode = fonts.mappings.tounicode - for unicode, v in next, tfmdata.characters do - local u = v.unicode - if u then - v.tounicode = tounicode(u) - end - end - -- - -- However, when we use a bitmap font those vectors can't be constructed because - -- that information is not carried with those fonts (there is no name info, nor - -- proper index info, nor unicodes at that end). So, we provide it ourselves. - -- - if tfmdata.usedbitmap then - tfm.addtounicode(tfmdata) + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + -- + -- As that can also mess with names and such, we are now ready for finalizing + -- the unicode information. This is a different order that for instance type one + -- (afm) files. First we try to deduce unicodes from already present information. + -- + otf.readers.unifymissing(tfmdata) + -- + -- Next we fill in the gaps, based on names from teh agl. Probably not much will + -- happen here. + -- + fonts.mappings.addtounicode(tfmdata,filename) + -- + -- The tounicode data is passed to the backend that constructs the vectors for us. + -- + tfmdata.tounicode = 1 + local tounicode = fonts.mappings.tounicode + for unicode, v in next, tfmdata.characters do + local u = v.unicode + if u then + v.tounicode = tounicode(u) end end -- - shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil + -- However, when we use a bitmap font those vectors can't be constructed because + -- that information is not carried with those fonts (there is no name info, nor + -- proper index info, nor unicodes at that end). So, we provide it ourselves. -- - if size < 0 then - size = idiv(65536 * -size,100) + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) end - parameters.factor = 1 -- already scaled - parameters.units = 1000 -- just in case - parameters.size = size - parameters.slant = parameters.slant or parameters[1] or 0 - parameters.space = parameters.space or parameters[2] or 0 - parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 - parameters.space_shrink = parameters.space_shrink or parameters[4] or 0 - parameters.x_height = parameters.x_height or parameters[5] or 0 - parameters.quad = parameters.quad or parameters[6] or 0 - parameters.extra_space = parameters.extra_space or parameters[7] or 0 - -- - constructors.enhanceparameters(parameters) -- official copies for us + end + -- + shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil + -- + if size < 0 then + size = idiv(65536 * -size,100) + end + parameters.factor = 1 -- already scaled + parameters.units = 1000 -- just in case + parameters.size = size + parameters.slant = parameters.slant or parameters[1] or 0 + parameters.space = parameters.space or parameters[2] or 0 + parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink = parameters.space_shrink or parameters[4] or 0 + parameters.x_height = parameters.x_height or parameters[5] or 0 + parameters.quad = parameters.quad or parameters[6] or 0 + parameters.extra_space = parameters.extra_space or parameters[7] or 0 + -- + constructors.enhanceparameters(parameters) -- official copies for us + -- + properties.private = properties.private or tfmdata.private or privateoffset + -- + if newtfmdata then -- - properties.private = properties.private or tfmdata.private or privateoffset + -- We do nothing as we assume flat tfm files. It would become real messy + -- otherwise and I don't have something for testing on my system anyway. -- - if newtfmdata then - -- - -- We do nothing as we assume flat tfm files. It would become real messy - -- otherwise and I don't have something for testing on my system anyway. - -- - elseif loadtfmvf then - -- already loaded - local fonts = tfmdata.fonts - if fonts then - for i=1,#fonts do - local font = fonts[i] - local id = font.id - if not id then - local name = font.name - local size = font.size - if name and size then - local data, id = constructors.readanddefine(name,size) - if id then - font.id = id - font.name = nil - font.size = nil - end - end - end + elseif constructors.resolvevirtualtoo then + fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here + local vfname = findbinfile(specification.name, 'ovf') + if vfname and vfname ~= "" then + local vfdata = loadvf(vfname,size) + if vfdata then + local chars = tfmdata.characters + for k,v in next, vfdata.characters do + chars[k].commands = v.commands end - end - elseif constructors.resolvevirtualtoo then - fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here - local vfname = findbinfile(specification.name, 'ovf') - if vfname and vfname ~= "" then - local vfdata = loadvf(vfname,size) - if vfdata then - local chars = tfmdata.characters - for k,v in next, vfdata.characters do - chars[k].commands = v.commands - end - properties.virtualized = true - tfmdata.fonts = vfdata.fonts - tfmdata.type = "virtual" -- else nested calls with cummulative scaling - local fontlist = vfdata.fonts - local name = file.nameonly(filename) - for i=1,#fontlist do - local n = fontlist[i].name - local s = fontlist[i].size - local d = depth[filename] - s = constructors.scaled(s,vfdata.designsize) - if d > tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i] = { id = 0 } - elseif (d > 1) and (s > tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i] = { id = 0 } - else - local t, id = constructors.readanddefine(n,s) - fontlist[i] = { id = id } - end + properties.virtualized = true + tfmdata.fonts = vfdata.fonts + tfmdata.type = "virtual" -- else nested calls with cummulative scaling + local fontlist = vfdata.fonts + local name = file.nameonly(filename) + for i=1,#fontlist do + local n = fontlist[i].name + local s = fontlist[i].size + local d = depth[filename] + s = constructors.scaled(s,vfdata.designsize) + if d > tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i] = { id = 0 } + elseif (d > 1) and (s > tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i] = { id = 0 } + else + local t, id = constructors.readanddefine(n,s) + fontlist[i] = { id = id } end end end end - -- - -- This is for old times sake (and context specific) so we comment it. It has - -- to do with encoding prefixes (a context naming that was later adopted by - -- the lm/gyre project) - -- - -- if not features.encoding then - -- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") - -- if filename and encoding and encodings.known and encodings.known[encoding] then - -- features.encoding = encoding - -- end - -- end - -- - -- Some afterthoughts: - -- - properties.haskerns = true - properties.hasligatures = true - properties.hasitalics = true - resources.unicodes = { } - resources.lookuptags = { } - -- - depth[filename] = depth[filename] - 1 - -- - return tfmdata - else - depth[filename] = depth[filename] - 1 end + -- + properties.haskerns = true + properties.hasligatures = true + properties.hasitalics = true + resources.unicodes = { } + resources.lookuptags = { } + -- + depth[filename] = depth[filename] - 1 + -- + return tfmdata + else + depth[filename] = depth[filename] - 1 end +end - check_tfm = function(specification,fullname) -- we could split up like afm/otf - local foundname = findbinfile(fullname, 'tfm') or "" - if foundname == "" then - foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context - end - if foundname == "" then - foundname = fonts.names.getfilename(fullname,"tfm") or "" - end - if foundname ~= "" then - specification.filename = foundname - specification.format = "ofm" - return read_from_tfm(specification) - elseif trace_defining then - report_defining("loading tfm with name %a fails",specification.name) - end +local function check_tfm(specification,fullname) -- we could split up like afm/otf + local foundname = findbinfile(fullname, 'tfm') or "" + if foundname == "" then + foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context + end + if foundname == "" then + foundname = fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) end - end readers.check_tfm = check_tfm 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 46b6847d331..1b039a43866 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-file.lua @@ -73,13 +73,9 @@ local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg -- better this way: ------ tricky = S("/\\") * P(-1) local attributes = lfs.attributes function lfs.isdir(name) - -- if not lpegmatch(tricky,name) then - -- name = name .. "/." - -- end return attributes(name,"mode") == "directory" end @@ -336,43 +332,52 @@ end -- But after some testing Taco and I came up with the more robust -- variant: -function file.is_writable(name) - if not name then - -- error - elseif lfs.isdir(name) then - name = name .. "/m_t_x_t_e_s_t.tmp" - local f = io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f = io.open(name,"ab") - if f then - f:close() - return true - end - else - local f = io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true +if lfs.isreadablefile and lfs.iswritablefile then + + file.is_readable = lfs.isreadablefile + file.is_writable = lfs.iswritablefile + +else + + function file.is_writable(name) + if not name then + -- error + elseif lfs.isdir(name) then + name = name .. "/m_t_x_t_e_s_t.tmp" + local f = io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true + end + elseif lfs.isfile(name) then + local f = io.open(name,"ab") + if f then + f:close() + return true + end + else + local f = io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end end + return false end - return false -end -local readable = P("r") * Cc(true) + local readable = P("r") * Cc(true) -function file.is_readable(name) - if name then - local a = attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false + function file.is_readable(name) + if name then + local a = attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end + end file.isreadable = file.is_readable -- depricated 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 ddd499022fa..5570e83dc8d 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-lua.lua @@ -228,10 +228,10 @@ 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 +-- 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: @@ -248,3 +248,8 @@ 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 + +if LUAVERSION > 5.3 then + -- collectgarbage("collect") + -- collectgarbage("generational") -- crashes on unix +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 eae13513990..192347b0619 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-l-table.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['l-table'] = { 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 concat, sort = table.concat, table.sort local format, lower, dump = string.format, string.lower, string.dump local getmetatable, setmetatable = getmetatable, setmetatable local lpegmatch, patterns = lpeg.match, lpeg.patterns @@ -26,7 +26,8 @@ function table.getn(t) end function table.strip(tab) - local lst, l = { }, 0 + local lst = { } + local l = 0 for i=1,#tab do local s = lpegmatch(stripper,tab[i]) or "" if s == "" then @@ -41,7 +42,8 @@ end function table.keys(t) if t then - local keys, k = { }, 0 + local keys = { } + local k = 0 for key in next, t do k = k + 1 keys[k] = key @@ -145,28 +147,30 @@ end local function sortedkeys(tab) if tab then - local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed + local srt = { } + local category = 0 -- 0=unknown 1=string, 2=number 3=mixed + local s = 0 for key in next, tab do s = s + 1 srt[s] = key - if category == 3 then - -- no further check - elseif category == 1 then - if type(key) ~= "string" then - category = 3 - end - elseif category == 2 then - if type(key) ~= "number" then - category = 3 - end - else + if category ~= 3 then local tkey = type(key) - if tkey == "string" then - category = 1 - elseif tkey == "number" then - category = 2 + if category == 1 then + if tkey ~= "string" then + category = 3 + end + elseif category == 2 then + if tkey ~= "number" then + category = 3 + end else - category = 3 + if tkey == "string" then + category = 1 + elseif tkey == "number" then + category = 2 + else + category = 3 + end end end end @@ -185,7 +189,8 @@ end local function sortedhashonly(tab) if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if type(key) == "string" then s = s + 1 @@ -203,7 +208,8 @@ end local function sortedindexonly(tab) if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if type(key) == "number" then s = s + 1 @@ -221,7 +227,8 @@ end local function sortedhashkeys(tab,cmp) -- fast one if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if key then s= s + 1 @@ -317,7 +324,9 @@ end -- end function table.merge(t, ...) -- first one is target - t = t or { } + if not t then + t = { } + end for i=1,select("#",...) do for k, v in next, (select(i,...)) do t[k] = v @@ -383,7 +392,8 @@ end -- end function table.imerged(...) - local tmp, ntmp = { }, 0 + local tmp = { } + local ntmp = 0 for i=1,select("#",...) do local nst = select(i,...) for j=1,#nst do @@ -420,7 +430,9 @@ end -- todo : copy without metatable local function copy(t,tables) -- taken from lua wiki, slightly adapted - tables = tables or { } + if not tables then + tables = { } + end local tcopy = { } if not tables[t] then tables[t] = tcopy @@ -471,7 +483,8 @@ function table.tohash(t,value) end function table.fromhash(t) - local hsh, h = { }, 0 + local hsh = { } + local h = 0 for k, v in next, t do if v then h = h + 1 @@ -669,7 +682,8 @@ local function do_serialize(root,name,depth,level,indexed) end -- we could check for k (index) being number (cardinal) if root and next(root) ~= nil then - local first, last = nil, 0 + local first = nil + local last = 0 if compact then last = #root for k=1,last do @@ -960,7 +974,8 @@ end -- number : [number] = { } function table.serialize(root,name,specification) - local t, n = { }, 0 + local t = { } + local n = 0 local function flush(s) n = n + 1 t[n] = s @@ -984,13 +999,15 @@ function table.tofile(filename,root,name,specification) local f = io.open(filename,'w') if f then if maxtab > 1 then - local t, n = { }, 0 + local t = { } + local n = 0 local function flush(s) n = n + 1 t[n] = s if n > maxtab then f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice - t, n = { }, 0 -- we could recycle t if needed + t = { } -- we could recycle t if needed + n = 0 end end serialize(flush,root,name,specification) @@ -1008,12 +1025,12 @@ end local function flattened(t,f,depth) -- also handles { nil, 1, nil, 2 } if f == nil then - f = { } + f = { } depth = 0xFFFF elseif tonumber(f) then -- assume that only two arguments are given depth = f - f = { } + f = { } elseif not depth then depth = 0xFFFF end @@ -1101,8 +1118,12 @@ local function are_equal(a,b,n,m) -- indexed if a == b then return true elseif a and b and #a == #b then - n = n or 1 - m = m or #a + if not n then + n = 1 + end + if not m then + m = #a + end for i=n,m do local ai, bi = a[i], b[i] if ai==bi then @@ -1215,7 +1236,8 @@ end function table.reversed(t) if t then - local tt, tn = { }, #t + local tt = { } + local tn = #t if tn > 0 then local ttn = 0 for i=tn,1,-1 do @@ -1332,8 +1354,8 @@ end function table.unique(old) local hash = { } - local new = { } - local n = 0 + local new = { } + local n = 0 for i=1,#old do local oi = old[i] if not hash[oi] then @@ -1354,12 +1376,14 @@ end function table.values(t,s) -- optional sort flag if t then - local values, keys, v = { }, { }, 0 + local values = { } + local keys = { } + local v = 0 for key, value in next, t do if not keys[value] then v = v + 1 values[v] = value - keys[k] = key + keys[k] = key end end if s then diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-reference.lua index d470094fcf1..8a940cc22ba 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 : 02/14/19 16:57:24 +-- merge date : 05/18/19 10:42:24 do -- begin closure to overcome local limits and interference @@ -119,8 +119,7 @@ if not FFISUPPORTED then elseif not ffi.number then ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then end end -- closure @@ -1045,7 +1044,7 @@ if not modules then modules={} end modules ['l-table']={ } 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 concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable local lpegmatch,patterns=lpeg.match,lpeg.patterns @@ -1055,7 +1054,8 @@ function table.getn(t) return t and #t end function table.strip(tab) - local lst,l={},0 + local lst={} + local l=0 for i=1,#tab do local s=lpegmatch(stripper,tab[i]) or "" if s=="" then @@ -1068,7 +1068,8 @@ function table.strip(tab) end function table.keys(t) if t then - local keys,k={},0 + local keys={} + local k=0 for key in next,t do k=k+1 keys[k]=key @@ -1099,27 +1100,30 @@ local function compare(a,b) end local function sortedkeys(tab) if tab then - local srt,category,s={},0,0 + local srt={} + local category=0 + local s=0 for key in next,tab do s=s+1 srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else + if category~=3 then local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 + if category==1 then + if tkey~="string" then + category=3 + end + elseif category==2 then + if tkey~="number" then + category=3 + end else - category=3 + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 + else + category=3 + end end end end @@ -1136,7 +1140,8 @@ local function sortedkeys(tab) end local function sortedhashonly(tab) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if type(key)=="string" then s=s+1 @@ -1153,7 +1158,8 @@ local function sortedhashonly(tab) end local function sortedindexonly(tab) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if type(key)=="number" then s=s+1 @@ -1170,7 +1176,8 @@ local function sortedindexonly(tab) end local function sortedhashkeys(tab,cmp) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if key then s=s+1 @@ -1246,7 +1253,9 @@ function table.prepend(t,list) return t end function table.merge(t,...) - t=t or {} + if not t then + t={} + end for i=1,select("#",...) do for k,v in next,(select(i,...)) do t[k]=v @@ -1275,7 +1284,8 @@ function table.imerge(t,...) return t end function table.imerged(...) - local tmp,ntmp={},0 + local tmp={} + local ntmp=0 for i=1,select("#",...) do local nst=select(i,...) for j=1,#nst do @@ -1307,7 +1317,9 @@ local function fastcopy(old,metatabletoo) end end local function copy(t,tables) - tables=tables or {} + if not tables then + tables={} + end local tcopy={} if not tables[t] then tables[t]=tcopy @@ -1354,7 +1366,8 @@ function table.tohash(t,value) return h end function table.fromhash(t) - local hsh,h={},0 + local hsh={} + local h=0 for k,v in next,t do if v then h=h+1 @@ -1455,7 +1468,8 @@ local function do_serialize(root,name,depth,level,indexed) end end if root and next(root)~=nil then - local first,last=nil,0 + local first=nil + local last=0 if compact then last=#root for k=1,last do @@ -1714,7 +1728,8 @@ local function serialize(_handle,root,name,specification) handle("}") end function table.serialize(root,name,specification) - local t,n={},0 + local t={} + local n=0 local function flush(s) n=n+1 t[n]=s @@ -1728,13 +1743,15 @@ function table.tofile(filename,root,name,specification) local f=io.open(filename,'w') if f then if maxtab>1 then - local t,n={},0 + local t={} + local n=0 local function flush(s) n=n+1 t[n]=s if n>maxtab then f:write(concat(t,"\n"),"\n") - t,n={},0 + t={} + n=0 end end serialize(flush,root,name,specification) @@ -1836,8 +1853,12 @@ local function are_equal(a,b,n,m) if a==b then return true elseif a and b and #a==#b then - n=n or 1 - m=m or #a + if not n then + n=1 + end + if not m then + m=#a + end for i=n,m do local ai,bi=a[i],b[i] if ai==bi then @@ -1937,7 +1958,8 @@ function table.mirrored(t) end function table.reversed(t) if t then - local tt,tn={},#t + local tt={} + local tn=#t if tn>0 then local ttn=0 for i=tn,1,-1 do @@ -2050,7 +2072,9 @@ function table.sorted(t,...) end function table.values(t,s) if t then - local values,keys,v={},{},0 + local values={} + local keys={} + local v=0 for key,value in next,t do if not keys[value] then v=v+1 @@ -2652,40 +2676,45 @@ local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) return str and lpegmatch(reslasher,str) end -function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true +if lfs.isreadablefile and lfs.iswritablefile then + file.is_readable=lfs.isreadablefile + file.is_writable=lfs.iswritablefile +else + function file.is_writable(name) + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true + end + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end end - end - return false -end -local readable=P("r")*Cc(true) -function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else return false end + local readable=P("r")*Cc(true) + function file.is_readable(name) + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end + end end file.isreadable=file.is_readable file.iswritable=file.is_writable @@ -3045,7 +3074,6 @@ local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,s local load,dump=load,string.dump 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,utflen=utf.char,utf.byte,utf.len @@ -3384,8 +3412,8 @@ local environment={ formattednumber=number.formatted, sparseexponent=number.sparseexponent, formattedfloat=number.formattedfloat, - stripzero=lpeg.patterns.stripzero, - stripzeros=lpeg.patterns.stripzeros, + stripzero=patterns.stripzero, + stripzeros=patterns.stripzeros, FORMAT=string.f9, } local arguments={ "a1" } @@ -3472,7 +3500,7 @@ local format_F=function(f) end local format_k=function(b,a) n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0) end local format_g=function(f) n=n+1 @@ -3828,9 +3856,9 @@ patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"" 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('"')) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) +add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape }) +add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape }) +add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 local cquote=Cc('"') @@ -3862,6 +3890,27 @@ local f_16_16=formatters["%0.5N"] function number.to16dot16(n) return f_16_16(n/65536.0) end +if not string.explode then + local tsplitat=lpeg.tsplitat + local p_utf=patterns.utf8character + local p_check=C(p_utf)*(P("+")*Cc(true))^0 + local p_split=Ct(C(p_utf)^0) + local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0) + function string.explode(str,symbol) + if symbol=="" then + return lpegmatch(p_split,str) + elseif symbol then + local a,b=lpegmatch(p_check,symbol) + if b then + return lpegmatch(tsplitat(P(a)^1),str) + else + return lpegmatch(tsplitat(a),str) + end + else + return lpegmatch(p_space,str) + end + end +end end -- closure @@ -4074,6 +4123,32 @@ if bit32 then local b=char(n%256) f:write(b,a) end + function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) + end + function files.writecardinal2le(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + f:write(a,b) + end + function files.writecardinal4le(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(a,b,c,d) + end else local floor=math.floor function files.writecardinal2(f,n) @@ -4082,16 +4157,32 @@ else local b=char(n%256) f:write(b,a) end -end -function files.writecardinal4(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + function files.writecardinal4(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + n=floor(n/256) + local c=char(n%256) + n=floor(n/256) + local d=char(n%256) + f:write(d,c,b,a) + end + function files.writecardinal2le(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(a,b) + end + function files.writecardinal4le(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + n=floor(n/256) + local c=char(n%256) + n=floor(n/256) + local d=char(n%256) + f:write(a,b,c,d) + end end function files.writestring(f,s) f:write(char(byte(s,1,#s))) @@ -4104,10 +4195,18 @@ if fio and fio.readcardinal1 then files.readcardinal2=fio.readcardinal2 files.readcardinal3=fio.readcardinal3 files.readcardinal4=fio.readcardinal4 + files.readcardinal1le=fio.readcardinal1le or files.readcardinal1le + files.readcardinal2le=fio.readcardinal2le or files.readcardinal2le + files.readcardinal3le=fio.readcardinal3le or files.readcardinal3le + files.readcardinal4le=fio.readcardinal4le or files.readcardinal4le files.readinteger1=fio.readinteger1 files.readinteger2=fio.readinteger2 files.readinteger3=fio.readinteger3 files.readinteger4=fio.readinteger4 + files.readinteger1le=fio.readinteger1le or files.readinteger1le + files.readinteger2le=fio.readinteger2le or files.readinteger2le + files.readinteger3le=fio.readinteger3le or files.readinteger3le + files.readinteger4le=fio.readinteger4le or files.readinteger4le files.readfixed2=fio.readfixed2 files.readfixed4=fio.readfixed4 files.read2dot14=fio.read2dot14 @@ -4128,6 +4227,24 @@ if fio and fio.readcardinal1 then skipposition(f,4*(n or 1)) end end +if fio and fio.writecardinal1 then + files.writecardinal1=fio.writecardinal1 + files.writecardinal2=fio.writecardinal2 + files.writecardinal3=fio.writecardinal3 + files.writecardinal4=fio.writecardinal4 + files.writecardinal1le=fio.writecardinal1le + files.writecardinal2le=fio.writecardinal2le + files.writecardinal3le=fio.writecardinal3le + files.writecardinal4le=fio.writecardinal4le + files.writeinteger1=fio.writeinteger1 or fio.writecardinal1 + files.writeinteger2=fio.writeinteger2 or fio.writecardinal2 + files.writeinteger3=fio.writeinteger3 or fio.writecardinal3 + files.writeinteger4=fio.writeinteger4 or fio.writecardinal4 + files.writeinteger1le=files.writeinteger1le or fio.writecardinal1le + files.writeinteger2le=files.writeinteger2le or fio.writecardinal2le + files.writeinteger3le=files.writeinteger3le or fio.writecardinal3le + files.writeinteger4le=files.writeinteger4le or fio.writecardinal4le +end if fio and fio.readcardinaltable then files.readcardinaltable=fio.readcardinaltable files.readintegertable=fio.readintegertable @@ -4712,67 +4829,8 @@ end nodes.nodecodes=nodecodes nodes.glyphcodes=glyphcodes nodes.disccodes=disccodes -local flush_node=node.flush_node -local remove_node=node.remove -local traverse_id=node.traverse_id nodes.handlers.protectglyphs=node.protect_glyphs -nodes.handlers.unprotectglyphs=node.unprotect_glyphs -function nodes.remove(head,current,free_too) - local t=current - head,current=remove_node(head,current) - if t then - if free_too then - flush_node(t) - t=nil - else - t.next,t.prev=nil,nil - end - end - return head,current,t -end -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end -local getfield=node.getfield -local setfield=node.setfield -nodes.getfield=getfield -nodes.setfield=setfield -nodes.getattr=getfield -nodes.setattr=setfield -nodes.tostring=node.tostring or tostring -nodes.copy=node.copy -nodes.copy_node=node.copy -nodes.copy_list=node.copy_list -nodes.delete=node.delete -nodes.dimensions=node.dimensions -nodes.end_of_math=node.end_of_math -nodes.flush_list=node.flush_list -nodes.flush_node=node.flush_node -nodes.flush=node.flush_node -nodes.free=node.free -nodes.insert_after=node.insert_after -nodes.insert_before=node.insert_before -nodes.hpack=node.hpack -nodes.new=node.new -nodes.tail=node.tail -nodes.traverse=node.traverse -nodes.traverse_id=node.traverse_id -nodes.slide=node.slide -nodes.vpack=node.vpack -nodes.first_glyph=node.first_glyph -nodes.has_glyph=node.has_glyph or node.first_glyph -nodes.current_attr=node.current_attr -nodes.has_field=node.has_field -nodes.last_node=node.last_node -nodes.usedlist=node.usedlist -nodes.protrusion_skippable=node.protrusion_skippable -nodes.write=node.write -nodes.has_attribute=node.has_attribute -nodes.set_attribute=node.set_attribute -nodes.unset_attribute=node.unset_attribute -nodes.protect_glyphs=node.protect_glyphs -nodes.unprotect_glyphs=node.unprotect_glyphs -nodes.mlist_to_hlist=node.mlist_to_hlist +nodes.handlers.unprotectglyphs=node.unprotect_glyphs local direct=node.direct local nuts={} nodes.nuts=nuts @@ -4802,7 +4860,6 @@ nuts.setattr=direct.setfield nuts.setboth=direct.setboth nuts.setchar=direct.setchar nuts.setcomponents=direct.setcomponents -nuts.setdir=direct.setdir nuts.setdirection=direct.setdirection nuts.setdisc=direct.setdisc nuts.setfield=setfield @@ -4815,8 +4872,8 @@ nuts.setprev=direct.setprev nuts.setsplit=direct.setsplit nuts.setsubtype=direct.setsubtype nuts.setwidth=direct.setwidth -nuts.is_char=direct.is_char -nuts.is_glyph=direct.is_glyph +nuts.getglyphdata=nuts.getattr +nuts.setglyphdata=nuts.setattr nuts.ischar=direct.is_char nuts.isglyph=direct.is_glyph nuts.copy=direct.copy @@ -4840,20 +4897,6 @@ nuts.traverse=direct.traverse nuts.traverse_char=direct.traverse_char nuts.traverse_glyph=direct.traverse_glyph nuts.traverse_id=direct.traverse_id -if not nuts.getdirection then - local getdir=direct.getdir - function nuts.getdirection(n) - local d=getdir(n) - if d=="TLT" then return 0 - elseif d=="TRT" then return 1 - elseif d=="+TLT" then return 0,false - elseif d=="+TRT" then return 1,false - elseif d=="-TLT" then return 0,true - elseif d=="-TRT" then return 1,true - else return 0 - end - end -end local propertydata=direct.get_properties_table() nodes.properties={ data=propertydata } if direct.set_properties_mode then @@ -8637,7 +8680,6 @@ function constructors.scale(tfmdata,specification) local hasitalics=properties.hasitalics local autoitalicamount=properties.autoitalicamount local stackmath=not properties.nostackmath - local nonames=properties.noglyphnames local haskerns=properties.haskerns or properties.mode=="base" local hasligatures=properties.hasligatures or properties.mode=="base" local realdimensions=properties.realdimensions @@ -8744,6 +8786,7 @@ function constructors.scale(tfmdata,specification) local width=description.width local height=description.height local depth=description.depth + local isunicode=description.unicode if realdimensions then if not height or height==0 then local bb=description.boundingbox @@ -8768,16 +8811,16 @@ function constructors.scale(tfmdata,specification) if height then height=vdelta*height else height=scaledheight end if depth and depth~=0 then depth=delta*depth - if nonames then + if isunicode then chr={ index=index, height=height, depth=depth, width=width, + unicode=isunicode, } else chr={ - name=description.name, index=index, height=height, depth=depth, @@ -8785,33 +8828,23 @@ function constructors.scale(tfmdata,specification) } end else - if nonames then + if isunicode then chr={ index=index, height=height, width=width, + unicode=isunicode, } else chr={ - name=description.name, index=index, height=height, width=width, } end end - local isunicode=description.unicode if addtounicode then - if isunicode then - chr.unicode=isunicode - chr.tounicode=tounicode(isunicode) - else - chr.tounicode=unknowncode - end - else - if isunicode then - chr.unicode=isunicode - end + chr.tounicode=isunicode and tounicode(isunicode) or unknowncode end if hasquality then local ve=character.expansion_factor @@ -8881,7 +8914,10 @@ function constructors.scale(tfmdata,specification) if stackmath then local mk=character.mathkerns if mk then - local tr,tl,br,bl=mk.topright,mk.topleft,mk.bottomright,mk.bottomleft + local tr=mk.topright + local tl=mk.topleft + local br=mk.bottomright + local bl=mk.bottomleft chr.mathkern={ top_right=tr and mathkerns(tr,vdelta) or nil, top_left=tl and mathkerns(tl,vdelta) or nil, @@ -9062,11 +9098,11 @@ function constructors.finalize(tfmdata) if not properties.virtualized then properties.virtualized=tfmdata.type=="virtual" end - properties.fontname=tfmdata.fontname - properties.filename=tfmdata.filename - properties.fullname=tfmdata.fullname - properties.name=tfmdata.name - properties.psname=tfmdata.psname + properties.fontname=properties.fontname or tfmdata.fontname + properties.filename=properties.filename or tfmdata.filename + properties.fullname=properties.fullname or tfmdata.fullname + properties.name=properties.name or tfmdata.name + properties.psname=properties.psname or tfmdata.psname properties.encodingbytes=tfmdata.encodingbytes or 1 properties.embedding=tfmdata.embedding or "subset" properties.tounicode=tfmdata.tounicode or 1 @@ -9167,7 +9203,9 @@ hashmethods.normal=function(list) end end function constructors.hashinstance(specification,force) - local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks + local hash=specification.hash + local size=specification.size + local fallbacks=specification.fallbacks if force or not hash then hash=constructors.hashfeatures(specification) specification.hash=hash @@ -9534,7 +9572,8 @@ function constructors.initializefeatures(what,tfmdata,features,trace,report) end end function constructors.collectprocessors(what,tfmdata,features,trace,report) - local processes,nofprocesses={},0 + local processes={} + local nofprocesses=0 if features and next(features) then local properties=tfmdata.properties local whathandler=handlers[what] @@ -10071,7 +10110,8 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) glyph.unicode=unicode end else - local t,n={},0 + local t={} + local n=0 for l=1,nsplit do local base=split[l] local u=unicodes[base] or unicodevector[base] or contextvector[name] @@ -10410,7 +10450,6 @@ local P,R,S,C,Cs,Cc,Ct,Carg,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg 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.nospaces @@ -14945,7 +14984,8 @@ end end end local function setbias(globals,locals) - local g,l=#globals,#locals + local g=#globals + local l=#locals return ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 @@ -15351,8 +15391,8 @@ function readers.cff(f,fontdata,specification) if private then local data=private.data if type(data)=="table" then - cffinfo.defaultwidth=data.defaultwidth or cffinfo.defaultwidth - cffinfo.nominalwidth=data.nominalwidth or cffinfo.nominalwidth + cffinfo.defaultwidth=data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth=data.nominalwidthx or cffinfo.nominalwidth cffinfo.bluevalues=data.bluevalues cffinfo.otherblues=data.otherblues cffinfo.familyblues=data.familyblues @@ -15681,7 +15721,8 @@ local function contours2outlines_normal(glyphs,shapes) local nofsegments=0 glyph.segments=segments if nofcontours>0 then - local px,py=0,0 + local px=0 + local py=0 local first=1 for i=1,nofcontours do local last=contours[i] @@ -15708,15 +15749,20 @@ local function contours2outlines_normal(glyphs,shapes) end control_pt=first_pt end - local x,y=first_pt[1],first_pt[2] + local x=first_pt[1] + local y=first_pt[2] if not done then - xmin,ymin,xmax,ymax=x,y,x,y + xmin=x + ymin=y + xmax=x + ymax=y done=true end nofsegments=nofsegments+1 segments[nofsegments]={ x,y,"m" } if not quadratic then - px,py=x,y + px=x + py=y end local previous_pt=first_pt for i=first,last do @@ -15735,8 +15781,10 @@ local function contours2outlines_normal(glyphs,shapes) 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] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=current_pt[2] nofsegments=nofsegments+1 if quadratic then segments[nofsegments]={ x1,y1,x2,y2,"q" } @@ -15746,8 +15794,10 @@ local function contours2outlines_normal(glyphs,shapes) 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] + local x2=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=control_pt[2] nofsegments=nofsegments+1 if quadratic then segments[nofsegments]={ x1,y1,x2,y2,"q" } @@ -15762,14 +15812,17 @@ local function contours2outlines_normal(glyphs,shapes) if first_pt==last_pt then else nofsegments=nofsegments+1 - local x2,y2=first_pt[1],first_pt[2] + local x2=first_pt[1] + local y2=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] + local x1=control_pt[1] + local y1=control_pt[2] segments[nofsegments]={ x1,y1,x2,y2,"q" } else - local x1,y1=control_pt[1],control_pt[2] + local x1=control_pt[1] + local y1=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 @@ -15828,7 +15881,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt=first_pt end - local x,y=first_pt[1],first_pt[2] + local x=first_pt[1] + local y=first_pt[2] if not done then xmin,ymin,xmax,ymax=x,y,x,y done=true @@ -15841,7 +15895,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments]={ x,y,"m" } end if not quadratic then - px,py=x,y + px=x + py=y end local previous_pt=first_pt for i=first,last do @@ -15850,7 +15905,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) local previous_on=previous_pt[3] if previous_on then if current_on then - local x,y=current_pt[1],current_pt[2] + local x=current_pt[1] + local y=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 @@ -15858,14 +15914,17 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments]={ x,y,"l" } end if not quadratic then - px,py=x,y + px=x + py=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] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=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 @@ -15888,8 +15947,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) 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] + local x2=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=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 @@ -15921,8 +15982,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) 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] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=first_pt[1] + local y2=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 @@ -17818,6 +17881,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local sets=readarray(f) sets=readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta) coverage=readcoverage(f,tableoffset+coverage) + local shared={} for index,newindex in next,coverage do local set=sets[newindex+1] local hash={} @@ -17825,18 +17889,24 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local value=set[i] if value then local other=value[1] - local first=value[2] - local second=value[3] - if first or second then - hash[other]={ first,second or nil } - else - hash[other]=nil + local share=shared[value] + if share==nil then + local first=value[2] + local second=value[3] + if first or second then + share={ first,second or nil } + else + share=false + end + shared[value]=share end + hash[other]=share or nil end end coverage[index]=hash end return { + shared=shared and true or nil, format="pair", coverage=coverage, } @@ -17853,6 +17923,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly classdef1=readclassdef(f,tableoffset+classdef1,coverage) classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs) local usedcoverage={} + local shared={} for g1,c1 in next,classdef1 do if coverage[g1] then local l1=classlist[c1] @@ -17864,8 +17935,17 @@ 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 or nil } - else + local s1=shared[first] + if s1==nil then + s1={} + shared[first]=s1 + end + local s2=s1[second] + if s2==nil then + s2={ first,second or nil } + s1[second]=s2 + end + hash[paired]=s2 end end end @@ -17874,6 +17954,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly end end return { + shared=shared and true or nil, format="pair", coverage=usedcoverage, } @@ -19587,12 +19668,13 @@ function readers.avar(f,fontdata,specification) 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 + local from=read2dot14(f) + local to=read2dot14(f) + if lastfrom and from<=lastfrom then + elseif lastto and to>=lastto then else - values[#values+1]={ f,t } - lastfrom,lastto=f,t + values[#values+1]={ from,to } + lastfrom,lastto=from,to end end nofvalues=#values @@ -21074,7 +21156,9 @@ function readers.pack(data) end return false elseif nt>=threshold then - local one,two,rest=0,0,0 + local one=0 + local two=0 + local rest=0 if pass==1 then for k,v in next,c do if v==1 then @@ -21162,16 +21246,30 @@ function readers.pack(data) if kind=="gpos_pair" then local c=step.coverage if c then - if step.format=="pair" then + if step.format~="pair" then + for g1,d1 in next,c do + c[g1]=pack_normal(d1) + end + elseif step.shared then + local shared={} for g1,d1 in next,c do 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 + if not shared[d2] then + 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 + shared[d2]=true + end end end + if pass==2 then + step.shared=nil + end else 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 end end @@ -22457,7 +22555,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.107 +otf.version=3.108 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) @@ -22822,7 +22920,6 @@ local function copytotfm(data,cache_id) properties.space=spacer properties.encodingbytes=2 properties.format=data.format or formats.otf - properties.noglyphnames=true properties.filename=filename properties.fontname=fontname properties.fullname=fullname @@ -23176,7 +23273,9 @@ local function gref(descriptions,n) return f_unicode(n) end elseif n then - local num,nam,j={},{},0 + local num={} + local nam={} + local j=0 for i=1,#n do local ni=n[i] if tonumber(ni) then @@ -23381,12 +23480,15 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local done=trace_baseinit and trace_ligatures and {} for i=1,nofligatures do local ligature=ligatures[i] - local unicode,tree=ligature[1],ligature[2] + local unicode=ligature[1] + local tree=ligature[2] make_1(present,tree,"ctx_"..unicode) end for i=1,nofligatures do local ligature=ligatures[i] - local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3] + local unicode=ligature[1] + local tree=ligature[2] + local lookupname=ligature[3] make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) end end @@ -23639,7 +23741,7 @@ local getboth=nuts.getboth local getdisc=nuts.getdisc local setdisc=nuts.setdisc local setoffsets=nuts.setoffsets -local ischar=nuts.is_char +local ischar=nuts.ischar local getkern=nuts.getkern local setkern=nuts.setkern local setlink=nuts.setlink @@ -23952,7 +24054,8 @@ function injections.setmove(current,factor,rlmode,x,injection) 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]) + local dx=factor*(ba[1]-ma[1]) + local dy=factor*(ba[2]-ma[2]) nofregisteredmarks=nofregisteredmarks+1 if rlmode>=0 then dx=tfmbase.width-dx @@ -25069,7 +25172,7 @@ local getprop=nuts.getprop local setprop=nuts.setprop local getsubtype=nuts.getsubtype local getchar=nuts.getchar -local ischar=nuts.is_char +local ischar=nuts.ischar local end_of_math=nuts.end_of_math local nodecodes=nodes.nodecodes local disc_code=nodecodes.disc @@ -25278,9 +25381,9 @@ if not classifiers then characters.classifiers=classifiers end function methods.arab(head,font,attr) - local first,last=nil,nil - local c_first,c_last=nil,nil - local current,done=head,false + local first,last,c_first,c_last + local current=head + local done=false current=tonut(current) while current do local char,id=ischar(current,font) @@ -25486,8 +25589,6 @@ local setprev=nuts.setprev local getboth=nuts.getboth local setboth=nuts.setboth local getid=nuts.getid -local getattr=nuts.getattr -local setattr=nuts.setattr local getprop=nuts.getprop local setprop=nuts.setprop local getsubtype=nuts.getsubtype @@ -25500,7 +25601,9 @@ local setlink=nuts.setlink local getcomponents=nuts.getcomponents local setcomponents=nuts.setcomponents local getwidth=nuts.getwidth -local ischar=nuts.is_char +local getattr=nuts.getattr +local getglyphdata=nuts.getglyphdata +local ischar=nuts.ischar local isglyph=nuts.isglyph local usesfont=nuts.uses_font local insert_node_after=nuts.insert_after @@ -26021,8 +26124,8 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev=getprev(start) if stop then setnext(stop) - local tail=getprev(stop) local copy=copy_node_list(start) + local tail=stop local liat=find_node_tail(copy) if pre then setlink(liat,pre) @@ -26113,7 +26216,8 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end local format=step.format if format=="pair" then - local a,b=krn[1],krn[2] + local a=krn[1] + local b=krn[2] if a==true then elseif a then local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) @@ -26631,7 +26735,8 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm end local format=currentlookup.format if format=="pair" then - local a,b=krn[1],krn[2] + local a=krn[1] + local b=krn[2] if a==true then elseif a then local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") @@ -28101,7 +28206,7 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then local lookupmatch=lookupcache[char] @@ -28135,7 +28240,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end local startnext=getnext(start) if not a or (a==attr) then @@ -28210,7 +28315,7 @@ end 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) + a=getglyphdata(sub) end if not a or (a==attr) then for n in nextnode,sub do @@ -28244,7 +28349,7 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then for i=1,nofsteps do @@ -28285,7 +28390,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end local startnext=getnext(start) if not a or (a==attr) then @@ -28363,7 +28468,7 @@ end 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) + a=getglyphdata(sub) end if not a or (a==attr) then for n in nextnode,sub do @@ -28514,7 +28619,7 @@ do if m then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then for i=m[1],m[2] do @@ -28558,7 +28663,7 @@ do if lookupmatch then local a if attr then - if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + if getglyphdata(start)==attr and (not attribute or getprop(start,a_state)==attribute) then a=true end elseif not attribute or getprop(start,a_state)==attribute then @@ -28614,7 +28719,7 @@ do if m then local a if attr then - if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + if getglyphdata(start)==attr and (not attribute or getprop(start,a_state)==attribute) then a=true end elseif not attribute or getprop(start,a_state)==attribute then @@ -29065,7 +29170,7 @@ local setprev=nuts.setprev local setchar=nuts.setchar local getprop=nuts.getprop local setprop=nuts.setprop -local ischar=nuts.is_char +local ischar=nuts.ischar local insert_node_after=nuts.insert_after local copy_node=nuts.copy local remove_node=nuts.remove @@ -30034,7 +30139,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) end function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) local stop=getnext(start) - local font=getfont(start) + local font=getfont(start) local last=start while stop do local char=ischar(stop,font) @@ -31668,7 +31773,8 @@ local function addfeature(data,feature,specifications) if not nocheck and not description then skip=skip+1 elseif type(replacement)=="table" then - local r,n={},0 + local r={} + local n=0 for i=1,#replacement do local u=tounicode(replacement[i]) if nocheck or descriptions[u] then @@ -32601,13 +32707,15 @@ 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 and attr.size or 0,attr and attr.modification or 0 + local size=attr and attr.size or 0 + local time=attr and attr.modification or 0 local pfbfile=file.replacesuffix(name,"pfb") local pfbname=resolvers.findfile(pfbfile,"pfb") or "" if pfbname=="" then pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or "" end - local pfbsize,pfbtime=0,0 + local pfbsize=0 + local pfbtime=0 if pfbname~="" then local attr=lfs.attributes(pfbname) pfbsize=attr.size or 0 @@ -32816,7 +32924,8 @@ local addthem=function(rawdata,ligatures) local one=descriptions[unicodes[ligname]] if one then for _,pair in next,ligdata do - local two,three=unicodes[pair[1]],unicodes[pair[2]] + local two=unicodes[pair[1]] + local three=unicodes[pair[2]] if two and three then local ol=one.ligatures if ol then @@ -32916,7 +33025,8 @@ local function adddimensions(data) for unicode,description in next,data.descriptions do local bb=description.boundingbox if bb then - local ht,dp=bb[4],-bb[2] + local ht=bb[4] + local dp=-bb[2] if ht==0 or ht<0 then else description.height=ht @@ -32945,8 +33055,9 @@ local function copytotfm(data) local filename=constructors.checkedfilename(resources) local fontname=metadata.fontname or metadata.fullname local fullname=metadata.fullname or metadata.fontname - local endash=0x0020 + local endash=0x2013 local emdash=0x2014 + local space=0x0020 local spacer="space" local spaceunits=500 local monospaced=metadata.monospaced @@ -32957,26 +33068,32 @@ local function copytotfm(data) parameters.italicangle=italicangle parameters.charwidth=charwidth parameters.charxheight=charxheight + local d_endash=descriptions[endash] + local d_emdash=descriptions[emdash] + local d_space=descriptions[space] + if not d_space or d_space==0 then + d_space=d_endash + end + if d_space then + spaceunits,spacer=d_space.width or 0,"space" + end if properties.monospaced then - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width,"emdash" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" + if spaceunits==0 and d_emdash then + spaceunits,spacer=d_emdash.width or 0,"emdash" end else - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" + if spaceunits==0 and d_endash then + spaceunits,spacer=d_emdash.width or 0,"endash" end end - spaceunits=tonumber(spaceunits) - if spaceunits<200 then + if spaceunits==0 and charwidth then + spaceunits,spacer=charwidth or 0,"charwidth" + end + if spaceunits==0 then + spaceunits=tonumber(spaceunits) or 500 + end + if spaceunits==0 then + spaceunits=500 end parameters.slant=0 parameters.space=spaceunits @@ -33182,7 +33299,7 @@ local function check_afm(specification,fullname) if foundname=="" then foundname=fonts.names.getfilename(fullname,"afm") or "" end - if foundname=="" and afm.autoprefixed then + if fullname and foundname=="" and afm.autoprefixed then local encoding,shortname=match(fullname,"^(.-)%-(.*)$") if encoding and shortname and fonts.encodings.known[encoding] then shortname=findbinfile(shortname,'afm') or "" @@ -33424,7 +33541,7 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-tfm']={ +if not modules then modules={} end modules ['luatex-fonts-tfm']={ version=1.001, comment="companion to font-ini.mkiv", author="Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -33460,7 +33577,7 @@ local registertfmenhancer=tfmenhancers.register local charcommand=helpers.commands.char constructors.resolvevirtualtoo=false fonts.formats.tfm="type1" -fonts.formats.ofm="type1" +fonts.formats.ofm="type1" function tfm.setfeatures(tfmdata,features) local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) if okay then @@ -33469,191 +33586,156 @@ function tfm.setfeatures(tfmdata,features) return {} end end -local depth={} -local read_from_tfm,check_tfm do - local tfmreaders=context and tfm.readers - local loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - local loadtfm=font.read_tfm - local loadvf=font.read_vf - directives.register("fonts.tfm.builtin",function(v) - loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - if v and loadtfm then - loadtfmvf=false - end - end) - read_from_tfm=function(specification) - local filename=specification.filename - local size=specification.size - depth[filename]=(depth[filename] or 0)+1 - if trace_defining then - report_defining("loading tfm file %a at size %s",filename,size) - end - local tfmdata - if loadtfmvf then - tfmdata=loadtfmvf(filename,size) - else - tfmdata=loadtfm(filename,size) +local depth={} +local loadtfm=font.read_tfm +local loadvf=font.read_vf +local function read_from_tfm(specification) + local filename=specification.filename + local size=specification.size + depth[filename]=(depth[filename] or 0)+1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata=loadtfm(filename,size) + if tfmdata then + local features=specification.features and specification.features.normal or {} + local features=constructors.checkedfeatures("tfm",features) + specification.features.normal=features + local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata=newtfmdata end - if tfmdata then - local features=specification.features and specification.features.normal or {} - local features=constructors.checkedfeatures("tfm",features) - specification.features.normal=features - local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata=newtfmdata - end - local resources=tfmdata.resources or {} - local properties=tfmdata.properties or {} - local parameters=tfmdata.parameters or {} - local shared=tfmdata.shared or {} - shared.features=features - shared.resources=resources - properties.name=tfmdata.name - properties.fontname=tfmdata.fontname - properties.psname=tfmdata.psname - properties.fullname=tfmdata.fullname - properties.filename=specification.filename - properties.format=tfmdata.format or fonts.formats.tfm - properties.usedbitmap=tfmdata.usedbitmap - tfmdata.properties=properties - tfmdata.resources=resources - tfmdata.parameters=parameters - tfmdata.shared=shared - shared.rawdata={ resources=resources } - shared.features=features - if newtfmdata then - if not resources.marks then - resources.marks={} - end - if not resources.sequences then - resources.sequences={} - end - if not resources.features then - resources.features={ - gsub={}, - gpos={}, - } - end - if not tfmdata.changed then - tfmdata.changed={} - end - if not tfmdata.descriptions then - tfmdata.descriptions=tfmdata.characters - end - otf.readers.addunicodetable(tfmdata) - tfmenhancers.apply(tfmdata,filename) - constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) - otf.readers.unifymissing(tfmdata) - fonts.mappings.addtounicode(tfmdata,filename) - tfmdata.tounicode=1 - local tounicode=fonts.mappings.tounicode - for unicode,v in next,tfmdata.characters do - local u=v.unicode - if u then - v.tounicode=tounicode(u) - end - end - if tfmdata.usedbitmap then - tfm.addtounicode(tfmdata) - end - end - shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil - if size<0 then - size=idiv(65536*-size,100) - end - parameters.factor=1 - parameters.units=1000 - parameters.size=size - parameters.slant=parameters.slant or parameters[1] or 0 - parameters.space=parameters.space or parameters[2] or 0 - parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 - parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 - parameters.x_height=parameters.x_height or parameters[5] or 0 - 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 loadtfmvf then - local fonts=tfmdata.fonts - if fonts then - for i=1,#fonts do - local font=fonts[i] - local id=font.id - if not id then - local name=font.name - local size=font.size - if name and size then - local data,id=constructors.readanddefine(name,size) - if id then - font.id=id - font.name=nil - font.size=nil - end - end - end - end - end - elseif constructors.resolvevirtualtoo then - fonts.loggers.register(tfmdata,file.suffix(filename),specification) - local vfname=findbinfile(specification.name,'ovf') - if vfname and vfname~="" then - local vfdata=loadvf(vfname,size) - if vfdata then - local chars=tfmdata.characters - for k,v in next,vfdata.characters do - chars[k].commands=v.commands - end - properties.virtualized=true - tfmdata.fonts=vfdata.fonts - tfmdata.type="virtual" - local fontlist=vfdata.fonts - local name=file.nameonly(filename) - for i=1,#fontlist do - local n=fontlist[i].name - local s=fontlist[i].size - local d=depth[filename] - s=constructors.scaled(s,vfdata.designsize) - if d>tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i]={ id=0 } - elseif (d>1) and (s>tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i]={ id=0 } - else - local t,id=constructors.readanddefine(n,s) - fontlist[i]={ id=id } - end + local resources=tfmdata.resources or {} + local properties=tfmdata.properties or {} + local parameters=tfmdata.parameters or {} + local shared=tfmdata.shared or {} + shared.features=features + shared.resources=resources + properties.name=tfmdata.name + properties.fontname=tfmdata.fontname + properties.psname=tfmdata.psname + properties.fullname=tfmdata.fullname + properties.filename=specification.filename + properties.format=tfmdata.format or fonts.formats.tfm + properties.usedbitmap=tfmdata.usedbitmap + tfmdata.properties=properties + tfmdata.resources=resources + tfmdata.parameters=parameters + tfmdata.shared=shared + shared.rawdata={ resources=resources } + shared.features=features + if newtfmdata then + if not resources.marks then + resources.marks={} + end + if not resources.sequences then + resources.sequences={} + end + if not resources.features then + resources.features={ + gsub={}, + gpos={}, + } + end + if not tfmdata.changed then + tfmdata.changed={} + end + if not tfmdata.descriptions then + tfmdata.descriptions=tfmdata.characters + end + otf.readers.addunicodetable(tfmdata) + tfmenhancers.apply(tfmdata,filename) + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + otf.readers.unifymissing(tfmdata) + fonts.mappings.addtounicode(tfmdata,filename) + tfmdata.tounicode=1 + local tounicode=fonts.mappings.tounicode + for unicode,v in next,tfmdata.characters do + local u=v.unicode + if u then + v.tounicode=tounicode(u) + end + end + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil + if size<0 then + size=idiv(65536*-size,100) + end + parameters.factor=1 + parameters.units=1000 + parameters.size=size + parameters.slant=parameters.slant or parameters[1] or 0 + parameters.space=parameters.space or parameters[2] or 0 + parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 + parameters.x_height=parameters.x_height or parameters[5] or 0 + 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) + local vfname=findbinfile(specification.name,'ovf') + if vfname and vfname~="" then + local vfdata=loadvf(vfname,size) + if vfdata then + local chars=tfmdata.characters + for k,v in next,vfdata.characters do + chars[k].commands=v.commands + end + properties.virtualized=true + tfmdata.fonts=vfdata.fonts + tfmdata.type="virtual" + local fontlist=vfdata.fonts + local name=file.nameonly(filename) + for i=1,#fontlist do + local n=fontlist[i].name + local s=fontlist[i].size + local d=depth[filename] + s=constructors.scaled(s,vfdata.designsize) + if d>tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i]={ id=0 } + elseif (d>1) and (s>tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i]={ id=0 } + else + local t,id=constructors.readanddefine(n,s) + fontlist[i]={ id=id } end end end end - properties.haskerns=true - properties.hasligatures=true - properties.hasitalics=true - resources.unicodes={} - resources.lookuptags={} - depth[filename]=depth[filename]-1 - return tfmdata - else - depth[filename]=depth[filename]-1 end + properties.haskerns=true + properties.hasligatures=true + properties.hasitalics=true + resources.unicodes={} + resources.lookuptags={} + depth[filename]=depth[filename]-1 + return tfmdata + else + depth[filename]=depth[filename]-1 end - check_tfm=function(specification,fullname) - local foundname=findbinfile(fullname,'tfm') or "" - if foundname=="" then - foundname=findbinfile(fullname,'ofm') or "" - end - if foundname=="" then - foundname=fonts.names.getfilename(fullname,"tfm") or "" - end - if foundname~="" then - specification.filename=foundname - specification.format="ofm" - return read_from_tfm(specification) - elseif trace_defining then - report_defining("loading tfm with name %a fails",specification.name) - end +end +local function check_tfm(specification,fullname) + local foundname=findbinfile(fullname,'tfm') or "" + if foundname=="" then + foundname=findbinfile(fullname,'ofm') or "" + end + if foundname=="" then + foundname=fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname~="" then + specification.filename=foundname + specification.format="ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) end end readers.check_tfm=check_tfm 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 9f96a01b911..79af277437b 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-fil.lua @@ -14,10 +14,14 @@ local char = string.char -- flac files). In Lua 5.3 we can probably do this better. Some code will move -- here. +-- We could comment those that are in fio and sio. + utilities = utilities or { } local files = { } utilities.files = files +-- we could have a gc method that closes but files auto close anyway + local zerobased = { } function files.open(filename,zb) @@ -249,7 +253,7 @@ end if bit32 then - local rshift = bit32.rshift + local rshift = bit32.rshift function files.writecardinal2(f,n) local a = char(n % 256) @@ -258,6 +262,35 @@ if bit32 then f:write(b,a) end + function files.writecardinal4(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + n = rshift(n,8) + local c = char(n % 256) + n = rshift(n,8) + local d = char(n % 256) + f:write(d,c,b,a) + end + + function files.writecardinal2le(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + f:write(a,b) + end + + function files.writecardinal4le(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + n = rshift(n,8) + local c = char(n % 256) + n = rshift(n,8) + local d = char(n % 256) + f:write(a,b,c,d) + end + else local floor = math.floor @@ -269,17 +302,35 @@ else f:write(b,a) end -end + function files.writecardinal4(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + n = floor(n/256) + local c = char(n % 256) + n = floor(n/256) + local d = char(n % 256) + f:write(d,c,b,a) + end + + function files.writecardinal2le(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + f:write(a,b) + end + + function files.writecardinal4le(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + n = floor(n/256) + local c = char(n % 256) + n = floor(n/256) + local d = char(n % 256) + f:write(a,b,c,d) + end -function files.writecardinal4(f,n) - local a = char(n % 256) - n = rshift(n,8) - local b = char(n % 256) - n = rshift(n,8) - local c = char(n % 256) - n = rshift(n,8) - local d = char(n % 256) - f:write(d,c,b,a) end function files.writestring(f,s) @@ -292,30 +343,42 @@ 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 + files.readcardinal1 = fio.readcardinal1 + files.readcardinal2 = fio.readcardinal2 + files.readcardinal3 = fio.readcardinal3 + files.readcardinal4 = fio.readcardinal4 + + files.readcardinal1le = fio.readcardinal1le or files.readcardinal1le + files.readcardinal2le = fio.readcardinal2le or files.readcardinal2le + files.readcardinal3le = fio.readcardinal3le or files.readcardinal3le + files.readcardinal4le = fio.readcardinal4le or files.readcardinal4le + + files.readinteger1 = fio.readinteger1 + files.readinteger2 = fio.readinteger2 + files.readinteger3 = fio.readinteger3 + files.readinteger4 = fio.readinteger4 + + files.readinteger1le = fio.readinteger1le or files.readinteger1le + files.readinteger2le = fio.readinteger2le or files.readinteger2le + files.readinteger3le = fio.readinteger3le or files.readinteger3le + files.readinteger4le = fio.readinteger4le or files.readinteger4le + + 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)) @@ -327,6 +390,30 @@ if fio and fio.readcardinal1 then end +if fio and fio.writecardinal1 then + + files.writecardinal1 = fio.writecardinal1 + files.writecardinal2 = fio.writecardinal2 + files.writecardinal3 = fio.writecardinal3 + files.writecardinal4 = fio.writecardinal4 + + files.writecardinal1le = fio.writecardinal1le + files.writecardinal2le = fio.writecardinal2le + files.writecardinal3le = fio.writecardinal3le + files.writecardinal4le = fio.writecardinal4le + + files.writeinteger1 = fio.writeinteger1 or fio.writecardinal1 + files.writeinteger2 = fio.writeinteger2 or fio.writecardinal2 + files.writeinteger3 = fio.writeinteger3 or fio.writecardinal3 + files.writeinteger4 = fio.writeinteger4 or fio.writecardinal4 + + files.writeinteger1le = files.writeinteger1le or fio.writecardinal1le + files.writeinteger2le = files.writeinteger2le or fio.writecardinal2le + files.writeinteger3le = files.writeinteger3le or fio.writecardinal3le + files.writeinteger4le = files.writeinteger4le or fio.writecardinal4le + +end + if fio and fio.readcardinaltable then files.readcardinaltable = fio.readcardinaltable 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 713c294ebe7..5470c2fd698 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-util-str.lua @@ -14,7 +14,6 @@ local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, str local load, dump = load, string.dump 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, utflen = utf.char, utf.byte, utf.len @@ -610,8 +609,8 @@ local environment = { formattednumber = number.formatted, sparseexponent = number.sparseexponent, formattedfloat = number.formattedfloat, - stripzero = lpeg.patterns.stripzero, - stripzeros = lpeg.patterns.stripzeros, + stripzero = patterns.stripzero, + stripzeros = patterns.stripzeros, FORMAT = string.f9, } @@ -745,7 +744,7 @@ 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) + return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0) end local format_g = function(f) @@ -1329,9 +1328,9 @@ patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n" -- 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)]],{ xmlescape = lpeg.patterns.xmlescape }) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = lpeg.patterns.texescape }) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = lpeg.patterns.luaescape }) +add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape = patterns.xmlescape }) +add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = patterns.texescape }) +add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = patterns.luaescape }) -- -- yes or no: -- @@ -1409,3 +1408,31 @@ local f_16_16 = formatters["%0.5N"] function number.to16dot16(n) return f_16_16(n/65536.0) end + +-- + +if not string.explode then + + local tsplitat = lpeg.tsplitat + + local p_utf = patterns.utf8character + local p_check = C(p_utf) * (P("+") * Cc(true))^0 + local p_split = Ct(C(p_utf)^0) + local p_space = Ct((C(1-P(" ")^1) + P(" ")^1)^0) + + function string.explode(str,symbol) + if symbol == "" then + return lpegmatch(p_split,str) + elseif symbol then + local a, b = lpegmatch(p_check,symbol) + if b then + return lpegmatch(tsplitat(P(a)^1),str) + else + return lpegmatch(tsplitat(a),str) + end + else + return lpegmatch(p_space,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 428bfddcff7..da9cdcc9981 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua @@ -6,8 +6,8 @@ local ProvidesLuaModule = { name = "luaotfload-auxiliary", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / auxiliary functions", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua index 17536b21647..4ef6b978e4a 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua @@ -5,8 +5,8 @@ local ProvidesLuaModule = { name = "luaotfload-colors", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / color", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Dohyun Kim, David Carlisle", diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua index d88c9ed7713..e4923d37b26 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua @@ -7,8 +7,8 @@ local ProvidesLuaModule = { name = "luaotfload-configuration", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / config file reader", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua index 6918c4abf87..385944a5ab6 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua @@ -5,8 +5,8 @@ do -- block to avoid to many local variables error local ProvidesLuaModule = { name = "luaotfload-database", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / database", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", @@ -529,9 +529,15 @@ load_names = function (dry_run, no_rebuild) end names_version = names.version if db_version ~= names_version then - logreport ("both", 0, "db", - [[Version mismatch; expected %d, got %d.]], - names_version, db_version) + if math.tointeger(db_version) then + logreport ("both", 0, "db", + [[Version mismatch; expected %d, got %d.]], + names_version, db_version) + else + logreport ("both", 0, "db", + [[Version mismatch; expected %d, got invalid data.]], + names_version, db_version) + end if not fonts_reloaded then logreport ("both", 0, "db", [[Force rebuild.]]) data = update_names (initialize_namedata (get_font_filter ()), @@ -1097,7 +1103,7 @@ do if conv ~= nil then logreport ("both", 4, "db", "Interpreting design sizes as %q, factor %.6f.", - dim, conv) + dim, conv or 1) design_size_dimension = conv return end @@ -1474,7 +1480,9 @@ local get_english_names = function (metadata) certain. --]]-- if platformnames then - --namesource = platformnames.macintosh or platformnames.windows + if platformnames.windows and platformnames.macintosh then + return table.merge(platformnames.macintosh, platformnames.windows) + end namesource = platformnames.windows or platformnames.macintosh end return namesource or metadata diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua index bec72097433..c738cd4316a 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua @@ -7,8 +7,8 @@ local ProvidesLuaModule = { name = "luaotfload-diagnostics", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload-tool submodule / diagnostics", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua index 20406fd8122..d2d6d81482c 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua @@ -5,8 +5,8 @@ local ProvidesLuaModule = { name = "luaotfload-features", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / features", license = "GPL v2.0", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang, Marcel Krüger", @@ -199,824 +199,6 @@ end ---[[ begin excerpt from font-ott.lua ]] -local scripts = { - ["arab"] = "arabic", - ["armn"] = "armenian", - ["bali"] = "balinese", - ["beng"] = "bengali", - ["bopo"] = "bopomofo", - ["brai"] = "braille", - ["bugi"] = "buginese", - ["buhd"] = "buhid", - ["byzm"] = "byzantine music", - ["cans"] = "canadian syllabics", - ["cher"] = "cherokee", - ["copt"] = "coptic", - ["cprt"] = "cypriot syllabary", - ["cyrl"] = "cyrillic", - ["deva"] = "devanagari", - ["dsrt"] = "deseret", - ["ethi"] = "ethiopic", - ["geor"] = "georgian", - ["glag"] = "glagolitic", - ["goth"] = "gothic", - ["grek"] = "greek", - ["gujr"] = "gujarati", - ["guru"] = "gurmukhi", - ["hang"] = "hangul", - ["hani"] = "cjk ideographic", - ["hano"] = "hanunoo", - ["hebr"] = "hebrew", - ["ital"] = "old italic", - ["jamo"] = "hangul jamo", - ["java"] = "javanese", - ["kana"] = "hiragana and katakana", - ["khar"] = "kharosthi", - ["khmr"] = "khmer", - ["knda"] = "kannada", - ["lao" ] = "lao", - ["latn"] = "latin", - ["limb"] = "limbu", - ["linb"] = "linear b", - ["math"] = "mathematical alphanumeric symbols", - ["mlym"] = "malayalam", - ["mong"] = "mongolian", - ["musc"] = "musical symbols", - ["mymr"] = "myanmar", - ["nko" ] = "n\"ko", - ["ogam"] = "ogham", - ["orya"] = "oriya", - ["osma"] = "osmanya", - ["phag"] = "phags-pa", - ["phnx"] = "phoenician", - ["runr"] = "runic", - ["shaw"] = "shavian", - ["sinh"] = "sinhala", - ["sylo"] = "syloti nagri", - ["syrc"] = "syriac", - ["tagb"] = "tagbanwa", - ["tale"] = "tai le", - ["talu"] = "tai lu", - ["taml"] = "tamil", - ["telu"] = "telugu", - ["tfng"] = "tifinagh", - ["tglg"] = "tagalog", - ["thaa"] = "thaana", - ["thai"] = "thai", - ["tibt"] = "tibetan", - ["ugar"] = "ugaritic cuneiform", - ["xpeo"] = "old persian cuneiform", - ["xsux"] = "sumero-akkadian cuneiform", - ["yi" ] = "yi", -} -- [[ [scripts] ]] - -local languages = { - ["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", -} --[[ [languages] ]] - -local features = { - ["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 math", -- math - ["ruby"] = "ruby notation forms", - ["salt"] = "stylistic alternates", - ["sinf"] = "scientific inferiors", - ["size"] = "optical size", - ["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 ..", -} --[[ [features] ]] - -local baselines = { - ["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" -} --[[ [baselines] ]] - local swapped = function (h) local r = { } for k, v in next, h do @@ -1025,10 +207,11 @@ local swapped = function (h) return r end +local tables = otf.tables +local scripts = tables.scripts +local languages = tables.languages local verbosescripts = swapped(scripts ) local verboselanguages = swapped(languages) -local verbosefeatures = swapped(features ) -local verbosebaselines = swapped(baselines) ---[[ end excerpt from font-ott.lua ]] diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua index e20d17c153b..ce363840c47 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-filelist.lua @@ -6,8 +6,8 @@ local ProvidesLuaModule = { name = "luaotfload-filelist", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / filelist", license = "GPL v2.0" } @@ -205,7 +205,7 @@ luaotfload.filelist.data = { 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 = "fonts-tfm" , ours = nil , ext = ".lua", kind = kind_merged , gitdir=gitdirimp, texdir = texdirtex , ctxdir= ctxdirbas, ctxtype = "ctxgene" , ctxpref = "luatex-" }, { 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-" }, diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-glyphlist.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-glyphlist.lua index 897385116c1..a97ed1fde8d 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-glyphlist.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-glyphlist.lua @@ -1,7 +1,7 @@ local ProvidesLuaModule = { name = "luaotfload-glyphlist", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / autogenerated glyphlist", copyright = "derived from https://raw.githubusercontent.com/adobe-type-tools/agl-aglfn/master/glyphlist.txt", original = "Adobe Glyph List, version 2.0, September 20, 2002", diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua index a78883ad992..f91d85a93de 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-init.lua @@ -7,8 +7,8 @@ local ProvidesLuaModule = { name = "luaotfload-init", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / initialization", license = "GPL v2.0" } @@ -285,7 +285,7 @@ local context_modules = { { ctx, "font-onr" }, { ctx, "font-one" }, { ctx, "font-afk" }, - { ctx, "font-tfm" }, + { ctx, "luatex-fonts-tfm" }, { ctx, "font-lua" }, { ctx, "font-def" }, { ltx, "luatex-fonts-def" }, @@ -579,7 +579,7 @@ local init_main = function () load_fontloader_module "font-onr" load_fontloader_module "font-one" load_fontloader_module "font-afk" - load_fontloader_module "font-tfm" + load_fontloader_module "fonts-tfm" load_fontloader_module "font-lua" load_fontloader_module "font-def" load_fontloader_module "fonts-def" diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua index c89d89cfded..6cd8dcced36 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua @@ -5,8 +5,8 @@ local ProvidesLuaModule = { name = "luaotfload-letterspace", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / color", license = "GPL v2.0", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -76,12 +76,26 @@ local glyph_code = node.id"glyph" local kern_code = node.id"kern" local disc_code = node.id"disc" local glue_code = node.id"glue" +local whatsit_code = node.id"whatsit" local fonthashes = fonts.hashes local identifiers = fonthashes.identifiers local chardata = fonthashes.characters local otffeatures = fonts.constructors.newfeatures "otf" +local function getprevreal(n) + repeat + n = getprev(n) + until not n or getid(n) ~= whatsit_code + return n +end +local function getnextreal(n) + repeat + n = getnext(n) + until not n or getid(n) ~= whatsit_code + return n +end + --[[doc-- Since the letterspacing method was derived initially from Context’s @@ -261,7 +275,7 @@ kerncharacters = function (head) end -- kern ligature --- 3) apply the extra kerning - local prev = getprev(start) + local prev = getprevreal(start) if prev then local pid = getid(prev) @@ -288,7 +302,7 @@ kerncharacters = function (head) or prev_subtype == userkern_code --- attribute; we may need a test then - local pprev = getprev(prev) + local pprev = getprevreal(prev) local pprev_id = getid(pprev) if keeptogether @@ -332,8 +346,8 @@ kerncharacters = function (head) elseif pid == disc_code then local disc = prev -- disc local pre, post, replace = getdisc (disc) - local prv = getprev(disc) - local nxt = getnext(disc) + local prv = getprevreal(disc) + local nxt = getnextreal(disc) if pre and prv then -- must pair with start.prev -- this one happens in most cases @@ -353,7 +367,6 @@ kerncharacters = function (head) local tail = find_node_tail(post) setnext(tail, after) setprev(after, tail) - setnext(after, nil) post = kerncharacters (post) setnext(getprev(after), nil) setfield(disc, "post", post) diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua index 52ddb635974..ba63b9c0ab9 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua @@ -8,8 +8,8 @@ local ProvidesLuaModule = { name = "luaotfload-loaders", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / callback handling", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua index 88b48dd9901..2561eade488 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua @@ -6,8 +6,8 @@ local ProvidesLuaModule = { name = "luaotfload-log", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / logging", license = "GPL v2.0", author = "Khaled Hosny, Elie Roux, Philipp Gesang", diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua index c5bc6e148df..422ebfed2d1 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua @@ -20,8 +20,8 @@ local authors = "\z -- version number is used below! local ProvidesLuaModule = { name = "luaotfload-main", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload entry point", 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 737b4784aa3..a727abda07e 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua @@ -7,8 +7,8 @@ local ProvidesLuaModule = { name = "luaotfload-parsers", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / filelist", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-resolvers.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-resolvers.lua index d71ddd75f3d..7c004c1f21e 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-resolvers.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-resolvers.lua @@ -11,8 +11,8 @@ local ProvidesLuaModule = { name = "luaotfload-resolvers", - version = "2.96", --TAGVERSION - date = "2019-02-14", --TAGDATE + version = "2.97", --TAGVERSION + date = "2019-05-18", --TAGDATE description = "luaotfload submodule / resolvers", license = "GPL v2.0" } diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua index 3fce3009c26..5dc23493998 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua @@ -1,87 +1,87 @@ return { ["hashes"]={ - { "fontloader-2019-02-14.lua", "6d0a7150bf73b0e7fd3d9b13b0f511f4" }, - { "fontloader-util-fil.lua", "a12919215a51a443ad0128ff9d9f8b36" }, - { "fontloader-util-str.lua", "5ad378f7733e22062bc70596c6a75c67" }, + { "fontloader-2019-05-18.lua", "af4223350ab821b795edff7b293d4a0c" }, + { "fontloader-util-fil.lua", "4bb3e4dc72e308d8ed67cd7a80027fa7" }, + { "fontloader-util-str.lua", "a09020dcaed195ea9acaace2b7b9a66f" }, { "fontloader-l-unicode.lua", "d46cc6cf18fb3f368ef1e404dc9fcb5c" }, { "fontloader-l-math.lua", "a373be3ed2db0d5f98588fa81abca48f" }, { "fontloader-l-boolean.lua", "18ed6c4b2c40dd87224ea33229548d20" }, - { "fontloader-l-file.lua", "97e91122d940fc0007b2fc6b75b749e9" }, + { "fontloader-l-file.lua", "3d6ea476061292a0da98c3f65cdabe46" }, { "fontloader-l-io.lua", "42608ad95eb2822fdc370d1c11f08fb5" }, - { "fontloader-l-table.lua", "ab29284239c2fadf3195c6af0d9da3fd" }, + { "fontloader-l-table.lua", "bc6b9fca25a9d65bead10e250db68bb1" }, { "fontloader-l-string.lua", "2b20a19dfc8d00e856196a446336625e" }, { "fontloader-l-function.lua", "f771cc91839ebcdfc094083434fbe00f" }, { "fontloader-l-lpeg.lua", "a5364ddabb490408da9276ea7f7a7ba1" }, - { "fontloader-l-lua.lua", "9006c1918bc360bc036d5374436e839b" }, + { "fontloader-l-lua.lua", "10134a2dd786bd16b69377eaddab2906" }, { "fontloader-fonts-gbn.lua", "d25472d54c4841db43a745764a63533e" }, { "fontloader-fonts-lig.lua", "b9dbe77ce747d4c35bb2a20ffbe5aa51" }, { "fontloader-fonts-ext.lua", "01015ab3758cdc2af29394e6d502a91a" }, { "fontloader-fonts-def.lua", "5ad79120ebc5e60f4d322fb3ee13bffe" }, + { "fontloader-fonts-tfm.lua", "3bbba3214fd0b8c6f35ad85592fc2917" }, { "fontloader-fonts-enc.lua", "3e71a54297e8f85a1ac438bb0f20dd79" }, { "fontloader-fonts-mis.lua", "bc9eb43c27f63ce9d0fff67e104fe1c6" }, { "fontloader-basics-chr.lua", "a8b8316248b40cc9bc1be19050f7074f" }, - { "fontloader-basics-nod.lua", "c5185eab8319653452cc5957c787f4be" }, + { "fontloader-basics-nod.lua", "aa71dcb849fbe4bdf2464cb2a1ef0456" }, { "fontloader-font-imp-effects.lua", "73a660359a0ec71e44cc2b7225a715ac" }, { "fontloader-font-imp-italics.lua", "fe1ca80fb5ea4a2f8d2d5c484e7ba913" }, { "fontloader-font-imp-ligatures.lua", "043daa4fcccf2560868da359d71d3a4a" }, { "fontloader-font-imp-tex.lua", "77c374b0ef00c2fb12188ec42beb4257" }, { "fontloader-font-def.lua", "f66c365dae4499f982d8bf16e5d37de3" }, { "fontloader-font-lua.lua", "55b281fb98f7bd848fc19928f376f647" }, - { "fontloader-font-tfm.lua", "f1a3796cce3838210248eb1daee6ea83" }, { "fontloader-font-afk.lua", "54d554530e75c57c56ee76234724e26d" }, - { "fontloader-font-one.lua", "b0a175e8f123feb797c7a5a9b02b85a0" }, + { "fontloader-font-one.lua", "987c5c5ed3754ad2feab80985067d59e" }, { "fontloader-font-onr.lua", "20b0d2753f58ff91180947ce4078571e" }, - { "fontloader-font-otc.lua", "088ba25667dfc5036867d007797e1602" }, + { "fontloader-font-otc.lua", "95a4ff28ba4afb55a978a4aecfd688bf" }, { "fontloader-font-ocl.lua", "280ad7888c7c386010598e9fdb83f466" }, - { "fontloader-font-osd.lua", "883c29eaccf966c9ad9ab205a920de08" }, - { "fontloader-font-ots.lua", "e2bfdc0d27729ce54048d94ff701f37f" }, - { "fontloader-font-ota.lua", "5503fc4d2bd8c6a2cbb2db1b1651e402" }, - { "fontloader-font-otj.lua", "e49771140e5ed2f28ce680ad9d672dc7" }, - { "fontloader-font-oto.lua", "6ba2e73177b18007e74de324c324806c" }, - { "fontloader-font-otl.lua", "0836c8396cae2bcfd4020186e5e8d7e0" }, - { "fontloader-font-oup.lua", "26b481cd9efebf7047810800930dff58" }, - { "fontloader-font-dsp.lua", "7959312318af6ed8fbd9edbeb2b1a335" }, - { "fontloader-font-ttf.lua", "fe1b771df5d6442a10fcfa1388f3eed2" }, - { "fontloader-font-cff.lua", "fda3887cbaad0b82d06d3cbffdfff560" }, + { "fontloader-font-osd.lua", "e8111d24e652a181bf2bbd5149fb66d4" }, + { "fontloader-font-ots.lua", "0da86e8e56e342169221ec66c4f05318" }, + { "fontloader-font-ota.lua", "d6dfb94563d6a52675e274b2e673e4a6" }, + { "fontloader-font-otj.lua", "bd772fd29bdec537c3c4e9d971b80325" }, + { "fontloader-font-oto.lua", "54ea5c823993e536950b2245e94aee93" }, + { "fontloader-font-otl.lua", "b041e8512af19d28edbbebc683f7cd51" }, + { "fontloader-font-oup.lua", "669e479e716999edc626a1f045bd76fa" }, + { "fontloader-font-dsp.lua", "b5bf2f1c198e027a0d4ededcdf3947b4" }, + { "fontloader-font-ttf.lua", "f2d53377b264d59368703e659a7bc228" }, + { "fontloader-font-cff.lua", "7ff1a757f6a26f57f635014cc8a174fe" }, { "fontloader-font-ott.lua", "a8b78a27cbb22d4f697a8dd801a73eea" }, { "fontloader-font-oti.lua", "dbae7722baae24d917a17176553825cf" }, - { "fontloader-font-otr.lua", "2c35abf43f9a64bdd99240593d432d8a" }, + { "fontloader-font-otr.lua", "340999eb6c53879787a7560bc1a30360" }, { "fontloader-font-vfc.lua", "94937140f2c909e9c831ba021f1ab303" }, - { "fontloader-font-map.lua", "210b9288eef0df624da638b65d27291b" }, + { "fontloader-font-map.lua", "f486746e90fe972de4b73e208ac7cbb2" }, { "fontloader-font-cid.lua", "4d87988efa86020a14708ee03c23415f" }, - { "fontloader-font-con.lua", "ecfc697058b63e508300b6133f97c74c" }, + { "fontloader-font-con.lua", "f7d973760207e820b954a1e478a6a347" }, { "fontloader-font-ini.lua", "4299a02110bbd7c0d27e131235c5319d" }, { "fontloader-data-con.lua", "7ce546725b1550f655c78ac9d69419ca" }, - { "fontloader-reference.lua", "a0176453bfa9952a793ed7377f053f42" }, + { "fontloader-reference.lua", "06c79e8da5a0141322bf4fa7303753db" }, { "fontloader-basics-gen.lua", "b21e91bbd534f77e368f0ec13f865aed" }, { "mktests", "c7cff7025962922944376acc1ffa9c47" }, - { "mkstatus", "2dc1052ac96cce3dfe7100a203346440" }, + { "mkstatus", "54c20ea0757ef99b5f01b7c6bdeb69f4" }, { "mkcharacters", "92c24bb582fc84c0365634f29eb89863" }, { "mkglyphlist", "557836886d4f0e6d656eac3ded4456a2" }, - { "mkimport", "1788927ee10b87112e200466151f1fbf" }, - { "luaotfload-glyphlist.lua", "4e368a6a6d5cee2423edcb322035ffd7" }, + { "mkimport", "60e0b11a1a68719033e86a3e0f4d5e86" }, + { "luaotfload-glyphlist.lua", "c17cc5b6a874fea4725ef1447d98d48f" }, { "luaotfload-characters.lua", "1ef110e1710f53689b2e22783f648b14" }, - { "luaotfload-resolvers.lua", "263efbb207740d71173ac9b8d406dbe9" }, - { "luaotfload-parsers.lua", "08ba2d4ef8220fc1fcc71f95c3adfa4b" }, - { "luaotfload-loaders.lua", "322049c77ff38d3b4070a9d216ed6c8d" }, - { "luaotfload-letterspace.lua", "962196d328f20aac9c185a7a0c989c11" }, - { "luaotfload-features.lua", "12d72cb68c8de4084de38f18eeb8eb35" }, - { "luaotfload-database.lua", "c839bbb78d78759f761e030ae68ff00b" }, - { "luaotfload-configuration.lua", "d015920c510ff47a48f8c2cf76193520" }, - { "luaotfload-colors.lua", "56e7199ec45542b6f5f9a8c304ffa8c3" }, - { "luaotfload-auxiliary.lua", "aab59a311785dfdccb25f9337b210e94" }, - { "luaotfload-filelist.lua", "32027c3ca011e8a3c892045ee7aba6d2" }, - { "luaotfload-tool.lua", "834da97f3cdb4f8725a45084606adbad" }, - { "luaotfload-diagnostics.lua", "f9e38e6fd30ef1544e9e4988ecbcd4dd" }, - { "luaotfload-log.lua", "6dce33a06f2f84803181a017b3e0b7f6" }, - { "luaotfload-init.lua", "0a03643156fb4f11edac7b611a45e372" }, - { "luaotfload-main.lua", "92421306444906f60d55cfaec75b5020" }, + { "luaotfload-resolvers.lua", "ad6862959cf2834c17161cf607b3b549" }, + { "luaotfload-parsers.lua", "33555595b544effa65646476cc24cd49" }, + { "luaotfload-loaders.lua", "9223c8551aabd9cbd48fba4778ce35bf" }, + { "luaotfload-letterspace.lua", "e4c5c5ce88fa8c0ace98130d88fe6509" }, + { "luaotfload-features.lua", "7f1dbbd587c0eda8a561420dc0cb6dac" }, + { "luaotfload-database.lua", "5b35db067a22ca1e18c28d2ca1336e47" }, + { "luaotfload-configuration.lua", "dba9d42bdf0ea8b62d05a1f4b033f255" }, + { "luaotfload-colors.lua", "bdc46e95a543767612e72ccfe1365796" }, + { "luaotfload-auxiliary.lua", "10ca85d4d0cc0511c845f7e7af72cb17" }, + { "luaotfload-filelist.lua", "f948ffa6f2497dae412d35fc4246f7bb" }, + { "luaotfload-tool.lua", "d1a47905960d7f32dd51c4d7e8c5564f" }, + { "luaotfload-diagnostics.lua", "e859506183be49f4a7bb27d2c7518499" }, + { "luaotfload-log.lua", "8be58667b8e14eaa7cb2213f3b13d543" }, + { "luaotfload-init.lua", "d9be3995344aee603255c115c2d26792" }, + { "luaotfload-main.lua", "01588c31ddfe55b5db4fbc20ce579a8e" }, }, ["notes"]={ ["committer"]="Ulrike Fischer <fischer@troubleshooting-tex.de>", - ["description"]="v2.96", - ["loader"]="fontloader-2019-02-14.lua", - ["revision"]="a4b43cefc8f0c45a2ff7b1b627124c57f176ce09", - ["timestamp"]="2019-02-24 22:12:26 +0100", + ["description"]="v2.97", + ["loader"]="fontloader-2019-05-18.lua", + ["revision"]="e70d156b9b36c4e1029d7e613eb414d45b54c508", + ["timestamp"]="2019-05-19 14:34:44 +0200", }, }
\ No newline at end of file |