diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 51 | ||||
-rw-r--r-- | filegraph.dot | 51 | ||||
-rw-r--r-- | font-age.lua | 3744 | ||||
-rwxr-xr-x | fontdbutil.lua | 72 | ||||
-rw-r--r-- | luaotfload-basics-gen.lua | 48 | ||||
-rw-r--r-- | luaotfload-database.lua | 880 | ||||
-rw-r--r-- | luaotfload-features.lua | 74 | ||||
-rw-r--r-- | luaotfload-merged.lua | 856 | ||||
-rw-r--r-- | luaotfload-override.lua | 5 | ||||
-rw-r--r-- | luaotfload.dtx | 89 | ||||
-rwxr-xr-x | mkglyphlist | 143 | ||||
-rw-r--r-- | tests/lookups.tex | 6 |
13 files changed, 1773 insertions, 4248 deletions
@@ -31,3 +31,5 @@ tests/*.dvi tests/*.ofm tests/*.ovp tests/*.ovf +tests/*.sty +tests/luaotfload* @@ -1,30 +1,34 @@ # Makefile for luaotfload -NAME = luaotfload -DOC = $(NAME).pdf -DTX = $(NAME).dtx -OTFL = $(wildcard otfl-*.lua) otfl-blacklist.cnf font-age.lua -SCRIPT = mkluatexfontdb.lua +NAME = luaotfload +DOC = $(NAME).pdf +DTX = $(NAME).dtx +OTFL = $(wildcard otfl-*.lua) otfl-blacklist.cnf font-age.lua +SCRIPT = fontdbutil + +GLYPHSCRIPT = mkglyphlist +GLYPHSOURCE = glyphlist.txt GRAPH = filegraph DOTPDF = $(GRAPH).pdf DOT = $(GRAPH).dot # Files grouped by generation mode -GRAPHED = $(DOTPDF) -COMPILED = $(DOC) -UNPACKED = luaotfload.sty luaotfload.lua -GENERATED = $(GRAPHED) $(COMPILED) $(UNPACKED) -SOURCE = $(DTX) $(OTFL) README Makefile NEWS $(SCRIPT) +GLYPHS = font-age.lua +GRAPHED = $(DOTPDF) +COMPILED = $(DOC) +UNPACKED = luaotfload.sty luaotfload.lua +GENERATED = $(GRAPHED) $(COMPILED) $(UNPACKED) $(GLYPHS) +SOURCE = $(DTX) $(OTFL) README Makefile NEWS $(SCRIPT) $(GLYPHSCRIPT) # test files -TESTDIR = tests -TESTFILES = $(wildcard $(TESTDIR)/*.tex $(TESTDIR)/*.ltx) -TESTFILES_SYS = $(TESTDIR)/systemfonts.tex $(TESTDIR)/fontconfig_conf_reading.tex -TESTFILES_TL = $(filter-out $(TESTFILES_SYS), $(TESTFILES)) +TESTDIR = tests +TESTFILES = $(wildcard $(TESTDIR)/*.tex $(TESTDIR)/*.ltx) +TESTFILES_SYS = $(TESTDIR)/systemfonts.tex $(TESTDIR)/fontconfig_conf_reading.tex +TESTFILES_TL = $(filter-out $(TESTFILES_SYS), $(TESTFILES)) # Files grouped by installation location -SCRIPTFILES = $(SCRIPT) +SCRIPTFILES = $(SCRIPT) $(GLYPHSCRIPT) RUNFILES = $(UNPACKED) $(OTFL) DOCFILES = $(DOC) README NEWS SRCFILES = $(DTX) Makefile @@ -42,21 +46,26 @@ SRCDIR = $(TEXMFROOT)/source/$(FORMAT)/$(NAME) TEXMFROOT = $(shell kpsewhich --var-value TEXMFHOME) CTAN_ZIP = $(NAME).zip -TDS_ZIP = $(NAME).tds.zip -ZIPS = $(CTAN_ZIP) $(TDS_ZIP) +TDS_ZIP = $(NAME).tds.zip +ZIPS = $(CTAN_ZIP) $(TDS_ZIP) -DO_TEX = tex --interaction=batchmode $< >/dev/null -DO_LATEX = latexmk -pdf -pdflatex=lualatex -silent $< >/dev/null -DO_GRAPHVIZ = dot -Tpdf -o $@ $< > /dev/null +DO_TEX = tex --interaction=batchmode $< >/dev/null +DO_LATEX = latexmk -pdf -pdflatex=lualatex -silent $< >/dev/null +DO_GRAPHVIZ = dot -Tpdf -o $@ $< > /dev/null +DO_GLYPHLIST = texlua ./mkglyphlist > /dev/null all: $(GENERATED) graph: $(GRAPHED) doc: $(GRAPHED) $(COMPILED) unpack: $(UNPACKED) +glyphs: $(GLYPHS) ctan: check $(CTAN_ZIP) tds: $(TDS_ZIP) world: all ctan +$(GLYPHS): /dev/null + $(DO_GLYPHLIST) + $(GRAPHED): $(DOT) $(DO_GRAPHVIZ) @@ -118,5 +127,5 @@ clean: @$(RM) -- *.log *.aux *.toc *.idx *.ind *.ilg *.out $(TESTDIR)/*.log mrproper: clean - @$(RM) -- $(GENERATED) $(ZIPS) $(TESTDIR)/*.pdf + @$(RM) -- $(GENERATED) $(ZIPS) $(GLYPHSOURCE) $(TESTDIR)/*.pdf diff --git a/filegraph.dot b/filegraph.dot index 9b79953..a0eadec 100644 --- a/filegraph.dot +++ b/filegraph.dot @@ -27,6 +27,9 @@ strict digraph luaotfload_files { //looks weird with circo ... /* ···································································· * file structure * ································································· */ + fontdbutil -> font_names [label="--update", + style=dashed] + luaotfload -> otfl_fonts_merged [label="merged"] luaotfload -> merged_lua_libs [label="unmerged", style=solid] luaotfload -> merged_luatex_fonts [label="unmerged", style=solid] @@ -35,7 +38,6 @@ strict digraph luaotfload_files { //looks weird with circo ... luaotfload -> luaotfload_libs luaotfload -> otfl_blacklist_cnf - otfl_fonts_merged -> merged_lua_libs [label="merged", style=dotted, lhead=cluster_merged] @@ -46,12 +48,36 @@ strict digraph luaotfload_files { //looks weird with circo ... style=dotted, lhead=cluster_merged] + merged_luatex_fonts -> font_age [label="luatex-fonts-enc.lua", + ltail=cluster_merged] + + luaotfload_libs -> font_names [label="luaotfload-database.lua"] + mkglyphlist -> font_age [label="generates from glyphlist.txt", + style=dashed] + + subgraph { rank = same; mkglyphlist; fontdbutil; luaotfload } /* ···································································· * main files * ································································· */ + fontdbutil [label = "fontdbutil\nmkluatexfontdb.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#01012222", + style = "filled,rounded", + penwidth=2] + + mkglyphlist [label = "mkglyphlist", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#01012222", + style = "filled,rounded", + penwidth=2] + luaotfload [label = "luaotfload.lua", shape = rect, width = "3.2cm", @@ -81,6 +107,22 @@ strict digraph luaotfload_files { //looks weird with circo ... * ································································· */ + font_age [style = "filled,dashed", + shape = rect, + width = "3.2cm", + fillcolor = "#01012222", + color = grey40, + style = "filled,dotted,rounded", + label = "font-age.lua"] + + font_names [style = "filled,dashed", + shape = rect, + width = "3.2cm", + fillcolor = "#01012222", + color = grey40, + style = "filled,dotted,rounded", + label = "luaotfload-names.lua\nluaotfload-names.luc"] + otfl_blacklist_cnf [style = "filled,dashed", shape = rect, width = "3.2cm", @@ -97,10 +139,9 @@ strict digraph luaotfload_files { //looks weird with circo ... label = < <table cellborder="0" bgcolor="#FFFFFFAA"> <th> <td colspan="2"> <font point-size="12" face="Iwona Italic">Luaotfload Libraries</font> </td> </th> - <tr> <td>luaotfload-font-otc.lua</td> <td>luaotfload-lib-dir.lua</td> </tr> - <tr> <td>luaotfload-override.lua</td> <td>luaotfload-loaders.lua</td> </tr> - <tr> <td>luaotfload-database.lua</td> <td>luaotfload-color.lua</td> </tr> - <tr> <td>luaotfload-features.lua</td> </tr> + <tr> <td>luaotfload-lib-dir.lua</td> <td>luaotfload-features.lua</td> </tr> + <tr> <td>luaotfload-override.lua</td> <td>luaotfload-loaders.lua</td> </tr> + <tr> <td>luaotfload-database.lua</td> <td>luaotfload-color.lua</td> </tr> </table> >, ] diff --git a/font-age.lua b/font-age.lua deleted file mode 100644 index 741bb47..0000000 --- a/font-age.lua +++ /dev/null @@ -1,3744 +0,0 @@ -if not modules then modules = { } end modules ['font-age'] = { - version = 1.001, - comment = "companion to font-gee.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "derived from http://www.adobe.com/devnet/opentype/archives/glyphlist.txt", - original = "Adobe Glyph List, version 2.0, September 20, 2002", -} - -if context then - texio.write_nl("fatal error: this module is not for context") - os.exit() -end - -return { -- generated - ["A"]=65, - ["AE"]=198, - ["AEacute"]=508, - ["AEmacron"]=482, - ["Aacute"]=193, - ["Abreve"]=258, - ["Abreveacute"]=7854, - ["Abrevecyrillic"]=1232, - ["Abrevedotbelow"]=7862, - ["Abrevegrave"]=7856, - ["Abrevehookabove"]=7858, - ["Abrevetilde"]=7860, - ["Acaron"]=461, - ["Acircle"]=9398, - ["Acircumflex"]=194, - ["Acircumflexacute"]=7844, - ["Acircumflexdotbelow"]=7852, - ["Acircumflexgrave"]=7846, - ["Acircumflexhookabove"]=7848, - ["Acircumflextilde"]=7850, - ["Adblgrave"]=512, - ["Adieresis"]=196, - ["Adieresiscyrillic"]=1234, - ["Adieresismacron"]=478, - ["Adotbelow"]=7840, - ["Adotmacron"]=480, - ["Agrave"]=192, - ["Ahookabove"]=7842, - ["Aiecyrillic"]=1236, - ["Ainvertedbreve"]=514, - ["Alpha"]=913, - ["Alphatonos"]=902, - ["Amacron"]=256, - ["Amonospace"]=65313, - ["Aogonek"]=260, - ["Aring"]=197, - ["Aringacute"]=506, - ["Aringbelow"]=7680, - ["Atilde"]=195, - ["Aybarmenian"]=1329, - ["B"]=66, - ["Bcircle"]=9399, - ["Bdotaccent"]=7682, - ["Bdotbelow"]=7684, - ["Benarmenian"]=1330, - ["Beta"]=914, - ["Bhook"]=385, - ["Blinebelow"]=7686, - ["Bmonospace"]=65314, - ["Btopbar"]=386, - ["C"]=67, - ["Caarmenian"]=1342, - ["Cacute"]=262, - ["Ccaron"]=268, - ["Ccedilla"]=199, - ["Ccedillaacute"]=7688, - ["Ccircle"]=9400, - ["Ccircumflex"]=264, - ["Cdotaccent"]=266, - ["Chaarmenian"]=1353, - ["Cheabkhasiancyrillic"]=1212, - ["Chedescenderabkhasiancyrillic"]=1214, - ["Chedescendercyrillic"]=1206, - ["Chedieresiscyrillic"]=1268, - ["Cheharmenian"]=1347, - ["Chekhakassiancyrillic"]=1227, - ["Cheverticalstrokecyrillic"]=1208, - ["Chi"]=935, - ["Chook"]=391, - ["Cmonospace"]=65315, - ["Coarmenian"]=1361, - ["D"]=68, - ["DZ"]=497, - ["DZcaron"]=452, - ["Daarmenian"]=1332, - ["Dafrican"]=393, - ["Dcaron"]=270, - ["Dcedilla"]=7696, - ["Dcircle"]=9401, - ["Dcircumflexbelow"]=7698, - ["Ddotaccent"]=7690, - ["Ddotbelow"]=7692, - ["Deicoptic"]=1006, - ["Deltagreek"]=916, - ["Dhook"]=394, - ["Digammagreek"]=988, - ["Dlinebelow"]=7694, - ["Dmonospace"]=65316, - ["Dslash"]=272, - ["Dtopbar"]=395, - ["Dz"]=498, - ["Dzcaron"]=453, - ["Dzeabkhasiancyrillic"]=1248, - ["E"]=69, - ["Eacute"]=201, - ["Ebreve"]=276, - ["Ecaron"]=282, - ["Ecedillabreve"]=7708, - ["Echarmenian"]=1333, - ["Ecircle"]=9402, - ["Ecircumflex"]=202, - ["Ecircumflexacute"]=7870, - ["Ecircumflexbelow"]=7704, - ["Ecircumflexdotbelow"]=7878, - ["Ecircumflexgrave"]=7872, - ["Ecircumflexhookabove"]=7874, - ["Ecircumflextilde"]=7876, - ["Edblgrave"]=516, - ["Edieresis"]=203, - ["Edotaccent"]=278, - ["Edotbelow"]=7864, - ["Egrave"]=200, - ["Eharmenian"]=1335, - ["Ehookabove"]=7866, - ["Eightroman"]=8551, - ["Einvertedbreve"]=518, - ["Eiotifiedcyrillic"]=1124, - ["Elevenroman"]=8554, - ["Emacron"]=274, - ["Emacronacute"]=7702, - ["Emacrongrave"]=7700, - ["Emonospace"]=65317, - ["Endescendercyrillic"]=1186, - ["Eng"]=330, - ["Enghecyrillic"]=1188, - ["Enhookcyrillic"]=1223, - ["Eogonek"]=280, - ["Eopen"]=400, - ["Epsilon"]=917, - ["Epsilontonos"]=904, - ["Ereversed"]=398, - ["Esdescendercyrillic"]=1194, - ["Esh"]=425, - ["Eta"]=919, - ["Etarmenian"]=1336, - ["Etatonos"]=905, - ["Eth"]=208, - ["Etilde"]=7868, - ["Etildebelow"]=7706, - ["Ezh"]=439, - ["Ezhcaron"]=494, - ["Ezhreversed"]=440, - ["F"]=70, - ["Fcircle"]=9403, - ["Fdotaccent"]=7710, - ["Feharmenian"]=1366, - ["Feicoptic"]=996, - ["Fhook"]=401, - ["Fiveroman"]=8548, - ["Fmonospace"]=65318, - ["Fourroman"]=8547, - ["G"]=71, - ["GBsquare"]=13191, - ["Gacute"]=500, - ["Gamma"]=915, - ["Gammaafrican"]=404, - ["Gangiacoptic"]=1002, - ["Gbreve"]=286, - ["Gcaron"]=486, - ["Gcircle"]=9404, - ["Gcircumflex"]=284, - ["Gcommaaccent"]=290, - ["Gdotaccent"]=288, - ["Ghadarmenian"]=1346, - ["Ghemiddlehookcyrillic"]=1172, - ["Ghestrokecyrillic"]=1170, - ["Ghook"]=403, - ["Gimarmenian"]=1331, - ["Gmacron"]=7712, - ["Gmonospace"]=65319, - ["Gsmallhook"]=667, - ["Gstroke"]=484, - ["H"]=72, - ["HPsquare"]=13259, - ["Haabkhasiancyrillic"]=1192, - ["Hadescendercyrillic"]=1202, - ["Hbar"]=294, - ["Hbrevebelow"]=7722, - ["Hcedilla"]=7720, - ["Hcircle"]=9405, - ["Hcircumflex"]=292, - ["Hdieresis"]=7718, - ["Hdotaccent"]=7714, - ["Hdotbelow"]=7716, - ["Hmonospace"]=65320, - ["Hoarmenian"]=1344, - ["Horicoptic"]=1000, - ["Hzsquare"]=13200, - ["I"]=73, - ["IJ"]=306, - ["Iacute"]=205, - ["Ibreve"]=300, - ["Icaron"]=463, - ["Icircle"]=9406, - ["Icircumflex"]=206, - ["Idblgrave"]=520, - ["Idieresis"]=207, - ["Idieresisacute"]=7726, - ["Idieresiscyrillic"]=1252, - ["Idotaccent"]=304, - ["Idotbelow"]=7882, - ["Iebrevecyrillic"]=1238, - ["Ifraktur"]=8465, - ["Igrave"]=204, - ["Ihookabove"]=7880, - ["Iinvertedbreve"]=522, - ["Imacron"]=298, - ["Imacroncyrillic"]=1250, - ["Imonospace"]=65321, - ["Iniarmenian"]=1339, - ["Iogonek"]=302, - ["Iota"]=921, - ["Iotaafrican"]=406, - ["Iotadieresis"]=938, - ["Iotatonos"]=906, - ["Istroke"]=407, - ["Itilde"]=296, - ["Itildebelow"]=7724, - ["Izhitsadblgravecyrillic"]=1142, - ["J"]=74, - ["Jaarmenian"]=1345, - ["Jcircle"]=9407, - ["Jcircumflex"]=308, - ["Jheharmenian"]=1355, - ["Jmonospace"]=65322, - ["K"]=75, - ["KBsquare"]=13189, - ["KKsquare"]=13261, - ["Kabashkircyrillic"]=1184, - ["Kacute"]=7728, - ["Kadescendercyrillic"]=1178, - ["Kahookcyrillic"]=1219, - ["Kappa"]=922, - ["Kastrokecyrillic"]=1182, - ["Kaverticalstrokecyrillic"]=1180, - ["Kcaron"]=488, - ["Kcircle"]=9408, - ["Kcommaaccent"]=310, - ["Kdotbelow"]=7730, - ["Keharmenian"]=1364, - ["Kenarmenian"]=1343, - ["Kheicoptic"]=998, - ["Khook"]=408, - ["Klinebelow"]=7732, - ["Kmonospace"]=65323, - ["Koppacyrillic"]=1152, - ["Koppagreek"]=990, - ["Ksicyrillic"]=1134, - ["L"]=76, - ["LJ"]=455, - ["Lacute"]=313, - ["Lambda"]=923, - ["Lcaron"]=317, - ["Lcircle"]=9409, - ["Lcircumflexbelow"]=7740, - ["Lcommaaccent"]=315, - ["Ldotaccent"]=319, - ["Ldotbelow"]=7734, - ["Ldotbelowmacron"]=7736, - ["Liwnarmenian"]=1340, - ["Lj"]=456, - ["Llinebelow"]=7738, - ["Lmonospace"]=65324, - ["Lslash"]=321, - ["M"]=77, - ["MBsquare"]=13190, - ["Macute"]=7742, - ["Mcircle"]=9410, - ["Mdotaccent"]=7744, - ["Mdotbelow"]=7746, - ["Menarmenian"]=1348, - ["Mmonospace"]=65325, - ["Mturned"]=412, - ["Mu"]=924, - ["N"]=78, - ["NJ"]=458, - ["Nacute"]=323, - ["Ncaron"]=327, - ["Ncircle"]=9411, - ["Ncircumflexbelow"]=7754, - ["Ncommaaccent"]=325, - ["Ndotaccent"]=7748, - ["Ndotbelow"]=7750, - ["Nhookleft"]=413, - ["Nineroman"]=8552, - ["Nj"]=459, - ["Nlinebelow"]=7752, - ["Nmonospace"]=65326, - ["Nowarmenian"]=1350, - ["Ntilde"]=209, - ["Nu"]=925, - ["O"]=79, - ["OE"]=338, - ["Oacute"]=211, - ["Obarredcyrillic"]=1256, - ["Obarreddieresiscyrillic"]=1258, - ["Obreve"]=334, - ["Ocaron"]=465, - ["Ocenteredtilde"]=415, - ["Ocircle"]=9412, - ["Ocircumflex"]=212, - ["Ocircumflexacute"]=7888, - ["Ocircumflexdotbelow"]=7896, - ["Ocircumflexgrave"]=7890, - ["Ocircumflexhookabove"]=7892, - ["Ocircumflextilde"]=7894, - ["Odblgrave"]=524, - ["Odieresis"]=214, - ["Odieresiscyrillic"]=1254, - ["Odotbelow"]=7884, - ["Ograve"]=210, - ["Oharmenian"]=1365, - ["Ohookabove"]=7886, - ["Ohorn"]=416, - ["Ohornacute"]=7898, - ["Ohorndotbelow"]=7906, - ["Ohorngrave"]=7900, - ["Ohornhookabove"]=7902, - ["Ohorntilde"]=7904, - ["Ohungarumlaut"]=336, - ["Oi"]=418, - ["Oinvertedbreve"]=526, - ["Omacron"]=332, - ["Omacronacute"]=7762, - ["Omacrongrave"]=7760, - ["Omega"]=8486, - ["Omegacyrillic"]=1120, - ["Omegagreek"]=937, - ["Omegaroundcyrillic"]=1146, - ["Omegatitlocyrillic"]=1148, - ["Omegatonos"]=911, - ["Omicron"]=927, - ["Omicrontonos"]=908, - ["Omonospace"]=65327, - ["Oneroman"]=8544, - ["Oogonek"]=490, - ["Oogonekmacron"]=492, - ["Oopen"]=390, - ["Oslash"]=216, - ["Ostrokeacute"]=510, - ["Otcyrillic"]=1150, - ["Otilde"]=213, - ["Otildeacute"]=7756, - ["Otildedieresis"]=7758, - ["P"]=80, - ["Pacute"]=7764, - ["Pcircle"]=9413, - ["Pdotaccent"]=7766, - ["Peharmenian"]=1354, - ["Pemiddlehookcyrillic"]=1190, - ["Phi"]=934, - ["Phook"]=420, - ["Pi"]=928, - ["Piwrarmenian"]=1363, - ["Pmonospace"]=65328, - ["Psi"]=936, - ["Psicyrillic"]=1136, - ["Q"]=81, - ["Qcircle"]=9414, - ["Qmonospace"]=65329, - ["R"]=82, - ["Raarmenian"]=1356, - ["Racute"]=340, - ["Rcaron"]=344, - ["Rcircle"]=9415, - ["Rcommaaccent"]=342, - ["Rdblgrave"]=528, - ["Rdotaccent"]=7768, - ["Rdotbelow"]=7770, - ["Rdotbelowmacron"]=7772, - ["Reharmenian"]=1360, - ["Rfraktur"]=8476, - ["Rho"]=929, - ["Rinvertedbreve"]=530, - ["Rlinebelow"]=7774, - ["Rmonospace"]=65330, - ["Rsmallinverted"]=641, - ["Rsmallinvertedsuperior"]=694, - ["S"]=83, - ["SF010000"]=9484, - ["SF020000"]=9492, - ["SF030000"]=9488, - ["SF040000"]=9496, - ["SF050000"]=9532, - ["SF060000"]=9516, - ["SF070000"]=9524, - ["SF080000"]=9500, - ["SF090000"]=9508, - ["SF100000"]=9472, - ["SF110000"]=9474, - ["SF190000"]=9569, - ["SF200000"]=9570, - ["SF210000"]=9558, - ["SF220000"]=9557, - ["SF230000"]=9571, - ["SF240000"]=9553, - ["SF250000"]=9559, - ["SF260000"]=9565, - ["SF270000"]=9564, - ["SF280000"]=9563, - ["SF360000"]=9566, - ["SF370000"]=9567, - ["SF380000"]=9562, - ["SF390000"]=9556, - ["SF400000"]=9577, - ["SF410000"]=9574, - ["SF420000"]=9568, - ["SF430000"]=9552, - ["SF440000"]=9580, - ["SF450000"]=9575, - ["SF460000"]=9576, - ["SF470000"]=9572, - ["SF480000"]=9573, - ["SF490000"]=9561, - ["SF500000"]=9560, - ["SF510000"]=9554, - ["SF520000"]=9555, - ["SF530000"]=9579, - ["SF540000"]=9578, - ["Sacute"]=346, - ["Sacutedotaccent"]=7780, - ["Sampigreek"]=992, - ["Scaron"]=352, - ["Scarondotaccent"]=7782, - ["Scedilla"]=350, - ["Schwa"]=399, - ["Schwacyrillic"]=1240, - ["Schwadieresiscyrillic"]=1242, - ["Scircle"]=9416, - ["Scircumflex"]=348, - ["Scommaaccent"]=536, - ["Sdotaccent"]=7776, - ["Sdotbelow"]=7778, - ["Sdotbelowdotaccent"]=7784, - ["Seharmenian"]=1357, - ["Sevenroman"]=8550, - ["Shaarmenian"]=1351, - ["Sheicoptic"]=994, - ["Shhacyrillic"]=1210, - ["Shimacoptic"]=1004, - ["Sigma"]=931, - ["Sixroman"]=8549, - ["Smonospace"]=65331, - ["Stigmagreek"]=986, - ["T"]=84, - ["Tau"]=932, - ["Tbar"]=358, - ["Tcaron"]=356, - ["Tcircle"]=9417, - ["Tcircumflexbelow"]=7792, - ["Tcommaaccent"]=354, - ["Tdotaccent"]=7786, - ["Tdotbelow"]=7788, - ["Tedescendercyrillic"]=1196, - ["Tenroman"]=8553, - ["Tetsecyrillic"]=1204, - ["Theta"]=920, - ["Thook"]=428, - ["Thorn"]=222, - ["Threeroman"]=8546, - ["Tiwnarmenian"]=1359, - ["Tlinebelow"]=7790, - ["Tmonospace"]=65332, - ["Toarmenian"]=1337, - ["Tonefive"]=444, - ["Tonesix"]=388, - ["Tonetwo"]=423, - ["Tretroflexhook"]=430, - ["Twelveroman"]=8555, - ["Tworoman"]=8545, - ["U"]=85, - ["Uacute"]=218, - ["Ubreve"]=364, - ["Ucaron"]=467, - ["Ucircle"]=9418, - ["Ucircumflex"]=219, - ["Ucircumflexbelow"]=7798, - ["Udblgrave"]=532, - ["Udieresis"]=220, - ["Udieresisacute"]=471, - ["Udieresisbelow"]=7794, - ["Udieresiscaron"]=473, - ["Udieresiscyrillic"]=1264, - ["Udieresisgrave"]=475, - ["Udieresismacron"]=469, - ["Udotbelow"]=7908, - ["Ugrave"]=217, - ["Uhookabove"]=7910, - ["Uhorn"]=431, - ["Uhornacute"]=7912, - ["Uhorndotbelow"]=7920, - ["Uhorngrave"]=7914, - ["Uhornhookabove"]=7916, - ["Uhorntilde"]=7918, - ["Uhungarumlaut"]=368, - ["Uhungarumlautcyrillic"]=1266, - ["Uinvertedbreve"]=534, - ["Ukcyrillic"]=1144, - ["Umacron"]=362, - ["Umacroncyrillic"]=1262, - ["Umacrondieresis"]=7802, - ["Umonospace"]=65333, - ["Uogonek"]=370, - ["Upsilon"]=933, - ["Upsilonacutehooksymbolgreek"]=979, - ["Upsilonafrican"]=433, - ["Upsilondieresis"]=939, - ["Upsilondieresishooksymbolgreek"]=980, - ["Upsilonhooksymbol"]=978, - ["Upsilontonos"]=910, - ["Uring"]=366, - ["Ustraightcyrillic"]=1198, - ["Ustraightstrokecyrillic"]=1200, - ["Utilde"]=360, - ["Utildeacute"]=7800, - ["Utildebelow"]=7796, - ["V"]=86, - ["Vcircle"]=9419, - ["Vdotbelow"]=7806, - ["Vewarmenian"]=1358, - ["Vhook"]=434, - ["Vmonospace"]=65334, - ["Voarmenian"]=1352, - ["Vtilde"]=7804, - ["W"]=87, - ["Wacute"]=7810, - ["Wcircle"]=9420, - ["Wcircumflex"]=372, - ["Wdieresis"]=7812, - ["Wdotaccent"]=7814, - ["Wdotbelow"]=7816, - ["Wgrave"]=7808, - ["Wmonospace"]=65335, - ["X"]=88, - ["Xcircle"]=9421, - ["Xdieresis"]=7820, - ["Xdotaccent"]=7818, - ["Xeharmenian"]=1341, - ["Xi"]=926, - ["Xmonospace"]=65336, - ["Y"]=89, - ["Yacute"]=221, - ["Ycircle"]=9422, - ["Ycircumflex"]=374, - ["Ydieresis"]=376, - ["Ydotaccent"]=7822, - ["Ydotbelow"]=7924, - ["Yerudieresiscyrillic"]=1272, - ["Ygrave"]=7922, - ["Yhook"]=435, - ["Yhookabove"]=7926, - ["Yiarmenian"]=1349, - ["Yiwnarmenian"]=1362, - ["Ymonospace"]=65337, - ["Ytilde"]=7928, - ["Yusbigcyrillic"]=1130, - ["Yusbigiotifiedcyrillic"]=1132, - ["Yuslittlecyrillic"]=1126, - ["Yuslittleiotifiedcyrillic"]=1128, - ["Z"]=90, - ["Zaarmenian"]=1334, - ["Zacute"]=377, - ["Zcaron"]=381, - ["Zcircle"]=9423, - ["Zcircumflex"]=7824, - ["Zdotaccent"]=379, - ["Zdotbelow"]=7826, - ["Zedescendercyrillic"]=1176, - ["Zedieresiscyrillic"]=1246, - ["Zeta"]=918, - ["Zhearmenian"]=1338, - ["Zhebrevecyrillic"]=1217, - ["Zhedescendercyrillic"]=1174, - ["Zhedieresiscyrillic"]=1244, - ["Zlinebelow"]=7828, - ["Zmonospace"]=65338, - ["Zstroke"]=437, - ["a"]=97, - ["aabengali"]=2438, - ["aacute"]=225, - ["aadeva"]=2310, - ["aagujarati"]=2694, - ["aagurmukhi"]=2566, - ["aamatragurmukhi"]=2622, - ["aarusquare"]=13059, - ["aavowelsignbengali"]=2494, - ["aavowelsigndeva"]=2366, - ["aavowelsigngujarati"]=2750, - ["abbreviationmarkarmenian"]=1375, - ["abbreviationsigndeva"]=2416, - ["abengali"]=2437, - ["abopomofo"]=12570, - ["abreve"]=259, - ["abreveacute"]=7855, - ["abrevecyrillic"]=1233, - ["abrevedotbelow"]=7863, - ["abrevegrave"]=7857, - ["abrevehookabove"]=7859, - ["abrevetilde"]=7861, - ["acaron"]=462, - ["acircle"]=9424, - ["acircumflex"]=226, - ["acircumflexacute"]=7845, - ["acircumflexdotbelow"]=7853, - ["acircumflexgrave"]=7847, - ["acircumflexhookabove"]=7849, - ["acircumflextilde"]=7851, - ["acute"]=180, - ["acutebelowcmb"]=791, - ["acutecomb"]=769, - ["acutedeva"]=2388, - ["acutelowmod"]=719, - ["acutetonecmb"]=833, - ["adblgrave"]=513, - ["addakgurmukhi"]=2673, - ["adeva"]=2309, - ["adieresis"]=228, - ["adieresiscyrillic"]=1235, - ["adieresismacron"]=479, - ["adotbelow"]=7841, - ["adotmacron"]=481, - ["ae"]=230, - ["aeacute"]=509, - ["aekorean"]=12624, - ["aemacron"]=483, - ["afii10017"]=1040, - ["afii10018"]=1041, - ["afii10019"]=1042, - ["afii10020"]=1043, - ["afii10021"]=1044, - ["afii10022"]=1045, - ["afii10023"]=1025, - ["afii10024"]=1046, - ["afii10025"]=1047, - ["afii10026"]=1048, - ["afii10027"]=1049, - ["afii10028"]=1050, - ["afii10029"]=1051, - ["afii10030"]=1052, - ["afii10031"]=1053, - ["afii10032"]=1054, - ["afii10033"]=1055, - ["afii10034"]=1056, - ["afii10035"]=1057, - ["afii10036"]=1058, - ["afii10037"]=1059, - ["afii10038"]=1060, - ["afii10039"]=1061, - ["afii10040"]=1062, - ["afii10041"]=1063, - ["afii10042"]=1064, - ["afii10043"]=1065, - ["afii10044"]=1066, - ["afii10045"]=1067, - ["afii10046"]=1068, - ["afii10047"]=1069, - ["afii10048"]=1070, - ["afii10049"]=1071, - ["afii10050"]=1168, - ["afii10051"]=1026, - ["afii10052"]=1027, - ["afii10053"]=1028, - ["afii10054"]=1029, - ["afii10055"]=1030, - ["afii10056"]=1031, - ["afii10057"]=1032, - ["afii10058"]=1033, - ["afii10059"]=1034, - ["afii10060"]=1035, - ["afii10061"]=1036, - ["afii10062"]=1038, - ["afii10065"]=1072, - ["afii10145"]=1039, - ["afii10146"]=1122, - ["afii10147"]=1138, - ["afii10148"]=1140, - ["afii299"]=8206, - ["afii300"]=8207, - ["afii301"]=8205, - ["afii57534"]=1749, - ["afii61573"]=8236, - ["afii61574"]=8237, - ["afii61575"]=8238, - ["agrave"]=224, - ["agujarati"]=2693, - ["agurmukhi"]=2565, - ["ahiragana"]=12354, - ["ahookabove"]=7843, - ["aibengali"]=2448, - ["aibopomofo"]=12574, - ["aideva"]=2320, - ["aiecyrillic"]=1237, - ["aigujarati"]=2704, - ["aigurmukhi"]=2576, - ["aimatragurmukhi"]=2632, - ["ainarabic"]=1593, - ["ainfinalarabic"]=65226, - ["aininitialarabic"]=65227, - ["ainmedialarabic"]=65228, - ["ainvertedbreve"]=515, - ["aivowelsignbengali"]=2504, - ["aivowelsigndeva"]=2376, - ["aivowelsigngujarati"]=2760, - ["akatakana"]=12450, - ["akatakanahalfwidth"]=65393, - ["akorean"]=12623, - ["alefarabic"]=1575, - ["alefdageshhebrew"]=64304, - ["aleffinalarabic"]=65166, - ["alefhamzaabovearabic"]=1571, - ["alefhamzaabovefinalarabic"]=65156, - ["alefhamzabelowarabic"]=1573, - ["alefhamzabelowfinalarabic"]=65160, - ["alefhebrew"]=1488, - ["aleflamedhebrew"]=64335, - ["alefmaddaabovearabic"]=1570, - ["alefmaddaabovefinalarabic"]=65154, - ["alefmaksuraarabic"]=1609, - ["alefmaksurafinalarabic"]=65264, - ["alefpatahhebrew"]=64302, - ["alefqamatshebrew"]=64303, - ["aleph"]=8501, - ["allequal"]=8780, - ["alpha"]=945, - ["alphatonos"]=940, - ["amacron"]=257, - ["amonospace"]=65345, - ["ampersand"]=38, - ["ampersandmonospace"]=65286, - ["amsquare"]=13250, - ["anbopomofo"]=12578, - ["angbopomofo"]=12580, - ["angkhankhuthai"]=3674, - ["angle"]=8736, - ["anglebracketleft"]=12296, - ["anglebracketleftvertical"]=65087, - ["anglebracketright"]=12297, - ["anglebracketrightvertical"]=65088, - ["angleleft"]=9001, - ["angleright"]=9002, - ["angstrom"]=8491, - ["anoteleia"]=903, - ["anudattadeva"]=2386, - ["anusvarabengali"]=2434, - ["anusvaradeva"]=2306, - ["anusvaragujarati"]=2690, - ["aogonek"]=261, - ["apaatosquare"]=13056, - ["aparen"]=9372, - ["apostrophearmenian"]=1370, - ["apostrophemod"]=700, - ["apple"]=63743, - ["approaches"]=8784, - ["approxequal"]=8776, - ["approxequalorimage"]=8786, - ["araeaekorean"]=12686, - ["araeakorean"]=12685, - ["arc"]=8978, - ["arighthalfring"]=7834, - ["aring"]=229, - ["aringacute"]=507, - ["aringbelow"]=7681, - ["arrowboth"]=8596, - ["arrowdashdown"]=8675, - ["arrowdashleft"]=8672, - ["arrowdashright"]=8674, - ["arrowdashup"]=8673, - ["arrowdbldown"]=8659, - ["arrowdblup"]=8657, - ["arrowdown"]=8595, - ["arrowdownleft"]=8601, - ["arrowdownright"]=8600, - ["arrowdownwhite"]=8681, - ["arrowheaddownmod"]=709, - ["arrowheadleftmod"]=706, - ["arrowheadrightmod"]=707, - ["arrowheadupmod"]=708, - ["arrowleft"]=8592, - ["arrowleftdbl"]=8656, - ["arrowleftdblstroke"]=8653, - ["arrowleftoverright"]=8646, - ["arrowleftwhite"]=8678, - ["arrowright"]=8594, - ["arrowrightdblstroke"]=8655, - ["arrowrightheavy"]=10142, - ["arrowrightoverleft"]=8644, - ["arrowrightwhite"]=8680, - ["arrowtableft"]=8676, - ["arrowtabright"]=8677, - ["arrowup"]=8593, - ["arrowupdn"]=8597, - ["arrowupdownbase"]=8616, - ["arrowupleft"]=8598, - ["arrowupleftofdown"]=8645, - ["arrowupright"]=8599, - ["arrowupwhite"]=8679, - ["asciicircum"]=94, - ["asciicircummonospace"]=65342, - ["asciitilde"]=126, - ["asciitildemonospace"]=65374, - ["ascript"]=593, - ["ascriptturned"]=594, - ["asmallhiragana"]=12353, - ["asmallkatakana"]=12449, - ["asmallkatakanahalfwidth"]=65383, - ["asterisk"]=42, - ["asteriskarabic"]=1645, - ["asteriskmath"]=8727, - ["asteriskmonospace"]=65290, - ["asterisksmall"]=65121, - ["asterism"]=8258, - ["asymptoticallyequal"]=8771, - ["at"]=64, - ["atilde"]=227, - ["atmonospace"]=65312, - ["atsmall"]=65131, - ["aturned"]=592, - ["aubengali"]=2452, - ["aubopomofo"]=12576, - ["audeva"]=2324, - ["augujarati"]=2708, - ["augurmukhi"]=2580, - ["aulengthmarkbengali"]=2519, - ["aumatragurmukhi"]=2636, - ["auvowelsignbengali"]=2508, - ["auvowelsigndeva"]=2380, - ["auvowelsigngujarati"]=2764, - ["avagrahadeva"]=2365, - ["aybarmenian"]=1377, - ["ayinaltonehebrew"]=64288, - ["ayinhebrew"]=1506, - ["b"]=98, - ["babengali"]=2476, - ["backslash"]=92, - ["backslashmonospace"]=65340, - ["badeva"]=2348, - ["bagujarati"]=2732, - ["bagurmukhi"]=2604, - ["bahiragana"]=12400, - ["bahtthai"]=3647, - ["bakatakana"]=12496, - ["barmonospace"]=65372, - ["bbopomofo"]=12549, - ["bcircle"]=9425, - ["bdotaccent"]=7683, - ["bdotbelow"]=7685, - ["beamedsixteenthnotes"]=9836, - ["because"]=8757, - ["becyrillic"]=1073, - ["beharabic"]=1576, - ["behfinalarabic"]=65168, - ["behinitialarabic"]=65169, - ["behiragana"]=12409, - ["behmedialarabic"]=65170, - ["behmeeminitialarabic"]=64671, - ["behmeemisolatedarabic"]=64520, - ["behnoonfinalarabic"]=64621, - ["bekatakana"]=12505, - ["benarmenian"]=1378, - ["beta"]=946, - ["betasymbolgreek"]=976, - ["betdageshhebrew"]=64305, - ["bethebrew"]=1489, - ["betrafehebrew"]=64332, - ["bhabengali"]=2477, - ["bhadeva"]=2349, - ["bhagujarati"]=2733, - ["bhagurmukhi"]=2605, - ["bhook"]=595, - ["bihiragana"]=12403, - ["bikatakana"]=12499, - ["bilabialclick"]=664, - ["bindigurmukhi"]=2562, - ["birusquare"]=13105, - ["blackcircle"]=9679, - ["blackdiamond"]=9670, - ["blackleftpointingtriangle"]=9664, - ["blacklenticularbracketleft"]=12304, - ["blacklenticularbracketleftvertical"]=65083, - ["blacklenticularbracketright"]=12305, - ["blacklenticularbracketrightvertical"]=65084, - ["blacklowerlefttriangle"]=9699, - ["blacklowerrighttriangle"]=9698, - ["blackrightpointingtriangle"]=9654, - ["blacksmallsquare"]=9642, - ["blackstar"]=9733, - ["blackupperlefttriangle"]=9700, - ["blackupperrighttriangle"]=9701, - ["blackuppointingsmalltriangle"]=9652, - ["blank"]=9251, - ["blinebelow"]=7687, - ["block"]=9608, - ["bmonospace"]=65346, - ["bobaimaithai"]=3610, - ["bohiragana"]=12412, - ["bokatakana"]=12508, - ["bparen"]=9373, - ["bqsquare"]=13251, - ["braceleft"]=123, - ["braceleftmonospace"]=65371, - ["braceleftsmall"]=65115, - ["braceleftvertical"]=65079, - ["braceright"]=125, - ["bracerightmonospace"]=65373, - ["bracerightsmall"]=65116, - ["bracerightvertical"]=65080, - ["bracketleft"]=91, - ["bracketleftmonospace"]=65339, - ["bracketright"]=93, - ["bracketrightmonospace"]=65341, - ["breve"]=728, - ["brevebelowcmb"]=814, - ["brevecmb"]=774, - ["breveinvertedbelowcmb"]=815, - ["breveinvertedcmb"]=785, - ["breveinverteddoublecmb"]=865, - ["bridgebelowcmb"]=810, - ["bridgeinvertedbelowcmb"]=826, - ["brokenbar"]=166, - ["bstroke"]=384, - ["btopbar"]=387, - ["buhiragana"]=12406, - ["bukatakana"]=12502, - ["bullet"]=8226, - ["bulletoperator"]=8729, - ["bullseye"]=9678, - ["c"]=99, - ["caarmenian"]=1390, - ["cabengali"]=2458, - ["cacute"]=263, - ["cadeva"]=2330, - ["cagujarati"]=2714, - ["cagurmukhi"]=2586, - ["calsquare"]=13192, - ["candrabindubengali"]=2433, - ["candrabinducmb"]=784, - ["candrabindudeva"]=2305, - ["candrabindugujarati"]=2689, - ["capslock"]=8682, - ["careof"]=8453, - ["caron"]=711, - ["caronbelowcmb"]=812, - ["caroncmb"]=780, - ["carriagereturn"]=8629, - ["cbopomofo"]=12568, - ["ccaron"]=269, - ["ccedilla"]=231, - ["ccedillaacute"]=7689, - ["ccircle"]=9426, - ["ccircumflex"]=265, - ["ccurl"]=597, - ["cdotaccent"]=267, - ["cdsquare"]=13253, - ["cedilla"]=184, - ["cedillacmb"]=807, - ["cent"]=162, - ["centigrade"]=8451, - ["centmonospace"]=65504, - ["chaarmenian"]=1401, - ["chabengali"]=2459, - ["chadeva"]=2331, - ["chagujarati"]=2715, - ["chagurmukhi"]=2587, - ["chbopomofo"]=12564, - ["cheabkhasiancyrillic"]=1213, - ["checkmark"]=10003, - ["checyrillic"]=1095, - ["chedescenderabkhasiancyrillic"]=1215, - ["chedescendercyrillic"]=1207, - ["chedieresiscyrillic"]=1269, - ["cheharmenian"]=1395, - ["chekhakassiancyrillic"]=1228, - ["cheverticalstrokecyrillic"]=1209, - ["chi"]=967, - ["chieuchacirclekorean"]=12919, - ["chieuchaparenkorean"]=12823, - ["chieuchcirclekorean"]=12905, - ["chieuchkorean"]=12618, - ["chieuchparenkorean"]=12809, - ["chochangthai"]=3594, - ["chochanthai"]=3592, - ["chochingthai"]=3593, - ["chochoethai"]=3596, - ["chook"]=392, - ["cieucacirclekorean"]=12918, - ["cieucaparenkorean"]=12822, - ["cieuccirclekorean"]=12904, - ["cieuckorean"]=12616, - ["cieucparenkorean"]=12808, - ["cieucuparenkorean"]=12828, - ["circleot"]=8857, - ["circlepostalmark"]=12342, - ["circlewithlefthalfblack"]=9680, - ["circlewithrighthalfblack"]=9681, - ["circumflex"]=710, - ["circumflexbelowcmb"]=813, - ["circumflexcmb"]=770, - ["clear"]=8999, - ["clickalveolar"]=450, - ["clickdental"]=448, - ["clicklateral"]=449, - ["clickretroflex"]=451, - ["clubsuitblack"]=9827, - ["clubsuitwhite"]=9831, - ["cmcubedsquare"]=13220, - ["cmonospace"]=65347, - ["cmsquaredsquare"]=13216, - ["coarmenian"]=1409, - ["colon"]=58, - ["colonmonospace"]=65306, - ["colonsign"]=8353, - ["colonsmall"]=65109, - ["colontriangularhalfmod"]=721, - ["colontriangularmod"]=720, - ["comma"]=44, - ["commaabovecmb"]=787, - ["commaaboverightcmb"]=789, - ["commaarabic"]=1548, - ["commaarmenian"]=1373, - ["commamonospace"]=65292, - ["commareversedabovecmb"]=788, - ["commareversedmod"]=701, - ["commasmall"]=65104, - ["commaturnedabovecmb"]=786, - ["commaturnedmod"]=699, - ["congruent"]=8773, - ["contourintegral"]=8750, - ["control"]=8963, - ["controlACK"]=6, - ["controlBEL"]=7, - ["controlBS"]=8, - ["controlCAN"]=24, - ["controlCR"]=13, - ["controlDC1"]=17, - ["controlDC2"]=18, - ["controlDC3"]=19, - ["controlDC4"]=20, - ["controlDEL"]=127, - ["controlDLE"]=16, - ["controlEM"]=25, - ["controlENQ"]=5, - ["controlEOT"]=4, - ["controlESC"]=27, - ["controlETB"]=23, - ["controlETX"]=3, - ["controlFF"]=12, - ["controlFS"]=28, - ["controlGS"]=29, - ["controlHT"]=9, - ["controlLF"]=10, - ["controlNAK"]=21, - ["controlRS"]=30, - ["controlSI"]=15, - ["controlSO"]=14, - ["controlSOT"]=2, - ["controlSTX"]=1, - ["controlSUB"]=26, - ["controlSYN"]=22, - ["controlUS"]=31, - ["controlVT"]=11, - ["copyright"]=169, - ["cornerbracketleft"]=12300, - ["cornerbracketlefthalfwidth"]=65378, - ["cornerbracketleftvertical"]=65089, - ["cornerbracketright"]=12301, - ["cornerbracketrighthalfwidth"]=65379, - ["cornerbracketrightvertical"]=65090, - ["corporationsquare"]=13183, - ["cosquare"]=13255, - ["coverkgsquare"]=13254, - ["cparen"]=9374, - ["cruzeiro"]=8354, - ["cstretched"]=663, - ["curlyand"]=8911, - ["curlyor"]=8910, - ["currency"]=164, - ["d"]=100, - ["daarmenian"]=1380, - ["dabengali"]=2470, - ["dadarabic"]=1590, - ["dadeva"]=2342, - ["dadfinalarabic"]=65214, - ["dadinitialarabic"]=65215, - ["dadmedialarabic"]=65216, - ["dageshhebrew"]=1468, - ["dagger"]=8224, - ["daggerdbl"]=8225, - ["dagujarati"]=2726, - ["dagurmukhi"]=2598, - ["dahiragana"]=12384, - ["dakatakana"]=12480, - ["dalarabic"]=1583, - ["daletdageshhebrew"]=64307, - ["dalettserehebrew"]=1491, - ["dalfinalarabic"]=65194, - ["dammalowarabic"]=1615, - ["dammatanarabic"]=1612, - ["danda"]=2404, - ["dargalefthebrew"]=1447, - ["dasiapneumatacyrilliccmb"]=1157, - ["dblanglebracketleft"]=12298, - ["dblanglebracketleftvertical"]=65085, - ["dblanglebracketright"]=12299, - ["dblanglebracketrightvertical"]=65086, - ["dblarchinvertedbelowcmb"]=811, - ["dblarrowleft"]=8660, - ["dblarrowright"]=8658, - ["dbldanda"]=2405, - ["dblgravecmb"]=783, - ["dblintegral"]=8748, - ["dbllowlinecmb"]=819, - ["dbloverlinecmb"]=831, - ["dblprimemod"]=698, - ["dblverticalbar"]=8214, - ["dblverticallineabovecmb"]=782, - ["dbopomofo"]=12553, - ["dbsquare"]=13256, - ["dcaron"]=271, - ["dcedilla"]=7697, - ["dcircle"]=9427, - ["dcircumflexbelow"]=7699, - ["ddabengali"]=2465, - ["ddadeva"]=2337, - ["ddagujarati"]=2721, - ["ddagurmukhi"]=2593, - ["ddalarabic"]=1672, - ["ddalfinalarabic"]=64393, - ["dddhadeva"]=2396, - ["ddhabengali"]=2466, - ["ddhadeva"]=2338, - ["ddhagujarati"]=2722, - ["ddhagurmukhi"]=2594, - ["ddotaccent"]=7691, - ["ddotbelow"]=7693, - ["decimalseparatorpersian"]=1643, - ["decyrillic"]=1076, - ["degree"]=176, - ["dehihebrew"]=1453, - ["dehiragana"]=12391, - ["deicoptic"]=1007, - ["dekatakana"]=12487, - ["deleteleft"]=9003, - ["deleteright"]=8998, - ["delta"]=948, - ["deltaturned"]=397, - ["denominatorminusonenumeratorbengali"]=2552, - ["dezh"]=676, - ["dhabengali"]=2471, - ["dhadeva"]=2343, - ["dhagujarati"]=2727, - ["dhagurmukhi"]=2599, - ["dhook"]=599, - ["dialytikatonoscmb"]=836, - ["diamond"]=9830, - ["diamondsuitwhite"]=9826, - ["dieresis"]=168, - ["dieresisbelowcmb"]=804, - ["dieresiscmb"]=776, - ["dieresistonos"]=901, - ["dihiragana"]=12386, - ["dikatakana"]=12482, - ["dittomark"]=12291, - ["divide"]=247, - ["divides"]=8739, - ["divisionslash"]=8725, - ["djecyrillic"]=1106, - ["dlinebelow"]=7695, - ["dlsquare"]=13207, - ["dmacron"]=273, - ["dmonospace"]=65348, - ["dnblock"]=9604, - ["dochadathai"]=3598, - ["dodekthai"]=3604, - ["dohiragana"]=12393, - ["dokatakana"]=12489, - ["dollar"]=36, - ["dollarmonospace"]=65284, - ["dollarsmall"]=65129, - ["dong"]=8363, - ["dorusquare"]=13094, - ["dotaccent"]=729, - ["dotaccentcmb"]=775, - ["dotbelowcomb"]=803, - ["dotkatakana"]=12539, - ["dotlessi"]=305, - ["dotlessjstrokehook"]=644, - ["dotmath"]=8901, - ["dottedcircle"]=9676, - ["downtackbelowcmb"]=798, - ["downtackmod"]=725, - ["dparen"]=9375, - ["dtail"]=598, - ["dtopbar"]=396, - ["duhiragana"]=12389, - ["dukatakana"]=12485, - ["dz"]=499, - ["dzaltone"]=675, - ["dzcaron"]=454, - ["dzcurl"]=677, - ["dzeabkhasiancyrillic"]=1249, - ["dzecyrillic"]=1109, - ["dzhecyrillic"]=1119, - ["e"]=101, - ["eacute"]=233, - ["earth"]=9793, - ["ebengali"]=2447, - ["ebopomofo"]=12572, - ["ebreve"]=277, - ["ecandradeva"]=2317, - ["ecandragujarati"]=2701, - ["ecandravowelsigndeva"]=2373, - ["ecandravowelsigngujarati"]=2757, - ["ecaron"]=283, - ["ecedillabreve"]=7709, - ["echarmenian"]=1381, - ["echyiwnarmenian"]=1415, - ["ecircle"]=9428, - ["ecircumflex"]=234, - ["ecircumflexacute"]=7871, - ["ecircumflexbelow"]=7705, - ["ecircumflexdotbelow"]=7879, - ["ecircumflexgrave"]=7873, - ["ecircumflexhookabove"]=7875, - ["ecircumflextilde"]=7877, - ["ecyrillic"]=1108, - ["edblgrave"]=517, - ["edeva"]=2319, - ["edieresis"]=235, - ["edotaccent"]=279, - ["edotbelow"]=7865, - ["eegurmukhi"]=2575, - ["eematragurmukhi"]=2631, - ["efcyrillic"]=1092, - ["egrave"]=232, - ["egujarati"]=2703, - ["eharmenian"]=1383, - ["ehbopomofo"]=12573, - ["ehiragana"]=12360, - ["ehookabove"]=7867, - ["eibopomofo"]=12575, - ["eight"]=56, - ["eightbengali"]=2542, - ["eightcircle"]=9319, - ["eightcircleinversesansserif"]=10129, - ["eightdeva"]=2414, - ["eighteencircle"]=9329, - ["eighteenparen"]=9349, - ["eighteenperiod"]=9369, - ["eightgujarati"]=2798, - ["eightgurmukhi"]=2670, - ["eighthackarabic"]=1640, - ["eighthangzhou"]=12328, - ["eightideographicparen"]=12839, - ["eightinferior"]=8328, - ["eightmonospace"]=65304, - ["eightparen"]=9339, - ["eightperiod"]=9359, - ["eightpersian"]=1784, - ["eightroman"]=8567, - ["eightsuperior"]=8312, - ["eightthai"]=3672, - ["einvertedbreve"]=519, - ["eiotifiedcyrillic"]=1125, - ["ekatakana"]=12456, - ["ekatakanahalfwidth"]=65396, - ["ekonkargurmukhi"]=2676, - ["ekorean"]=12628, - ["elcyrillic"]=1083, - ["element"]=8712, - ["elevencircle"]=9322, - ["elevenparen"]=9342, - ["elevenperiod"]=9362, - ["elevenroman"]=8570, - ["ellipsis"]=8230, - ["ellipsisvertical"]=8942, - ["emacron"]=275, - ["emacronacute"]=7703, - ["emacrongrave"]=7701, - ["emcyrillic"]=1084, - ["emdash"]=8212, - ["emdashvertical"]=65073, - ["emonospace"]=65349, - ["emphasismarkarmenian"]=1371, - ["emptyset"]=8709, - ["enbopomofo"]=12579, - ["encyrillic"]=1085, - ["endash"]=8211, - ["endashvertical"]=65074, - ["endescendercyrillic"]=1187, - ["eng"]=331, - ["engbopomofo"]=12581, - ["enghecyrillic"]=1189, - ["enhookcyrillic"]=1224, - ["enspace"]=8194, - ["eogonek"]=281, - ["eokorean"]=12627, - ["eopen"]=603, - ["eopenclosed"]=666, - ["eopenreversed"]=604, - ["eopenreversedclosed"]=606, - ["eopenreversedhook"]=605, - ["eparen"]=9376, - ["epsilon"]=949, - ["epsilontonos"]=941, - ["equal"]=61, - ["equalmonospace"]=65309, - ["equalsmall"]=65126, - ["equalsuperior"]=8316, - ["equivalence"]=8801, - ["erbopomofo"]=12582, - ["ercyrillic"]=1088, - ["ereversed"]=600, - ["ereversedcyrillic"]=1101, - ["escyrillic"]=1089, - ["esdescendercyrillic"]=1195, - ["esh"]=643, - ["eshcurl"]=646, - ["eshortdeva"]=2318, - ["eshortvowelsigndeva"]=2374, - ["eshreversedloop"]=426, - ["eshsquatreversed"]=645, - ["esmallhiragana"]=12359, - ["esmallkatakana"]=12455, - ["esmallkatakanahalfwidth"]=65386, - ["estimated"]=8494, - ["eta"]=951, - ["etarmenian"]=1384, - ["etatonos"]=942, - ["eth"]=240, - ["etilde"]=7869, - ["etildebelow"]=7707, - ["etnahtalefthebrew"]=1425, - ["eturned"]=477, - ["eukorean"]=12641, - ["euro"]=8364, - ["evowelsignbengali"]=2503, - ["evowelsigndeva"]=2375, - ["evowelsigngujarati"]=2759, - ["exclam"]=33, - ["exclamarmenian"]=1372, - ["exclamdbl"]=8252, - ["exclamdown"]=161, - ["exclammonospace"]=65281, - ["ezh"]=658, - ["ezhcaron"]=495, - ["ezhcurl"]=659, - ["ezhreversed"]=441, - ["ezhtail"]=442, - ["f"]=102, - ["fadeva"]=2398, - ["fagurmukhi"]=2654, - ["fahrenheit"]=8457, - ["fathalowarabic"]=1614, - ["fathatanarabic"]=1611, - ["fbopomofo"]=12552, - ["fcircle"]=9429, - ["fdotaccent"]=7711, - ["feharabic"]=1601, - ["feharmenian"]=1414, - ["fehfinalarabic"]=65234, - ["fehinitialarabic"]=65235, - ["fehmedialarabic"]=65236, - ["feicoptic"]=997, - ["ff"]=64256, - ["ffi"]=64259, - ["ffl"]=64260, - ["fi"]=64257, - ["fifteencircle"]=9326, - ["fifteenparen"]=9346, - ["fifteenperiod"]=9366, - ["figuredash"]=8210, - ["filledbox"]=9632, - ["filledrect"]=9644, - ["finalkafdageshhebrew"]=64314, - ["finalkafshevahebrew"]=1498, - ["finalmemhebrew"]=1501, - ["finalnunhebrew"]=1503, - ["finalpehebrew"]=1507, - ["finaltsadihebrew"]=1509, - ["firsttonechinese"]=713, - ["fisheye"]=9673, - ["fitacyrillic"]=1139, - ["five"]=53, - ["fivebengali"]=2539, - ["fivecircle"]=9316, - ["fivecircleinversesansserif"]=10126, - ["fivedeva"]=2411, - ["fiveeighths"]=8541, - ["fivegujarati"]=2795, - ["fivegurmukhi"]=2667, - ["fivehackarabic"]=1637, - ["fivehangzhou"]=12325, - ["fiveideographicparen"]=12836, - ["fiveinferior"]=8325, - ["fivemonospace"]=65301, - ["fiveparen"]=9336, - ["fiveperiod"]=9356, - ["fivepersian"]=1781, - ["fiveroman"]=8564, - ["fivesuperior"]=8309, - ["fivethai"]=3669, - ["fl"]=64258, - ["florin"]=402, - ["fmonospace"]=65350, - ["fmsquare"]=13209, - ["fofanthai"]=3615, - ["fofathai"]=3613, - ["fongmanthai"]=3663, - ["four"]=52, - ["fourbengali"]=2538, - ["fourcircle"]=9315, - ["fourcircleinversesansserif"]=10125, - ["fourdeva"]=2410, - ["fourgujarati"]=2794, - ["fourgurmukhi"]=2666, - ["fourhackarabic"]=1636, - ["fourhangzhou"]=12324, - ["fourideographicparen"]=12835, - ["fourinferior"]=8324, - ["fourmonospace"]=65300, - ["fournumeratorbengali"]=2551, - ["fourparen"]=9335, - ["fourperiod"]=9355, - ["fourpersian"]=1780, - ["fourroman"]=8563, - ["foursuperior"]=8308, - ["fourteencircle"]=9325, - ["fourteenparen"]=9345, - ["fourteenperiod"]=9365, - ["fourthai"]=3668, - ["fourthtonechinese"]=715, - ["fparen"]=9377, - ["fraction"]=8260, - ["franc"]=8355, - ["g"]=103, - ["gabengali"]=2455, - ["gacute"]=501, - ["gadeva"]=2327, - ["gafarabic"]=1711, - ["gaffinalarabic"]=64403, - ["gafinitialarabic"]=64404, - ["gafmedialarabic"]=64405, - ["gagujarati"]=2711, - ["gagurmukhi"]=2583, - ["gahiragana"]=12364, - ["gakatakana"]=12460, - ["gamma"]=947, - ["gammalatinsmall"]=611, - ["gammasuperior"]=736, - ["gangiacoptic"]=1003, - ["gbopomofo"]=12557, - ["gbreve"]=287, - ["gcaron"]=487, - ["gcircle"]=9430, - ["gcircumflex"]=285, - ["gcommaaccent"]=291, - ["gdotaccent"]=289, - ["gecyrillic"]=1075, - ["gehiragana"]=12370, - ["gekatakana"]=12466, - ["geometricallyequal"]=8785, - ["gereshaccenthebrew"]=1436, - ["gereshhebrew"]=1523, - ["gereshmuqdamhebrew"]=1437, - ["germandbls"]=223, - ["gershayimaccenthebrew"]=1438, - ["gershayimhebrew"]=1524, - ["getamark"]=12307, - ["ghabengali"]=2456, - ["ghadarmenian"]=1394, - ["ghadeva"]=2328, - ["ghagujarati"]=2712, - ["ghagurmukhi"]=2584, - ["ghainarabic"]=1594, - ["ghainfinalarabic"]=65230, - ["ghaininitialarabic"]=65231, - ["ghainmedialarabic"]=65232, - ["ghemiddlehookcyrillic"]=1173, - ["ghestrokecyrillic"]=1171, - ["gheupturncyrillic"]=1169, - ["ghhadeva"]=2394, - ["ghhagurmukhi"]=2650, - ["ghook"]=608, - ["ghzsquare"]=13203, - ["gihiragana"]=12366, - ["gikatakana"]=12462, - ["gimarmenian"]=1379, - ["gimeldageshhebrew"]=64306, - ["gimelhebrew"]=1490, - ["gjecyrillic"]=1107, - ["glottalinvertedstroke"]=446, - ["glottalstop"]=660, - ["glottalstopinverted"]=662, - ["glottalstopmod"]=704, - ["glottalstopreversed"]=661, - ["glottalstopreversedmod"]=705, - ["glottalstopreversedsuperior"]=740, - ["glottalstopstroke"]=673, - ["glottalstopstrokereversed"]=674, - ["gmacron"]=7713, - ["gmonospace"]=65351, - ["gohiragana"]=12372, - ["gokatakana"]=12468, - ["gparen"]=9378, - ["gpasquare"]=13228, - ["grave"]=96, - ["gravebelowcmb"]=790, - ["gravecomb"]=768, - ["gravedeva"]=2387, - ["gravelowmod"]=718, - ["gravemonospace"]=65344, - ["gravetonecmb"]=832, - ["greater"]=62, - ["greaterequal"]=8805, - ["greaterequalorless"]=8923, - ["greatermonospace"]=65310, - ["greaterorequivalent"]=8819, - ["greaterorless"]=8823, - ["greateroverequal"]=8807, - ["greatersmall"]=65125, - ["gscript"]=609, - ["gstroke"]=485, - ["guhiragana"]=12368, - ["guillemotleft"]=171, - ["guillemotright"]=187, - ["guilsinglleft"]=8249, - ["guilsinglright"]=8250, - ["gukatakana"]=12464, - ["guramusquare"]=13080, - ["gysquare"]=13257, - ["h"]=104, - ["haabkhasiancyrillic"]=1193, - ["habengali"]=2489, - ["hadescendercyrillic"]=1203, - ["hadeva"]=2361, - ["hagujarati"]=2745, - ["hagurmukhi"]=2617, - ["haharabic"]=1581, - ["hahfinalarabic"]=65186, - ["hahinitialarabic"]=65187, - ["hahiragana"]=12399, - ["hahmedialarabic"]=65188, - ["haitusquare"]=13098, - ["hakatakana"]=12495, - ["hakatakanahalfwidth"]=65418, - ["halantgurmukhi"]=2637, - ["hamzasukunarabic"]=1569, - ["hangulfiller"]=12644, - ["hardsigncyrillic"]=1098, - ["harpoonleftbarbup"]=8636, - ["harpoonrightbarbup"]=8640, - ["hasquare"]=13258, - ["hatafpatahwidehebrew"]=1458, - ["hatafqamatswidehebrew"]=1459, - ["hatafsegolwidehebrew"]=1457, - ["hbar"]=295, - ["hbopomofo"]=12559, - ["hbrevebelow"]=7723, - ["hcedilla"]=7721, - ["hcircle"]=9431, - ["hcircumflex"]=293, - ["hdieresis"]=7719, - ["hdotaccent"]=7715, - ["hdotbelow"]=7717, - ["heartsuitblack"]=9829, - ["heartsuitwhite"]=9825, - ["hedageshhebrew"]=64308, - ["hehaltonearabic"]=1729, - ["heharabic"]=1607, - ["hehebrew"]=1492, - ["hehfinalaltonearabic"]=64423, - ["hehfinalarabic"]=65258, - ["hehhamzaabovefinalarabic"]=64421, - ["hehhamzaaboveisolatedarabic"]=64420, - ["hehinitialaltonearabic"]=64424, - ["hehinitialarabic"]=65259, - ["hehiragana"]=12408, - ["hehmedialaltonearabic"]=64425, - ["hehmedialarabic"]=65260, - ["heiseierasquare"]=13179, - ["hekatakana"]=12504, - ["hekatakanahalfwidth"]=65421, - ["hekutaarusquare"]=13110, - ["henghook"]=615, - ["herutusquare"]=13113, - ["hethebrew"]=1495, - ["hhook"]=614, - ["hhooksuperior"]=689, - ["hieuhacirclekorean"]=12923, - ["hieuhaparenkorean"]=12827, - ["hieuhcirclekorean"]=12909, - ["hieuhkorean"]=12622, - ["hieuhparenkorean"]=12813, - ["hihiragana"]=12402, - ["hikatakana"]=12498, - ["hikatakanahalfwidth"]=65419, - ["hiriqwidehebrew"]=1460, - ["hlinebelow"]=7830, - ["hmonospace"]=65352, - ["hoarmenian"]=1392, - ["hohipthai"]=3627, - ["hohiragana"]=12411, - ["hokatakana"]=12507, - ["hokatakanahalfwidth"]=65422, - ["holamwidehebrew"]=1465, - ["honokhukthai"]=3630, - ["hookcmb"]=777, - ["hookpalatalizedbelowcmb"]=801, - ["hookretroflexbelowcmb"]=802, - ["hoonsquare"]=13122, - ["horicoptic"]=1001, - ["horizontalbar"]=8213, - ["horncmb"]=795, - ["hotsprings"]=9832, - ["house"]=8962, - ["hparen"]=9379, - ["hsuperior"]=688, - ["hturned"]=613, - ["huhiragana"]=12405, - ["huiitosquare"]=13107, - ["hukatakana"]=12501, - ["hukatakanahalfwidth"]=65420, - ["hungarumlaut"]=733, - ["hungarumlautcmb"]=779, - ["hv"]=405, - ["hyphen"]=45, - ["hyphenmonospace"]=65293, - ["hyphensmall"]=65123, - ["hyphentwo"]=8208, - ["i"]=105, - ["iacute"]=237, - ["iacyrillic"]=1103, - ["ibengali"]=2439, - ["ibopomofo"]=12583, - ["ibreve"]=301, - ["icaron"]=464, - ["icircle"]=9432, - ["icircumflex"]=238, - ["icyrillic"]=1110, - ["idblgrave"]=521, - ["ideographearthcircle"]=12943, - ["ideographfirecircle"]=12939, - ["ideographicallianceparen"]=12863, - ["ideographiccallparen"]=12858, - ["ideographiccentrecircle"]=12965, - ["ideographicclose"]=12294, - ["ideographiccomma"]=12289, - ["ideographiccommaleft"]=65380, - ["ideographiccongratulationparen"]=12855, - ["ideographiccorrectcircle"]=12963, - ["ideographicearthparen"]=12847, - ["ideographicenterpriseparen"]=12861, - ["ideographicexcellentcircle"]=12957, - ["ideographicfestivalparen"]=12864, - ["ideographicfinancialcircle"]=12950, - ["ideographicfinancialparen"]=12854, - ["ideographicfireparen"]=12843, - ["ideographichaveparen"]=12850, - ["ideographichighcircle"]=12964, - ["ideographiciterationmark"]=12293, - ["ideographiclaborcircle"]=12952, - ["ideographiclaborparen"]=12856, - ["ideographicleftcircle"]=12967, - ["ideographiclowcircle"]=12966, - ["ideographicmedicinecircle"]=12969, - ["ideographicmetalparen"]=12846, - ["ideographicmoonparen"]=12842, - ["ideographicnameparen"]=12852, - ["ideographicperiod"]=12290, - ["ideographicprintcircle"]=12958, - ["ideographicreachparen"]=12867, - ["ideographicrepresentparen"]=12857, - ["ideographicresourceparen"]=12862, - ["ideographicrightcircle"]=12968, - ["ideographicsecretcircle"]=12953, - ["ideographicselfparen"]=12866, - ["ideographicsocietyparen"]=12851, - ["ideographicspace"]=12288, - ["ideographicspecialparen"]=12853, - ["ideographicstockparen"]=12849, - ["ideographicstudyparen"]=12859, - ["ideographicsunparen"]=12848, - ["ideographicsuperviseparen"]=12860, - ["ideographicwaterparen"]=12844, - ["ideographicwoodparen"]=12845, - ["ideographiczero"]=12295, - ["ideographmetalcircle"]=12942, - ["ideographmooncircle"]=12938, - ["ideographnamecircle"]=12948, - ["ideographsuncircle"]=12944, - ["ideographwatercircle"]=12940, - ["ideographwoodcircle"]=12941, - ["ideva"]=2311, - ["idieresis"]=239, - ["idieresisacute"]=7727, - ["idieresiscyrillic"]=1253, - ["idotbelow"]=7883, - ["iebrevecyrillic"]=1239, - ["iecyrillic"]=1077, - ["ieungacirclekorean"]=12917, - ["ieungaparenkorean"]=12821, - ["ieungcirclekorean"]=12903, - ["ieungkorean"]=12615, - ["ieungparenkorean"]=12807, - ["igrave"]=236, - ["igujarati"]=2695, - ["igurmukhi"]=2567, - ["ihiragana"]=12356, - ["ihookabove"]=7881, - ["iibengali"]=2440, - ["iicyrillic"]=1080, - ["iideva"]=2312, - ["iigujarati"]=2696, - ["iigurmukhi"]=2568, - ["iimatragurmukhi"]=2624, - ["iinvertedbreve"]=523, - ["iishortcyrillic"]=1081, - ["iivowelsignbengali"]=2496, - ["iivowelsigndeva"]=2368, - ["iivowelsigngujarati"]=2752, - ["ij"]=307, - ["ikatakana"]=12452, - ["ikatakanahalfwidth"]=65394, - ["ikorean"]=12643, - ["iluyhebrew"]=1452, - ["imacron"]=299, - ["imacroncyrillic"]=1251, - ["imageorapproximatelyequal"]=8787, - ["imatragurmukhi"]=2623, - ["imonospace"]=65353, - ["increment"]=8710, - ["infinity"]=8734, - ["iniarmenian"]=1387, - ["integral"]=8747, - ["integralbt"]=8993, - ["integraltp"]=8992, - ["intersection"]=8745, - ["intisquare"]=13061, - ["invbullet"]=9688, - ["invsmileface"]=9787, - ["iocyrillic"]=1105, - ["iogonek"]=303, - ["iota"]=953, - ["iotadieresis"]=970, - ["iotadieresistonos"]=912, - ["iotalatin"]=617, - ["iotatonos"]=943, - ["iparen"]=9380, - ["irigurmukhi"]=2674, - ["ismallhiragana"]=12355, - ["ismallkatakana"]=12451, - ["ismallkatakanahalfwidth"]=65384, - ["issharbengali"]=2554, - ["istroke"]=616, - ["iterationhiragana"]=12445, - ["iterationkatakana"]=12541, - ["itilde"]=297, - ["itildebelow"]=7725, - ["iubopomofo"]=12585, - ["iucyrillic"]=1102, - ["ivowelsignbengali"]=2495, - ["ivowelsigndeva"]=2367, - ["ivowelsigngujarati"]=2751, - ["izhitsacyrillic"]=1141, - ["izhitsadblgravecyrillic"]=1143, - ["j"]=106, - ["jaarmenian"]=1393, - ["jabengali"]=2460, - ["jadeva"]=2332, - ["jagujarati"]=2716, - ["jagurmukhi"]=2588, - ["jbopomofo"]=12560, - ["jcaron"]=496, - ["jcircle"]=9433, - ["jcircumflex"]=309, - ["jcrossedtail"]=669, - ["jdotlessstroke"]=607, - ["jecyrillic"]=1112, - ["jeemarabic"]=1580, - ["jeemfinalarabic"]=65182, - ["jeeminitialarabic"]=65183, - ["jeemmedialarabic"]=65184, - ["jeharabic"]=1688, - ["jehfinalarabic"]=64395, - ["jhabengali"]=2461, - ["jhadeva"]=2333, - ["jhagujarati"]=2717, - ["jhagurmukhi"]=2589, - ["jheharmenian"]=1403, - ["jis"]=12292, - ["jmonospace"]=65354, - ["jparen"]=9381, - ["jsuperior"]=690, - ["k"]=107, - ["kabashkircyrillic"]=1185, - ["kabengali"]=2453, - ["kacute"]=7729, - ["kacyrillic"]=1082, - ["kadescendercyrillic"]=1179, - ["kadeva"]=2325, - ["kafarabic"]=1603, - ["kafdageshhebrew"]=64315, - ["kaffinalarabic"]=65242, - ["kafhebrew"]=1499, - ["kafinitialarabic"]=65243, - ["kafmedialarabic"]=65244, - ["kafrafehebrew"]=64333, - ["kagujarati"]=2709, - ["kagurmukhi"]=2581, - ["kahiragana"]=12363, - ["kahookcyrillic"]=1220, - ["kakatakana"]=12459, - ["kakatakanahalfwidth"]=65398, - ["kappa"]=954, - ["kappasymbolgreek"]=1008, - ["kapyeounmieumkorean"]=12657, - ["kapyeounphieuphkorean"]=12676, - ["kapyeounpieupkorean"]=12664, - ["kapyeounssangpieupkorean"]=12665, - ["karoriisquare"]=13069, - ["kasmallkatakana"]=12533, - ["kasquare"]=13188, - ["kasraarabic"]=1616, - ["kasratanarabic"]=1613, - ["kastrokecyrillic"]=1183, - ["katahiraprolongmarkhalfwidth"]=65392, - ["kaverticalstrokecyrillic"]=1181, - ["kbopomofo"]=12558, - ["kcalsquare"]=13193, - ["kcaron"]=489, - ["kcircle"]=9434, - ["kcommaaccent"]=311, - ["kdotbelow"]=7731, - ["keharmenian"]=1412, - ["kehiragana"]=12369, - ["kekatakana"]=12465, - ["kekatakanahalfwidth"]=65401, - ["kenarmenian"]=1391, - ["kesmallkatakana"]=12534, - ["kgreenlandic"]=312, - ["khabengali"]=2454, - ["khacyrillic"]=1093, - ["khadeva"]=2326, - ["khagujarati"]=2710, - ["khagurmukhi"]=2582, - ["khaharabic"]=1582, - ["khahfinalarabic"]=65190, - ["khahinitialarabic"]=65191, - ["khahmedialarabic"]=65192, - ["kheicoptic"]=999, - ["khhadeva"]=2393, - ["khhagurmukhi"]=2649, - ["khieukhacirclekorean"]=12920, - ["khieukhaparenkorean"]=12824, - ["khieukhcirclekorean"]=12906, - ["khieukhkorean"]=12619, - ["khieukhparenkorean"]=12810, - ["khokhaithai"]=3586, - ["khokhonthai"]=3589, - ["khokhuatthai"]=3587, - ["khokhwaithai"]=3588, - ["khomutthai"]=3675, - ["khook"]=409, - ["khorakhangthai"]=3590, - ["khzsquare"]=13201, - ["kihiragana"]=12365, - ["kikatakana"]=12461, - ["kikatakanahalfwidth"]=65399, - ["kiroguramusquare"]=13077, - ["kiromeetorusquare"]=13078, - ["kirosquare"]=13076, - ["kiyeokacirclekorean"]=12910, - ["kiyeokaparenkorean"]=12814, - ["kiyeokcirclekorean"]=12896, - ["kiyeokkorean"]=12593, - ["kiyeokparenkorean"]=12800, - ["kiyeoksioskorean"]=12595, - ["kjecyrillic"]=1116, - ["klinebelow"]=7733, - ["klsquare"]=13208, - ["kmcubedsquare"]=13222, - ["kmonospace"]=65355, - ["kmsquaredsquare"]=13218, - ["kohiragana"]=12371, - ["kohmsquare"]=13248, - ["kokaithai"]=3585, - ["kokatakana"]=12467, - ["kokatakanahalfwidth"]=65402, - ["kooposquare"]=13086, - ["koppacyrillic"]=1153, - ["koreanstandardsymbol"]=12927, - ["koroniscmb"]=835, - ["kparen"]=9382, - ["kpasquare"]=13226, - ["ksicyrillic"]=1135, - ["ktsquare"]=13263, - ["kturned"]=670, - ["kuhiragana"]=12367, - ["kukatakana"]=12463, - ["kukatakanahalfwidth"]=65400, - ["kvsquare"]=13240, - ["kwsquare"]=13246, - ["l"]=108, - ["labengali"]=2482, - ["lacute"]=314, - ["ladeva"]=2354, - ["lagujarati"]=2738, - ["lagurmukhi"]=2610, - ["lakkhangyaothai"]=3653, - ["lamaleffinalarabic"]=65276, - ["lamalefhamzaabovefinalarabic"]=65272, - ["lamalefhamzaaboveisolatedarabic"]=65271, - ["lamalefhamzabelowfinalarabic"]=65274, - ["lamalefhamzabelowisolatedarabic"]=65273, - ["lamalefisolatedarabic"]=65275, - ["lamalefmaddaabovefinalarabic"]=65270, - ["lamalefmaddaaboveisolatedarabic"]=65269, - ["lamarabic"]=1604, - ["lambda"]=955, - ["lambdastroke"]=411, - ["lameddageshhebrew"]=64316, - ["lamedholamhebrew"]=1500, - ["lamfinalarabic"]=65246, - ["lamhahinitialarabic"]=64714, - ["lamjeeminitialarabic"]=64713, - ["lamkhahinitialarabic"]=64715, - ["lamlamhehisolatedarabic"]=65010, - ["lammedialarabic"]=65248, - ["lammeemhahinitialarabic"]=64904, - ["lammeeminitialarabic"]=64716, - ["lammeemkhahinitialarabic"]=65247, - ["largecircle"]=9711, - ["lbar"]=410, - ["lbelt"]=620, - ["lbopomofo"]=12556, - ["lcaron"]=318, - ["lcircle"]=9435, - ["lcircumflexbelow"]=7741, - ["lcommaaccent"]=316, - ["ldotaccent"]=320, - ["ldotbelow"]=7735, - ["ldotbelowmacron"]=7737, - ["leftangleabovecmb"]=794, - ["lefttackbelowcmb"]=792, - ["less"]=60, - ["lessequal"]=8804, - ["lessequalorgreater"]=8922, - ["lessmonospace"]=65308, - ["lessorequivalent"]=8818, - ["lessorgreater"]=8822, - ["lessoverequal"]=8806, - ["lesssmall"]=65124, - ["lezh"]=622, - ["lfblock"]=9612, - ["lhookretroflex"]=621, - ["lira"]=8356, - ["liwnarmenian"]=1388, - ["lj"]=457, - ["ljecyrillic"]=1113, - ["lladeva"]=2355, - ["llagujarati"]=2739, - ["llinebelow"]=7739, - ["llladeva"]=2356, - ["llvocalicbengali"]=2529, - ["llvocalicdeva"]=2401, - ["llvocalicvowelsignbengali"]=2531, - ["llvocalicvowelsigndeva"]=2403, - ["lmiddletilde"]=619, - ["lmonospace"]=65356, - ["lmsquare"]=13264, - ["lochulathai"]=3628, - ["logicaland"]=8743, - ["logicalnot"]=172, - ["logicalor"]=8744, - ["lolingthai"]=3621, - ["lowlinecenterline"]=65102, - ["lowlinecmb"]=818, - ["lowlinedashed"]=65101, - ["lozenge"]=9674, - ["lparen"]=9383, - ["lslash"]=322, - ["lsquare"]=8467, - ["luthai"]=3622, - ["lvocalicbengali"]=2444, - ["lvocalicdeva"]=2316, - ["lvocalicvowelsignbengali"]=2530, - ["lvocalicvowelsigndeva"]=2402, - ["lxsquare"]=13267, - ["m"]=109, - ["mabengali"]=2478, - ["macron"]=175, - ["macronbelowcmb"]=817, - ["macroncmb"]=772, - ["macronlowmod"]=717, - ["macronmonospace"]=65507, - ["macute"]=7743, - ["madeva"]=2350, - ["magujarati"]=2734, - ["magurmukhi"]=2606, - ["mahapakhlefthebrew"]=1444, - ["mahiragana"]=12414, - ["maichattawathai"]=3659, - ["maiekthai"]=3656, - ["maihanakatthai"]=3633, - ["maitaikhuthai"]=3655, - ["maithothai"]=3657, - ["maitrithai"]=3658, - ["maiyamokthai"]=3654, - ["makatakana"]=12510, - ["makatakanahalfwidth"]=65423, - ["mansyonsquare"]=13127, - ["maqafhebrew"]=1470, - ["mars"]=9794, - ["masoracirclehebrew"]=1455, - ["masquare"]=13187, - ["mbopomofo"]=12551, - ["mbsquare"]=13268, - ["mcircle"]=9436, - ["mcubedsquare"]=13221, - ["mdotaccent"]=7745, - ["mdotbelow"]=7747, - ["meemarabic"]=1605, - ["meemfinalarabic"]=65250, - ["meeminitialarabic"]=65251, - ["meemmedialarabic"]=65252, - ["meemmeeminitialarabic"]=64721, - ["meemmeemisolatedarabic"]=64584, - ["meetorusquare"]=13133, - ["mehiragana"]=12417, - ["meizierasquare"]=13182, - ["mekatakana"]=12513, - ["mekatakanahalfwidth"]=65426, - ["memdageshhebrew"]=64318, - ["memhebrew"]=1502, - ["menarmenian"]=1396, - ["merkhakefulalefthebrew"]=1446, - ["merkhalefthebrew"]=1445, - ["mhook"]=625, - ["mhzsquare"]=13202, - ["middledotkatakanahalfwidth"]=65381, - ["mieumacirclekorean"]=12914, - ["mieumaparenkorean"]=12818, - ["mieumcirclekorean"]=12900, - ["mieumkorean"]=12609, - ["mieumpansioskorean"]=12656, - ["mieumparenkorean"]=12804, - ["mieumpieupkorean"]=12654, - ["mieumsioskorean"]=12655, - ["mihiragana"]=12415, - ["mikatakana"]=12511, - ["mikatakanahalfwidth"]=65424, - ["minus"]=8722, - ["minusbelowcmb"]=800, - ["minuscircle"]=8854, - ["minusmod"]=727, - ["minusplus"]=8723, - ["minute"]=8242, - ["miribaarusquare"]=13130, - ["mirisquare"]=13129, - ["mlonglegturned"]=624, - ["mlsquare"]=13206, - ["mmcubedsquare"]=13219, - ["mmonospace"]=65357, - ["mmsquaredsquare"]=13215, - ["mohiragana"]=12418, - ["mohmsquare"]=13249, - ["mokatakana"]=12514, - ["mokatakanahalfwidth"]=65427, - ["molsquare"]=13270, - ["momathai"]=3617, - ["moverssquare"]=13223, - ["moverssquaredsquare"]=13224, - ["mparen"]=9384, - ["mpasquare"]=13227, - ["mssquare"]=13235, - ["mturned"]=623, - ["mu1"]=181, - ["muasquare"]=13186, - ["muchgreater"]=8811, - ["muchless"]=8810, - ["mufsquare"]=13196, - ["mugreek"]=956, - ["mugsquare"]=13197, - ["muhiragana"]=12416, - ["mukatakana"]=12512, - ["mukatakanahalfwidth"]=65425, - ["mulsquare"]=13205, - ["multiply"]=215, - ["mumsquare"]=13211, - ["munahlefthebrew"]=1443, - ["musicalnote"]=9834, - ["musicalnotedbl"]=9835, - ["musicflatsign"]=9837, - ["musicsharpsign"]=9839, - ["mussquare"]=13234, - ["muvsquare"]=13238, - ["muwsquare"]=13244, - ["mvmegasquare"]=13241, - ["mvsquare"]=13239, - ["mwmegasquare"]=13247, - ["mwsquare"]=13245, - ["n"]=110, - ["nabengali"]=2472, - ["nabla"]=8711, - ["nacute"]=324, - ["nadeva"]=2344, - ["nagujarati"]=2728, - ["nagurmukhi"]=2600, - ["nahiragana"]=12394, - ["nakatakana"]=12490, - ["nakatakanahalfwidth"]=65413, - ["nasquare"]=13185, - ["nbopomofo"]=12555, - ["ncaron"]=328, - ["ncircle"]=9437, - ["ncircumflexbelow"]=7755, - ["ncommaaccent"]=326, - ["ndotaccent"]=7749, - ["ndotbelow"]=7751, - ["nehiragana"]=12397, - ["nekatakana"]=12493, - ["nekatakanahalfwidth"]=65416, - ["nfsquare"]=13195, - ["ngabengali"]=2457, - ["ngadeva"]=2329, - ["ngagujarati"]=2713, - ["ngagurmukhi"]=2585, - ["ngonguthai"]=3591, - ["nhiragana"]=12435, - ["nhookleft"]=626, - ["nhookretroflex"]=627, - ["nieunacirclekorean"]=12911, - ["nieunaparenkorean"]=12815, - ["nieuncieuckorean"]=12597, - ["nieuncirclekorean"]=12897, - ["nieunhieuhkorean"]=12598, - ["nieunkorean"]=12596, - ["nieunpansioskorean"]=12648, - ["nieunparenkorean"]=12801, - ["nieunsioskorean"]=12647, - ["nieuntikeutkorean"]=12646, - ["nihiragana"]=12395, - ["nikatakana"]=12491, - ["nikatakanahalfwidth"]=65414, - ["nikhahitthai"]=3661, - ["nine"]=57, - ["ninebengali"]=2543, - ["ninecircle"]=9320, - ["ninecircleinversesansserif"]=10130, - ["ninedeva"]=2415, - ["ninegujarati"]=2799, - ["ninegurmukhi"]=2671, - ["ninehackarabic"]=1641, - ["ninehangzhou"]=12329, - ["nineideographicparen"]=12840, - ["nineinferior"]=8329, - ["ninemonospace"]=65305, - ["nineparen"]=9340, - ["nineperiod"]=9360, - ["ninepersian"]=1785, - ["nineroman"]=8568, - ["ninesuperior"]=8313, - ["nineteencircle"]=9330, - ["nineteenparen"]=9350, - ["nineteenperiod"]=9370, - ["ninethai"]=3673, - ["nj"]=460, - ["njecyrillic"]=1114, - ["nkatakana"]=12531, - ["nkatakanahalfwidth"]=65437, - ["nlegrightlong"]=414, - ["nlinebelow"]=7753, - ["nmonospace"]=65358, - ["nmsquare"]=13210, - ["nnabengali"]=2467, - ["nnadeva"]=2339, - ["nnagujarati"]=2723, - ["nnagurmukhi"]=2595, - ["nnnadeva"]=2345, - ["nohiragana"]=12398, - ["nokatakana"]=12494, - ["nokatakanahalfwidth"]=65417, - ["nonbreakingspace"]=160, - ["nonenthai"]=3603, - ["nonuthai"]=3609, - ["noonarabic"]=1606, - ["noonfinalarabic"]=65254, - ["noonghunnaarabic"]=1722, - ["noonghunnafinalarabic"]=64415, - ["nooninitialarabic"]=65255, - ["noonjeeminitialarabic"]=64722, - ["noonjeemisolatedarabic"]=64587, - ["noonmedialarabic"]=65256, - ["noonmeeminitialarabic"]=64725, - ["noonmeemisolatedarabic"]=64590, - ["noonnoonfinalarabic"]=64653, - ["notcontains"]=8716, - ["notelementof"]=8713, - ["notequal"]=8800, - ["notgreater"]=8815, - ["notgreaternorequal"]=8817, - ["notgreaternorless"]=8825, - ["notidentical"]=8802, - ["notless"]=8814, - ["notlessnorequal"]=8816, - ["notparallel"]=8742, - ["notprecedes"]=8832, - ["notsubset"]=8836, - ["notsucceeds"]=8833, - ["notsuperset"]=8837, - ["nowarmenian"]=1398, - ["nparen"]=9385, - ["nssquare"]=13233, - ["nsuperior"]=8319, - ["ntilde"]=241, - ["nu"]=957, - ["nuhiragana"]=12396, - ["nukatakana"]=12492, - ["nukatakanahalfwidth"]=65415, - ["nuktabengali"]=2492, - ["nuktadeva"]=2364, - ["nuktagujarati"]=2748, - ["nuktagurmukhi"]=2620, - ["numbersign"]=35, - ["numbersignmonospace"]=65283, - ["numbersignsmall"]=65119, - ["numeralsigngreek"]=884, - ["numeralsignlowergreek"]=885, - ["numero"]=8470, - ["nundageshhebrew"]=64320, - ["nunhebrew"]=1504, - ["nvsquare"]=13237, - ["nwsquare"]=13243, - ["nyabengali"]=2462, - ["nyadeva"]=2334, - ["nyagujarati"]=2718, - ["nyagurmukhi"]=2590, - ["o"]=111, - ["oacute"]=243, - ["oangthai"]=3629, - ["obarred"]=629, - ["obarredcyrillic"]=1257, - ["obarreddieresiscyrillic"]=1259, - ["obengali"]=2451, - ["obopomofo"]=12571, - ["obreve"]=335, - ["ocandradeva"]=2321, - ["ocandragujarati"]=2705, - ["ocandravowelsigndeva"]=2377, - ["ocandravowelsigngujarati"]=2761, - ["ocaron"]=466, - ["ocircle"]=9438, - ["ocircumflex"]=244, - ["ocircumflexacute"]=7889, - ["ocircumflexdotbelow"]=7897, - ["ocircumflexgrave"]=7891, - ["ocircumflexhookabove"]=7893, - ["ocircumflextilde"]=7895, - ["ocyrillic"]=1086, - ["odblgrave"]=525, - ["odeva"]=2323, - ["odieresis"]=246, - ["odieresiscyrillic"]=1255, - ["odotbelow"]=7885, - ["oe"]=339, - ["oekorean"]=12634, - ["ogonek"]=731, - ["ogonekcmb"]=808, - ["ograve"]=242, - ["ogujarati"]=2707, - ["oharmenian"]=1413, - ["ohiragana"]=12362, - ["ohookabove"]=7887, - ["ohorn"]=417, - ["ohornacute"]=7899, - ["ohorndotbelow"]=7907, - ["ohorngrave"]=7901, - ["ohornhookabove"]=7903, - ["ohorntilde"]=7905, - ["ohungarumlaut"]=337, - ["oi"]=419, - ["oinvertedbreve"]=527, - ["okatakana"]=12458, - ["okatakanahalfwidth"]=65397, - ["okorean"]=12631, - ["olehebrew"]=1451, - ["omacron"]=333, - ["omacronacute"]=7763, - ["omacrongrave"]=7761, - ["omdeva"]=2384, - ["omega"]=969, - ["omegacyrillic"]=1121, - ["omegalatinclosed"]=631, - ["omegaroundcyrillic"]=1147, - ["omegatitlocyrillic"]=1149, - ["omegatonos"]=974, - ["omgujarati"]=2768, - ["omicron"]=959, - ["omicrontonos"]=972, - ["omonospace"]=65359, - ["one"]=49, - ["onebengali"]=2535, - ["onecircle"]=9312, - ["onecircleinversesansserif"]=10122, - ["onedeva"]=2407, - ["onedotenleader"]=8228, - ["oneeighth"]=8539, - ["onegujarati"]=2791, - ["onegurmukhi"]=2663, - ["onehackarabic"]=1633, - ["onehalf"]=189, - ["onehangzhou"]=12321, - ["oneideographicparen"]=12832, - ["oneinferior"]=8321, - ["onemonospace"]=65297, - ["onenumeratorbengali"]=2548, - ["oneparen"]=9332, - ["oneperiod"]=9352, - ["onepersian"]=1777, - ["onequarter"]=188, - ["oneroman"]=8560, - ["onesuperior"]=185, - ["onethai"]=3665, - ["onethird"]=8531, - ["oogonek"]=491, - ["oogonekmacron"]=493, - ["oogurmukhi"]=2579, - ["oomatragurmukhi"]=2635, - ["oopen"]=596, - ["oparen"]=9386, - ["option"]=8997, - ["ordfeminine"]=170, - ["ordmasculine"]=186, - ["oshortdeva"]=2322, - ["oshortvowelsigndeva"]=2378, - ["oslash"]=248, - ["osmallhiragana"]=12361, - ["osmallkatakana"]=12457, - ["osmallkatakanahalfwidth"]=65387, - ["ostrokeacute"]=511, - ["otcyrillic"]=1151, - ["otilde"]=245, - ["otildeacute"]=7757, - ["otildedieresis"]=7759, - ["oubopomofo"]=12577, - ["overline"]=8254, - ["overlinecenterline"]=65098, - ["overlinecmb"]=773, - ["overlinedashed"]=65097, - ["overlinedblwavy"]=65100, - ["overlinewavy"]=65099, - ["ovowelsignbengali"]=2507, - ["ovowelsigndeva"]=2379, - ["ovowelsigngujarati"]=2763, - ["p"]=112, - ["paampssquare"]=13184, - ["paasentosquare"]=13099, - ["pabengali"]=2474, - ["pacute"]=7765, - ["padeva"]=2346, - ["pagedown"]=8671, - ["pageup"]=8670, - ["pagujarati"]=2730, - ["pagurmukhi"]=2602, - ["pahiragana"]=12401, - ["paiyannoithai"]=3631, - ["pakatakana"]=12497, - ["palatalizationcyrilliccmb"]=1156, - ["palochkacyrillic"]=1216, - ["pansioskorean"]=12671, - ["paragraph"]=182, - ["parallel"]=8741, - ["parenleft"]=40, - ["parenleftaltonearabic"]=64830, - ["parenleftinferior"]=8333, - ["parenleftmonospace"]=65288, - ["parenleftsmall"]=65113, - ["parenleftsuperior"]=8317, - ["parenleftvertical"]=65077, - ["parenright"]=41, - ["parenrightaltonearabic"]=64831, - ["parenrightinferior"]=8334, - ["parenrightmonospace"]=65289, - ["parenrightsmall"]=65114, - ["parenrightsuperior"]=8318, - ["parenrightvertical"]=65078, - ["partialdiff"]=8706, - ["paseqhebrew"]=1472, - ["pashtahebrew"]=1433, - ["pasquare"]=13225, - ["patahwidehebrew"]=1463, - ["pazerhebrew"]=1441, - ["pbopomofo"]=12550, - ["pcircle"]=9439, - ["pdotaccent"]=7767, - ["pecyrillic"]=1087, - ["pedageshhebrew"]=64324, - ["peezisquare"]=13115, - ["pefinaldageshhebrew"]=64323, - ["peharabic"]=1662, - ["peharmenian"]=1402, - ["pehebrew"]=1508, - ["pehfinalarabic"]=64343, - ["pehinitialarabic"]=64344, - ["pehiragana"]=12410, - ["pehmedialarabic"]=64345, - ["pekatakana"]=12506, - ["pemiddlehookcyrillic"]=1191, - ["perafehebrew"]=64334, - ["percent"]=37, - ["percentarabic"]=1642, - ["percentmonospace"]=65285, - ["percentsmall"]=65130, - ["period"]=46, - ["periodarmenian"]=1417, - ["periodcentered"]=183, - ["periodhalfwidth"]=65377, - ["periodmonospace"]=65294, - ["periodsmall"]=65106, - ["perispomenigreekcmb"]=834, - ["perpendicular"]=8869, - ["perthousand"]=8240, - ["peseta"]=8359, - ["pfsquare"]=13194, - ["phabengali"]=2475, - ["phadeva"]=2347, - ["phagujarati"]=2731, - ["phagurmukhi"]=2603, - ["phi"]=966, - ["phieuphacirclekorean"]=12922, - ["phieuphaparenkorean"]=12826, - ["phieuphcirclekorean"]=12908, - ["phieuphkorean"]=12621, - ["phieuphparenkorean"]=12812, - ["philatin"]=632, - ["phinthuthai"]=3642, - ["phisymbolgreek"]=981, - ["phook"]=421, - ["phophanthai"]=3614, - ["phophungthai"]=3612, - ["phosamphaothai"]=3616, - ["pi"]=960, - ["pieupacirclekorean"]=12915, - ["pieupaparenkorean"]=12819, - ["pieupcieuckorean"]=12662, - ["pieupcirclekorean"]=12901, - ["pieupkiyeokkorean"]=12658, - ["pieupkorean"]=12610, - ["pieupparenkorean"]=12805, - ["pieupsioskiyeokkorean"]=12660, - ["pieupsioskorean"]=12612, - ["pieupsiostikeutkorean"]=12661, - ["pieupthieuthkorean"]=12663, - ["pieuptikeutkorean"]=12659, - ["pihiragana"]=12404, - ["pikatakana"]=12500, - ["pisymbolgreek"]=982, - ["piwrarmenian"]=1411, - ["plus"]=43, - ["plusbelowcmb"]=799, - ["pluscircle"]=8853, - ["plusminus"]=177, - ["plusmod"]=726, - ["plusmonospace"]=65291, - ["plussmall"]=65122, - ["plussuperior"]=8314, - ["pmonospace"]=65360, - ["pmsquare"]=13272, - ["pohiragana"]=12413, - ["pointingindexdownwhite"]=9759, - ["pointingindexleftwhite"]=9756, - ["pointingindexrightwhite"]=9758, - ["pointingindexupwhite"]=9757, - ["pokatakana"]=12509, - ["poplathai"]=3611, - ["postalmark"]=12306, - ["postalmarkface"]=12320, - ["pparen"]=9387, - ["precedes"]=8826, - ["prescription"]=8478, - ["primemod"]=697, - ["primereversed"]=8245, - ["product"]=8719, - ["projective"]=8965, - ["prolongedkana"]=12540, - ["propellor"]=8984, - ["proportion"]=8759, - ["proportional"]=8733, - ["psi"]=968, - ["psicyrillic"]=1137, - ["psilipneumatacyrilliccmb"]=1158, - ["pssquare"]=13232, - ["puhiragana"]=12407, - ["pukatakana"]=12503, - ["pvsquare"]=13236, - ["pwsquare"]=13242, - ["q"]=113, - ["qadeva"]=2392, - ["qadmahebrew"]=1448, - ["qafarabic"]=1602, - ["qaffinalarabic"]=65238, - ["qafinitialarabic"]=65239, - ["qafmedialarabic"]=65240, - ["qamatswidehebrew"]=1464, - ["qarneyparahebrew"]=1439, - ["qbopomofo"]=12561, - ["qcircle"]=9440, - ["qhook"]=672, - ["qmonospace"]=65361, - ["qofdageshhebrew"]=64327, - ["qoftserehebrew"]=1511, - ["qparen"]=9388, - ["quarternote"]=9833, - ["qubutswidehebrew"]=1467, - ["question"]=63, - ["questionarabic"]=1567, - ["questionarmenian"]=1374, - ["questiondown"]=191, - ["questiongreek"]=894, - ["questionmonospace"]=65311, - ["quotedbl"]=34, - ["quotedblbase"]=8222, - ["quotedblleft"]=8220, - ["quotedblmonospace"]=65282, - ["quotedblprime"]=12318, - ["quotedblprimereversed"]=12317, - ["quotedblright"]=8221, - ["quoteleft"]=8216, - ["quotereversed"]=8219, - ["quoteright"]=8217, - ["quoterightn"]=329, - ["quotesinglbase"]=8218, - ["quotesingle"]=39, - ["quotesinglemonospace"]=65287, - ["r"]=114, - ["raarmenian"]=1404, - ["rabengali"]=2480, - ["racute"]=341, - ["radeva"]=2352, - ["radical"]=8730, - ["radoverssquare"]=13230, - ["radoverssquaredsquare"]=13231, - ["radsquare"]=13229, - ["rafehebrew"]=1471, - ["ragujarati"]=2736, - ["ragurmukhi"]=2608, - ["rahiragana"]=12425, - ["rakatakana"]=12521, - ["rakatakanahalfwidth"]=65431, - ["ralowerdiagonalbengali"]=2545, - ["ramiddlediagonalbengali"]=2544, - ["ramshorn"]=612, - ["ratio"]=8758, - ["rbopomofo"]=12566, - ["rcaron"]=345, - ["rcircle"]=9441, - ["rcommaaccent"]=343, - ["rdblgrave"]=529, - ["rdotaccent"]=7769, - ["rdotbelow"]=7771, - ["rdotbelowmacron"]=7773, - ["referencemark"]=8251, - ["registered"]=174, - ["reharmenian"]=1408, - ["rehfinalarabic"]=65198, - ["rehiragana"]=12428, - ["rehyehaleflamarabic"]=1585, - ["rekatakana"]=12524, - ["rekatakanahalfwidth"]=65434, - ["reshdageshhebrew"]=64328, - ["reshtserehebrew"]=1512, - ["reversedtilde"]=8765, - ["reviamugrashhebrew"]=1431, - ["revlogicalnot"]=8976, - ["rfishhook"]=638, - ["rfishhookreversed"]=639, - ["rhabengali"]=2525, - ["rhadeva"]=2397, - ["rho"]=961, - ["rhook"]=637, - ["rhookturned"]=635, - ["rhookturnedsuperior"]=693, - ["rhosymbolgreek"]=1009, - ["rhotichookmod"]=734, - ["rieulacirclekorean"]=12913, - ["rieulaparenkorean"]=12817, - ["rieulcirclekorean"]=12899, - ["rieulhieuhkorean"]=12608, - ["rieulkiyeokkorean"]=12602, - ["rieulkiyeoksioskorean"]=12649, - ["rieulkorean"]=12601, - ["rieulmieumkorean"]=12603, - ["rieulpansioskorean"]=12652, - ["rieulparenkorean"]=12803, - ["rieulphieuphkorean"]=12607, - ["rieulpieupkorean"]=12604, - ["rieulpieupsioskorean"]=12651, - ["rieulsioskorean"]=12605, - ["rieulthieuthkorean"]=12606, - ["rieultikeutkorean"]=12650, - ["rieulyeorinhieuhkorean"]=12653, - ["rightangle"]=8735, - ["righttackbelowcmb"]=793, - ["righttriangle"]=8895, - ["rihiragana"]=12426, - ["rikatakana"]=12522, - ["rikatakanahalfwidth"]=65432, - ["ring"]=730, - ["ringbelowcmb"]=805, - ["ringcmb"]=778, - ["ringhalfleft"]=703, - ["ringhalfleftarmenian"]=1369, - ["ringhalfleftbelowcmb"]=796, - ["ringhalfleftcentered"]=723, - ["ringhalfright"]=702, - ["ringhalfrightbelowcmb"]=825, - ["ringhalfrightcentered"]=722, - ["rinvertedbreve"]=531, - ["rittorusquare"]=13137, - ["rlinebelow"]=7775, - ["rlongleg"]=636, - ["rlonglegturned"]=634, - ["rmonospace"]=65362, - ["rohiragana"]=12429, - ["rokatakana"]=12525, - ["rokatakanahalfwidth"]=65435, - ["roruathai"]=3619, - ["rparen"]=9389, - ["rrabengali"]=2524, - ["rradeva"]=2353, - ["rragurmukhi"]=2652, - ["rreharabic"]=1681, - ["rrehfinalarabic"]=64397, - ["rrvocalicbengali"]=2528, - ["rrvocalicdeva"]=2400, - ["rrvocalicgujarati"]=2784, - ["rrvocalicvowelsignbengali"]=2500, - ["rrvocalicvowelsigndeva"]=2372, - ["rrvocalicvowelsigngujarati"]=2756, - ["rtblock"]=9616, - ["rturned"]=633, - ["rturnedsuperior"]=692, - ["ruhiragana"]=12427, - ["rukatakana"]=12523, - ["rukatakanahalfwidth"]=65433, - ["rupeemarkbengali"]=2546, - ["rupeesignbengali"]=2547, - ["ruthai"]=3620, - ["rvocalicbengali"]=2443, - ["rvocalicdeva"]=2315, - ["rvocalicgujarati"]=2699, - ["rvocalicvowelsignbengali"]=2499, - ["rvocalicvowelsigndeva"]=2371, - ["rvocalicvowelsigngujarati"]=2755, - ["s"]=115, - ["sabengali"]=2488, - ["sacute"]=347, - ["sacutedotaccent"]=7781, - ["sadarabic"]=1589, - ["sadeva"]=2360, - ["sadfinalarabic"]=65210, - ["sadinitialarabic"]=65211, - ["sadmedialarabic"]=65212, - ["sagujarati"]=2744, - ["sagurmukhi"]=2616, - ["sahiragana"]=12373, - ["sakatakana"]=12469, - ["sakatakanahalfwidth"]=65403, - ["sallallahoualayhewasallamarabic"]=65018, - ["samekhdageshhebrew"]=64321, - ["samekhhebrew"]=1505, - ["saraaathai"]=3634, - ["saraaethai"]=3649, - ["saraaimaimalaithai"]=3652, - ["saraaimaimuanthai"]=3651, - ["saraamthai"]=3635, - ["saraathai"]=3632, - ["saraethai"]=3648, - ["saraiithai"]=3637, - ["saraithai"]=3636, - ["saraothai"]=3650, - ["saraueethai"]=3639, - ["sarauethai"]=3638, - ["sarauthai"]=3640, - ["sarauuthai"]=3641, - ["sbopomofo"]=12569, - ["scaron"]=353, - ["scarondotaccent"]=7783, - ["scedilla"]=351, - ["schwa"]=601, - ["schwacyrillic"]=1241, - ["schwadieresiscyrillic"]=1243, - ["schwahook"]=602, - ["scircle"]=9442, - ["scircumflex"]=349, - ["scommaaccent"]=537, - ["sdotaccent"]=7777, - ["sdotbelow"]=7779, - ["sdotbelowdotaccent"]=7785, - ["seagullbelowcmb"]=828, - ["second"]=8243, - ["secondtonechinese"]=714, - ["section"]=167, - ["seenarabic"]=1587, - ["seenfinalarabic"]=65202, - ["seeninitialarabic"]=65203, - ["seenmedialarabic"]=65204, - ["segoltahebrew"]=1426, - ["segolwidehebrew"]=1462, - ["seharmenian"]=1405, - ["sehiragana"]=12379, - ["sekatakana"]=12475, - ["sekatakanahalfwidth"]=65406, - ["semicolon"]=59, - ["semicolonarabic"]=1563, - ["semicolonmonospace"]=65307, - ["semicolonsmall"]=65108, - ["semivoicedmarkkana"]=12444, - ["semivoicedmarkkanahalfwidth"]=65439, - ["sentisquare"]=13090, - ["sentosquare"]=13091, - ["seven"]=55, - ["sevenbengali"]=2541, - ["sevencircle"]=9318, - ["sevencircleinversesansserif"]=10128, - ["sevendeva"]=2413, - ["seveneighths"]=8542, - ["sevengujarati"]=2797, - ["sevengurmukhi"]=2669, - ["sevenhackarabic"]=1639, - ["sevenhangzhou"]=12327, - ["sevenideographicparen"]=12838, - ["seveninferior"]=8327, - ["sevenmonospace"]=65303, - ["sevenparen"]=9338, - ["sevenperiod"]=9358, - ["sevenpersian"]=1783, - ["sevenroman"]=8566, - ["sevensuperior"]=8311, - ["seventeencircle"]=9328, - ["seventeenparen"]=9348, - ["seventeenperiod"]=9368, - ["seventhai"]=3671, - ["shaarmenian"]=1399, - ["shabengali"]=2486, - ["shacyrillic"]=1096, - ["shaddadammaarabic"]=64609, - ["shaddadammatanarabic"]=64606, - ["shaddafathaarabic"]=64608, - ["shaddafathatanarabic"]=1617, - ["shaddakasraarabic"]=64610, - ["shaddakasratanarabic"]=64607, - ["shadedark"]=9619, - ["shadelight"]=9617, - ["shademedium"]=9618, - ["shadeva"]=2358, - ["shagujarati"]=2742, - ["shagurmukhi"]=2614, - ["shalshelethebrew"]=1427, - ["shbopomofo"]=12565, - ["shchacyrillic"]=1097, - ["sheenarabic"]=1588, - ["sheenfinalarabic"]=65206, - ["sheeninitialarabic"]=65207, - ["sheenmedialarabic"]=65208, - ["sheicoptic"]=995, - ["sheqelhebrew"]=8362, - ["shevawidehebrew"]=1456, - ["shhacyrillic"]=1211, - ["shimacoptic"]=1005, - ["shindageshhebrew"]=64329, - ["shindageshshindothebrew"]=64300, - ["shindageshsindothebrew"]=64301, - ["shindothebrew"]=1473, - ["shinhebrew"]=1513, - ["shinshindothebrew"]=64298, - ["shinsindothebrew"]=64299, - ["shook"]=642, - ["sigma"]=963, - ["sigmafinal"]=962, - ["sigmalunatesymbolgreek"]=1010, - ["sihiragana"]=12375, - ["sikatakana"]=12471, - ["sikatakanahalfwidth"]=65404, - ["siluqlefthebrew"]=1469, - ["sindothebrew"]=1474, - ["siosacirclekorean"]=12916, - ["siosaparenkorean"]=12820, - ["sioscieuckorean"]=12670, - ["sioscirclekorean"]=12902, - ["sioskiyeokkorean"]=12666, - ["sioskorean"]=12613, - ["siosnieunkorean"]=12667, - ["siosparenkorean"]=12806, - ["siospieupkorean"]=12669, - ["siostikeutkorean"]=12668, - ["six"]=54, - ["sixbengali"]=2540, - ["sixcircle"]=9317, - ["sixcircleinversesansserif"]=10127, - ["sixdeva"]=2412, - ["sixgujarati"]=2796, - ["sixgurmukhi"]=2668, - ["sixhackarabic"]=1638, - ["sixhangzhou"]=12326, - ["sixideographicparen"]=12837, - ["sixinferior"]=8326, - ["sixmonospace"]=65302, - ["sixparen"]=9337, - ["sixperiod"]=9357, - ["sixpersian"]=1782, - ["sixroman"]=8565, - ["sixsuperior"]=8310, - ["sixteencircle"]=9327, - ["sixteencurrencydenominatorbengali"]=2553, - ["sixteenparen"]=9347, - ["sixteenperiod"]=9367, - ["sixthai"]=3670, - ["slash"]=47, - ["slashmonospace"]=65295, - ["slong"]=383, - ["slongdotaccent"]=7835, - ["smonospace"]=65363, - ["sofpasuqhebrew"]=1475, - ["softhyphen"]=173, - ["softsigncyrillic"]=1100, - ["sohiragana"]=12381, - ["sokatakana"]=12477, - ["sokatakanahalfwidth"]=65407, - ["soliduslongoverlaycmb"]=824, - ["solidusshortoverlaycmb"]=823, - ["sorusithai"]=3625, - ["sosalathai"]=3624, - ["sosothai"]=3595, - ["sosuathai"]=3626, - ["space"]=32, - ["spadesuitblack"]=9824, - ["spadesuitwhite"]=9828, - ["sparen"]=9390, - ["squarebelowcmb"]=827, - ["squarecc"]=13252, - ["squarecm"]=13213, - ["squarediagonalcrosshatchfill"]=9641, - ["squarehorizontalfill"]=9636, - ["squarekg"]=13199, - ["squarekm"]=13214, - ["squarekmcapital"]=13262, - ["squareln"]=13265, - ["squarelog"]=13266, - ["squaremg"]=13198, - ["squaremil"]=13269, - ["squaremm"]=13212, - ["squaremsquared"]=13217, - ["squareorthogonalcrosshatchfill"]=9638, - ["squareupperlefttolowerrightfill"]=9639, - ["squareupperrighttolowerleftfill"]=9640, - ["squareverticalfill"]=9637, - ["squarewhitewithsmallblack"]=9635, - ["srsquare"]=13275, - ["ssabengali"]=2487, - ["ssadeva"]=2359, - ["ssagujarati"]=2743, - ["ssangcieuckorean"]=12617, - ["ssanghieuhkorean"]=12677, - ["ssangieungkorean"]=12672, - ["ssangkiyeokkorean"]=12594, - ["ssangnieunkorean"]=12645, - ["ssangpieupkorean"]=12611, - ["ssangsioskorean"]=12614, - ["ssangtikeutkorean"]=12600, - ["sterling"]=163, - ["sterlingmonospace"]=65505, - ["strokelongoverlaycmb"]=822, - ["strokeshortoverlaycmb"]=821, - ["subset"]=8834, - ["subsetnotequal"]=8842, - ["subsetorequal"]=8838, - ["succeeds"]=8827, - ["suchthat"]=8715, - ["suhiragana"]=12377, - ["sukatakana"]=12473, - ["sukatakanahalfwidth"]=65405, - ["sukunarabic"]=1618, - ["summation"]=8721, - ["sun"]=9788, - ["superset"]=8835, - ["supersetnotequal"]=8843, - ["supersetorequal"]=8839, - ["svsquare"]=13276, - ["syouwaerasquare"]=13180, - ["t"]=116, - ["tabengali"]=2468, - ["tackdown"]=8868, - ["tackleft"]=8867, - ["tadeva"]=2340, - ["tagujarati"]=2724, - ["tagurmukhi"]=2596, - ["taharabic"]=1591, - ["tahfinalarabic"]=65218, - ["tahinitialarabic"]=65219, - ["tahiragana"]=12383, - ["tahmedialarabic"]=65220, - ["taisyouerasquare"]=13181, - ["takatakana"]=12479, - ["takatakanahalfwidth"]=65408, - ["tatweelarabic"]=1600, - ["tau"]=964, - ["tavdageshhebrew"]=64330, - ["tavhebrew"]=1514, - ["tbar"]=359, - ["tbopomofo"]=12554, - ["tcaron"]=357, - ["tccurl"]=680, - ["tcheharabic"]=1670, - ["tchehfinalarabic"]=64379, - ["tchehmedialarabic"]=64381, - ["tchehmeeminitialarabic"]=64380, - ["tcircle"]=9443, - ["tcircumflexbelow"]=7793, - ["tcommaaccent"]=355, - ["tdieresis"]=7831, - ["tdotaccent"]=7787, - ["tdotbelow"]=7789, - ["tecyrillic"]=1090, - ["tedescendercyrillic"]=1197, - ["teharabic"]=1578, - ["tehfinalarabic"]=65174, - ["tehhahinitialarabic"]=64674, - ["tehhahisolatedarabic"]=64524, - ["tehinitialarabic"]=65175, - ["tehiragana"]=12390, - ["tehjeeminitialarabic"]=64673, - ["tehjeemisolatedarabic"]=64523, - ["tehmarbutaarabic"]=1577, - ["tehmarbutafinalarabic"]=65172, - ["tehmedialarabic"]=65176, - ["tehmeeminitialarabic"]=64676, - ["tehmeemisolatedarabic"]=64526, - ["tehnoonfinalarabic"]=64627, - ["tekatakana"]=12486, - ["tekatakanahalfwidth"]=65411, - ["telephone"]=8481, - ["telephoneblack"]=9742, - ["telishagedolahebrew"]=1440, - ["telishaqetanahebrew"]=1449, - ["tencircle"]=9321, - ["tenideographicparen"]=12841, - ["tenparen"]=9341, - ["tenperiod"]=9361, - ["tenroman"]=8569, - ["tesh"]=679, - ["tetdageshhebrew"]=64312, - ["tethebrew"]=1496, - ["tetsecyrillic"]=1205, - ["tevirlefthebrew"]=1435, - ["thabengali"]=2469, - ["thadeva"]=2341, - ["thagujarati"]=2725, - ["thagurmukhi"]=2597, - ["thalarabic"]=1584, - ["thalfinalarabic"]=65196, - ["thanthakhatthai"]=3660, - ["theharabic"]=1579, - ["thehfinalarabic"]=65178, - ["thehinitialarabic"]=65179, - ["thehmedialarabic"]=65180, - ["thereexists"]=8707, - ["therefore"]=8756, - ["theta"]=952, - ["thetasymbolgreek"]=977, - ["thieuthacirclekorean"]=12921, - ["thieuthaparenkorean"]=12825, - ["thieuthcirclekorean"]=12907, - ["thieuthkorean"]=12620, - ["thieuthparenkorean"]=12811, - ["thirteencircle"]=9324, - ["thirteenparen"]=9344, - ["thirteenperiod"]=9364, - ["thonangmonthothai"]=3601, - ["thook"]=429, - ["thophuthaothai"]=3602, - ["thorn"]=254, - ["thothahanthai"]=3607, - ["thothanthai"]=3600, - ["thothongthai"]=3608, - ["thothungthai"]=3606, - ["thousandcyrillic"]=1154, - ["thousandsseparatorpersian"]=1644, - ["three"]=51, - ["threebengali"]=2537, - ["threecircle"]=9314, - ["threecircleinversesansserif"]=10124, - ["threedeva"]=2409, - ["threeeighths"]=8540, - ["threegujarati"]=2793, - ["threegurmukhi"]=2665, - ["threehackarabic"]=1635, - ["threehangzhou"]=12323, - ["threeideographicparen"]=12834, - ["threeinferior"]=8323, - ["threemonospace"]=65299, - ["threenumeratorbengali"]=2550, - ["threeparen"]=9334, - ["threeperiod"]=9354, - ["threepersian"]=1779, - ["threequarters"]=190, - ["threeroman"]=8562, - ["threesuperior"]=179, - ["threethai"]=3667, - ["thzsquare"]=13204, - ["tihiragana"]=12385, - ["tikatakana"]=12481, - ["tikatakanahalfwidth"]=65409, - ["tikeutacirclekorean"]=12912, - ["tikeutaparenkorean"]=12816, - ["tikeutcirclekorean"]=12898, - ["tikeutkorean"]=12599, - ["tikeutparenkorean"]=12802, - ["tilde"]=732, - ["tildebelowcmb"]=816, - ["tildecomb"]=771, - ["tildedoublecmb"]=864, - ["tildeoperator"]=8764, - ["tildeoverlaycmb"]=820, - ["tildeverticalcmb"]=830, - ["timescircle"]=8855, - ["tipehalefthebrew"]=1430, - ["tippigurmukhi"]=2672, - ["titlocyrilliccmb"]=1155, - ["tiwnarmenian"]=1407, - ["tlinebelow"]=7791, - ["tmonospace"]=65364, - ["toarmenian"]=1385, - ["tohiragana"]=12392, - ["tokatakana"]=12488, - ["tokatakanahalfwidth"]=65412, - ["tonebarextrahighmod"]=741, - ["tonebarextralowmod"]=745, - ["tonebarhighmod"]=742, - ["tonebarlowmod"]=744, - ["tonebarmidmod"]=743, - ["tonefive"]=445, - ["tonesix"]=389, - ["tonetwo"]=424, - ["tonos"]=900, - ["tonsquare"]=13095, - ["topatakthai"]=3599, - ["tortoiseshellbracketleft"]=12308, - ["tortoiseshellbracketleftsmall"]=65117, - ["tortoiseshellbracketleftvertical"]=65081, - ["tortoiseshellbracketright"]=12309, - ["tortoiseshellbracketrightsmall"]=65118, - ["tortoiseshellbracketrightvertical"]=65082, - ["totaothai"]=3605, - ["tpalatalhook"]=427, - ["tparen"]=9391, - ["trademark"]=8482, - ["tretroflexhook"]=648, - ["triagdn"]=9660, - ["triaglf"]=9668, - ["triagrt"]=9658, - ["triagup"]=9650, - ["ts"]=678, - ["tsadidageshhebrew"]=64326, - ["tsadihebrew"]=1510, - ["tsecyrillic"]=1094, - ["tserewidehebrew"]=1461, - ["tshecyrillic"]=1115, - ["ttabengali"]=2463, - ["ttadeva"]=2335, - ["ttagujarati"]=2719, - ["ttagurmukhi"]=2591, - ["tteharabic"]=1657, - ["ttehfinalarabic"]=64359, - ["ttehinitialarabic"]=64360, - ["ttehmedialarabic"]=64361, - ["tthabengali"]=2464, - ["tthadeva"]=2336, - ["tthagujarati"]=2720, - ["tthagurmukhi"]=2592, - ["tturned"]=647, - ["tuhiragana"]=12388, - ["tukatakana"]=12484, - ["tukatakanahalfwidth"]=65410, - ["tusmallhiragana"]=12387, - ["tusmallkatakana"]=12483, - ["tusmallkatakanahalfwidth"]=65391, - ["twelvecircle"]=9323, - ["twelveparen"]=9343, - ["twelveperiod"]=9363, - ["twelveroman"]=8571, - ["twentycircle"]=9331, - ["twentyparen"]=9351, - ["twentyperiod"]=9371, - ["two"]=50, - ["twobengali"]=2536, - ["twocircle"]=9313, - ["twocircleinversesansserif"]=10123, - ["twodeva"]=2408, - ["twodotleader"]=8229, - ["twodotleadervertical"]=65072, - ["twogujarati"]=2792, - ["twogurmukhi"]=2664, - ["twohackarabic"]=1634, - ["twohangzhou"]=12322, - ["twoideographicparen"]=12833, - ["twoinferior"]=8322, - ["twomonospace"]=65298, - ["twonumeratorbengali"]=2549, - ["twoparen"]=9333, - ["twoperiod"]=9353, - ["twopersian"]=1778, - ["tworoman"]=8561, - ["twostroke"]=443, - ["twosuperior"]=178, - ["twothai"]=3666, - ["twothirds"]=8532, - ["u"]=117, - ["uacute"]=250, - ["ubar"]=649, - ["ubengali"]=2441, - ["ubopomofo"]=12584, - ["ubreve"]=365, - ["ucaron"]=468, - ["ucircle"]=9444, - ["ucircumflex"]=251, - ["ucircumflexbelow"]=7799, - ["ucyrillic"]=1091, - ["udattadeva"]=2385, - ["udblgrave"]=533, - ["udeva"]=2313, - ["udieresis"]=252, - ["udieresisacute"]=472, - ["udieresisbelow"]=7795, - ["udieresiscaron"]=474, - ["udieresiscyrillic"]=1265, - ["udieresisgrave"]=476, - ["udieresismacron"]=470, - ["udotbelow"]=7909, - ["ugrave"]=249, - ["ugujarati"]=2697, - ["ugurmukhi"]=2569, - ["uhiragana"]=12358, - ["uhookabove"]=7911, - ["uhorn"]=432, - ["uhornacute"]=7913, - ["uhorndotbelow"]=7921, - ["uhorngrave"]=7915, - ["uhornhookabove"]=7917, - ["uhorntilde"]=7919, - ["uhungarumlaut"]=369, - ["uhungarumlautcyrillic"]=1267, - ["uinvertedbreve"]=535, - ["ukatakana"]=12454, - ["ukatakanahalfwidth"]=65395, - ["ukcyrillic"]=1145, - ["ukorean"]=12636, - ["umacron"]=363, - ["umacroncyrillic"]=1263, - ["umacrondieresis"]=7803, - ["umatragurmukhi"]=2625, - ["umonospace"]=65365, - ["underscore"]=95, - ["underscoredbl"]=8215, - ["underscoremonospace"]=65343, - ["underscorevertical"]=65075, - ["underscorewavy"]=65103, - ["union"]=8746, - ["universal"]=8704, - ["uogonek"]=371, - ["uparen"]=9392, - ["upblock"]=9600, - ["upperdothebrew"]=1476, - ["upsilon"]=965, - ["upsilondieresis"]=971, - ["upsilondieresistonos"]=944, - ["upsilonlatin"]=650, - ["upsilontonos"]=973, - ["uptackbelowcmb"]=797, - ["uptackmod"]=724, - ["uragurmukhi"]=2675, - ["uring"]=367, - ["ushortcyrillic"]=1118, - ["usmallhiragana"]=12357, - ["usmallkatakana"]=12453, - ["usmallkatakanahalfwidth"]=65385, - ["ustraightcyrillic"]=1199, - ["ustraightstrokecyrillic"]=1201, - ["utilde"]=361, - ["utildeacute"]=7801, - ["utildebelow"]=7797, - ["uubengali"]=2442, - ["uudeva"]=2314, - ["uugujarati"]=2698, - ["uugurmukhi"]=2570, - ["uumatragurmukhi"]=2626, - ["uuvowelsignbengali"]=2498, - ["uuvowelsigndeva"]=2370, - ["uuvowelsigngujarati"]=2754, - ["uvowelsignbengali"]=2497, - ["uvowelsigndeva"]=2369, - ["uvowelsigngujarati"]=2753, - ["v"]=118, - ["vadeva"]=2357, - ["vagujarati"]=2741, - ["vagurmukhi"]=2613, - ["vakatakana"]=12535, - ["vavdageshhebrew"]=64309, - ["vavhebrew"]=1493, - ["vavholamhebrew"]=64331, - ["vavvavhebrew"]=1520, - ["vavyodhebrew"]=1521, - ["vcircle"]=9445, - ["vdotbelow"]=7807, - ["vecyrillic"]=1074, - ["veharabic"]=1700, - ["vehfinalarabic"]=64363, - ["vehinitialarabic"]=64364, - ["vehmedialarabic"]=64365, - ["vekatakana"]=12537, - ["venus"]=9792, - ["verticalbar"]=124, - ["verticallineabovecmb"]=781, - ["verticallinebelowcmb"]=809, - ["verticallinelowmod"]=716, - ["verticallinemod"]=712, - ["vewarmenian"]=1406, - ["vhook"]=651, - ["vikatakana"]=12536, - ["viramabengali"]=2509, - ["viramadeva"]=2381, - ["viramagujarati"]=2765, - ["visargabengali"]=2435, - ["visargadeva"]=2307, - ["visargagujarati"]=2691, - ["vmonospace"]=65366, - ["voarmenian"]=1400, - ["voicediterationhiragana"]=12446, - ["voicediterationkatakana"]=12542, - ["voicedmarkkana"]=12443, - ["voicedmarkkanahalfwidth"]=65438, - ["vokatakana"]=12538, - ["vparen"]=9393, - ["vtilde"]=7805, - ["vturned"]=652, - ["vuhiragana"]=12436, - ["vukatakana"]=12532, - ["w"]=119, - ["wacute"]=7811, - ["waekorean"]=12633, - ["wahiragana"]=12431, - ["wakatakana"]=12527, - ["wakatakanahalfwidth"]=65436, - ["wakorean"]=12632, - ["wasmallhiragana"]=12430, - ["wasmallkatakana"]=12526, - ["wattosquare"]=13143, - ["wavedash"]=12316, - ["wavyunderscorevertical"]=65076, - ["wawarabic"]=1608, - ["wawfinalarabic"]=65262, - ["wawhamzaabovearabic"]=1572, - ["wawhamzaabovefinalarabic"]=65158, - ["wbsquare"]=13277, - ["wcircle"]=9446, - ["wcircumflex"]=373, - ["wdieresis"]=7813, - ["wdotaccent"]=7815, - ["wdotbelow"]=7817, - ["wehiragana"]=12433, - ["weierstrass"]=8472, - ["wekatakana"]=12529, - ["wekorean"]=12638, - ["weokorean"]=12637, - ["wgrave"]=7809, - ["whitebullet"]=9702, - ["whitecircle"]=9675, - ["whitecircleinverse"]=9689, - ["whitecornerbracketleft"]=12302, - ["whitecornerbracketleftvertical"]=65091, - ["whitecornerbracketright"]=12303, - ["whitecornerbracketrightvertical"]=65092, - ["whitediamond"]=9671, - ["whitediamondcontainingblacksmalldiamond"]=9672, - ["whitedownpointingsmalltriangle"]=9663, - ["whitedownpointingtriangle"]=9661, - ["whiteleftpointingsmalltriangle"]=9667, - ["whiteleftpointingtriangle"]=9665, - ["whitelenticularbracketleft"]=12310, - ["whitelenticularbracketright"]=12311, - ["whiterightpointingsmalltriangle"]=9657, - ["whiterightpointingtriangle"]=9655, - ["whitesmallsquare"]=9643, - ["whitesmilingface"]=9786, - ["whitesquare"]=9633, - ["whitestar"]=9734, - ["whitetelephone"]=9743, - ["whitetortoiseshellbracketleft"]=12312, - ["whitetortoiseshellbracketright"]=12313, - ["whiteuppointingsmalltriangle"]=9653, - ["whiteuppointingtriangle"]=9651, - ["wihiragana"]=12432, - ["wikatakana"]=12528, - ["wikorean"]=12639, - ["wmonospace"]=65367, - ["wohiragana"]=12434, - ["wokatakana"]=12530, - ["wokatakanahalfwidth"]=65382, - ["won"]=8361, - ["wonmonospace"]=65510, - ["wowaenthai"]=3623, - ["wparen"]=9394, - ["wring"]=7832, - ["wsuperior"]=695, - ["wturned"]=653, - ["wynn"]=447, - ["x"]=120, - ["xabovecmb"]=829, - ["xbopomofo"]=12562, - ["xcircle"]=9447, - ["xdieresis"]=7821, - ["xdotaccent"]=7819, - ["xeharmenian"]=1389, - ["xi"]=958, - ["xmonospace"]=65368, - ["xparen"]=9395, - ["xsuperior"]=739, - ["y"]=121, - ["yaadosquare"]=13134, - ["yabengali"]=2479, - ["yacute"]=253, - ["yadeva"]=2351, - ["yaekorean"]=12626, - ["yagujarati"]=2735, - ["yagurmukhi"]=2607, - ["yahiragana"]=12420, - ["yakatakana"]=12516, - ["yakatakanahalfwidth"]=65428, - ["yakorean"]=12625, - ["yamakkanthai"]=3662, - ["yasmallhiragana"]=12419, - ["yasmallkatakana"]=12515, - ["yasmallkatakanahalfwidth"]=65388, - ["yatcyrillic"]=1123, - ["ycircle"]=9448, - ["ycircumflex"]=375, - ["ydieresis"]=255, - ["ydotaccent"]=7823, - ["ydotbelow"]=7925, - ["yeharabic"]=1610, - ["yehbarreearabic"]=1746, - ["yehbarreefinalarabic"]=64431, - ["yehfinalarabic"]=65266, - ["yehhamzaabovearabic"]=1574, - ["yehhamzaabovefinalarabic"]=65162, - ["yehhamzaaboveinitialarabic"]=65163, - ["yehhamzaabovemedialarabic"]=65164, - ["yehinitialarabic"]=65267, - ["yehmedialarabic"]=65268, - ["yehmeeminitialarabic"]=64733, - ["yehmeemisolatedarabic"]=64600, - ["yehnoonfinalarabic"]=64660, - ["yehthreedotsbelowarabic"]=1745, - ["yekorean"]=12630, - ["yen"]=165, - ["yenmonospace"]=65509, - ["yeokorean"]=12629, - ["yeorinhieuhkorean"]=12678, - ["yerahbenyomolefthebrew"]=1450, - ["yericyrillic"]=1099, - ["yerudieresiscyrillic"]=1273, - ["yesieungkorean"]=12673, - ["yesieungpansioskorean"]=12675, - ["yesieungsioskorean"]=12674, - ["yetivhebrew"]=1434, - ["ygrave"]=7923, - ["yhook"]=436, - ["yhookabove"]=7927, - ["yiarmenian"]=1397, - ["yicyrillic"]=1111, - ["yikorean"]=12642, - ["yinyang"]=9775, - ["yiwnarmenian"]=1410, - ["ymonospace"]=65369, - ["yoddageshhebrew"]=64313, - ["yodhebrew"]=1497, - ["yodyodhebrew"]=1522, - ["yodyodpatahhebrew"]=64287, - ["yohiragana"]=12424, - ["yoikorean"]=12681, - ["yokatakana"]=12520, - ["yokatakanahalfwidth"]=65430, - ["yokorean"]=12635, - ["yosmallhiragana"]=12423, - ["yosmallkatakana"]=12519, - ["yosmallkatakanahalfwidth"]=65390, - ["yotgreek"]=1011, - ["yoyaekorean"]=12680, - ["yoyakorean"]=12679, - ["yoyakthai"]=3618, - ["yoyingthai"]=3597, - ["yparen"]=9396, - ["ypogegrammeni"]=890, - ["ypogegrammenigreekcmb"]=837, - ["yr"]=422, - ["yring"]=7833, - ["ysuperior"]=696, - ["ytilde"]=7929, - ["yturned"]=654, - ["yuhiragana"]=12422, - ["yuikorean"]=12684, - ["yukatakana"]=12518, - ["yukatakanahalfwidth"]=65429, - ["yukorean"]=12640, - ["yusbigcyrillic"]=1131, - ["yusbigiotifiedcyrillic"]=1133, - ["yuslittlecyrillic"]=1127, - ["yuslittleiotifiedcyrillic"]=1129, - ["yusmallhiragana"]=12421, - ["yusmallkatakana"]=12517, - ["yusmallkatakanahalfwidth"]=65389, - ["yuyekorean"]=12683, - ["yuyeokorean"]=12682, - ["yyabengali"]=2527, - ["yyadeva"]=2399, - ["z"]=122, - ["zaarmenian"]=1382, - ["zacute"]=378, - ["zadeva"]=2395, - ["zagurmukhi"]=2651, - ["zaharabic"]=1592, - ["zahfinalarabic"]=65222, - ["zahinitialarabic"]=65223, - ["zahiragana"]=12374, - ["zahmedialarabic"]=65224, - ["zainarabic"]=1586, - ["zainfinalarabic"]=65200, - ["zakatakana"]=12470, - ["zaqefgadolhebrew"]=1429, - ["zaqefqatanhebrew"]=1428, - ["zarqahebrew"]=1432, - ["zayindageshhebrew"]=64310, - ["zayinhebrew"]=1494, - ["zbopomofo"]=12567, - ["zcaron"]=382, - ["zcircle"]=9449, - ["zcircumflex"]=7825, - ["zcurl"]=657, - ["zdotaccent"]=380, - ["zdotbelow"]=7827, - ["zecyrillic"]=1079, - ["zedescendercyrillic"]=1177, - ["zedieresiscyrillic"]=1247, - ["zehiragana"]=12380, - ["zekatakana"]=12476, - ["zero"]=48, - ["zerobengali"]=2534, - ["zerodeva"]=2406, - ["zerogujarati"]=2790, - ["zerogurmukhi"]=2662, - ["zerohackarabic"]=1632, - ["zeroinferior"]=8320, - ["zeromonospace"]=65296, - ["zeropersian"]=1776, - ["zerosuperior"]=8304, - ["zerothai"]=3664, - ["zerowidthjoiner"]=65279, - ["zerowidthnonjoiner"]=8204, - ["zerowidthspace"]=8203, - ["zeta"]=950, - ["zhbopomofo"]=12563, - ["zhearmenian"]=1386, - ["zhebrevecyrillic"]=1218, - ["zhecyrillic"]=1078, - ["zhedescendercyrillic"]=1175, - ["zhedieresiscyrillic"]=1245, - ["zihiragana"]=12376, - ["zikatakana"]=12472, - ["zinorhebrew"]=1454, - ["zlinebelow"]=7829, - ["zmonospace"]=65370, - ["zohiragana"]=12382, - ["zokatakana"]=12478, - ["zparen"]=9397, - ["zretroflexhook"]=656, - ["zstroke"]=438, - ["zuhiragana"]=12378, - ["zukatakana"]=12474, - - -- extras - - ["Dcroat"]=272, - ["Delta"]=8710, - ["Euro"]=8364, - ["H18533"]=9679, - ["H18543"]=9642, - ["H18551"]=9643, - ["H22073"]=9633, - ["Ldot"]=319, - ["Oslashacute"]=510, - ["SF10000"]=9484, - ["SF20000"]=9492, - ["SF30000"]=9488, - ["SF40000"]=9496, - ["SF50000"]=9532, - ["SF60000"]=9516, - ["SF70000"]=9524, - ["SF80000"]=9500, - ["SF90000"]=9508, - ["Upsilon1"]=978, - ["afii10066"]=1073, - ["afii10067"]=1074, - ["afii10068"]=1075, - ["afii10069"]=1076, - ["afii10070"]=1077, - ["afii10071"]=1105, - ["afii10072"]=1078, - ["afii10073"]=1079, - ["afii10074"]=1080, - ["afii10075"]=1081, - ["afii10076"]=1082, - ["afii10077"]=1083, - ["afii10078"]=1084, - ["afii10079"]=1085, - ["afii10080"]=1086, - ["afii10081"]=1087, - ["afii10082"]=1088, - ["afii10083"]=1089, - ["afii10084"]=1090, - ["afii10085"]=1091, - ["afii10086"]=1092, - ["afii10087"]=1093, - ["afii10088"]=1094, - ["afii10089"]=1095, - ["afii10090"]=1096, - ["afii10091"]=1097, - ["afii10092"]=1098, - ["afii10093"]=1099, - ["afii10094"]=1100, - ["afii10095"]=1101, - ["afii10096"]=1102, - ["afii10097"]=1103, - ["afii10098"]=1169, - ["afii10099"]=1106, - ["afii10100"]=1107, - ["afii10101"]=1108, - ["afii10102"]=1109, - ["afii10103"]=1110, - ["afii10104"]=1111, - ["afii10105"]=1112, - ["afii10106"]=1113, - ["afii10107"]=1114, - ["afii10108"]=1115, - ["afii10109"]=1116, - ["afii10110"]=1118, - ["afii10193"]=1119, - ["afii10194"]=1123, - ["afii10195"]=1139, - ["afii10196"]=1141, - ["afii10846"]=1241, - ["afii208"]=8213, - ["afii57381"]=1642, - ["afii57388"]=1548, - ["afii57392"]=1632, - ["afii57393"]=1633, - ["afii57394"]=1634, - ["afii57395"]=1635, - ["afii57396"]=1636, - ["afii57397"]=1637, - ["afii57398"]=1638, - ["afii57399"]=1639, - ["afii57400"]=1640, - ["afii57401"]=1641, - ["afii57403"]=1563, - ["afii57407"]=1567, - ["afii57409"]=1569, - ["afii57410"]=1570, - ["afii57411"]=1571, - ["afii57412"]=1572, - ["afii57413"]=1573, - ["afii57414"]=1574, - ["afii57415"]=1575, - ["afii57416"]=1576, - ["afii57417"]=1577, - ["afii57418"]=1578, - ["afii57419"]=1579, - ["afii57420"]=1580, - ["afii57421"]=1581, - ["afii57422"]=1582, - ["afii57423"]=1583, - ["afii57424"]=1584, - ["afii57425"]=1585, - ["afii57426"]=1586, - ["afii57427"]=1587, - ["afii57428"]=1588, - ["afii57429"]=1589, - ["afii57430"]=1590, - ["afii57431"]=1591, - ["afii57432"]=1592, - ["afii57433"]=1593, - ["afii57434"]=1594, - ["afii57440"]=1600, - ["afii57441"]=1601, - ["afii57442"]=1602, - ["afii57443"]=1603, - ["afii57444"]=1604, - ["afii57445"]=1605, - ["afii57446"]=1606, - ["afii57448"]=1608, - ["afii57449"]=1609, - ["afii57450"]=1610, - ["afii57451"]=1611, - ["afii57452"]=1612, - ["afii57453"]=1613, - ["afii57454"]=1614, - ["afii57455"]=1615, - ["afii57456"]=1616, - ["afii57457"]=1617, - ["afii57458"]=1618, - ["afii57470"]=1607, - ["afii57505"]=1700, - ["afii57506"]=1662, - ["afii57507"]=1670, - ["afii57508"]=1688, - ["afii57509"]=1711, - ["afii57511"]=1657, - ["afii57512"]=1672, - ["afii57513"]=1681, - ["afii57514"]=1722, - ["afii57519"]=1746, - ["afii57636"]=8362, - ["afii57645"]=1470, - ["afii57658"]=1475, - ["afii57664"]=1488, - ["afii57665"]=1489, - ["afii57666"]=1490, - ["afii57667"]=1491, - ["afii57668"]=1492, - ["afii57669"]=1493, - ["afii57670"]=1494, - ["afii57671"]=1495, - ["afii57672"]=1496, - ["afii57673"]=1497, - ["afii57674"]=1498, - ["afii57675"]=1499, - ["afii57676"]=1500, - ["afii57677"]=1501, - ["afii57678"]=1502, - ["afii57679"]=1503, - ["afii57680"]=1504, - ["afii57681"]=1505, - ["afii57682"]=1506, - ["afii57683"]=1507, - ["afii57684"]=1508, - ["afii57685"]=1509, - ["afii57686"]=1510, - ["afii57687"]=1511, - ["afii57688"]=1512, - ["afii57689"]=1513, - ["afii57690"]=1514, - ["afii57716"]=1520, - ["afii57717"]=1521, - ["afii57718"]=1522, - ["afii57793"]=1460, - ["afii57794"]=1461, - ["afii57795"]=1462, - ["afii57796"]=1467, - ["afii57797"]=1464, - ["afii57798"]=1463, - ["afii57799"]=1456, - ["afii57800"]=1458, - ["afii57801"]=1457, - ["afii57802"]=1459, - ["afii57803"]=1474, - ["afii57804"]=1473, - ["afii57806"]=1465, - ["afii57807"]=1468, - ["afii57839"]=1469, - ["afii57841"]=1471, - ["afii57842"]=1472, - ["afii57929"]=700, - ["afii61248"]=8453, - ["afii61289"]=8467, - ["afii61352"]=8470, - ["afii61664"]=8204, - ["afii63167"]=1645, - ["afii64937"]=701, - ["arrowdblboth"]=8660, - ["arrowdblleft"]=8656, - ["arrowdblright"]=8658, - ["arrowupdnbse"]=8616, - ["bar"]=124, - ["circle"]=9675, - ["circlemultiply"]=8855, - ["circleplus"]=8853, - ["club"]=9827, - ["colonmonetary"]=8353, - ["dcroat"]=273, - ["dkshade"]=9619, - ["existential"]=8707, - ["female"]=9792, - ["gradient"]=8711, - ["heart"]=9829, - ["hookabovecomb"]=777, - ["invcircle"]=9689, - ["ldot"]=320, - ["longs"]=383, - ["ltshade"]=9617, - ["male"]=9794, - ["mu"]=181, - ["napostrophe"]=329, - ["notelement"]=8713, - ["omega1"]=982, - ["openbullet"]=9702, - ["orthogonal"]=8735, - ["oslashacute"]=511, - ["phi1"]=981, - ["propersubset"]=8834, - ["propersuperset"]=8835, - ["reflexsubset"]=8838, - ["reflexsuperset"]=8839, - ["shade"]=9618, - ["sigma1"]=962, - ["similar"]=8764, - ["smileface"]=9786, - ["spacehackarabic"]=32, - ["spade"]=9824, - ["theta1"]=977, - ["twodotenleader"]=8229, -} diff --git a/fontdbutil.lua b/fontdbutil.lua index 31c7dfa..d76678f 100755 --- a/fontdbutil.lua +++ b/fontdbutil.lua @@ -1,11 +1,15 @@ #!/usr/bin/env texlua ---[[ + +--[[doc-- This file was originally written by Elie Roux and Khaled Hosny and is under CC0 license (see http://creativecommons.org/publicdomain/zero/1.0/legalcode). -This file is a wrapper for the luaotfload's font names module. It is part of the -luaotfload bundle, please see the luaotfload documentation for more info. ---]] +This file is a wrapper for the luaotfload font names module +(luaotfload-database.lua). It is part of the luaotfload bundle, please +see the luaotfload documentation for more info. Report bugs to +\url{https://github.com/lualatex/luaotfload/issues}. + +--doc]]-- kpse.set_program_name"luatex" @@ -14,18 +18,17 @@ local texiowrite_nl = texio.write_nl local stringfind = string.find local stringlower = string.lower --- First we need to be able to load module (code copied from --- luatexbase-loader.sty): + local loader_file = "luatexbase.loader.lua" local loader_path = assert(kpse.find_file(loader_file, "lua"), "File '"..loader_file.."' not found") + string.quoted = string.quoted or function (str) return string.format("%q",str) end ---texiowrite_nl("("..loader_path..")") -dofile(loader_path) -- FIXME this pollutes stdout with filenames +dofile(loader_path) --[[doc-- Depending on how the script is called we change its behavior. @@ -73,7 +76,20 @@ config.lualibs.prefer_merged = true config.lualibs.load_extended = false require"lualibs" + +--[[doc-- +\fileent{luatex-basics-gen.lua} calls functions from the +\luafunction{texio.*} library; too much for our taste. +We intercept them with dummies. +--doc]]-- + +local dummy_function = function ( ) end +local backup_write, backup_write_nl = texio.write, texio.write_nl + +texio.write, texio.write_nl = dummy_function, dummy_function require"luaotfload-basics-gen.lua" +texio.write, texio.write_nl = backup_write, backup_write_nl + require"luaotfload-override.lua" --- this populates the logs.* namespace require"luaotfload-database" require"alt_getopt" @@ -103,6 +119,8 @@ This tool is part of the luaotfload package. Valid options are: -V --version print version and exit -h --help print this message + --alias=<name> force behavior of “fontdbutil” or legacy + “mkluatexfontdb” ------------------------------------------------------------------------------- DATABASE @@ -136,6 +154,8 @@ Valid options: -vvv print all steps of directory searching -V --version print version and exit -h --help print this message + --alias=<name> force behavior of “fontdbutil” or legacy + “mkluatexfontdb” The font database will be saved to %s @@ -171,10 +191,10 @@ local show_font_info = function (filename) local fontinfo = fontloader.info(fullname) local nfonts = #fontinfo if nfonts > 0 then -- true type collection - logs.names_report(true, 0, "resolve", + logs.names_report(true, 1, "resolve", [[%s is a font collection]], filename) for n = 1, nfonts do - logs.names_report(true, 0, "resolve", + logs.names_report(true, 1, "resolve", [[showing info for font no. %d]], n) show_info_items(fontinfo[n]) end @@ -182,7 +202,7 @@ local show_font_info = function (filename) show_info_items(fontinfo) end else - logs.names_report(true, 0, "resolve", + logs.names_report(true, 1, "resolve", "font %s not found", filename) end end @@ -205,7 +225,7 @@ local actions = { } --- (jobspec -> (bool * bool)) list actions.loglevel = function (job) logs.set_loglevel(job.log_level) - logs.names_report("log", 2, "util", + logs.names_report("info", 3, "util", "setting log level", "%d", job.log_level) return true, true end @@ -223,8 +243,8 @@ end actions.generate = function (job) local fontnames, savedname fontnames = names.update(fontnames, job.force_reload) - logs.names_report("log", 0, "db", - "fonts in the database", "%i", #fontnames.mappings) + logs.names_report("info", 2, "db", + "Fonts in the database: %i", #fontnames.mappings) savedname = names.save(fontnames) if savedname then --- FIXME have names.save return bool return true, true @@ -246,18 +266,18 @@ actions.query = function (job) fonts.names.resolve(nil, nil, tmpspec) if success then - logs.names_report(false, 0, + logs.names_report(false, 1, "resolve", "Font “%s” found!", query) - logs.names_report(false, 0, + logs.names_report(false, 1, "resolve", "Resolved file name “%s”:", foundname) if job.show_info then show_font_info(foundname) end else - logs.names_report(false, 0, + logs.names_report(false, 1, "resolve", "Cannot find “%s”.", query) if job.fuzzy == true then - logs.names_report(false, 2, + logs.names_report(false, 1, "resolve", "Looking for close matches, this may take a while ...") local success = fonts.names.find_closest(query, job.fuzzy_limit) end @@ -279,14 +299,11 @@ local process_cmdline = function ( ) -- unit -> jobspec local result = { -- jobspec force_reload = nil, query = "", - log_level = 1, + log_level = 1, --- 2 is approx. the old behavior } - if config.luaotfload.self == "mkluatexfontdb" then - action_pending["generate"] = true - end - local long_options = { + alias = 1, find = 1, force = "f", fuzzy = "F", @@ -347,8 +364,17 @@ local process_cmdline = function ( ) -- unit -> jobspec end elseif v == "i" then result.show_info = true + elseif v == "alias" then + config.luaotfload.self = optarg[n] end end + + if config.luaotfload.self == "mkluatexfontdb" then + action_pending["generate"] = true + print(result.log_level) + result.log_level = math.max(2, result.log_level) + print(result.log_level) + end return result end diff --git a/luaotfload-basics-gen.lua b/luaotfload-basics-gen.lua index 727086e..61f3910 100644 --- a/luaotfload-basics-gen.lua +++ b/luaotfload-basics-gen.lua @@ -130,7 +130,9 @@ end caches = { } -local writable, readables = nil, { } +local writable = nil +local readables = { } +local usingjit = jit if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then caches.namespace = 'generic' @@ -204,7 +206,7 @@ end local function makefullname(path,name) if path and path ~= "" then name = "temp-" .. name -- clash prevention - return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),"luc") + return file.addsuffix(file.join(path,name),"lua"), file.addsuffix(file.join(path,name),usingjit and "lub" or "luc") end end @@ -265,26 +267,36 @@ end -- this) in which case one should limit the method to luac and enable support -- for execution. -caches.compilemethod = "both" +-- function caches.compile(data,luaname,lucname) +-- local d = io.loaddata(luaname) +-- if not d or d == "" then +-- d = table.serialize(data,true) -- slow +-- end +-- if d and d ~= "" then +-- local f = io.open(lucname,'w') +-- if f then +-- local s = loadstring(d) +-- if s then +-- f:write(string.dump(s,true)) +-- end +-- f:close() +-- end +-- end +-- end function caches.compile(data,luaname,lucname) - local done = false - if caches.compilemethod == "luac" or caches.compilemethod == "both" then - done = os.spawn("texluac -o " .. string.quoted(lucname) .. " -s " .. string.quoted(luaname)) == 0 + local d = io.loaddata(luaname) + if not d or d == "" then + d = table.serialize(data,true) -- slow end - if not done and (caches.compilemethod == "dump" or caches.compilemethod == "both") then - local d = io.loaddata(luaname) - if not d or d == "" then - d = table.serialize(data,true) -- slow - end - if d and d ~= "" then - local f = io.open(lucname,'w') - if f then - local s - if _G["loadstring"] then s=loadstring(d) else s=load(d) end - f:write(string.dump(s)) - f:close() + if d and d ~= "" then + local f = io.open(lucname,'w') + if f then + local s = loadstring(d) + if s then + f:write(string.dump(s,true)) end + f:close() end end end diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 19b04db..e8f3d1d 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -18,6 +18,7 @@ local pcall = pcall local require = require local tonumber = tonumber +local fontloaderinfo = fontloader.info local iolines = io.lines local ioopen = io.open local kpseexpand_path = kpse.expand_path @@ -45,6 +46,8 @@ local utf8lower = unicode.utf8.lower local dirglob = dir.glob local dirmkdirs = dir.mkdirs local filebasename = file.basename +local filenameonly = file.nameonly +local filedirname = file.dirname local filecollapsepath = file.collapsepath or file.collapse_path local fileextname = file.extname local fileiswritable = file.iswritable @@ -81,32 +84,6 @@ end names.path.dir = writable_path names.path.path = filejoin(writable_path, names.path.basename) - ----- <FIXME> ---- ---- these lines load some binary module called “lualatex-platform” ---- that doesn’t appear to build with Lua 5.2. I’m going ahead and ---- disable it for the time being until someone clarifies what it ---- is supposed to do and whether we should care to fix it. ---- ---local success = pcall(require, "luatexbase.modutils") ---if success then --- success = pcall(luatexbase.require_module, --- "lualatex-platform", "2011/03/30") --- print(success) ---end - ---local get_installed_fonts ---if success then --- get_installed_fonts = lualatex.platform.get_installed_fonts ---else --- function get_installed_fonts() --- end ---end ----- </FIXME> - -local get_installed_fonts = nil - --[[doc-- Auxiliary functions --doc]]-- @@ -121,10 +98,46 @@ local sanitize_string = function (str) return nil end +--[[doc-- +This is a sketch of the db: + + type dbobj = { + mappings : fontentry list; + status : filestatus; + version : float; + } + and fontentry = { + familyname : string; + filename : (string * bool); + fontname : string; + fullname : string; + names : { + family : string; + fullname : string; + psname : string; + subfamily : string; + } + size : int list; + slant : int; + weight : int; + width : int; + } + and filestatus = (fullname, { index : int list; timestamp : int }) dict + +beware that this is a reconstruction and may be incomplete. + +--doc]]-- + local fontnames_init = function ( ) return { mappings = { }, status = { }, + --- adding filename mapping increases the + --- size of the serialized db on my system + --- (5840 font files) by a factor of ... + barenames = { },--- incr. by 1.11 + basenames = { },--- incr. by 1.22 +-- fullnames = { },--- incr. by 1.48 version = names.version, } end @@ -180,14 +193,18 @@ local save_names local scan_external_dir local update_names +--- unit -> dbobj load_names = function ( ) + local starttime = os.gettimeofday() local foundname, data = load_lua_file(names.path.path) if data then report("info", 1, "db", "Font names database loaded", "%s", foundname) + report("info", 3, "db", "Loading took %0.f ms", + 1000*(os.gettimeofday()-starttime)) else - report("info", 0, "db", + report("info", 1, "db", [[Font names database not found, generating new one. This can take several minutes; please be patient.]]) data = update_names(fontnames_init()) @@ -204,10 +221,6 @@ do regular = { "normal", "roman", "plain", "book", "medium", }, - --- TODO note from Élie Roux - --- boldregular was for old versions of Linux Libertine, is it still useful? - --- semibold is in new versions of Linux Libertine, but there is also a bold, - --- not sure it's useful here... bold = { "demi", "demibold", "semibold", "boldregular",}, italic = { "regularitalic", "normalitalic", @@ -227,6 +240,55 @@ end local fonts_loaded = false local fonts_reloaded = false +local crude_file_lookup_verbose = function (data, filename) + local found = data.barenames[filename] + if found then + report("info", 0, "db", + "crude file lookup: req=%s; hit=bare; ret=%s", + filename, found[1]) + return found + end +-- found = data.fullnames[filename] +-- if found then +-- report("info", 0, "db", +-- "crude file lookup: req=%s; hit=bare; ret=%s", +-- filename, found[1]) +-- return found +-- end + found = data.basenames[filename] + if found then + report("info", 0, "db", + "crude file lookup: req=%s; hit=bare; ret=%s", + filename, found[1]) + return found + end + found = resolvers.findfile(filename, "tfm") + if found then + report("info", 0, "db", + "crude file lookup: req=tfm; hit=bare; ret=%s", found) + return { found, false } + end + found = resolvers.findfile(filename, "ofm") + if found then + report("info", 0, "db", + "crude file lookup: req=ofm; hit=bare; ret=%s", found) + return { found, false } + end + return false +end + +local crude_file_lookup = function (data, filename) + local found = data.barenames[filename] +-- or data.fullnames[filename] + or data.basenames[filename] + if found then return found end + found = resolvers.findfile(filename, "tfm") + if found then return { found, false } end + found = resolvers.findfile(filename, "ofm") + if found then return { found, false } end + return false +end + --[[doc-- Luatex-fonts, the font-loader package luaotfload imports, comes with @@ -253,8 +315,10 @@ font database created by the mkluatexfontdb script. --- · specification: string (== <lookup> ":" <name>) --- · sub: string --- ---- the return value of “resolve” is the file name of the requested ---- font +--- the first return value of “resolve” is the file name of the +--- requested font (string) +--- the second is of type bool or string and indicates the subfont of a +--- ttc --- --- 'a -> 'a -> table -> (string * string | bool * bool) --- @@ -264,6 +328,18 @@ font database created by the mkluatexfontdb script. --- --- resolve = function (_,_,specification) -- the 1st two parameters are used by ConTeXt + if not fonts_loaded then + names.data = load_names() + fonts_loaded = true + end + local data = names.data + + if specification.lookup == "file" then + local found = crude_file_lookup(data, specification.name) + --local found = crude_file_lookup_verbose(data, specification.name) + if found then return found[1], found[2], true end + end + local name = sanitize_string(specification.name) local style = sanitize_string(specification.style) or "regular" @@ -274,152 +350,170 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con size = specification.size / 65536 end - if not fonts_loaded then - names.data = load_names() - fonts_loaded = true + if type(data) ~= "table" then + --- this catches a case where load_names() doesn’t + --- return a database object, which can happen only + --- in case there is valid Lua code in the database, + --- but it’s not a table, e.g. it contains an integer. + if not fonts_reloaded then + return reload_db("invalid database; not a table", + resolve, nil, nil, specification + ) + end + --- unsucessfully reloaded; bail + return specification.name, false, false end - local data = names.data - if type(data) == "table" then - local db_version, nms_version = data.version, names.version - if data.version ~= names.version then - report("log", 0, "db", - [[version mismatch; expected %4.3f, got %4.3f]], - nms_version, db_version - ) - return reload_db(resolve, nil, nil, specification) + local db_version, nms_version = data.version, names.version + if db_version ~= nms_version then + report("log", 0, "db", + [[version mismatch; expected %4.3f, got %4.3f]], + nms_version, db_version + ) + return reload_db("version mismatch", resolve, nil, nil, specification) + end + + if not data.mappings then + return reload_db("invalid database; missing font mapping", + resolve, nil, nil, specification + ) + end + + local found = { } + local synonym_set = style_synonyms.set + for _,face in next, data.mappings do + --- TODO we really should store those in dedicated + --- .sanitized field + local family = sanitize_string(face.names and face.names.family) + local subfamily = sanitize_string(face.names and face.names.subfamily) + local fullname = sanitize_string(face.names and face.names.fullname) + local psname = sanitize_string(face.names and face.names.psname) + local fontname = sanitize_string(face.fontname) + local pfullname = sanitize_string(face.fullname) + local optsize, dsnsize, maxsize, minsize + if #face.size > 0 then + optsize = face.size + dsnsize = optsize[1] and optsize[1] / 10 + -- can be nil + maxsize = optsize[2] and optsize[2] / 10 or dsnsize + minsize = optsize[3] and optsize[3] / 10 or dsnsize end - if data.mappings then - local found = { } - local synonym_set = style_synonyms.set - for _,face in next, data.mappings do - --- TODO we really should store those in dedicated - --- .sanitized field - local family = sanitize_string(face.names and face.names.family) - local subfamily = sanitize_string(face.names and face.names.subfamily) - local fullname = sanitize_string(face.names and face.names.fullname) - local psname = sanitize_string(face.names and face.names.psname) - local fontname = sanitize_string(face.fontname) - local pfullname = sanitize_string(face.fullname) - local optsize, dsnsize, maxsize, minsize - if #face.size > 0 then - optsize = face.size - dsnsize = optsize[1] and optsize[1] / 10 - -- can be nil - maxsize = optsize[2] and optsize[2] / 10 or dsnsize - minsize = optsize[3] and optsize[3] / 10 or dsnsize - end - if name == family then - if subfamily == style then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - elseif synonym_set[style] and - synonym_set[style][subfamily] then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - elseif subfamily == "regular" or - synonym_set.regular[subfamily] then - found.fallback = face + + if name == family then + if subfamily == style then + if optsize then + if dsnsize == size + or (size > minsize and size <= maxsize) then + found[1] = face + break + else + found[#found+1] = face end else - if name == fullname - or name == pfullname - or name == fontname - or name == psname then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end + found[1] = face + break + end + elseif synonym_set[style] and + synonym_set[style][subfamily] + then + if optsize then + if dsnsize == size + or (size > minsize and size <= maxsize) then + found[1] = face + break + else + found[#found+1] = face end + else + found[1] = face + break end + elseif subfamily == "regular" or + synonym_set.regular[subfamily] then + found.fallback = face + elseif name == fullname then + --- happens with Libertine Mono which has + --- “mono” as subfamily + found[1] = face + break end - if #found == 1 then - if kpselookup(found[1].filename[1]) then - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, found[1].filename[1] - ) - return found[1].filename[1], found[1].filename[2], true - end - elseif #found > 1 then - -- we found matching font(s) but not in the requested optical - -- sizes, so we loop through the matches to find the one with - -- least difference from the requested size. - local closest - local least = math.huge -- initial value is infinity - for i,face in next, found do - local dsnsize = face.size[1]/10 - local difference = mathabs(dsnsize-size) - if difference < least then - closest = face - least = difference + + else + if name == fullname + or name == pfullname + or name == fontname + or name == psname then + if optsize then + if dsnsize == size + or (size > minsize and size <= maxsize) then + found[1] = face + break + else + found[#found+1] = face end + else + found[1] = face + break end - if kpselookup(closest.filename[1]) then - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, closest.filename[1] - ) - return closest.filename[1], closest.filename[2], true - end - elseif found.fallback then - return found.fallback.filename[1], found.fallback.filename[2], true end - --- no font found so far - if not fonts_reloaded then - --- last straw: try reloading the database - return reload_db(resolve, nil, nil, specification) - else - --- else, fallback to requested name - --- specification.name is empty with absolute paths, looks - --- like a bug in the specification parser <TODO< is it still - --- relevant? looks not... - return specification.name, false, false + end + end + + if #found == 1 then + if kpselookup(found[1].filename[1]) then + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, found[1].filename[1] + ) + return found[1].filename[1], found[1].filename[2], true + end + elseif #found > 1 then + -- we found matching font(s) but not in the requested optical + -- sizes, so we loop through the matches to find the one with + -- least difference from the requested size. + local closest + local least = math.huge -- initial value is infinity + for i,face in next, found do + local dsnsize = face.size[1]/10 + local difference = mathabs(dsnsize-size) + if difference < least then + closest = face + least = difference end end - else --- no db or outdated; reload names and retry - if not fonts_reloaded then - return reload_db(resolve, nil, nil, specification) - else --- unsucessfully reloaded; bail - return specification.name, false, false + if kpselookup(closest.filename[1]) then + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, closest.filename[1] + ) + return closest.filename[1], closest.filename[2], true end + elseif found.fallback then + return found.fallback.filename[1], found.fallback.filename[2], true + end + + --- no font found so far + if not fonts_reloaded then + --- last straw: try reloading the database + return reload_db( + "unresoled font name: “" .. name .. "”", + resolve, nil, nil, specification + ) end + + --- else, fallback to requested name + --- specification.name is empty with absolute paths, looks + --- like a bug in the specification parser <TODO< is it still + --- relevant? looks not... + return specification.name, false, false end --- resolve() --- when reload is triggered we update the database --- and then re-run the caller with the arg list ---- ('a -> 'a) -> 'a list -> 'a -reload_db = function (caller, ...) - report("log", 1, "db", "reload initiated") +--- string -> ('a -> 'a) -> 'a list -> 'a +reload_db = function (why, caller, ...) + report("log", 1, "db", "reload initiated; reason: “%s”", why) names.data = update_names() save_names(names.data) fonts_reloaded = true @@ -466,67 +560,65 @@ find_closest = function (name, limit) local data = names.data - if type(data) == "table" then - local by_distance = { } --- (int, string list) dict - local distances = { } --- int list - local cached = { } --- (string, int) dict - local mappings = data.mappings - local n_fonts = #mappings - - for n = 1, n_fonts do - local current = mappings[n] - local cnames = current.names - --[[ - This is simplistic but surpisingly fast. - Matching is performed against the “family” name - of a db record. We then store its “fullname” at - it edit distance. - We should probably do some weighting over all the - font name categories as well as whatever agrep - does. - --]] - if cnames then - local fullname, family = cnames.fullname, cnames.family - family = sanitize_string(family) - - local dist = cached[family]--- maybe already calculated - if not dist then - dist = iterative_levenshtein(name, family) - cached[family] = dist - end - local namelst = by_distance[dist] - if not namelst then --- first entry - namelst = { fullname } - distances[#distances+1] = dist - else --- append - namelst[#namelst+1] = fullname - end - by_distance[dist] = namelst + if type(data) ~= "table" then + return reload_db("no database", find_closest, name) + end + local by_distance = { } --- (int, string list) dict + local distances = { } --- int list + local cached = { } --- (string, int) dict + local mappings = data.mappings + local n_fonts = #mappings + + for n = 1, n_fonts do + local current = mappings[n] + local cnames = current.names + --[[ + This is simplistic but surpisingly fast. + Matching is performed against the “family” name + of a db record. We then store its “fullname” at + it edit distance. + We should probably do some weighting over all the + font name categories as well as whatever agrep + does. + --]] + if cnames then + local fullname, family = cnames.fullname, cnames.family + family = sanitize_string(family) + + local dist = cached[family]--- maybe already calculated + if not dist then + dist = iterative_levenshtein(name, family) + cached[family] = dist end - end - - --- print the matches according to their distance - local n_distances = #distances - if n_distances > 0 then --- got some data - tablesort(distances) - limit = mathmin(n_distances, limit) - report(false, 1, "query", - "displaying %d distance levels", limit) - - for i = 1, limit do - local dist = distances[i] - local namelst = by_distance[dist] - report(false, 0, "query", - "distance from “" .. name .. "”: " .. dist - .. "\n " .. tableconcat(namelst, "\n ") - ) + local namelst = by_distance[dist] + if not namelst then --- first entry + namelst = { fullname } + distances[#distances+1] = dist + else --- append + namelst[#namelst+1] = fullname end + by_distance[dist] = namelst + end + end - return true + --- print the matches according to their distance + local n_distances = #distances + if n_distances > 0 then --- got some data + tablesort(distances) + limit = mathmin(n_distances, limit) + report(false, 1, "query", + "displaying %d distance levels", limit) + + for i = 1, limit do + local dist = distances[i] + local namelst = by_distance[dist] + report(false, 0, "query", + "distance from “" .. name .. "”: " .. dist + .. "\n " .. tableconcat(namelst, "\n ") + ) end - return false - else --- need reload - return reload_db(find_closest, name) + + return true end return false end --- find_closest() @@ -595,107 +687,173 @@ font_fullinfo = function (filename, subfont, texmf) return tfmdata end -local load_font = function (filename, fontnames, newfontnames, texmf) - local newmappings = newfontnames.mappings - local newstatus = newfontnames.status - local mappings = fontnames.mappings - local status = fontnames.status - local basename = filebasename(filename) - local basefile = texmf and basename or filename - if filename then - if names.blacklist[filename] or - names.blacklist[basename] then - report("log", 2, "db", "ignoring font", "%s", filename) - return - end - local timestamp, db_timestamp - db_timestamp = status[basefile] and status[basefile].timestamp - timestamp = lfs.attributes(filename, "modification") - - local index_status = newstatus[basefile] or (not texmf and newstatus[basename]) - if index_status and index_status.timestamp == timestamp then - -- already indexed this run - return - end +--- we return true if the fond is new or re-indexed +--- string -> dbobj -> dbobj -> bool -> bool +local load_font = function (fullname, fontnames, newfontnames, texmf) + local newmappings = newfontnames.mappings + local newstatus = newfontnames.status - newstatus[basefile] = newstatus[basefile] or { } - newstatus[basefile].timestamp = timestamp - newstatus[basefile].index = newstatus[basefile].index or { } +-- local newfullnames = newfontnames.fullnames + local newbasenames = newfontnames.basenames + local newbarenames = newfontnames.barenames - if db_timestamp == timestamp and not newstatus[basefile].index[1] then - for _,v in next, status[basefile].index do - local index = #newstatus[basefile].index - newmappings[#newmappings+1] = mappings[v] - newstatus[basefile].index[index+1] = #newmappings - end - report("log", 1, "db", "font already indexed", "%s", basefile) - return + local mappings = fontnames.mappings + local status = fontnames.status +-- local fullnames = fontnames.fullnames + local basenames = fontnames.basenames + local barenames = fontnames.barenames + + local basename = filebasename(fullname) + local barename = filenameonly(fullname) + + --- entryname is apparently the identifier a font is + --- loaded by; it is different for files in the texmf + --- (due to kpse? idk.) + --- entryname = texmf : true -> basename | false -> fullname + local entryname = texmf and basename or fullname + + if not fullname then return false end + + if names.blacklist[fullname] + or names.blacklist[basename] + then + report("log", 2, "db", + "ignoring blacklisted font “%s”", fullname) + return false + end + local timestamp, db_timestamp + db_timestamp = status[entryname] + and status[entryname].timestamp + timestamp = lfs.attributes(fullname, "modification") + + local index_status = newstatus[entryname] + or (not texmf and newstatus[basename]) + local teststat = newstatus[entryname] + --- index_status: nil | false | table + if index_status and index_status.timestamp == timestamp then + -- already indexed this run + return false + end + + newstatus[entryname] = newstatus[entryname] or { } + newstatus[entryname].timestamp = timestamp + newstatus[entryname].index = newstatus[entryname].index or { } + + if db_timestamp == timestamp + and not newstatus[entryname].index[1] then + for _,v in next, status[entryname].index do + local index = #newstatus[entryname].index + local fullinfo = mappings[v] + newmappings[#newmappings+1] = fullinfo --- keep + newstatus[entryname].index[index+1] = #newmappings +-- newfullnames[fullname] = fullinfo.filename + newbasenames[basename] = fullinfo.filename + newbarenames[barename] = fullinfo.filename end - local info = fontloader.info(filename) - if info then - if type(info) == "table" and #info > 1 then - for i in next, info do - local fullinfo = font_fullinfo(filename, i-1, texmf) - if not fullinfo then - return - end - local index = newstatus[basefile].index[i] - if newstatus[basefile].index[i] then - index = newstatus[basefile].index[i] - else - index = #newmappings+1 - end - newmappings[index] = fullinfo - newstatus[basefile].index[i] = index - end - else - local fullinfo = font_fullinfo(filename, false, texmf) + report("log", 2, "db", "font “%s” already indexed", entryname) + return false + end + + local info = fontloaderinfo(fullname) + if info then + if type(info) == "table" and #info > 1 then --- ttc + for i in next, info do + local fullinfo = font_fullinfo(fullname, i-1, texmf) if not fullinfo then - return + return false end - local index - if newstatus[basefile].index[1] then - index = newstatus[basefile].index[1] + local index = newstatus[entryname].index[i] + if newstatus[entryname].index[i] then + index = newstatus[entryname].index[i] else index = #newmappings+1 end - newmappings[index] = fullinfo - newstatus[basefile].index[1] = index + newmappings[index] = fullinfo +-- newfullnames[fullname] = fullinfo.filename + newbasenames[basename] = fullinfo.filename + newbarenames[barename] = fullinfo.filename + newstatus[entryname].index[i] = index end else - report("log", 1, "db", "failed to load", "%s", basefile) + local fullinfo = font_fullinfo(fullname, false, texmf) + if not fullinfo then + return false + end + local index + if newstatus[entryname].index[1] then + index = newstatus[entryname].index[1] + else + index = #newmappings+1 + end + newmappings[index] = fullinfo +-- newfullnames[fullname] = { fullinfo.filename[1], fullinfo.filename[2] } + newbasenames[basename] = { fullinfo.filename[1], fullinfo.filename[2] } + newbarenames[barename] = { fullinfo.filename[1], fullinfo.filename[2] } + newstatus[entryname].index[1] = index end + + else --- missing info + report("log", 1, "db", "failed to load “%s”", entryname) + return false end + return true end -local function path_normalize(path) - --[[ - path normalization: - - a\b\c -> a/b/c - - a/../b -> b - - /cygdrive/a/b -> a:/b - - reading symlinks under non-Win32 - - using kpse.readable_file on Win32 - ]] - if os.type == "windows" or os.type == "msdos" or os.name == "cygwin" then - path = stringgsub(path, '\\', '/') - path = stringlower(path) - path = stringgsub(path, '^/cygdrive/(%a)/', '%1:/') - end - if os.type ~= "windows" and os.type ~= "msdos" then - local dest = lfs.readlink(path) - if dest then - if kpsereadable_file(dest) then - path = dest - elseif kpsereadable_file(filejoin(file.dirname(path), dest)) then - path = filejoin(file.dirname(path), dest) - else - -- broken symlink? +local path_normalize +do + --- os.type and os.name are constants so we + --- choose a normalization function in advance + --- instead of testing with every call + local os_type, os_name = os.type, os.name + local filecollapsepath = filecollapsepath + local lfsreadlink = lfs.readlink + + --- windows and dos + if os_type == "windows" or os_type == "msdos" then + --- ms platfom specific stuff + path_normalize = function (path) + path = stringgsub(path, '\\', '/') + path = stringlower(path) + path = stringgsub(path, '^/cygdrive/(%a)/', '%1:/') + path = filecollapsepath(path) + return path + end + + elseif os_name == "cygwin" then -- union of ms + unix + path_normalize = function (path) + path = stringgsub(path, '\\', '/') + path = stringlower(path) + path = stringgsub(path, '^/cygdrive/(%a)/', '%1:/') + local dest = lfsreadlink(path) + if dest then + if kpsereadable_file(dest) then + path = dest + elseif kpsereadable_file(filejoin(filedirname(path), dest)) then + path = filejoin(file.dirname(path), dest) + else + -- broken symlink? + end + end + path = filecollapsepath(path) + return path + end + + else -- posix + path_normalize = function (path) + local dest = lfsreadlink(path) + if dest then + if kpsereadable_file(dest) then + path = dest + elseif kpsereadable_file(filejoin(filedirname(path), dest)) then + path = filejoin(file.dirname(path), dest) + else + -- broken symlink? + end end + path = filecollapsepath(path) + return path end end - path = filecollapsepath(path) - return path end fonts.path_normalize = path_normalize @@ -723,7 +881,7 @@ local function read_blacklist() if stringsub(line, 1, 1) == "-" then whitelist[stringsub(line, 2, -1)] = true else - report("log", 2, "db", "blacklisted file", "%s", line) + report("log", 2, "db", "blacklisted file “%s”", line) blacklist[line] = true end end @@ -741,85 +899,59 @@ for key, value in next, font_extensions do font_extensions_set[value] = true end ---local installed_fonts_scanned = false --- ugh - ---- we already have scan_os_fonts don’t we? - ---local function scan_installed_fonts(fontnames, newfontnames) --- --- Try to query and add font list from operating system. --- --- This uses the lualatex-platform module. --- --- <phg>what for? why can’t we do this in Lua?</phg> --- report("info", 0, "Scanning fonts known to operating system...") --- local fonts = get_installed_fonts() --- if fonts and #fonts > 0 then --- installed_fonts_scanned = true --- report("log", 2, "operating system fonts found", "%d", #fonts) --- for key, value in next, fonts do --- local file = value.path --- if file then --- local ext = fileextname(file) --- if ext and font_extensions_set[ext] then --- file = path_normalize(file) --- report("log", 1, "loading font", "%s", file) --- load_font(file, fontnames, newfontnames, false) --- end --- end --- end --- else --- report("log", 2, "Could not retrieve list of installed fonts") --- end ---end - -local function scan_dir(dirname, fontnames, newfontnames, texmf) +--- string -> dbobj -> dbobj -> bool -> (int * int) +local scan_dir = function (dirname, fontnames, newfontnames, texmf) --[[ This function scans a directory and populates the list of fonts with all the fonts it finds. - dirname is the name of the directory to scan - - names is the font database to fill + - names is the font database to fill -> no such term!!! - texmf is a boolean saying if we are scanning a texmf directory ]] - local list, found = { }, { } - local nbfound = 0 + local n_scanned, n_new = 0, 0 --- total of fonts collected report("log", 2, "db", "scanning", "%s", dirname) for _,i in next, font_extensions do for _,ext in next, { i, stringupper(i) } do - found = dirglob(stringformat("%s/**.%s$", dirname, ext)) - -- note that glob fails silently on broken symlinks, which happens - -- sometimes in TeX Live. - report("log", 2, "db", - "fonts found", "%s '%s' fonts found", #found, ext) - nbfound = nbfound + #found - tableappend(list, found) + local found = dirglob(stringformat("%s/**.%s$", dirname, ext)) + local n_found = #found + --- note that glob fails silently on broken symlinks, which + --- happens sometimes in TeX Live. + report("log", 2, "db", "%s '%s' fonts found", n_found, ext) + n_scanned = n_scanned + n_found + for j=1, n_found do + local fullname = found[j] + fullname = path_normalize(fullname) + report("log", 2, "db", "loading font “%s”", fullname) + local new = load_font(fullname, fontnames, newfontnames, texmf) + if new then n_new = n_new + 1 end + end end end - report("log", 2, "db", - "fonts found", "%d fonts found in '%s'", nbfound, dirname) - - for _,file in next, list do - file = path_normalize(file) - report("log", 1, "db", - "loading font", "%s", file) - load_font(file, fontnames, newfontnames, texmf) - end + report("log", 2, "db", "%d fonts found in '%s'", n_scanned, dirname) + return n_scanned, n_new end local function scan_texmf_fonts(fontnames, newfontnames) + local n_scanned, n_new = 0, 0 --[[ This function scans all fonts in the texmf tree, through kpathsea variables OPENTYPEFONTS and TTFONTS of texmf.cnf ]] if stringis_empty(kpseexpand_path("$OSFONTDIR")) then - report("info", 1, "db", "Scanning TEXMF fonts...") + report("info", 2, "db", "Scanning TEXMF fonts...") else - report("info", 1, "db", "Scanning TEXMF and OS fonts...") + report("info", 2, "db", "Scanning TEXMF and OS fonts...") end local fontdirs = stringgsub(kpseexpand_path("$OPENTYPEFONTS"), "^%.", "") fontdirs = fontdirs .. stringgsub(kpseexpand_path("$TTFONTS"), "^%.", "") if not stringis_empty(fontdirs) then for _,d in next, filesplitpath(fontdirs) do - scan_dir(d, fontnames, newfontnames, true) + local found, new = scan_dir(d, fontnames, newfontnames, true) + n_scanned = n_scanned + found + n_new = n_new + new end end + return n_scanned, n_new end --[[ @@ -851,7 +983,7 @@ read_fonts_conf = function (path, results, passed_paths) passed_paths[#passed_paths+1] = path passed_paths_set = tabletohash(passed_paths, true) if not fh then - report("log", 2, "db", "cannot open file", "%s", path) + report("log", 2, "db", "cannot open file %s", path) return results end local incomments = false @@ -942,8 +1074,6 @@ local function get_os_dirs() else local passed_paths = {} local os_dirs = {} - -- what about ~/config/fontconfig/fonts.conf etc? - -- Answer: they should be included by the others, please report if it's not for _,p in next, {"/usr/local/etc/fonts/fonts.conf", "/etc/fonts/fonts.conf"} do if lfs.isfile(p) then read_fonts_conf(p, os_dirs, passed_paths) @@ -955,25 +1085,33 @@ local function get_os_dirs() end local function scan_os_fonts(fontnames, newfontnames) + local n_scanned, n_new = 0, 0 --[[ This function scans the OS fonts through - fontcache for Unix (reads the fonts.conf file and scans the directories) - a static set of directories for Windows and MacOSX ]] - report("info", 1, "db", "Scanning OS fonts...") - report("info", 2, "db", "Searching in static system directories...") + report("info", 2, "db", "Scanning OS fonts...") + report("info", 3, "db", "Searching in static system directories...") for _,d in next, get_os_dirs() do - scan_dir(d, fontnames, newfontnames, false) + local found, new = scan_dir(d, fontnames, newfontnames, false) + n_scanned = n_scanned + found + n_new = n_new + new end + return n_scanned, n_new end +--- dbobj -> bool -> dbobj update_names = function (fontnames, force) + local starttime = os.gettimeofday() + local n_scanned, n_new = 0, 0 --[[ The main function, scans everything - - fontnames is the final table to return + - “newfontnames” is the final table to return - force is whether we rebuild it from scratch or not ]] - report("info", 1, "db", "Updating the font names database") + report("info", 2, "db", "Updating the font names database" + .. (force and " forcefully" or "")) if force then fontnames = fontnames_init() @@ -991,16 +1129,29 @@ update_names = function (fontnames, force) read_blacklist() --installed_fonts_scanned = false --scan_installed_fonts(fontnames, newfontnames) --- see fixme above - scan_texmf_fonts(fontnames, newfontnames) + local scanned, new = scan_texmf_fonts(fontnames, newfontnames) + n_scanned = n_scanned + scanned + n_new = n_new + new --if not installed_fonts_scanned --and stringis_empty(kpseexpand_path("$OSFONTDIR")) if stringis_empty(kpseexpand_path("$OSFONTDIR")) then - scan_os_fonts(fontnames, newfontnames) + local scanned, new = scan_os_fonts(fontnames, newfontnames) + n_scanned = n_scanned + scanned + n_new = n_new + new end + --- stats: + --- before rewrite | after rewrite + --- partial: 804 ms | 701 ms + --- forced: 45384 ms | 44714 ms + report("info", 3, "db", + "Scanned %d font files; %d new entries.", n_scanned, n_new) + report("info", 3, "db", + "Rebuilt in %0.f ms", 1000*(os.gettimeofday()-starttime)) return newfontnames end +--- dbobj -> unit save_names = function (fontnames) local path = names.path.dir if not lfs.isdir(path) then @@ -1028,8 +1179,9 @@ scan_external_dir = function (dir) fonts_loaded = true end new_names = tablecopy(old_names) - scan_dir(dir, old_names, new_names) + local n_scanned, n_new = scan_dir(dir, old_names, new_names) names.data = new_names + return n_scanned, n_new end --- export functionality to the namespace “fonts.names” diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 0121ede..78f8256 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -37,6 +37,12 @@ local stringfind = string.find local stringexplode = string.explode local stringis_empty = string.is_empty +--[[doc-- +Apparently, these “modifiers” are another measure of emulating \XETEX, +cf. “About \XETEX”, by Jonathan Kew, 2005; and + “The \XETEX Reference Guide”, by Will Robertson, 2011. +--doc]]-- + local supported = { b = "bold", i = "italic", @@ -105,6 +111,8 @@ local defaults = { }, } +local global_defaults = { mode = "node" } + defaults.beng = defaults.deva defaults.guru = defaults.deva defaults.gujr = defaults.deva @@ -123,22 +131,36 @@ defaults.tibt = defaults.khmr defaults.lao = defaults.thai -local function set_default_features(script) - local features - local script = script or "dflt" +--- (string, string) dict -> (string, string) dict +local set_default_features = function (speclist) + local script = speclist.script or "dflt" + report("log", 0, "load font", "auto-selecting default features for script: %s", script) - if defaults[script] then - features = defaults[script] - else - features = defaults["dflt"] + + local requested = defaults[script] + if not requested then + report("log", 0, "load font", + "no defaults for script “%s”, falling back to “dflt”", + script) + requested = defaults.dflt end - for _,v in next, features do - if feature_list[v] ~= false then - feature_list[v] = true + + for i=1, #requested do + local feat = requested[i] + if speclist[feat] ~= false then + speclist[feat] = true end end + + for feat, state in next, global_defaults do + --- This is primarily intended for setting node + --- mode unless “base” is requested, as stated + --- in the manual. + if not speclist[feat] then speclist[feat] = state end + end + return speclist end local function issome () feature_list.lookup = 'name' end @@ -173,7 +195,7 @@ local pattern = (filename + fontname) * subvalue^0 * stylespec^0 * options^0 local function colonized(specification) -- xetex mode feature_list = { } lpeg.match(pattern,specification.specification) - set_default_features(feature_list.script) + feature_list = set_default_features(feature_list) if feature_list.style then specification.style = feature_list.style feature_list.style = nil @@ -213,20 +235,22 @@ end fonts.definers.registersplit(":",colonized,"cryptic") fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names] -function fonts.definers.applypostprocessors(tfmdata) - local postprocessors = tfmdata.postprocessors - if postprocessors then - for i=1,#postprocessors do - local extrahash = postprocessors[i](tfmdata) -- after scaling etc - if type(extrahash) == "string" and extrahash ~= "" then - -- e.g. a reencoding needs this - extrahash = string.gsub(lower(extrahash),"[^a-z]","-") - tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash) - end - end - end - return tfmdata -end +--- TODO below section is literally the same in luatex-fonts-def +--- why is it here? +--function fonts.definers.applypostprocessors(tfmdata) +-- local postprocessors = tfmdata.postprocessors +-- if postprocessors then +-- for i=1,#postprocessors do +-- local extrahash = postprocessors[i](tfmdata) -- after scaling etc +-- if type(extrahash) == "string" and extrahash ~= "" then +-- -- e.g. a reencoding needs this +-- extrahash = string.gsub(lower(extrahash),"[^a-z]","-") +-- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash) +-- end +-- end +-- end +-- return tfmdata +--end ---[[ end included font-ltx.lua ]] --[[doc-- diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index 314305a..da5e35a 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 04/20/13 13:33:53 +-- merge date : 04/24/13 13:39:43 do -- begin closure to overcome local limits and interference @@ -2978,7 +2978,9 @@ function resolvers.unresolve(s) return s end caches={} -local writable,readables=nil,{} +local writable=nil +local readables={} +local usingjit=jit if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then caches.namespace='generic' end @@ -3038,7 +3040,7 @@ end local function makefullname(path,name) if path and path~="" then name="temp-"..name - return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),"luc") + return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc") end end function caches.is_writable(path,name) @@ -3085,26 +3087,19 @@ function caches.savedata(path,name,data) end end end -caches.compilemethod="both" function caches.compile(data,luaname,lucname) - local done=false - if caches.compilemethod=="luac" or caches.compilemethod=="both" then - done=os.spawn("texluac -o "..string.quoted(lucname).." -s "..string.quoted(luaname))==0 + local d=io.loaddata(luaname) + if not d or d=="" then + d=table.serialize(data,true) end - if not done and (caches.compilemethod=="dump" or caches.compilemethod=="both") then - local d=io.loaddata(luaname) - if not d or d=="" then - d=table.serialize(data,true) - end - if d and d~="" then - local f=io.open(lucname,'w') - if f then - local s=loadstring(d) - if s then - f:write(string.dump(s,true)) - end - f:close() + if d and d~="" then + local f=io.open(lucname,'w') + if f then + local s=loadstring(d) + if s then + f:write(string.dump(s,true)) end + f:close() end end end @@ -6103,6 +6098,14 @@ actions["reorganize lookups"]=function(data,filename,raw) local current=coverage.current if current then current=t_uncover(splitter,t_u_cache,current) + local lookups=rule.lookups + if lookups then + for i=1,#current do + if not lookups[i] then + lookups[i]="" + end + end + end rule.current=t_hashed(current,t_h_cache) end local after=coverage.after @@ -10313,6 +10316,819 @@ end -- closure do -- begin closure to overcome local limits and interference +if not modules then modules={} end modules ['font-otp']={ + version=1.001, + comment="companion to font-otf.lua (packing)", + 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 sort,concat=table.sort,table.concat +local sortedhash=table.sortedhash +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") +fonts=fonts or {} +local handlers=fonts.handlers or {} +fonts.handlers=handlers +local otf=handlers.otf or {} +handlers.otf=otf +local enhancers=otf.enhancers or {} +otf.enhancers=enhancers +local glists=otf.glists or { "gsub","gpos" } +otf.glists=glists +local criterium=1 +local threshold=0 +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 +local function packdata(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_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_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_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_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 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 + else + return pack_final,pack_final,pack_final,pack_final,pack_final + end + end + local resources=data.resources + local lookuptypes=resources.lookuptypes + for pass=1,2 do + if trace_packing then + report_otf("start packing: stage 1, pass %s",pass) + end + local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass) + for unicode,description in next,data.descriptions do + local boundingbox=description.boundingbox + if boundingbox then + description.boundingbox=pack_indexed(boundingbox) + end + local slookups=description.slookups + if slookups then + for tag,slookup in next,slookups do + local what=lookuptypes[tag] + if what=="pair" then + local t=slookup[2] if t then slookup[2]=pack_indexed(t) end + local t=slookup[3] if t then slookup[3]=pack_indexed(t) end + elseif what~="substitution" then + slookups[tag]=pack_indexed(slookup) + end + end + end + local mlookups=description.mlookups + if mlookups then + for tag,mlookup in next,mlookups do + local what=lookuptypes[tag] + if what=="pair" then + for i=1,#mlookup do + local lookup=mlookup[i] + local t=lookup[2] if t then lookup[2]=pack_indexed(t) end + local t=lookup[3] if t then lookup[3]=pack_indexed(t) end + end + elseif what~="substitution" then + for i=1,#mlookup do + mlookup[i]=pack_indexed(mlookup[i]) + end + end + end + end + local kerns=description.kerns + if kerns then + for tag,kern in next,kerns do + kerns[tag]=pack_flat(kern) + end + 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 + local anchors=description.anchors + if anchors then + for what,anchor in next,anchors do + if what=="baselig" then + for _,a in next,anchor do + for k=1,#a do + a[k]=pack_indexed(a[k]) + end + end + else + for k,v in next,anchor do + anchor[k]=pack_indexed(v) + end + end + end + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.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 + local r=rule.lookups if r then rule.lookups=pack_indexed(r) end + end + end + end + end + local anchor_to_lookup=resources.anchor_to_lookup + if anchor_to_lookup then + for anchor,lookup in next,anchor_to_lookup do + anchor_to_lookup[anchor]=pack_normal(lookup) + end + end + local lookup_to_anchor=resources.lookup_to_anchor + if lookup_to_anchor then + for lookup,anchor in next,lookup_to_anchor do + lookup_to_anchor[lookup]=pack_normal(anchor) + end + end + local sequences=resources.sequences + if sequences then + for feature,sequence in next,sequences do + local flags=sequence.flags + if flags then + sequence.flags=pack_normal(flags) + end + local subtables=sequence.subtables + if subtables then + sequence.subtables=pack_normal(subtables) + end + local features=sequence.features + if features then + for script,feature in next,features do + features[script]=pack_normal(feature) + end + end + end + end + local lookups=resources.lookups + if lookups then + for name,lookup in next,lookups do + local flags=lookup.flags + if flags then + lookup.flags=pack_normal(flags) + end + local subtables=lookup.subtables + if subtables then + lookup.subtables=pack_normal(subtables) + end + end + end + local features=resources.features + if features then + for _,what in next,glists do + local list=features[what] + if list then + for feature,spec in next,list do + list[feature]=pack_normal(spec) + end + end + end + 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=packers(pass) + for unicode,description in next,data.descriptions do + local kerns=description.kerns + if kerns then + description.kerns=pack_normal(kerns) + end + local math=description.math + if math then + local kerns=math.kerns + if kerns then + math.kerns=pack_normal(kerns) + end + end + local anchors=description.anchors + if anchors then + description.anchors=pack_normal(anchors) + end + local mlookups=description.mlookups + if mlookups then + for tag,mlookup in next,mlookups do + mlookups[tag]=pack_normal(mlookup) + end + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.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 + local sequences=resources.sequences + if sequences then + for feature,sequence in next,sequences do + sequence.features=pack_normal(sequence.features) + end + end + if not success(2,pass) then + end + end + for pass=1,2 do + local pack_normal,pack_indexed,pack_flat,pack_boolean,pack_mixed=packers(pass) + for unicode,description in next,data.descriptions do + local slookups=description.slookups + if slookups then + description.slookups=pack_normal(slookups) + end + local mlookups=description.mlookups + if mlookups then + description.mlookups=pack_normal(mlookups) + end + end + end + end + end +end +local unpacked_mt={ + __index=function(t,k) + t[k]=false + return k + end +} +local function unpackdata(data) + if data then + local tables=data.tables + if tables then + local resources=data.resources + local lookuptypes=resources.lookuptypes + local unpacked={} + setmetatable(unpacked,unpacked_mt) + for unicode,description in next,data.descriptions do + local tv=tables[description.boundingbox] + if tv then + description.boundingbox=tv + end + local slookups=description.slookups + if slookups then + local tv=tables[slookups] + if tv then + description.slookups=tv + slookups=unpacked[tv] + end + if slookups then + for tag,lookup in next,slookups do + local what=lookuptypes[tag] + if what=="pair" then + local tv=tables[lookup[2]] + if tv then + lookup[2]=tv + end + local tv=tables[lookup[3]] + if tv then + lookup[3]=tv + end + elseif what~="substitution" then + local tv=tables[lookup] + if tv then + slookups[tag]=tv + end + end + end + end + end + local mlookups=description.mlookups + if mlookups then + local tv=tables[mlookups] + if tv then + description.mlookups=tv + mlookups=unpacked[tv] + end + if mlookups then + for tag,list in next,mlookups do + local tv=tables[list] + if tv then + mlookups[tag]=tv + list=unpacked[tv] + end + if list then + local what=lookuptypes[tag] + if what=="pair" then + for i=1,#list do + local lookup=list[i] + local tv=tables[lookup[2]] + if tv then + lookup[2]=tv + end + local tv=tables[lookup[3]] + if tv then + lookup[3]=tv + end + end + elseif what~="substitution" then + for i=1,#list do + local tv=tables[list[i]] + if tv then + list[i]=tv + end + end + end + end + end + end + end + local kerns=description.kerns + if kerns then + local tm=tables[kerns] + if tm then + description.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 + 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 + local anchors=description.anchors + if anchors then + local ta=tables[anchors] + if ta then + description.anchors=ta + anchors=unpacked[ta] + end + if anchors then + for tag,anchor in next,anchors do + if tag=="baselig" then + for _,list in next,anchor do + for i=1,#list do + local tv=tables[list[i]] + if tv then + list[i]=tv + end + end + end + else + for a,data in next,anchor do + local tv=tables[data] + if tv then + anchor[a]=tv + end + end + end + end + end + end + end + local lookups=data.lookups + if lookups then + for _,lookup in next,lookups do + local rules=lookup.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=unpacked[tv] + end + if before then + for i=1,#before do + local tv=tables[before[i]] + if tv then + before[i]=tv + end + end + end + end + local after=rule.after + if after then + local tv=tables[after] + if tv then + rule.after=tv + after=unpacked[tv] + end + if after then + for i=1,#after do + local tv=tables[after[i]] + if tv then + after[i]=tv + end + end + end + end + local current=rule.current + if current then + local tv=tables[current] + if tv then + rule.current=tv + current=unpacked[tv] + end + if current then + for i=1,#current do + local tv=tables[current[i]] + if tv then + current[i]=tv + end + end + end + end + local replacements=rule.replacements + if replacements then + local tv=tables[replacements] + if tv then + rule.replacements=tv + end + end + local fore=rule.fore + if fore then + local tv=tables[fore] + if tv then + rule.fore=tv + end + end + local back=rule.back + if back then + local tv=tables[back] + if tv then + rule.back=tv + end + end + local names=rule.names + if names then + local tv=tables[names] + if tv then + rule.names=tv + end + end + local lookups=rule.lookups + if lookups then + local tv=tables[lookups] + if tv then + rule.lookups=tv + end + end + end + end + end + end + local anchor_to_lookup=resources.anchor_to_lookup + if anchor_to_lookup then + for anchor,lookup in next,anchor_to_lookup do + local tv=tables[lookup] + if tv then + anchor_to_lookup[anchor]=tv + end + end + end + local lookup_to_anchor=resources.lookup_to_anchor + if lookup_to_anchor then + for lookup,anchor in next,lookup_to_anchor do + local tv=tables[anchor] + if tv then + lookup_to_anchor[lookup]=tv + end + end + end + local ls=resources.sequences + if ls then + for _,feature in next,ls do + local flags=feature.flags + if flags then + local tv=tables[flags] + if tv then + feature.flags=tv + end + end + local subtables=feature.subtables + if subtables then + local tv=tables[subtables] + if tv then + feature.subtables=tv + end + end + local features=feature.features + if features then + local tv=tables[features] + if tv then + feature.features=tv + features=unpacked[tv] + end + if features then + for script,data in next,features do + local tv=tables[data] + if tv then + features[script]=tv + end + end + end + end + end + end + local lookups=resources.lookups + if lookups then + for _,lookup in next,lookups do + local flags=lookup.flags + if flags then + local tv=tables[flags] + if tv then + lookup.flags=tv + end + end + local subtables=lookup.subtables + if subtables then + local tv=tables[subtables] + if tv then + lookup.subtables=tv + end + end + end + end + local features=resources.features + if features then + for _,what in next,glists do + local feature=features[what] + if feature then + for tag,spec in next,feature do + local tv=tables[spec] + if tv then + feature[tag]=tv + end + end + end + end + end + data.tables=nil + end + end +end +if otf.enhancers.register then + otf.enhancers.register("pack",packdata) + otf.enhancers.register("unpack",unpackdata) +end +otf.enhancers.unpack=unpackdata + +end -- closure + +do -- begin closure to overcome local limits and interference + if not modules then modules={} end modules ['luatex-fonts-lua']={ version=1.001, comment="companion to luatex-*.tex", diff --git a/luaotfload-override.lua b/luaotfload-override.lua index 94f2376..726000d 100644 --- a/luaotfload-override.lua +++ b/luaotfload-override.lua @@ -69,9 +69,12 @@ logs.names_report = function (mode, lvl, ...) end if not lvl then lvl = 0 end - if loglevel > lvl then + if loglevel >= lvl then if mode == "log" then log (...) + elseif mode == "both" then + log (...) + stdout (...) else stdout (...) end diff --git a/luaotfload.dtx b/luaotfload.dtx index 7c74a37..18e01d8 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -158,6 +158,8 @@ and the derived files \newcommand*\email[1]{\href{mailto:#1}{#1}} +\renewcommand\partname{Part}%% gets rid of the stupid “file” heading + \VerbatimFootnotes \begin{document} \DocInput{luaotfload.dtx}% @@ -868,6 +870,7 @@ and the derived files % \incitem{font-otf.lua} \incitem{font-otb.lua} % \incitem{node-inj.lua} \incitem{font-ota.lua} % \incitem{font-otn.lua} \incitem{font-def.lua} +% \incitem{font-otp.lua} % \end{itemize} % \end{multicols} % \end{itemize} @@ -882,6 +885,18 @@ and the derived files % \CONTEXT beta, all you have to do is remove % \fileent{luaotfload-merged.lua} from the search path. % +% Also, the merged file at some point +% loads the Adobe Glyph List from a \LUA table that is contained in +% \fileent{font-age.lua}, which is automatically generated by the +% script \fileent{mkglyphlist}.\footnote{% +% See \fileent{luaotfload-font-enc.lua}. +% The hard-coded file name is why the file lacks the \fileent{luaotfload-} +% prefix. +% } +% There is a make target \identifier{glyphs} that will create a fresh +% \fileent{font-age.lua} so we don’t need to import it from \CONTEXT +% any longer. +% % In addition to these, \identifier{luaotfload} requires a number of % files not contained in the merge. Some of these have no equivalent in % \LUATEX-Fonts or \CONTEXT, some were taken unmodified from the @@ -893,21 +908,20 @@ and the derived files % \normalitem{\fileent{#1}}% % \space--\hskip1em % } -% \ouritem {luaotfload-font-otc.lua} \fileent{font-otc} from \CONTEXT; -% font feature handling. -% \ouritem {luaotfload-lib-dir.lua} \fileent{l-dir} from \CONTEXT; -% contains functionality required -% by \fileent{luaotfload-font-nms.lua}. -% \ouritem {luaotfload-luat-ovr.lua} overrides the \CONTEXT logging -% functionality. -% \ouritem {luaotfload-font-pfb.lua} registers the \OpenType -% font reader as handler for -% Postscript fonts. -% \ouritem {luaotfload-font-nms.lua} font database. -% \ouritem {luaotfload-font-clr.lua} color handling. -% \ouritem {luaotfload-font-ltx.lua} font feature handling. -% \ouritem {luaotfload-features.lua} definitions of the \verb|anum| and -% \verb|tlig| features. +% \ouritem {luaotfload-features.lua} font feature handling; +% incorporates some of the code from +% \fileent{font-otc} from \CONTEXT; +% \ouritem {luaotfload-lib-dir.lua} \fileent{l-dir} from \CONTEXT; +% contains functionality required +% by \fileent{luaotfload-font-nms.lua}. +% \ouritem {luaotfload-override.lua} overrides the \CONTEXT logging +% functionality. +% \ouritem {luaotfload-loaders.lua} registers the \OpenType +% font reader as handler for +% Postscript fonts +% (\abbrev{pfa}, \abbrev{pfb}). +% \ouritem {luaotfload-database.lua} font names database. +% \ouritem {luaotfload-colors.lua} color handling. % \end{itemize} % % \begin{figure}[b] @@ -922,6 +936,10 @@ and the derived files % version of this package before reporting a bug, as % \identifier{luaotfload} is under active development and still a % moving target. +% The development takes place on \identifier{github} at +% \url{https://github.com/lualatex/luaotfload} where there is an issue +% tracker for submitting bug reports, feature requests and the likes +% requests and the likes. % % Errors during database generation can be traced by increasing % verbosity levels and redirecting log output to \fileent{stdout}: @@ -1024,13 +1042,19 @@ local error, warning, info, log = luatexbase.provides_module(luaotfload.module) % \end{macrocode} -% -% We set the minimum version requirement for \LUATEX to v0.74, as it was -% the first version to include version 5.2 of the \LUA interpreter. +% We set the minimum version requirement for \LUATEX to v0.76, +% because the font loader requires recent features like direct +% attribute indexing and \luafunction{node.end_of_math()} that aren’t +% available in earlier versions.\footnote{% +% See Taco’s announcement of v0.76: +% \url{http://comments.gmane.org/gmane.comp.tex.luatex.user/4042} +% and this commit by Hans that introduced those features. +% \url{http://repo.or.cz/w/context.git/commitdiff/a51f6cf6ee087046a2ae5927ed4edff0a1acec1b}. +% } % % \begin{macrocode} -local luatex_version = 74 +local luatex_version = 76 if tex.luatexversion < luatex_version then warning("LuaTeX v%.2f is old, v%.2f is recommended.", @@ -1093,7 +1117,6 @@ end % \fileent{luaotfload-merged.lua}. % If this file cannot be found, the original libraries from \CONTEXT of % which the merged code was composed are loaded instead. -% % The imported font loader will call \luafunction{callback.register} once % while reading \fileent{font-def.lua}. % This is unavoidable unless we modify the imported files, but harmless @@ -1251,6 +1274,7 @@ else--- the loading sequence is known to change, so this might have to loadmodule('node-inj.lua') loadmodule('font-ota.lua') loadmodule('font-otn.lua') + loadmodule('font-otp.lua')--- since 2013-04-23 loadmodule('luatex-fonts-lua.lua') loadmodule('font-def.lua') loadmodule('luatex-fonts-def.lua') @@ -1304,6 +1328,8 @@ add_to_callback("find_vf_file", loadmodule"lib-dir.lua" --- required by luaofload-database.lua loadmodule"override.lua" --- “luat-ovr” +logs.set_loglevel(0) + % \end{macrocode} % \CONTEXT does not support ofm, these lines were added in order to make it % work. However they do not seem necessary so they are commented for now. @@ -1325,9 +1351,17 @@ loadmodule"colors.lua" --- “font-clr” % \end{macrocode} % This hack makes fonts called with file method found by fonts.names.resolve -% instead of just trying to find them with kpse. It is necessary in case -% of fonts that are not accessible by kpse but present in the database, a -% quite common case under Linux. +% instead of just trying to find them with \identifier{kpse}. +% It is necessary in cases when font files are not reachable by +% \identifier{kpse} but present in the database, a quite common case +% under Linux. +% +% As of 2013-04-24 we have a workaround in the resolver that handles +% \verb|file:| lookups diverted this way. +% It requires some overhead due to additional extra data saved in the +% names database, and might vanish entirely once the font request syntax +% is understood. +% Until then it is considered a kludge, like the hack below. % % \begin{macrocode} @@ -1375,7 +1409,7 @@ local define_font_wrapper = function (...) --- definers.read if stringfind(k, "Percent") then -- keep percent values as is - print(k,v) + --print(k,v) mathconstants[k] = v else mathconstants[k] = v / units_per_em * size @@ -1401,8 +1435,10 @@ end % \begin{macrocode} local read_font_file = fonts.definers.read -local patch_defined_font = function (...) - local tfmdata = read_font_file(...)-- spec -> size -> id -> tmfdata + +--- spec -> size -> id -> tmfdata +local patch_defined_font = function (specification, size, id) + local tfmdata = read_font_file(specification, size, id) if type(tfmdata) == "table" then call_callback("luaotfload.patch_font", tfmdata) end @@ -1472,7 +1508,6 @@ loadmodule"features.lua" --- contains what was “font-ltx” and “font-otc” -- vim:tw=71:sw=4:ts=4:expandtab - % \end{macrocode} % % \iffalse diff --git a/mkglyphlist b/mkglyphlist new file mode 100755 index 0000000..9ee1528 --- /dev/null +++ b/mkglyphlist @@ -0,0 +1,143 @@ +#!/usr/bin/env texlua +----------------------------------------------------------------------- +-- FILE: mkglyphlist.lua +-- USAGE: ./mkglyphlist.lua +-- DESCRIPTION: part of the luaotfload package +-- REQUIREMENTS: lua, lpeg, luasocket, the lualibs package +-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> +-- VERSION: 1.0 +-- CREATED: 04/23/2013 12:42:17 PM CEST +----------------------------------------------------------------------- +-- config +----------------------------------------------------------------------- +local glyphfile = "./glyphlist.txt" +local font_age = "./font-age.lua" +local glyph_source = "http://partners.adobe.com/public/developer/en/opentype/glyphlist.txt" + +----------------------------------------------------------------------- +-- includes +----------------------------------------------------------------------- +require"lpeg" +require"socket" + +kpse.set_program_name"luatex" +dofile(kpse.find_file("lualibs-lua.lua", "lua")) +dofile(kpse.find_file("lualibs-lpeg.lua", "lua")) +dofile(kpse.find_file("lualibs-table.lua", "lua")) --- for serialization + +local C, Cf, Cg, Ct, P, R = + lpeg.C, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.R + +local http = socket.http + +----------------------------------------------------------------------- +-- functionality +----------------------------------------------------------------------- + +local dec_of_hex = function (hex) return tonumber(hex, 16) end + +local separator = P";" +local gartenzaun = P"#" +local eol = P"\n\r" + P"\r\n" + P"\r" + P"\n" +local space = P" " +local alphanum = R("az", "AZ", "09") +local hexdigit = R("af", "AF", "09") +local eof_tag = gartenzaun * P"--end" +local header_line = gartenzaun * (1-eol)^0 * eol +local codepoint = hexdigit^1 +local glyphname = alphanum^1 + +local definition = Cg(C(glyphname) * separator * (C(codepoint)/ dec_of_hex)) + --- With combined glyphs we take only the first + --- value as char-def and font-age do, and skip + --- the rest. + * (space * codepoint)^0 + * eol +local definitions = Cf(Ct"" * definition^1, rawset) + +local p_glyphs = header_line^0 * definitions * eof_tag + +local get_glyphs = function (data) + local res = lpeg.match(p_glyphs, data) + if not res then + print("error: could not parse glyph list") + os.exit(-1) + end + return res +end + +local file_header = [==[ +if not modules then modules = { } end modules ["font-age"] = { + version = 2.200, + comment = "part of the luaotfload package", + author = "luaotfload team / mkglyphlist", + copyright = "derived from %s", + original = "Adobe Glyph List, version 2.0, September 20, 2002", + dataonly = true, +} + +if context then + logs.report("fatal error","this module is not for context") + os.exit(-1) +end + +--[[doc-- +Everything below has been autogenerated. Run mkglyphlist to rebuild +font-age.lua. +--doc]]-- + +]==] + +local writedata = function (data) + data = table.serialize(data, true) + data = string.format(file_header, glyph_source) .. data + local fh = io.open(font_age, "wb") + if not fh then + print(string.format("error: %s not writable", font_age)) + os.exit(-1) + end + print(string.format("saving %d bytes to %s", #data, font_age)) + fh:write(data) + fh:close() +end + + +local get_raw get_raw = function (retry) + local fh = io.open(glyphfile, "rb") + if fh then + local data = fh:read"*all" + fh:close() + if data then return data end + elseif not retry then --- attempt download + print"info: retrieving glyph list from" + print(glyph_source) + local glyphdata = http.request(glyph_source) + if glyphdata then + local fh = io.open(glyphfile, "wb") + if not fh then + print"error: glyph file not writable" + os.exit(-1) + end + fh:write(glyphdata) + fh:close() + return get_raw(true) + end + print"error: download failed" + os.exit(-1) + end + print("error: could not obtain glyph data from "..glyphfile) + os.exit(-1) +end + +local main = function () + if arg[1] then glyphfile = arg[1] end + if arg[2] then font_age = arg[2] end + + local data = get_raw() + local parsed = get_glyphs(data) + writedata(parsed) + return 0 +end + + +return main() diff --git a/tests/lookups.tex b/tests/lookups.tex index db26312..8b03d8e 100644 --- a/tests/lookups.tex +++ b/tests/lookups.tex @@ -5,10 +5,16 @@ \font\second=file:antpoltltsemiexpd-bolditalic.otf at 42pt %% lookup font by name, with style in slash notation \font\third={name:Antykwa torunska/I} at 42pt +%% unspecified lookup; in definers.read: +%% - first it falls back to “file” +%% - empty “method” field triggers fallback to “name” +%% - names.resolve -> kpse.lookup -> hit! +\font\fourth=iwona at 42pt {\first foo \endgraf} {\second bar \endgraf} {\third baz \endgraf} +{\fourth xyzzy \endgraf} \bye |