diff options
author | Karl Berry <karl@freefriends.org> | 2020-03-05 00:48:46 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-03-05 00:48:46 +0000 |
commit | f210bce174e1f2f05305ab03e88e120a1cbfc4da (patch) | |
tree | 5c4e2ad096b5c745e859516ac3196fa0864292d5 /Master/texmf-dist/tex/generic | |
parent | 35fd641a3546acc0c62e0aa7f134888e36da30d4 (diff) |
context (from cont-tmf.zip of Feb 17 16:00, size 116339406)
git-svn-id: svn://tug.org/texlive/trunk@54086 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic')
7 files changed, 3238 insertions, 940 deletions
diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-chr.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-chr.lua index 14a55d7b011..0ac0eab14e1 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-chr.lua +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-chr.lua @@ -1,4 +1,4 @@ --- automatically generated from context data +-- automatically generated from context data (luatex-basics-prepare.tex) characters = characters or { } @@ -446,7 +446,6 @@ characters.classifiers={ [1803]=6, [1804]=6, [1805]=6, - [1807]=6, [1808]=3, [1809]=5, [1810]=2, @@ -627,6 +626,9 @@ characters.classifiers={ [2040]=6, [2041]=6, [2042]=2, + [2045]=5, + [2046]=6, + [2047]=6, [2070]=5, [2071]=5, [2072]=5, @@ -716,6 +718,7 @@ characters.classifiers={ [2235]=2, [2236]=2, [2237]=2, + [2259]=5, [2260]=5, [2261]=5, [2262]=5, @@ -792,6 +795,7 @@ characters.classifiers={ [2509]=5, [2530]=5, [2531]=5, + [2558]=5, [2561]=5, [2562]=5, [2620]=5, @@ -840,6 +844,7 @@ characters.classifiers={ [3008]=5, [3021]=5, [3072]=5, + [3076]=5, [3134]=5, [3135]=5, [3136]=5, @@ -901,6 +906,7 @@ characters.classifiers={ [3767]=5, [3768]=5, [3769]=5, + [3770]=5, [3771]=5, [3772]=5, [3784]=5, @@ -1139,6 +1145,7 @@ characters.classifiers={ [6261]=2, [6262]=2, [6263]=2, + [6264]=2, [6272]=4, [6273]=4, [6274]=4, @@ -1539,6 +1546,7 @@ characters.classifiers={ [43247]=5, [43248]=5, [43249]=5, + [43263]=5, [43302]=5, [43303]=5, [43304]=5, @@ -1702,6 +1710,83 @@ characters.classifiers={ [68525]=2, [68526]=2, [68527]=4, + [68864]=1, + [68865]=2, + [68866]=2, + [68867]=2, + [68868]=2, + [68869]=2, + [68870]=2, + [68871]=2, + [68872]=2, + [68873]=2, + [68874]=2, + [68875]=2, + [68876]=2, + [68877]=2, + [68878]=2, + [68879]=2, + [68880]=2, + [68881]=2, + [68882]=2, + [68883]=2, + [68884]=2, + [68885]=2, + [68886]=2, + [68887]=2, + [68888]=2, + [68889]=2, + [68890]=2, + [68891]=2, + [68892]=2, + [68893]=2, + [68894]=2, + [68895]=2, + [68896]=2, + [68897]=2, + [68898]=3, + [68899]=2, + [68900]=5, + [68901]=5, + [68902]=5, + [68903]=5, + [69424]=2, + [69425]=2, + [69426]=2, + [69427]=3, + [69428]=2, + [69429]=2, + [69430]=2, + [69431]=2, + [69432]=2, + [69433]=2, + [69434]=2, + [69435]=2, + [69436]=2, + [69437]=2, + [69438]=2, + [69439]=2, + [69440]=2, + [69441]=2, + [69442]=2, + [69443]=2, + [69444]=2, + [69445]=4, + [69446]=5, + [69447]=5, + [69448]=5, + [69449]=5, + [69450]=5, + [69451]=5, + [69452]=5, + [69453]=5, + [69454]=5, + [69455]=5, + [69456]=5, + [69457]=2, + [69458]=2, + [69459]=2, + [69460]=3, [69633]=5, [69688]=5, [69689]=5, @@ -1727,6 +1812,8 @@ characters.classifiers={ [69814]=5, [69817]=5, [69818]=5, + [69821]=4, + [69837]=4, [69888]=5, [69889]=5, [69890]=5, @@ -1776,6 +1863,7 @@ characters.classifiers={ [70378]=5, [70400]=5, [70401]=5, + [70459]=5, [70460]=5, [70464]=5, [70502]=5, @@ -1802,6 +1890,7 @@ characters.classifiers={ [70723]=5, [70724]=5, [70726]=5, + [70750]=5, [70835]=5, [70836]=5, [70837]=5, @@ -1855,6 +1944,24 @@ characters.classifiers={ [71465]=5, [71466]=5, [71467]=5, + [71727]=5, + [71728]=5, + [71729]=5, + [71730]=5, + [71731]=5, + [71732]=5, + [71733]=5, + [71734]=5, + [71735]=5, + [71737]=5, + [71738]=5, + [72148]=5, + [72149]=5, + [72150]=5, + [72151]=5, + [72154]=5, + [72155]=5, + [72160]=5, [72193]=5, [72194]=5, [72195]=5, @@ -1962,6 +2069,12 @@ characters.classifiers={ [73028]=5, [73029]=5, [73031]=5, + [73104]=5, + [73105]=5, + [73109]=5, + [73111]=5, + [73459]=5, + [73460]=5, [92912]=5, [92913]=5, [92914]=5, @@ -1974,6 +2087,7 @@ characters.classifiers={ [92980]=5, [92981]=5, [92982]=5, + [94031]=5, [94095]=5, [94096]=5, [94097]=5, @@ -2170,6 +2284,17 @@ characters.classifiers={ [122920]=5, [122921]=5, [122922]=5, + [123184]=5, + [123185]=5, + [123186]=5, + [123187]=5, + [123188]=5, + [123189]=5, + [123190]=5, + [123628]=5, + [123629]=5, + [123630]=5, + [123631]=5, [125136]=5, [125137]=5, [125138]=5, @@ -2273,6 +2398,7 @@ characters.indicgroups={ [2632]=true, [2635]=true, [2636]=true, + [2690]=true, [2757]=true, [2759]=true, [2760]=true, @@ -2284,7 +2410,6 @@ characters.indicgroups={ [3136]=true, [3142]=true, [3143]=true, - [3144]=true, [3146]=true, [3147]=true, [3148]=true, @@ -2292,6 +2417,21 @@ characters.indicgroups={ [3263]=true, [3270]=true, [3406]=true, + [4141]=true, + [4142]=true, + [4146]=true, + [4147]=true, + [4148]=true, + [4149]=true, + [4150]=true, + [4154]=true, + [4209]=true, + [4210]=true, + [4211]=true, + [4212]=true, + [4229]=true, + [4230]=true, + [4253]=true, [43232]=true, [43233]=true, [43234]=true, @@ -2310,6 +2450,8 @@ characters.indicgroups={ [43247]=true, [43248]=true, [43249]=true, + [43493]=true, + [43644]=true, }, ["after_half"]={}, ["after_main"]={ @@ -2331,6 +2473,7 @@ characters.indicgroups={ [2626]=true, [2672]=true, [2673]=true, + [2735]=true, [2750]=true, [2752]=true, [2753]=true, @@ -2494,10 +2637,24 @@ characters.indicgroups={ [3170]=true, [3171]=true, [3260]=true, + [3286]=true, [3298]=true, [3299]=true, [3426]=true, [3427]=true, + [4143]=true, + [4144]=true, + [4151]=true, + [4153]=true, + [4157]=true, + [4158]=true, + [4184]=true, + [4185]=true, + [4190]=true, + [4191]=true, + [4192]=true, + [4226]=true, + [4237]=true, }, ["consonant"]={ [2325]=true, @@ -2827,6 +2984,117 @@ characters.indicgroups={ [3384]=true, [3385]=true, [3386]=true, + [4096]=true, + [4097]=true, + [4098]=true, + [4099]=true, + [4100]=true, + [4101]=true, + [4102]=true, + [4103]=true, + [4104]=true, + [4105]=true, + [4106]=true, + [4107]=true, + [4108]=true, + [4109]=true, + [4110]=true, + [4111]=true, + [4112]=true, + [4113]=true, + [4114]=true, + [4115]=true, + [4116]=true, + [4117]=true, + [4118]=true, + [4119]=true, + [4120]=true, + [4121]=true, + [4122]=true, + [4123]=true, + [4124]=true, + [4125]=true, + [4126]=true, + [4127]=true, + [4128]=true, + [4155]=true, + [4156]=true, + [4157]=true, + [4158]=true, + [4159]=true, + [4176]=true, + [4177]=true, + [4186]=true, + [4187]=true, + [4188]=true, + [4189]=true, + [4190]=true, + [4191]=true, + [4192]=true, + [4193]=true, + [4197]=true, + [4198]=true, + [4206]=true, + [4207]=true, + [4208]=true, + [4213]=true, + [4214]=true, + [4215]=true, + [4216]=true, + [4217]=true, + [4218]=true, + [4219]=true, + [4220]=true, + [4221]=true, + [4222]=true, + [4223]=true, + [4224]=true, + [4225]=true, + [4226]=true, + [4238]=true, + [43488]=true, + [43489]=true, + [43490]=true, + [43491]=true, + [43492]=true, + [43495]=true, + [43496]=true, + [43497]=true, + [43498]=true, + [43499]=true, + [43500]=true, + [43501]=true, + [43502]=true, + [43503]=true, + [43514]=true, + [43515]=true, + [43516]=true, + [43517]=true, + [43518]=true, + [43616]=true, + [43617]=true, + [43618]=true, + [43619]=true, + [43620]=true, + [43621]=true, + [43622]=true, + [43623]=true, + [43624]=true, + [43625]=true, + [43626]=true, + [43628]=true, + [43629]=true, + [43630]=true, + [43631]=true, + [43633]=true, + [43634]=true, + [43635]=true, + [43636]=true, + [43637]=true, + [43638]=true, + [43642]=true, + [43646]=true, + [43647]=true, }, ["dependent_vowel"]={ [2362]=true, @@ -2855,13 +3123,14 @@ characters.indicgroups={ [2403]=true, [2494]=true, [2495]=true, - [2496]=true, [2497]=true, [2498]=true, [2499]=true, [2500]=true, [2503]=true, [2504]=true, + [2507]=true, + [2508]=true, [2622]=true, [2623]=true, [2624]=true, @@ -2936,6 +3205,8 @@ characters.indicgroups={ [3274]=true, [3275]=true, [3276]=true, + [3285]=true, + [3286]=true, [3298]=true, [3299]=true, [3390]=true, @@ -2954,6 +3225,35 @@ characters.indicgroups={ [3415]=true, [3426]=true, [3427]=true, + [4139]=true, + [4140]=true, + [4141]=true, + [4142]=true, + [4143]=true, + [4144]=true, + [4145]=true, + [4146]=true, + [4147]=true, + [4148]=true, + [4149]=true, + [4182]=true, + [4183]=true, + [4184]=true, + [4185]=true, + [4194]=true, + [4199]=true, + [4200]=true, + [4209]=true, + [4210]=true, + [4211]=true, + [4212]=true, + [4227]=true, + [4228]=true, + [4229]=true, + [4230]=true, + [4252]=true, + [4253]=true, + [43493]=true, }, ["halant"]={ [2381]=true, @@ -3111,6 +3411,20 @@ characters.indicgroups={ [3423]=true, [3424]=true, [3425]=true, + [4129]=true, + [4130]=true, + [4131]=true, + [4132]=true, + [4133]=true, + [4134]=true, + [4135]=true, + [4136]=true, + [4137]=true, + [4138]=true, + [4178]=true, + [4179]=true, + [4180]=true, + [4181]=true, }, ["nukta"]={ [2364]=true, @@ -3132,8 +3446,6 @@ characters.indicgroups={ [2383]=true, [2494]=true, [2496]=true, - [2503]=true, - [2504]=true, [2622]=true, [2624]=true, [2750]=true, @@ -3150,16 +3462,12 @@ characters.indicgroups={ [3139]=true, [3140]=true, [3262]=true, - [3264]=true, [3265]=true, [3266]=true, [3267]=true, [3268]=true, - [3271]=true, - [3272]=true, - [3274]=true, - [3275]=true, [3276]=true, + [3285]=true, [3390]=true, [3391]=true, [3392]=true, @@ -3168,25 +3476,58 @@ characters.indicgroups={ [3395]=true, [3396]=true, [3415]=true, + [4139]=true, + [4140]=true, + [4152]=true, + [4155]=true, + [4182]=true, + [4183]=true, + [4194]=true, + [4195]=true, + [4196]=true, + [4199]=true, + [4200]=true, + [4201]=true, + [4202]=true, + [4203]=true, + [4204]=true, + [4205]=true, + [4227]=true, + [4231]=true, + [4232]=true, + [4233]=true, + [4234]=true, + [4235]=true, + [4236]=true, + [4239]=true, + [4250]=true, + [4251]=true, + [4252]=true, + [43643]=true, + [43645]=true, }, ["pre_mark"]={ [2367]=true, [2382]=true, [2495]=true, + [2503]=true, + [2504]=true, [2623]=true, [2751]=true, [2887]=true, - [2888]=true, [3014]=true, [3015]=true, [3016]=true, [3398]=true, [3399]=true, [3400]=true, + [4145]=true, + [4228]=true, }, ["ra"]={ [2352]=true, [2480]=true, + [2544]=true, [2608]=true, [2736]=true, [2864]=true, @@ -3200,17 +3541,43 @@ characters.indicgroups={ [2386]=true, [2387]=true, [2388]=true, - [2507]=true, - [2508]=true, - [3277]=true, - [3405]=true, + [4151]=true, + [4195]=true, + [4196]=true, + [4201]=true, + [4202]=true, + [4203]=true, + [4204]=true, + [4205]=true, + [4231]=true, + [4232]=true, + [4233]=true, + [4234]=true, + [4235]=true, + [4236]=true, + [4237]=true, + [4239]=true, + [4250]=true, + [4251]=true, + [43643]=true, + [43644]=true, + [43645]=true, }, ["twopart_mark"]={ + [2507]={ 2503, 2494 }, + [2508]={ 2503, 2519 }, + [2888]={ 2887, 2902 }, [2891]={ 2887, 2878 }, [2892]={ 2887, 2903 }, [3018]={ 3014, 3006 }, [3019]={ 3015, 3006 }, [3020]={ 3014, 3031 }, + [3144]={ 3142, 3158 }, + [3264]={ 3263, 3285 }, + [3271]={ 3270, 3285 }, + [3272]={ 3270, 3286 }, + [3274]={ 3270, 3266 }, + [3275]={ 3274, 3285 }, [3402]={ 3398, 3390 }, [3403]={ 3399, 3390 }, [3404]={ 3398, 3415 }, @@ -3220,8 +3587,13 @@ characters.indicgroups={ [2305]=true, [2306]=true, [2307]=true, + [2433]=true, [3330]=true, [3331]=true, + [4150]=true, + [4152]=true, + [4153]=true, + [4154]=true, [43232]=true, [43233]=true, [43234]=true, @@ -3238,9 +3610,10 @@ characters.indicgroups={ [43245]=true, [43246]=true, [43247]=true, - [43248]=true, [43249]=true, }, } --- done +-- done, uncomment for testing: + +-- return characters.indicgroups diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua index 879da4bc792..be82277bd49 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-nod.lua @@ -12,7 +12,7 @@ end -- Don't depend on code here as it is only needed to complement the font handler -- code. I will move some to another namespace as I don't see other macro packages --- use the context logic. It's a subset anyway. +-- use the context logic. It's a subset anyway. More will be stripped. -- Attributes: @@ -73,80 +73,12 @@ nodes.disccodes = disccodes nodes.handlers.protectglyphs = node.protect_glyphs -- beware: nodes! nodes.handlers.unprotectglyphs = node.unprotect_glyphs -- beware: nodes! --- These are now gone in generic as they are context specific. - --- local flush_node = node.flush_node --- local remove_node = node.remove --- local traverse_id = node.traverse_id --- --- function nodes.remove(head, current, free_too) --- local t = current --- head, current = remove_node(head,current) --- if t then --- if free_too then --- flush_node(t) --- t = nil --- else --- t.next, t.prev = nil, nil --- end --- end --- return head, current, t --- end --- --- function nodes.delete(head,current) --- return nodes.remove(head,current,true) --- end - ------ getfield = node.getfield ------ setfield = node.setfield - ------.getfield = getfield ------.setfield = setfield ------.getattr = getfield ------.setattr = setfield - ------.tostring = node.tostring or tostring ------.copy = node.copy ------.copy_node = node.copy ------.copy_list = node.copy_list ------.delete = node.delete ------.dimensions = node.dimensions ------.end_of_math = node.end_of_math ------.flush_list = node.flush_list ------.flush_node = node.flush_node ------.flush = node.flush_node ------.free = node.free ------.insert_after = node.insert_after ------.insert_before = node.insert_before ------.hpack = node.hpack ------.new = node.new ------.tail = node.tail ------.traverse = node.traverse ------.traverse_id = node.traverse_id ------.slide = node.slide ------.vpack = node.vpack - ------.first_glyph = node.first_glyph ------.has_glyph = node.has_glyph or node.first_glyph ------.current_attr = node.current_attr ------.has_field = node.has_field ------.usedlist = node.usedlist ------.protrusion_skippable = node.protrusion_skippable ------.write = node.write - ------.has_attribute = node.has_attribute ------.set_attribute = node.set_attribute ------.unset_attribute = node.unset_attribute - ------.protect_glyphs = node.protect_glyphs ------.unprotect_glyphs = node.unprotect_glyphs ------.mlist_to_hlist = node.mlist_to_hlist - -- in generic code, at least for some time, we stay nodes, while in context -- we can go nuts (e.g. experimental); this split permits us us keep code -- used elsewhere stable but at the same time play around in context --- much of this will go away +-- much of this will go away .. it's part of the context interface and not +-- officially in luatex-*.lua local direct = node.direct local nuts = { } @@ -165,16 +97,13 @@ nuts.getattr = direct.get_attribute nuts.getboth = direct.getboth nuts.getchar = direct.getchar nuts.getcomponents = direct.getcomponents -----.getdepth = direct.getdepth -----.getdir = direct.getdir nuts.getdirection = direct.getdirection nuts.getdisc = direct.getdisc +nuts.getreplace = direct.getreplace nuts.getfield = direct.getfield nuts.getfont = direct.getfont -----.getheight = direct.getheight nuts.getid = direct.getid nuts.getkern = direct.getkern -----.getleader = direct.getleader nuts.getlist = direct.getlist nuts.getnext = direct.getnext nuts.getoffsets = direct.getoffsets @@ -185,15 +114,11 @@ nuts.setattr = direct.setfield nuts.setboth = direct.setboth nuts.setchar = direct.setchar nuts.setcomponents = direct.setcomponents -----.setdepth = direct.setdepth -nuts.setdir = direct.setdir nuts.setdirection = direct.setdirection nuts.setdisc = direct.setdisc +nuts.setreplace = direct.setreplace nuts.setfield = setfield -----.setfont = direct.setfont -----.setheight = direct.setheight nuts.setkern = direct.setkern -----.setleader = direct.setleader nuts.setlink = direct.setlink nuts.setlist = direct.setlist nuts.setnext = direct.setnext @@ -203,8 +128,9 @@ nuts.setsplit = direct.setsplit nuts.setsubtype = direct.setsubtype nuts.setwidth = direct.setwidth -nuts.is_char = direct.is_char -nuts.is_glyph = direct.is_glyph +nuts.getglyphdata = nuts.getattr +nuts.setglyphdata = nuts.setattr + nuts.ischar = direct.is_char nuts.isglyph = direct.is_glyph @@ -230,26 +156,6 @@ nuts.traverse_char = direct.traverse_char nuts.traverse_glyph = direct.traverse_glyph nuts.traverse_id = direct.traverse_id --- for now - -if not nuts.getdirection then - - local getdir = direct.getdir - - function nuts.getdirection(n) - local d = getdir(n) - if d == "TLT" then return 0 - elseif d == "TRT" then return 1 - elseif d == "+TLT" then return 0, false - elseif d == "+TRT" then return 1, false - elseif d == "-TLT" then return 0, true - elseif d == "-TRT" then return 1, true - else return 0 - end - end - -end - -- properties as used in the (new) injector: local propertydata = direct.get_properties_table() @@ -357,3 +263,30 @@ do } end + +if not nuts.setreplace then + + local getdisc = nuts.getdisc + local setfield = nuts.setfield + + function nuts.getreplace(n) + local _, _, h, _, _, t = getdisc(n,true) + return h, t + end + + function nuts.setreplace(n,h) + setfield(n,"replace",h) + end + +end + +do + + local getsubtype = nuts.getsubtype + + function nuts.start_of_par(n) + local s = getsubtype(n) + return s == 0 or s == 2 -- sorry, hardcoded, won't change anyway + end + +end diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-prepare.tex b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-prepare.tex index 47eaa73416c..069f772f77c 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-prepare.tex +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-basics-prepare.tex @@ -15,7 +15,8 @@ %D is needed because we don't want to load the (mostly not used in generic) data %D files. -%D Indicorder is not yet filled in completely. +%D Indicorder is not yet filled in completely. Some 'indic=m' are now 'indic=o' +%D due to patches/analysis by Kai Eigner. \startluacode @@ -69,7 +70,7 @@ for k, c in next, chardata do end local template = string.formatters [ [[ --- automatically generated from context data +-- automatically generated from context data (luatex-basics-prepare.tex) characters = characters or { } @@ -84,6 +85,8 @@ characters.blockrange = { } %s -- done + +return characters.indicgroups ]] ] io.savedata("luatex-basics-chr.lua",template( @@ -91,8 +94,33 @@ io.savedata("luatex-basics-chr.lua",template( table.serialize(indicgroups,"characters.indicgroups") )) + +-- -- code for comparing patched tables (info we feed back in char-def.lua) + +-- local hans = table.load("t:/sources/luatex-basics-chr.lua") +-- local kai = table.load("e:/tmp/indic/luatex-basics-chr.lua") +-- +-- for name, h in table.sortedhash(hans) do +-- for kk, vv in table.sortedhash(kai[name]) do +-- if h[kk] ~= vv and vv then +-- local _h = h[kk] +-- local _k = vv +-- if type(_h) ~= "table" or type(_k) ~= "table" or not table.identical(_h,_k) then +-- print("what", name) +-- print("index",kk) +-- print("hex ",string.format("%04X",kk)) +-- print("hans ",h[kk]) +-- print("kai ", vv) +-- print("") +-- end +-- end +-- end +-- end + \stopluacode + + \startTEXpage[offset=10pt] \tttf generated file: luatex-basics-chr.lua \stopTEXpage diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-core.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-core.lua index 6e1b31e9610..a0f46dd2ede 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-core.lua +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-core.lua @@ -1,13 +1,13 @@ --- luatex-core security and io overloads ........... +-- luatex-core security and io overloads .. -- if not modules then modules = { } end modules ['luatex-core'] = { --- version = 1.080, +-- version = 1.112, -- comment = 'companion to luatex', -- author = 'Hans Hagen & Luigi Scarso', -- copyright = 'LuaTeX Development Team', -- } -LUATEXCOREVERSION = 1.080 -- we reflect the luatex version where changes happened +LUATEXCOREVERSION = 1.112 -- we reflect the luatex version where changes happened -- This file overloads some Lua functions. The readline variants provide the same -- functionality as LuaTeX <= 1.04 and doing it this way permits us to keep the @@ -16,125 +16,135 @@ LUATEXCOREVERSION = 1.080 -- we reflect the luatex version where changes happene -- We test for functions already being defined so that we don't overload ones that -- are provided in the startup script. -local type, next, getmetatable, require = type, next, getmetatable, require -local find, gsub, format = string.find, string.gsub, string.format +local saferoption = status.safer_option +local shellescape = status.shell_escape -- 0 (disabled) 1 (anything) 2 (restricted) +local kpseused = status.kpse_used -- 0 1 -local io_open = io.open -local io_popen = io.popen -local io_lines = io.lines +if kpseused == 1 then -local fio_readline = fio.readline -local fio_checkpermission = fio.checkpermission -local fio_recordfilename = fio.recordfilename + local type = type + local gsub = string.gsub + local find = string.find -local mt = getmetatable(io.stderr) -local mt_lines = mt.lines -local saferoption = status.safer_option -local shellescape = status.shell_escape -- 0 (disabled) 1 (anything) 2 (restricted) -local kpseused = status.kpse_used -- 0 1 + local mt = getmetatable(io.stderr) + local mt_lines = mt.lines -local write_nl = texio.write_nl + local kpse_checkpermission = kpse.check_permission + local kpse_recordinputfile = kpse.record_input_file + local kpse_recordoutputfile = kpse.record_output_file -io.saved_lines = io_lines -- always readonly -mt.saved_lines = mt_lines -- always readonly + local io_open = io.open + local io_popen = io.popen + local io_lines = io.lines -local function luatex_io_open(name,how) - if not how then - how = 'r' - end - local f = io_open(name,how) - if f then - if type(how) == 'string' and find(how,'w') then - fio_recordfilename(name,'w') - else - fio_recordfilename(name,'r') + local fio_readline = fio.readline + + local write_nl = texio.write_nl + + io.saved_lines = io_lines -- always readonly + mt.saved_lines = mt_lines -- always readonly + + local function luatex_io_open(name,how) + if not how then + how = 'r' + end + local f = io_open(name,how) + if f then + if type(how) == 'string' and find(how,'w') then + kpse_recordoutputfile(name,'w') + else + kpse_recordinputfile(name,'r') + end end + return f end - return f -end -local function luatex_io_open_readonly(name,how) - if not how then - how = 'r' - else - how = gsub(how,'[^rb]','') - if how == '' then + local function luatex_io_open_readonly(name,how) + if not how then how = 'r' + else + how = gsub(how,'[^rb]','') + if how == '' then + how = 'r' + end end + local f = io_open(name,how) + if f then + fio_recordfilename(name,'r') + end + return f end - local f = io_open(name,how) - if f then - fio_recordfilename(name,'r') - end - return f -end -local function luatex_io_popen(name,...) - local okay, found = fio_checkpermission(name) - if okay and found then - return io_popen(found,...) + local function luatex_io_popen(name,...) + local okay, found = kpse_checkpermission(name) + if okay and found then + return io_popen(found,...) + end end -end --- local function luatex_io_lines(name,how) --- if name then --- local f = io_open(name,how or 'r') --- if f then --- return function() --- return fio_readline(f) --- end --- end --- else --- return io_lines() --- end --- end - --- For some reason the gc doesn't kick in so we need to close explitly --- so that the handle is flushed. - -local error, type = error, type - -local function luatex_io_lines(name,how) - if type(name) == "string" then - local f = io_open(name,how or 'r') - if f then - return function() - local l = fio_readline(f) - if not l then - f:close() + -- local function luatex_io_lines(name,how) + -- if name then + -- local f = io_open(name,how or 'r') + -- if f then + -- return function() + -- return fio_readline(f) + -- end + -- end + -- else + -- return io_lines() + -- end + -- end + + -- For some reason the gc doesn't kick in so we need to close explicitly + -- so that the handle is flushed. + + local error, type = error, type + + local function luatex_io_lines(name,how) + if type(name) == "string" then + local f = io_open(name,how or 'r') + if f then + return function() + local l = fio_readline(f) + if not l then + f:close() + end + return l end - return l + else + -- for those who like it this way: + error("patched 'io.lines' can't open '" .. name .. "'") end else - -- for those who like it this way: - error("patched 'io.lines' can't open '" .. name .. "'") + return io_lines() end - else - return io_lines() end -end -local function luatex_io_readline(f) - return function() - return fio_readline(f) + local function luatex_io_readline(f) + return function() + return fio_readline(f) + end end -end - -io.lines = luatex_io_lines -mt.lines = luatex_io_readline --- We assume management to be provided by the replacement of kpse. This is the --- case in ConTeXt. - -if kpseused == 1 then + io.lines = luatex_io_lines + mt.lines = luatex_io_readline io.open = luatex_io_open io.popen = luatex_io_popen +else + + -- we assume management elsewhere + end +-- maybe also only when in kpse mode + if saferoption == 1 then + local write_nl = texio.write_nl + local format = string.format + local function installdummy(str,f) local reported = false return function(...) @@ -176,8 +186,12 @@ if saferoption == 1 then debug = nil + -- os.[execute|os.spawn|os.exec] already are shellescape aware) + end +-- maybe also only when in kpse mode + if saferoption == 1 or shellescape ~= 1 then ffi = require('ffi') @@ -190,9 +204,6 @@ if saferoption == 1 or shellescape ~= 1 then end --- os.[execute|os.spawn|os.exec] already are shellescape aware) - - if md5 then local sum = md5.sum @@ -419,25 +430,25 @@ do end --- so far +-- start omit if utilities and utilities.merger and utilities.merger.compact then - local byte, format, gmatch = string.byte, string.format, string.gmatch + local byte, format, gmatch, gsub = string.byte, string.format, string.gmatch, string.gsub local concat = table.concat - local data = gsub(io.loaddata('luatex-core.lua'),'if%s+utilities.*','') + local data = io.loaddata('luatex-core.lua') + + data = gsub(data,'%-%-%s*start%s*omit.-%-%-%s*stop%s*omit%s*','') + data = gsub(data,'\r\n','\n') local t = { } local r = { } local n = 0 - local d = gsub(data,'\r\n','\n') -- be nice for unix - local s = utilities.merger.compact(d) -- no comments and less spaces + local s = utilities.merger.compact(data) -- no comments and less spaces t[#t+1] = '/* generated from and by luatex-core.lua */' t[#t+1] = '' - -- t[#t+1] = format('/*\n\n%s\n\n*/',d) - -- t[#t+1] = '' t[#t+1] = '#include "lua.h"' t[#t+1] = '#include "lauxlib.h"' t[#t+1] = '' @@ -446,7 +457,7 @@ if utilities and utilities.merger and utilities.merger.compact then t[#t+1] = 'int load_luatex_core_lua (lua_State * L)' t[#t+1] = '{' t[#t+1] = ' static unsigned char luatex_core_lua[] = {' - for c in gmatch(d,'.') do + for c in gmatch(data,'.') do if n == 16 then n = 1 t[#t+1] = ' ' .. concat(r,', ') .. ',' @@ -467,3 +478,5 @@ if utilities and utilities.merger and utilities.merger.compact then io.savedata('luatex-core-stripped.lua',s) end + +-- stop omit diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua index 766b869feef..41fbe10fd2a 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 03/21/19 21:39:34 +-- merge date : 2020-02-17 12:06 do -- begin closure to overcome local limits and interference @@ -121,6 +121,9 @@ elseif not ffi.number then end if LUAVERSION>5.3 then end +if status and os.setenv then + os.setenv("engine",string.lower(status.luatex_engine or "unknown")) +end end -- closure @@ -293,7 +296,7 @@ patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+unders patterns.somecontent=(anything-newline-space)^1 patterns.beginline=#(1-newline) patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) -function anywhere(pattern) +local function anywhere(pattern) return (1-P(pattern))^0*P(pattern) end lpeg.anywhere=anywhere @@ -977,9 +980,11 @@ function string.is_empty(str) end end local anything=patterns.anything -local allescapes=Cc("%")*S(".-+%?()[]*") -local someescapes=Cc("%")*S(".-+%()[]") -local matchescapes=Cc(".")*S("*?") +local moreescapes=Cc("%")*S(".-+%?()[]*$^{}") +local allescapes=Cc("%")*S(".-+%?()[]*") +local someescapes=Cc("%")*S(".-+%()[]") +local matchescapes=Cc(".")*S("*?") +local pattern_m=Cs ((moreescapes+anything )^0 ) local pattern_a=Cs ((allescapes+anything )^0 ) local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) @@ -989,6 +994,8 @@ end function string.topattern(str,lowercase,strict) if str=="" or type(str)~="string" then return ".*" + elseif strict=="all" then + str=lpegmatch(pattern_m,str) elseif strict then str=lpegmatch(pattern_c,str) else @@ -1042,7 +1049,7 @@ if not modules then modules={} end modules ['l-table']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select +local type,next,tostring,tonumber,select,rawget=type,next,tostring,tonumber,select,rawget local table,string=table,string local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump @@ -1376,13 +1383,13 @@ function table.fromhash(t) end return hsh end -local noquotes,hexify,handle,compact,inline,functions,metacheck +local noquotes,hexify,handle,compact,inline,functions,metacheck,accurate local reserved=table.tohash { 'and','break','do','else','elseif','end','false','for','function','if', 'in','local','nil','not','or','repeat','return','then','true','until','while', - 'NaN','goto', + 'NaN','goto','const', } -local function is_simple_table(t,hexify) +local function is_simple_table(t,hexify,accurate) local nt=#t if nt>0 then local n=0 @@ -1401,6 +1408,8 @@ local function is_simple_table(t,hexify) if tv=="number" then if hexify then tt[i]=format("0x%X",v) + elseif accurate then + tt[i]=format("%q",v) else tt[i]=v end @@ -1421,6 +1430,8 @@ local function is_simple_table(t,hexify) if tv=="number" then if hexify then tt[i+1]=format("0x%X",v) + elseif accurate then + tt[i+1]=format("%q",v) else tt[i+1]=v end @@ -1492,6 +1503,8 @@ local function do_serialize(root,name,depth,level,indexed) if tv=="number" then if hexify then handle(format("%s 0x%X,",depth,v)) + elseif accurate then + handle(format("%s %q,",depth,v)) else handle(format("%s %s,",depth,v)) end @@ -1501,7 +1514,7 @@ local function do_serialize(root,name,depth,level,indexed) if next(v)==nil then handle(format("%s {},",depth)) elseif inline then - local st=is_simple_table(v,hexify) + local st=is_simple_table(v,hexify,accurate) if st then handle(format("%s { %s },",depth,concat(st,", "))) else @@ -1529,12 +1542,16 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]=0x%X,",depth,k,v)) + elseif accurate then + handle(format("%s [%s]=%q,",depth,k,v)) else handle(format("%s [%s]=%s,",depth,k,v)) end elseif tk=="boolean" then if hexify then handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + elseif accurate then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) else handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) end @@ -1542,12 +1559,16 @@ local function do_serialize(root,name,depth,level,indexed) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then handle(format("%s %s=0x%X,",depth,k,v)) + elseif accurate then + handle(format("%s %s=%q,",depth,k,v)) else handle(format("%s %s=%s,",depth,k,v)) end else if hexify then handle(format("%s [%q]=0x%X,",depth,k,v)) + elseif accurate then + handle(format("%s [%q]=%q,",depth,k,v)) else handle(format("%s [%q]=%s,",depth,k,v)) end @@ -1556,6 +1577,8 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]=%q,",depth,k,v)) + elseif accurate then + handle(format("%s [%q]=%q,",depth,k,v)) else handle(format("%s [%s]=%q,",depth,k,v)) end @@ -1572,6 +1595,8 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]={},",depth,k)) + elseif accurate then + handle(format("%s [%q]={},",depth,k)) else handle(format("%s [%s]={},",depth,k)) end @@ -1584,11 +1609,13 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%q]={},",depth,k)) end elseif inline then - local st=is_simple_table(v,hexify) + local st=is_simple_table(v,hexify,accurate) if st then if tk=="number" then if hexify then handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) + elseif accurate then + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) else handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) end @@ -1610,6 +1637,8 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) + elseif accurate then + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) else handle(format("%s [%s]=%s,",depth,k,v and "true" or "false")) end @@ -1629,6 +1658,8 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]=load(%q),",depth,k,f)) + elseif accurate then + handle(format("%s [%q]=load(%q),",depth,k,f)) else handle(format("%s [%s]=load(%q),",depth,k,f)) end @@ -1646,6 +1677,8 @@ local function do_serialize(root,name,depth,level,indexed) if tk=="number" then if hexify then handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) + elseif accurate then + handle(format("%s [%q]=%q,",depth,k,tostring(v))) else handle(format("%s [%s]=%q,",depth,k,tostring(v))) end @@ -1669,6 +1702,7 @@ local function serialize(_handle,root,name,specification) if type(specification)=="table" then noquotes=specification.noquotes hexify=specification.hexify + accurate=specification.accurate handle=_handle or specification.handle or print functions=specification.functions compact=specification.compact @@ -1984,7 +2018,7 @@ end local function sequenced(t,sep,simple) if not t then return "" - elseif type(t)=="string" then + elseif type(t)~="table" then return t end local n=#t @@ -2023,7 +2057,11 @@ local function sequenced(t,sep,simple) end end end - return concat(s,sep or " | ") + if sep==true then + return "{ "..concat(s,", ").." }" + else + return concat(s,sep or " | ") + end end table.sequenced=sequenced function table.print(t,...) @@ -2163,7 +2201,7 @@ local open,flush,write,read=io.open,io.flush,io.write,io.read local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local type=type -if string.find(os.getenv("PATH"),";",1,true) then +if string.find(os.getenv("PATH") or "",";",1,true) then io.fileseparator,io.pathseparator="\\",";" else io.fileseparator,io.pathseparator="/",":" @@ -2518,15 +2556,24 @@ local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct local attributes=lfs.attributes function lfs.isdir(name) - return attributes(name,"mode")=="directory" + if name then + return attributes(name,"mode")=="directory" + end end function lfs.isfile(name) - local a=attributes(name,"mode") - return a=="file" or a=="link" or nil + if name then + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil + end end function lfs.isfound(name) - local a=attributes(name,"mode") - return (a=="file" or a=="link") and name or nil + if name then + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil + end +end +function lfs.modification(name) + return name and attributes(name,"modification") or nil end if sandbox then sandbox.redefine(lfs.isfile,"lfs.isfile") @@ -3388,6 +3435,13 @@ local template=[[ %s return function(%s) return %s end ]] +local pattern=Cs(Cc('"')*( + (1-S('"\\\n\r'))^1+P('"')/'\\"'+P('\\')/'\\\\'+P('\n')/'\\n'+P('\r')/'\\r' +)^0*Cc('"')) +patterns.escapedquotes=pattern +function string.escapedquotes(s) + return lpegmatch(pattern,s) +end local preamble="" local environment={ global=global or _G, @@ -3412,9 +3466,10 @@ local environment={ formattednumber=number.formatted, sparseexponent=number.sparseexponent, formattedfloat=number.formattedfloat, - stripzero=lpeg.patterns.stripzero, - stripzeros=lpeg.patterns.stripzeros, - FORMAT=string.f9, + stripzero=patterns.stripzero, + stripzeros=patterns.stripzeros, + escapedquotes=string.escapedquotes, + FORMAT=string.f6, } local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) @@ -3465,13 +3520,16 @@ local format_left=function(f) return format("a%s..utfpadding(a%s,%i)",n,n,-f) end end -local format_q=function() +local format_q=JITSUPPORTED and function() n=n+1 return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) +end or function() + n=n+1 + return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n) end local format_Q=function() n=n+1 - return format("format('%%q',tostring(a%s))",n) + return format("escapedquotes(tostring(a%s))",n) end local format_i=function(f) n=n+1 @@ -3622,12 +3680,25 @@ local format_n=function() n=n+1 return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) end -local format_N=function(f) - n=n+1 - if not f or f=="" then - f=".9" - end - return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) +local format_N if environment.FORMAT then + format_N=function(f) + n=n+1 + if not f or f=="" then + return format("FORMAT(a%s,'%%.9f')",n) + elseif f==".6" or f=="0.6" then + return format("FORMAT(a%s)",n) + else + return format("FORMAT(a%s,'%%%sf')",n,f) + end + end +else + format_N=function(f) + n=n+1 + if not f or f=="" then + f=".9" + end + return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) + end end local format_a=function(f) n=n+1 @@ -3856,9 +3927,9 @@ patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"" patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^0) patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"')) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) +add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape }) +add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape }) +add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 local cquote=Cc('"') @@ -3890,6 +3961,27 @@ local f_16_16=formatters["%0.5N"] function number.to16dot16(n) return f_16_16(n/65536.0) end +if not string.explode then + local tsplitat=lpeg.tsplitat + local p_utf=patterns.utf8character + local p_check=C(p_utf)*(P("+")*Cc(true))^0 + local p_split=Ct(C(p_utf)^0) + local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0) + function string.explode(str,symbol) + if symbol=="" then + return lpegmatch(p_split,str) + elseif symbol then + local a,b=lpegmatch(p_check,symbol) + if b then + return lpegmatch(tsplitat(P(a)^1),str) + else + return lpegmatch(tsplitat(a),str) + end + else + return lpegmatch(p_space,str) + end + end +end end -- closure @@ -4649,6 +4741,7 @@ if not modules then modules={} end modules ['data-con']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } +local setmetatable=setmetatable local format,lower,gsub=string.format,string.lower,string.gsub local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) @@ -4656,16 +4749,21 @@ local trace_storage=false trackers.register("resolvers.storage",function(v) tra containers=containers or {} local containers=containers containers.usecache=true +local getwritablepath=caches.getwritablepath +local getreadablepaths=caches.getreadablepaths +local cacheiswritable=caches.is_writable +local loaddatafromcache=caches.loaddata +local savedataincache=caches.savedata local report_containers=logs.reporter("resolvers","containers") local allocated={} local mt={ __index=function(t,k) if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + local writable=getwritablepath(t.category,t.subcategory) or { "." } t.writable=writable return writable elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + local readables=getreadablepaths(t.category,t.subcategory) or { "." } t.readables=readables return readables end @@ -4696,7 +4794,7 @@ function containers.define(category,subcategory,version,enabled) end end function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) + return container.enabled and caches and cacheiswritable(container.writable,name) end function containers.is_valid(container,name) if name and name~="" then @@ -4710,7 +4808,7 @@ function containers.read(container,name) local storage=container.storage local stored=storage[name] if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) + stored=loaddatafromcache(container.readables,name,container.writable) if stored and stored.cache_version==container.version then if trace_cache or trace_containers then report_containers("action %a, category %a, name %a","load",container.subcategory,name) @@ -4726,17 +4824,20 @@ function containers.read(container,name) end return stored end -function containers.write(container,name,data) +function containers.write(container,name,data,fast) if data then data.cache_version=container.version if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) + local unique=data.unique + local shared=data.shared + data.unique=nil + data.shared=nil + savedataincache(container.writable,name,data,fast) if trace_cache or trace_containers then report_containers("action %a, category %a, name %a","save",container.subcategory,name) end - data.unique,data.shared=unique,shared + data.unique=unique + data.shared=shared end if trace_cache or trace_containers then report_containers("action %a, category %a, name %a","store",container.subcategory,name) @@ -4825,6 +4926,7 @@ nuts.getchar=direct.getchar nuts.getcomponents=direct.getcomponents nuts.getdirection=direct.getdirection nuts.getdisc=direct.getdisc +nuts.getreplace=direct.getreplace nuts.getfield=direct.getfield nuts.getfont=direct.getfont nuts.getid=direct.getid @@ -4839,9 +4941,9 @@ nuts.setattr=direct.setfield nuts.setboth=direct.setboth nuts.setchar=direct.setchar nuts.setcomponents=direct.setcomponents -nuts.setdir=direct.setdir nuts.setdirection=direct.setdirection nuts.setdisc=direct.setdisc +nuts.setreplace=direct.setreplace nuts.setfield=setfield nuts.setkern=direct.setkern nuts.setlink=direct.setlink @@ -4852,8 +4954,8 @@ nuts.setprev=direct.setprev nuts.setsplit=direct.setsplit nuts.setsubtype=direct.setsubtype nuts.setwidth=direct.setwidth -nuts.is_char=direct.is_char -nuts.is_glyph=direct.is_glyph +nuts.getglyphdata=nuts.getattr +nuts.setglyphdata=nuts.setattr nuts.ischar=direct.is_char nuts.isglyph=direct.is_glyph nuts.copy=direct.copy @@ -4877,20 +4979,6 @@ nuts.traverse=direct.traverse nuts.traverse_char=direct.traverse_char nuts.traverse_glyph=direct.traverse_glyph nuts.traverse_id=direct.traverse_id -if not nuts.getdirection then - local getdir=direct.getdir - function nuts.getdirection(n) - local d=getdir(n) - if d=="TLT" then return 0 - elseif d=="TRT" then return 1 - elseif d=="+TLT" then return 0,false - elseif d=="+TRT" then return 1,false - elseif d=="-TLT" then return 0,true - elseif d=="-TRT" then return 1,true - else return 0 - end - end -end local propertydata=direct.get_properties_table() nodes.properties={ data=propertydata } if direct.set_properties_mode then @@ -4973,6 +5061,24 @@ do node=nuts.traverse(dummy), } end +if not nuts.setreplace then + local getdisc=nuts.getdisc + local setfield=nuts.setfield + function nuts.getreplace(n) + local _,_,h,_,_,t=getdisc(n,true) + return h,t + end + function nuts.setreplace(n,h) + setfield(n,"replace",h) + end +end +do + local getsubtype=nuts.getsubtype + function nuts.start_of_par(n) + local s=getsubtype(n) + return s==0 or s==2 + end +end end -- closure @@ -5419,7 +5525,6 @@ characters.classifiers={ [1803]=6, [1804]=6, [1805]=6, - [1807]=6, [1808]=3, [1809]=5, [1810]=2, @@ -5600,6 +5705,9 @@ characters.classifiers={ [2040]=6, [2041]=6, [2042]=2, + [2045]=5, + [2046]=6, + [2047]=6, [2070]=5, [2071]=5, [2072]=5, @@ -5689,6 +5797,7 @@ characters.classifiers={ [2235]=2, [2236]=2, [2237]=2, + [2259]=5, [2260]=5, [2261]=5, [2262]=5, @@ -5765,6 +5874,7 @@ characters.classifiers={ [2509]=5, [2530]=5, [2531]=5, + [2558]=5, [2561]=5, [2562]=5, [2620]=5, @@ -5813,6 +5923,7 @@ characters.classifiers={ [3008]=5, [3021]=5, [3072]=5, + [3076]=5, [3134]=5, [3135]=5, [3136]=5, @@ -5874,6 +5985,7 @@ characters.classifiers={ [3767]=5, [3768]=5, [3769]=5, + [3770]=5, [3771]=5, [3772]=5, [3784]=5, @@ -6112,6 +6224,7 @@ characters.classifiers={ [6261]=2, [6262]=2, [6263]=2, + [6264]=2, [6272]=4, [6273]=4, [6274]=4, @@ -6512,6 +6625,7 @@ characters.classifiers={ [43247]=5, [43248]=5, [43249]=5, + [43263]=5, [43302]=5, [43303]=5, [43304]=5, @@ -6675,6 +6789,83 @@ characters.classifiers={ [68525]=2, [68526]=2, [68527]=4, + [68864]=1, + [68865]=2, + [68866]=2, + [68867]=2, + [68868]=2, + [68869]=2, + [68870]=2, + [68871]=2, + [68872]=2, + [68873]=2, + [68874]=2, + [68875]=2, + [68876]=2, + [68877]=2, + [68878]=2, + [68879]=2, + [68880]=2, + [68881]=2, + [68882]=2, + [68883]=2, + [68884]=2, + [68885]=2, + [68886]=2, + [68887]=2, + [68888]=2, + [68889]=2, + [68890]=2, + [68891]=2, + [68892]=2, + [68893]=2, + [68894]=2, + [68895]=2, + [68896]=2, + [68897]=2, + [68898]=3, + [68899]=2, + [68900]=5, + [68901]=5, + [68902]=5, + [68903]=5, + [69424]=2, + [69425]=2, + [69426]=2, + [69427]=3, + [69428]=2, + [69429]=2, + [69430]=2, + [69431]=2, + [69432]=2, + [69433]=2, + [69434]=2, + [69435]=2, + [69436]=2, + [69437]=2, + [69438]=2, + [69439]=2, + [69440]=2, + [69441]=2, + [69442]=2, + [69443]=2, + [69444]=2, + [69445]=4, + [69446]=5, + [69447]=5, + [69448]=5, + [69449]=5, + [69450]=5, + [69451]=5, + [69452]=5, + [69453]=5, + [69454]=5, + [69455]=5, + [69456]=5, + [69457]=2, + [69458]=2, + [69459]=2, + [69460]=3, [69633]=5, [69688]=5, [69689]=5, @@ -6700,6 +6891,8 @@ characters.classifiers={ [69814]=5, [69817]=5, [69818]=5, + [69821]=4, + [69837]=4, [69888]=5, [69889]=5, [69890]=5, @@ -6749,6 +6942,7 @@ characters.classifiers={ [70378]=5, [70400]=5, [70401]=5, + [70459]=5, [70460]=5, [70464]=5, [70502]=5, @@ -6775,6 +6969,7 @@ characters.classifiers={ [70723]=5, [70724]=5, [70726]=5, + [70750]=5, [70835]=5, [70836]=5, [70837]=5, @@ -6828,6 +7023,24 @@ characters.classifiers={ [71465]=5, [71466]=5, [71467]=5, + [71727]=5, + [71728]=5, + [71729]=5, + [71730]=5, + [71731]=5, + [71732]=5, + [71733]=5, + [71734]=5, + [71735]=5, + [71737]=5, + [71738]=5, + [72148]=5, + [72149]=5, + [72150]=5, + [72151]=5, + [72154]=5, + [72155]=5, + [72160]=5, [72193]=5, [72194]=5, [72195]=5, @@ -6935,6 +7148,12 @@ characters.classifiers={ [73028]=5, [73029]=5, [73031]=5, + [73104]=5, + [73105]=5, + [73109]=5, + [73111]=5, + [73459]=5, + [73460]=5, [92912]=5, [92913]=5, [92914]=5, @@ -6947,6 +7166,7 @@ characters.classifiers={ [92980]=5, [92981]=5, [92982]=5, + [94031]=5, [94095]=5, [94096]=5, [94097]=5, @@ -7143,6 +7363,17 @@ characters.classifiers={ [122920]=5, [122921]=5, [122922]=5, + [123184]=5, + [123185]=5, + [123186]=5, + [123187]=5, + [123188]=5, + [123189]=5, + [123190]=5, + [123628]=5, + [123629]=5, + [123630]=5, + [123631]=5, [125136]=5, [125137]=5, [125138]=5, @@ -7245,6 +7476,7 @@ characters.indicgroups={ [2632]=true, [2635]=true, [2636]=true, + [2690]=true, [2757]=true, [2759]=true, [2760]=true, @@ -7256,7 +7488,6 @@ characters.indicgroups={ [3136]=true, [3142]=true, [3143]=true, - [3144]=true, [3146]=true, [3147]=true, [3148]=true, @@ -7264,6 +7495,21 @@ characters.indicgroups={ [3263]=true, [3270]=true, [3406]=true, + [4141]=true, + [4142]=true, + [4146]=true, + [4147]=true, + [4148]=true, + [4149]=true, + [4150]=true, + [4154]=true, + [4209]=true, + [4210]=true, + [4211]=true, + [4212]=true, + [4229]=true, + [4230]=true, + [4253]=true, [43232]=true, [43233]=true, [43234]=true, @@ -7282,6 +7528,8 @@ characters.indicgroups={ [43247]=true, [43248]=true, [43249]=true, + [43493]=true, + [43644]=true, }, ["after_half"]={}, ["after_main"]={ @@ -7303,6 +7551,7 @@ characters.indicgroups={ [2626]=true, [2672]=true, [2673]=true, + [2735]=true, [2750]=true, [2752]=true, [2753]=true, @@ -7466,10 +7715,24 @@ characters.indicgroups={ [3170]=true, [3171]=true, [3260]=true, + [3286]=true, [3298]=true, [3299]=true, [3426]=true, [3427]=true, + [4143]=true, + [4144]=true, + [4151]=true, + [4153]=true, + [4157]=true, + [4158]=true, + [4184]=true, + [4185]=true, + [4190]=true, + [4191]=true, + [4192]=true, + [4226]=true, + [4237]=true, }, ["consonant"]={ [2325]=true, @@ -7799,6 +8062,117 @@ characters.indicgroups={ [3384]=true, [3385]=true, [3386]=true, + [4096]=true, + [4097]=true, + [4098]=true, + [4099]=true, + [4100]=true, + [4101]=true, + [4102]=true, + [4103]=true, + [4104]=true, + [4105]=true, + [4106]=true, + [4107]=true, + [4108]=true, + [4109]=true, + [4110]=true, + [4111]=true, + [4112]=true, + [4113]=true, + [4114]=true, + [4115]=true, + [4116]=true, + [4117]=true, + [4118]=true, + [4119]=true, + [4120]=true, + [4121]=true, + [4122]=true, + [4123]=true, + [4124]=true, + [4125]=true, + [4126]=true, + [4127]=true, + [4128]=true, + [4155]=true, + [4156]=true, + [4157]=true, + [4158]=true, + [4159]=true, + [4176]=true, + [4177]=true, + [4186]=true, + [4187]=true, + [4188]=true, + [4189]=true, + [4190]=true, + [4191]=true, + [4192]=true, + [4193]=true, + [4197]=true, + [4198]=true, + [4206]=true, + [4207]=true, + [4208]=true, + [4213]=true, + [4214]=true, + [4215]=true, + [4216]=true, + [4217]=true, + [4218]=true, + [4219]=true, + [4220]=true, + [4221]=true, + [4222]=true, + [4223]=true, + [4224]=true, + [4225]=true, + [4226]=true, + [4238]=true, + [43488]=true, + [43489]=true, + [43490]=true, + [43491]=true, + [43492]=true, + [43495]=true, + [43496]=true, + [43497]=true, + [43498]=true, + [43499]=true, + [43500]=true, + [43501]=true, + [43502]=true, + [43503]=true, + [43514]=true, + [43515]=true, + [43516]=true, + [43517]=true, + [43518]=true, + [43616]=true, + [43617]=true, + [43618]=true, + [43619]=true, + [43620]=true, + [43621]=true, + [43622]=true, + [43623]=true, + [43624]=true, + [43625]=true, + [43626]=true, + [43628]=true, + [43629]=true, + [43630]=true, + [43631]=true, + [43633]=true, + [43634]=true, + [43635]=true, + [43636]=true, + [43637]=true, + [43638]=true, + [43642]=true, + [43646]=true, + [43647]=true, }, ["dependent_vowel"]={ [2362]=true, @@ -7827,13 +8201,14 @@ characters.indicgroups={ [2403]=true, [2494]=true, [2495]=true, - [2496]=true, [2497]=true, [2498]=true, [2499]=true, [2500]=true, [2503]=true, [2504]=true, + [2507]=true, + [2508]=true, [2622]=true, [2623]=true, [2624]=true, @@ -7908,6 +8283,8 @@ characters.indicgroups={ [3274]=true, [3275]=true, [3276]=true, + [3285]=true, + [3286]=true, [3298]=true, [3299]=true, [3390]=true, @@ -7926,6 +8303,35 @@ characters.indicgroups={ [3415]=true, [3426]=true, [3427]=true, + [4139]=true, + [4140]=true, + [4141]=true, + [4142]=true, + [4143]=true, + [4144]=true, + [4145]=true, + [4146]=true, + [4147]=true, + [4148]=true, + [4149]=true, + [4182]=true, + [4183]=true, + [4184]=true, + [4185]=true, + [4194]=true, + [4199]=true, + [4200]=true, + [4209]=true, + [4210]=true, + [4211]=true, + [4212]=true, + [4227]=true, + [4228]=true, + [4229]=true, + [4230]=true, + [4252]=true, + [4253]=true, + [43493]=true, }, ["halant"]={ [2381]=true, @@ -8083,6 +8489,20 @@ characters.indicgroups={ [3423]=true, [3424]=true, [3425]=true, + [4129]=true, + [4130]=true, + [4131]=true, + [4132]=true, + [4133]=true, + [4134]=true, + [4135]=true, + [4136]=true, + [4137]=true, + [4138]=true, + [4178]=true, + [4179]=true, + [4180]=true, + [4181]=true, }, ["nukta"]={ [2364]=true, @@ -8104,8 +8524,6 @@ characters.indicgroups={ [2383]=true, [2494]=true, [2496]=true, - [2503]=true, - [2504]=true, [2622]=true, [2624]=true, [2750]=true, @@ -8122,16 +8540,12 @@ characters.indicgroups={ [3139]=true, [3140]=true, [3262]=true, - [3264]=true, [3265]=true, [3266]=true, [3267]=true, [3268]=true, - [3271]=true, - [3272]=true, - [3274]=true, - [3275]=true, [3276]=true, + [3285]=true, [3390]=true, [3391]=true, [3392]=true, @@ -8140,25 +8554,58 @@ characters.indicgroups={ [3395]=true, [3396]=true, [3415]=true, + [4139]=true, + [4140]=true, + [4152]=true, + [4155]=true, + [4182]=true, + [4183]=true, + [4194]=true, + [4195]=true, + [4196]=true, + [4199]=true, + [4200]=true, + [4201]=true, + [4202]=true, + [4203]=true, + [4204]=true, + [4205]=true, + [4227]=true, + [4231]=true, + [4232]=true, + [4233]=true, + [4234]=true, + [4235]=true, + [4236]=true, + [4239]=true, + [4250]=true, + [4251]=true, + [4252]=true, + [43643]=true, + [43645]=true, }, ["pre_mark"]={ [2367]=true, [2382]=true, [2495]=true, + [2503]=true, + [2504]=true, [2623]=true, [2751]=true, [2887]=true, - [2888]=true, [3014]=true, [3015]=true, [3016]=true, [3398]=true, [3399]=true, [3400]=true, + [4145]=true, + [4228]=true, }, ["ra"]={ [2352]=true, [2480]=true, + [2544]=true, [2608]=true, [2736]=true, [2864]=true, @@ -8172,17 +8619,43 @@ characters.indicgroups={ [2386]=true, [2387]=true, [2388]=true, - [2507]=true, - [2508]=true, - [3277]=true, - [3405]=true, + [4151]=true, + [4195]=true, + [4196]=true, + [4201]=true, + [4202]=true, + [4203]=true, + [4204]=true, + [4205]=true, + [4231]=true, + [4232]=true, + [4233]=true, + [4234]=true, + [4235]=true, + [4236]=true, + [4237]=true, + [4239]=true, + [4250]=true, + [4251]=true, + [43643]=true, + [43644]=true, + [43645]=true, }, ["twopart_mark"]={ + [2507]={ 2503,2494 }, + [2508]={ 2503,2519 }, + [2888]={ 2887,2902 }, [2891]={ 2887,2878 }, [2892]={ 2887,2903 }, [3018]={ 3014,3006 }, [3019]={ 3015,3006 }, [3020]={ 3014,3031 }, + [3144]={ 3142,3158 }, + [3264]={ 3263,3285 }, + [3271]={ 3270,3285 }, + [3272]={ 3270,3286 }, + [3274]={ 3270,3266 }, + [3275]={ 3274,3285 }, [3402]={ 3398,3390 }, [3403]={ 3399,3390 }, [3404]={ 3398,3415 }, @@ -8192,8 +8665,13 @@ characters.indicgroups={ [2305]=true, [2306]=true, [2307]=true, + [2433]=true, [3330]=true, [3331]=true, + [4150]=true, + [4152]=true, + [4153]=true, + [4154]=true, [43232]=true, [43233]=true, [43234]=true, @@ -8210,7 +8688,6 @@ characters.indicgroups={ [43245]=true, [43246]=true, [43247]=true, - [43248]=true, [43249]=true, }, } @@ -8252,6 +8729,9 @@ fonts.privateoffsets={ mathbase=0xFF000, keepnames=false, } +if node and not tex.getfontoffamily then + tex.getfontoffamily=node.family_font +end end -- closure @@ -8318,13 +8798,13 @@ fonts.handlers=handlers local allocate=utilities.storage.allocate local setmetatableindex=table.setmetatableindex constructors.dontembed=allocate() -constructors.autocleanup=true constructors.namemode="fullpath" constructors.version=1.01 constructors.cache=containers.define("fonts","constructors",constructors.version,false) constructors.privateoffset=fonts.privateoffsets.textbase or 0xF0000 constructors.cacheintex=true constructors.addtounicode=true +constructors.fixprotrusion=true local designsizes=allocate() constructors.designsizes=designsizes local loadedfonts=allocate() @@ -8376,11 +8856,6 @@ function constructors.getmathparameter(tfmdata,name) end end function constructors.cleanuptable(tfmdata) - if constructors.autocleanup and tfmdata.properties.virtualized then - for k,v in next,tfmdata.characters do - if v.commands then v.commands=nil end - end - end end function constructors.calculatescale(tfmdata,scaledpoints) local parameters=tfmdata.parameters @@ -8593,7 +9068,8 @@ function constructors.scale(tfmdata,specification) local units=parameters.units or 1000 targetproperties.language=properties.language or "dflt" targetproperties.script=properties.script or "dflt" - targetproperties.mode=properties.mode or "base" + targetproperties.mode=properties.mode or "base" + targetproperties.method=properties.method local askedscaledpoints=scaledpoints local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification) local hdelta=delta @@ -8606,6 +9082,7 @@ function constructors.scale(tfmdata,specification) properties.direction=direction target.size=scaledpoints target.encodingbytes=properties.encodingbytes or 1 + target.subfont=properties.subfont target.embedding=properties.embedding or "subset" target.tounicode=1 target.cidinfo=properties.cidinfo @@ -8715,7 +9192,7 @@ function constructors.scale(tfmdata,specification) targetparameters.descender=delta*descender end constructors.enhanceparameters(targetparameters) - local protrusionfactor=(targetquad~=0 and 1000/targetquad) or 0 + local protrusionfactor=constructors.fixprotrusion and ((targetquad~=0 and 1000/targetquad) or 1) or 1 local scaledwidth=defaultwidth*hdelta local scaledheight=defaultheight*vdelta local scaleddepth=defaultdepth*vdelta @@ -9056,13 +9533,13 @@ function constructors.finalize(tfmdata) parameters.width=0 end if not parameters.slantfactor then - parameters.slantfactor=tfmdata.slant or 0 + parameters.slantfactor=(tfmdata.slant or 0)/1000 end if not parameters.extendfactor then - parameters.extendfactor=tfmdata.extend or 0 + parameters.extendfactor=(tfmdata.extend or 1000)/1000 end if not parameters.squeezefactor then - parameters.squeezefactor=tfmdata.squeeze or 0 + parameters.squeezefactor=(tfmdata.squeeze or 1000)/1000 end local designsize=parameters.designsize if designsize then @@ -9092,12 +9569,13 @@ function constructors.finalize(tfmdata) if not properties.virtualized then properties.virtualized=tfmdata.type=="virtual" end - properties.fontname=tfmdata.fontname - properties.filename=tfmdata.filename - properties.fullname=tfmdata.fullname - properties.name=tfmdata.name - properties.psname=tfmdata.psname + properties.fontname=properties.fontname or tfmdata.fontname + properties.filename=properties.filename or tfmdata.filename + properties.fullname=properties.fullname or tfmdata.fullname + properties.name=properties.name or tfmdata.name + properties.psname=properties.psname or tfmdata.psname properties.encodingbytes=tfmdata.encodingbytes or 1 + properties.subfont=tfmdata.subfont or nil properties.embedding=tfmdata.embedding or "subset" properties.tounicode=tfmdata.tounicode or 1 properties.cidinfo=tfmdata.cidinfo or nil @@ -9123,6 +9601,7 @@ function constructors.finalize(tfmdata) tfmdata.name=nil tfmdata.psname=nil tfmdata.encodingbytes=nil + tfmdata.subfont=nil tfmdata.embedding=nil tfmdata.tounicode=nil tfmdata.cidinfo=nil @@ -9185,6 +9664,7 @@ hashmethods.normal=function(list) m=m+1 t[m]=k..'='..tostring(v) end + sort(t) s[n]=k..'={'..concat(t,",").."}" else s[n]=k..'='..tostring(v) @@ -10436,7 +10916,7 @@ if not modules then modules={} end modules ['font-otr']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local next,type,tonumber=next,type,tonumber +local next,type,tonumber,rawget=next,type,tonumber,rawget local byte,lower,char,gsub=string.byte,string.lower,string.char,string.gsub local fullstrip=string.fullstrip local floor,round=math.floor,math.round @@ -10449,8 +10929,9 @@ local sortedhash=table.sortedhash local stripstring=string.nospaces local utf16_to_utf8_be=utf.utf16_to_utf8_be local report=logs.reporter("otf reader") -local trace_cmap=false -local trace_cmap_detail=false +local report_cmap=logs.reporter("otf reader","cmap") +local trace_cmap=false trackers.register("otf.cmap",function(v) trace_cmap=v end) +local trace_cmap_details=false trackers.register("otf.cmap.details",function(v) trace_cmap_details=v end) fonts=fonts or {} local handlers=fonts.handlers or {} fonts.handlers=handlers @@ -11112,15 +11593,18 @@ readers.vmtx=function(f,fontdata,specification) local glyphs=fontdata.glyphs local nofglyphs=fontdata.nofglyphs local vheight=0 - local vdefault=verticalheader.ascender+verticalheader.descender + local vdefault=verticalheader.ascender-verticalheader.descender local topsidebearing=0 for i=0,nofmetrics-1 do local glyph=glyphs[i] - vheight=readshort(f) + vheight=readushort(f) topsidebearing=readshort(f) if vheight~=0 and vheight~=vdefault then glyph.vheight=vheight end + if topsidebearing~=0 then + glyph.tsb=topsidebearing + end end for i=nofmetrics,nofglyphs-1 do local glyph=glyphs[i] @@ -11198,11 +11682,14 @@ local sequence={ { 3,1,4 }, { 3,10,12 }, { 0,3,4 }, + { 0,3,12 }, { 0,1,4 }, + { 0,1,12 }, { 0,0,6 }, { 3,0,6 }, + { 3,0,4 }, { 0,5,14 }, -{ 0,4,12 }, + { 0,4,12 }, { 3,10,13 }, } local supported={} @@ -11247,7 +11734,7 @@ formatreaders[4]=function(f,fontdata,offset) elseif startchar==0xFFFF and offset==0 then elseif offset==0xFFFF then elseif offset==0 then - if trace_cmap_detail then + if trace_cmap_details then report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar+delta)%65536) end for unicode=startchar,endchar do @@ -11279,8 +11766,8 @@ formatreaders[4]=function(f,fontdata,offset) end else local shift=(segment-nofsegments+offset/2)-startchar - if trace_cmap_detail then - report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536) + if trace_cmap_details then + report_cmap("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar+delta)%65536) end for unicode=startchar,endchar do local slot=shift+unicode @@ -11327,8 +11814,8 @@ formatreaders[6]=function(f,fontdata,offset) local count=readushort(f) local stop=start+count-1 local nofdone=0 - if trace_cmap_detail then - report("format 6 from %C to %C",2,start,stop) + if trace_cmap_details then + report_cmap("format 6 from %C to %C",2,start,stop) end for unicode=start,stop do local index=readushort(f) @@ -11360,8 +11847,8 @@ formatreaders[12]=function(f,fontdata,offset) local first=readulong(f) local last=readulong(f) local index=readulong(f) - if trace_cmap_detail then - report("format 12 from %C to %C starts at index %i",first,last,index) + if trace_cmap_details then + report_cmap("format 12 from %C to %C starts at index %i",first,last,index) end for unicode=first,last do local glyph=glyphs[index] @@ -11399,8 +11886,8 @@ formatreaders[13]=function(f,fontdata,offset) local last=readulong(f) local index=readulong(f) if first<privateoffset then - if trace_cmap_detail then - report("format 13 from %C to %C get index %i",first,last,index) + if trace_cmap_details then + report_cmap("format 13 from %C to %C get index %i",first,last,index) end local glyph=glyphs[index] local unicode=glyph.unicode @@ -11470,27 +11957,46 @@ formatreaders[14]=function(f,fontdata,offset) end end local function checkcmap(f,fontdata,records,platform,encoding,format) - local data=records[platform] - if not data then + local pdata=records[platform] + if not pdata then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","no platform",platform,encoding,format) + end return 0 end - data=data[encoding] - if not data then + local edata=pdata[encoding] + if not edata then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","no encoding",platform,encoding,format) + end return 0 end - data=data[format] - if not data then + local fdata=edata[format] + if not fdata then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","no format",platform,encoding,format) + end + return 0 + elseif type(fdata)~="number" then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","already done",platform,encoding,format) + end return 0 end + edata[format]=true local reader=formatreaders[format] if not reader then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","unsupported format",platform,encoding,format) + end return 0 end - local p=platforms[platform] - local e=encodings[p] - local n=reader(f,fontdata,data) or 0 - if trace_cmap then - report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n) + local n=reader(f,fontdata,fdata) or 0 + if trace_cmap_details or trace_cmap then + local p=platforms[platform] + local e=encodings[p] + report_cmap("checked, platform %i (%s), encoding %i (%s), format %i, new unicodes %i", + platform,p,encoding,e and e[encoding] or "?",format,n) end return n end @@ -11685,6 +12191,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst local postscript=fontdata.postscript or {} local fontheader=fontdata.fontheader or {} local cffinfo=fontdata.cffinfo or {} + local verticalheader=fontdata.verticalheader or {} local filename=fontdata.filename local weight=getname(fontdata,"weight") or (cffinfo and cffinfo.weight) or (metrics and metrics.weight) local width=getname(fontdata,"width") or (cffinfo and cffinfo.width ) or (metrics and metrics.width ) @@ -11750,6 +12257,7 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,inst platformnames=platformnames or nil, instancenames=instancenames or nil, tableoffsets=fontdata.tableoffsets, + defaultvheight=(verticalheader.ascender or 0)-(verticalheader.descender or 0) } if metricstoo then local keys={ @@ -12420,14 +12928,19 @@ otf.tables=tables local statistics=otf.statistics or {} otf.statistics=statistics local scripts=allocate { + ["adlm"]="adlam", + ["aghb"]="caucasian albanian", + ["ahom"]="ahom", ["arab"]="arabic", ["armi"]="imperial aramaic", ["armn"]="armenian", ["avst"]="avestan", ["bali"]="balinese", ["bamu"]="bamum", + ["bass"]="bassa vah", ["batk"]="batak", ["beng"]="bengali", + ["bhks"]="bhaiksuki", ["bng2"]="bengali variant 2", ["bopo"]="bopomofo", ["brah"]="brahmi", @@ -12443,23 +12956,33 @@ local scripts=allocate { ["copt"]="coptic", ["cprt"]="cypriot syllabary", ["cyrl"]="cyrillic", - ["deva"]="devanagari", ["dev2"]="devanagari variant 2", + ["deva"]="devanagari", + ["dogr"]="dogra", ["dsrt"]="deseret", + ["dupl"]="duployan", ["egyp"]="egyptian heiroglyphs", + ["elba"]="elbasan", ["ethi"]="ethiopic", ["geor"]="georgian", + ["gjr2"]="gujarati variant 2", ["glag"]="glagolitic", + ["gong"]="gunjala gondi", + ["gonm"]="masaram gondi", ["goth"]="gothic", + ["gran"]="grantha", ["grek"]="greek", ["gujr"]="gujarati", - ["gjr2"]="gujarati variant 2", - ["guru"]="gurmukhi", ["gur2"]="gurmukhi variant 2", + ["guru"]="gurmukhi", ["hang"]="hangul", ["hani"]="cjk ideographic", ["hano"]="hanunoo", + ["hatr"]="hatran", ["hebr"]="hebrew", + ["hluw"]="anatolian hieroglyphs", + ["hmng"]="pahawh hmong", + ["hung"]="old hungarian", ["ital"]="old italic", ["jamo"]="hangul jamo", ["java"]="javanese", @@ -12467,49 +12990,77 @@ local scripts=allocate { ["kana"]="hiragana and katakana", ["khar"]="kharosthi", ["khmr"]="khmer", - ["knda"]="kannada", + ["khoj"]="khojki", ["knd2"]="kannada variant 2", + ["knda"]="kannada", ["kthi"]="kaithi", ["lana"]="tai tham", ["lao" ]="lao", ["latn"]="latin", ["lepc"]="lepcha", ["limb"]="limbu", + ["lina"]="linear a", ["linb"]="linear b", ["lisu"]="lisu", ["lyci"]="lycian", ["lydi"]="lydian", + ["mahj"]="mahajani", + ["maka"]="makasar", ["mand"]="mandaic and mandaean", + ["mani"]="manichaean", + ["marc"]="marchen", ["math"]="mathematical alphanumeric symbols", + ["medf"]="medefaidrin", + ["mend"]="mende kikakui", ["merc"]="meroitic cursive", ["mero"]="meroitic hieroglyphs", - ["mlym"]="malayalam", ["mlm2"]="malayalam variant 2", + ["mlym"]="malayalam", + ["modi"]="modi", ["mong"]="mongolian", + ["mroo"]="mro", ["mtei"]="meitei Mayek", + ["mult"]="multani", ["musc"]="musical symbols", ["mym2"]="myanmar variant 2", ["mymr"]="myanmar", + ["narb"]="old north arabian", + ["nbat"]="nabataean", + ["newa"]="newa", ["nko" ]='n"ko', + ["nshu"]="nüshu", ["ogam"]="ogham", ["olck"]="ol chiki", ["orkh"]="old turkic and orkhon runic", - ["orya"]="oriya", ["ory2"]="odia variant 2", + ["orya"]="oriya", + ["osge"]="osage", ["osma"]="osmanya", + ["palm"]="palmyrene", + ["pauc"]="pau cin hau", + ["perm"]="old permic", ["phag"]="phags-pa", ["phli"]="inscriptional pahlavi", + ["phlp"]="psalter pahlavi", ["phnx"]="phoenician", + ["plrd"]="miao", ["prti"]="inscriptional parthian", ["rjng"]="rejang", + ["rohg"]="hanifi rohingya", ["runr"]="runic", ["samr"]="samaritan", ["sarb"]="old south arabian", ["saur"]="saurashtra", + ["sgnw"]="sign writing", ["shaw"]="shavian", ["shrd"]="sharada", + ["sidd"]="siddham", + ["sind"]="khudawadi", ["sinh"]="sinhala", + ["sogd"]="sogdian", + ["sogo"]="old sogdian", ["sora"]="sora sompeng", + ["soyo"]="soyombo", ["sund"]="sundanese", ["sylo"]="syloti nagri", ["syrc"]="syriac", @@ -12518,20 +13069,24 @@ local scripts=allocate { ["tale"]="tai le", ["talu"]="tai lu", ["taml"]="tamil", + ["tang"]="tangut", ["tavt"]="tai viet", - ["telu"]="telugu", ["tel2"]="telugu variant 2", + ["telu"]="telugu", ["tfng"]="tifinagh", ["tglg"]="tagalog", ["thaa"]="thaana", ["thai"]="thai", ["tibt"]="tibetan", + ["tirh"]="tirhuta", ["tml2"]="tamil variant 2", ["ugar"]="ugaritic cuneiform", ["vai" ]="vai", + ["wara"]="warang citi", ["xpeo"]="old persian cuneiform", ["xsux"]="sumero-akkadian cuneiform", ["yi" ]="yi", + ["zanb"]="zanabazar square", } local languages=allocate { ["aba" ]="abaza", @@ -12600,12 +13155,15 @@ local languages=allocate { ["brm" ]="burmese", ["brx" ]="bodo", ["bsh" ]="bashkir", + ["bsk" ]="burushaski", ["bti" ]="beti", ["bts" ]="batak simalungun", ["bug" ]="bugis", + ["byv" ]="medumba", ["cak" ]="kaqchikel", ["cat" ]="catalan", ["cbk" ]="zamboanga chavacano", + ["cchn"]="chinantec", ["ceb" ]="cebuano", ["cgg" ]="chiga", ["cha" ]="chamorro", @@ -12620,6 +13178,8 @@ local languages=allocate { ["chr" ]="cherokee", ["chu" ]="chuvash", ["chy" ]="cheyenne", + ["cja" ]="western cham", + ["cjm" ]="eastern cham", ["cmr" ]="comorian", ["cop" ]="coptic", ["cor" ]="cornish", @@ -12675,6 +13235,7 @@ local languages=allocate { ["fin" ]="finnish", ["fji" ]="fijian", ["fle" ]="dutch (flemish)", + ["fmp" ]="fe’fe’", ["fne" ]="forest nenets", ["fon" ]="fon", ["fos" ]="faroese", @@ -12753,6 +13314,7 @@ local languages=allocate { ["jan" ]="japanese", ["jav" ]="javanese", ["jbo" ]="lojban", + ["jct" ]="krymchak", ["jii" ]="yiddish", ["jud" ]="ladino", ["jul" ]="jula", @@ -12789,6 +13351,7 @@ local languages=allocate { ["kmn" ]="kumaoni", ["kmo" ]="komo", ["kms" ]="komso", + ["kmz" ]="khorasani turkic", ["knr" ]="kanuri", ["kod" ]="kodagu", ["koh" ]="korean old hangul", @@ -12865,6 +13428,7 @@ local languages=allocate { ["mar" ]="marathi", ["maw" ]="marwari", ["mbn" ]="mbundu", + ["mbo" ]="mbo", ["mch" ]="manchu", ["mcr" ]="moose cree", ["mde" ]="mende", @@ -12881,6 +13445,7 @@ local languages=allocate { ["mle" ]="male", ["mlg" ]="malagasy", ["mln" ]="malinke", + ["mlr" ]="malayalam reformed", ["mly" ]="malay", ["mnd" ]="mandinka", ["mng" ]="mongolian", @@ -12934,6 +13499,7 @@ local languages=allocate { ["nto" ]="esperanto", ["nym" ]="nyamwezi", ["nyn" ]="norwegian nynorsk", + ["nza" ]="mbembe tigon", ["oci" ]="occitan", ["ocr" ]="oji-cree", ["ojb" ]="ojibway", @@ -12997,6 +13563,7 @@ local languages=allocate { ["say" ]="sayisi", ["scn" ]="sicilian", ["sco" ]="scots", + ["scs" ]="north slavey", ["sek" ]="sekota", ["sel" ]="selkup", ["sga" ]="old irish", @@ -13041,6 +13608,9 @@ local languages=allocate { ["sxu" ]="upper saxon", ["syl" ]="sylheti", ["syr" ]="syriac", + ["syre"]="estrangela syriac", + ["syrj"]="western syriac", + ["syrn"]="eastern syriac", ["szl" ]="silesian", ["tab" ]="tabasaran", ["taj" ]="tajiki", @@ -13072,6 +13642,7 @@ local languages=allocate { ["tsj" ]="tshangla", ["tua" ]="turoyo aramaic", ["tul" ]="tulu", + ["tum" ]="tulu", ["tuv" ]="tuvin", ["tvl" ]="tuvalu", ["twi" ]="twi", @@ -13097,6 +13668,7 @@ local languages=allocate { ["wel" ]="welsh", ["wlf" ]="wolof", ["wln" ]="walloon", + ["wtm" ]="mewati", ["xbd" ]="lü", ["xhs" ]="xhosa", ["xjb" ]="minjangbal", @@ -13240,6 +13812,7 @@ local features=allocate { ["vkna"]="vertical kana alternates", ["vkrn"]="vertical kerning", ["vpal"]="proportional alternate vertical metrics", + ["vrtr"]="vertical alternates for rotation", ["vrt2"]="vertical rotation", ["zero"]="slashed zero", ["trep"]="traditional tex replacements", @@ -13462,7 +14035,7 @@ if not modules then modules={} end modules ['font-cff']={ license="see context related readme files" } local next,type,tonumber,rawget=next,type,tonumber,rawget -local byte,char,gmatch=string.byte,string.char,string.gmatch +local byte,char,gmatch,sub=string.byte,string.char,string.gmatch,string.sub local concat,remove,unpack=table.concat,table.remove,table.unpack local floor,abs,round,ceil,min,max=math.floor,math.abs,math.round,math.ceil,math.min,math.max local P,C,R,S,C,Cs,Ct=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Ct @@ -13569,12 +14142,51 @@ local defaultstrings={ [0]= "Thornsmall","Ydieresissmall","001.000","001.001","001.002","001.003", "Black","Bold","Book","Light","Medium","Regular","Roman","Semibold", } +local standardnames={ [0]= + false,false,false,false,false,false,false,false,false,false,false, + false,false,false,false,false,false,false,false,false,false,false, + false,false,false,false,false,false,false,false,false,false, + "space","exclam","quotedbl","numbersign","dollar","percent", + "ampersand","quoteright","parenleft","parenright","asterisk","plus", + "comma","hyphen","period","slash","zero","one","two","three","four", + "five","six","seven","eight","nine","colon","semicolon","less", + "equal","greater","question","at","A","B","C","D","E","F","G","H", + "I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W", + "X","Y","Z","bracketleft","backslash","bracketright","asciicircum", + "underscore","quoteleft","a","b","c","d","e","f","g","h","i","j", + "k","l","m","n","o","p","q","r","s","t","u","v","w","x","y", + "z","braceleft","bar","braceright","asciitilde",false,false,false, + false,false,false,false,false,false,false,false,false,false,false, + false,false,false,false,false,false,false,false,false,false,false, + false,false,false,false,false,false,false,false,false,"exclamdown", + "cent","sterling","fraction","yen","florin","section","currency", + "quotesingle","quotedblleft","guillemotleft","guilsinglleft", + "guilsinglright","fi","fl",false,"endash","dagger","daggerdbl", + "periodcentered",false,"paragraph","bullet","quotesinglbase", + "quotedblbase","quotedblright","guillemotright","ellipsis","perthousand", + false,"questiondown",false,"grave","acute","circumflex","tilde", + "macron","breve","dotaccent","dieresis",false,"ring","cedilla",false, + "hungarumlaut","ogonek","caron","emdash",false,false,false,false, + false,false,false,false,false,false,false,false,false,false,false, + false,"AE",false,"ordfeminine",false,false,false,false,"Lslash", + "Oslash","OE","ordmasculine",false,false,false,false,false,"ae", + false,false,false,"dotlessi",false,false,"lslash","oslash","oe", + "germandbls",false,false,false,false +} local cffreaders={ readbyte, readushort, readuint, readulong, } +directives.register("fonts.streamreader",function() + cffreaders={ + readbyte, + readushort, + readuint, + readulong, + } +end) local function readheader(f) local offset=getposition(f) local major=readbyte(f) @@ -13930,6 +14542,7 @@ do local x=0 local y=0 local width=false + local lsb=0 local r=0 local stems=0 local globalbias=0 @@ -13953,6 +14566,9 @@ do local factors=false local axis=false local vsindex=0 + local justpass=false + local seacs={} + local procidx=nil local function showstate(where) report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) end @@ -14492,14 +15108,14 @@ do top=0 end local function divide() - if version==1 then + if version=="cff" then local d=stack[top] top=top-1 stack[top]=stack[top]/d end end local function closepath() - if version==1 then + if version=="cff" then if trace_charstrings then showstate("closepath") end @@ -14507,54 +15123,73 @@ do top=0 end local function hsbw() - if version==1 then + if version=="cff" then if trace_charstrings then showstate("hsbw") end + lsb=stack[top-1] or 0 width=stack[top] end top=0 end - local function seac() - if version==1 then + local function sbw() + if version=="cff" then if trace_charstrings then - showstate("seac") + showstate("sbw") end + lsb=stack[top-3] + width=stack[top-1] end top=0 end - local function sbw() - if version==1 then + local function seac() + if version=="cff" then if trace_charstrings then - showstate("sbw") + showstate("seac") end - width=stack[top-1] end top=0 end + local popped=3 + local hints=3 local function callothersubr() - if version==1 then + if version=="cff" then if trace_charstrings then - showstate("callothersubr (unsupported)") + showstate("callothersubr") + end + if stack[top]==hints then + popped=stack[top-2] + else + popped=3 + end + local t=stack[top-1] + if t then + top=top-(t+2) + if top<0 then + top=0 + end + else + top=0 end + else + top=0 end - top=0 end local function pop() - if version==1 then + if version=="cff" then if trace_charstrings then - showstate("pop (unsupported)") + showstate("pop") end top=top+1 - stack[top]=0 + stack[top]=popped else top=0 end end local function setcurrentpoint() - if version==1 then + if version=="cff" then if trace_charstrings then - showstate("pop (unsupported)") + showstate("setcurrentpoint (unsupported)") end x=x+stack[top-1] y=y+stack[top] @@ -14680,6 +15315,39 @@ do vhcurveto, hvcurveto, } + local reverse={ [0]="unsupported", + "getstem", + "unsupported", + "getstem", + "vmoveto", + "rlineto", + "hlineto", + "vlineto", + "rrcurveto", + "unsupported", + "unsupported", + "unsupported", + "unsupported", + "hsbw", + "unsupported", + "setvsindex", + "blend", + "unsupported", + "getstem", + "getmask", + "getmask", + "rmoveto", + "hmoveto", + "getstem", + "rcurveline", + "rlinecurve", + "vvcurveto", + "hhcurveto", + "unsupported", + "unsupported", + "vhcurveto", + "hvcurveto", + } local subactions={ [000]=dotsection, [001]=getstem3, @@ -14793,7 +15461,7 @@ do local function call(scope,list,bias) depth=depth+1 if top==0 then - showstate(formatters["unknown %s call"](scope)) + showstate(formatters["unknown %s call %s, case %s"](scope,"?",1)) top=0 else local index=stack[top]+bias @@ -14805,13 +15473,12 @@ do if tab then process(tab) else - showstate(formatters["unknown %s call %i"](scope,index)) + showstate(formatters["unknown %s call %s, case %s"](scope,index,2)) top=0 end end depth=depth-1 end - local justpass=false process=function(tab) local i=1 local n=#tab @@ -14875,13 +15542,24 @@ do i=i+1 local t=tab[i] if justpass then - if t>=34 or t<=37 then + if t>=34 and t<=37 then for i=1,top do r=r+1;result[r]=encode[stack[i]] end r=r+1;result[r]=chars[12] r=r+1;result[r]=chars[t] top=0 + elseif t==6 then + seacs[procidx]={ + asb=stack[1], + adx=stack[2], + ady=stack[3], + base=stack[4], + accent=stack[5], + width=width, + lsb=lsb, + } + top=0 else local a=subactions[t] if a then @@ -14911,44 +15589,52 @@ do i=i+s+1 elseif t==1 or t==3 or t==18 or operation==23 then p_getstem() -if true then - if top>0 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] + if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 end + r=r+1;result[r]=chars[t] + else top=0 end - r=r+1;result[r]=chars[t] -else - top=0 -end i=i+1 elseif t==19 or t==20 then local s=p_getmask() or 0 -if true then - if top>0 then - for i=1,top do - r=r+1;result[r]=encode[stack[i]] + if true then + if top>0 then + for i=1,top do + r=r+1;result[r]=encode[stack[i]] + end + top=0 + end + r=r+1;result[r]=chars[t] + for j=1,s do + i=i+1 + r=r+1;result[r]=chars[tab[i]] end + else + i=i+s top=0 end - r=r+1;result[r]=chars[t] - for j=1,s do - i=i+1 - r=r+1;result[r]=chars[tab[i]] - end -else - i=i+s - top=0 -end i=i+1 elseif t==9 then top=0 i=i+1 elseif t==13 then - local s=hsbw() or 0 - i=i+s+1 + hsbw() + if version=="cff" then + r=r+1;result[r]=encode[lsb] + r=r+1;result[r]=chars[22] + else + end + i=i+1 else + if trace_charstrings then + showstate(reverse[t] or "<action>") + end if top>0 then for i=1,top do r=r+1;result[r]=encode[stack[i]] @@ -14969,7 +15655,7 @@ end end else if trace_charstrings then - showvalue("<action>",t) + showstate(reverse[t] or "<action>") end top=0 i=i+1 @@ -14977,14 +15663,18 @@ end end end end - local function setbias(globals,locals) + local function setbias(globals,locals,nobias) + if nobias then + return 0,0 + else local g=#globals local l=#locals return ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 + end end - local function processshape(tab,index) + local function processshape(tab,index,hack) if not tab then glyphs[index]={ boundingbox={ 0,0,0,0 }, @@ -14997,10 +15687,13 @@ end x=0 y=0 width=false + lsb=0 r=0 top=0 stems=0 result={} + popped=3 + procidx=index xmin=0 xmax=0 ymin=0 @@ -15014,6 +15707,9 @@ end updateregions(vsindex) end process(tab) + if hack then + return x,y + end local boundingbox={ round(xmin), round(ymin), @@ -15068,6 +15764,8 @@ end axis=false regions=data.regions justpass=streams==true + popped=3 + seacs={} if regions then regions={ regions } axis=data.factors or false @@ -15081,6 +15779,8 @@ end locals=false globals=false strings=false + popped=3 + seacs={} end local function setwidths(private) if not private then @@ -15092,7 +15792,7 @@ end end return privatedata.nominalwidthx or 0,privatedata.defaultwidthx or 0 end - parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams) + parsecharstrings=function(fontdata,data,glphs,doshapes,tversion,streams,nobias) local dictionary=data.dictionaries[1] local charstrings=dictionary.charstrings keepcurve=doshapes @@ -15103,13 +15803,36 @@ end charset=dictionary.charset vsindex=dictionary.vsindex or 0 glyphs=glphs or {} - globalbias,localbias=setbias(globals,locals) + globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) if charstrings then startparsing(fontdata,data,streams) for index=1,#charstrings do processshape(charstrings[index],index-1) end + if justpass and next(seacs) then + local charset=data.dictionaries[1].charset + if charset then + local lookup=table.swapped(charset) + for index,v in next,seacs do + local bindex=lookup[standardnames[v.base]] + local aindex=lookup[standardnames[v.accent]] + local bglyph=bindex and glyphs[bindex] + local aglyph=aindex and glyphs[aindex] + if bglyph and aglyph then + local jp=justpass + justpass=false + local x,y=processshape(charstrings[bindex+1],bindex,true) + justpass=jp + local base=bglyph.stream + local accent=aglyph.stream + local moveto=encode[-x-v.asb+v.adx]..chars[22]..encode[-y+v.ady]..chars[ 4] + base=sub(base,1,#base-1) + glyphs[index].stream=base..moveto..accent + end + end + end + end stopparsing(fontdata,data) else report("no charstrings") @@ -15125,8 +15848,9 @@ end charset=false vsindex=dictionary.vsindex or 0 glyphs=glphs or {} - justpass=streams==true - globalbias,localbias=setbias(globals,locals) + justpass=streams==true + seacs={} + globalbias,localbias=setbias(globals,locals,nobias) nominalwidth,defaultwidth=setwidths(dictionary.private) processshape(tab,index-1) end @@ -15385,8 +16109,8 @@ function readers.cff(f,fontdata,specification) if private then local data=private.data if type(data)=="table" then - cffinfo.defaultwidth=data.defaultwidth or cffinfo.defaultwidth - cffinfo.nominalwidth=data.nominalwidth or cffinfo.nominalwidth + cffinfo.defaultwidth=data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth=data.nominalwidthx or cffinfo.nominalwidth cffinfo.bluevalues=data.bluevalues cffinfo.otherblues=data.otherblues cffinfo.familyblues=data.familyblues @@ -16097,7 +16821,14 @@ local function repackpoints(glyphs,shapes) currentx=px currenty=py if lastflag==fl then - nofflags=nofflags+1 + if nofflags==255 then + lastflag=lastflag+0x08 + r=r+1 result[r]=char(lastflag,nofflags-1) + nofflags=1 + lastflag=fl + else + nofflags=nofflags+1 + end else if nofflags==1 then r=r+1 result[r]=chars[lastflag] @@ -17875,6 +18606,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local sets=readarray(f) sets=readpairsets(f,tableoffset,sets,format1,format2,mainoffset,getdelta) coverage=readcoverage(f,tableoffset+coverage) + local shared={} for index,newindex in next,coverage do local set=sets[newindex+1] local hash={} @@ -17882,18 +18614,24 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local value=set[i] if value then local other=value[1] - local first=value[2] - local second=value[3] - if first or second then - hash[other]={ first,second or nil } - else - hash[other]=nil + local share=shared[value] + if share==nil then + local first=value[2] + local second=value[3] + if first or second then + share={ first,second or nil } + else + share=false + end + shared[value]=share end + hash[other]=share or nil end end coverage[index]=hash end return { + shared=shared and true or nil, format="pair", coverage=coverage, } @@ -17910,6 +18648,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly classdef1=readclassdef(f,tableoffset+classdef1,coverage) classdef2=readclassdef(f,tableoffset+classdef2,nofglyphs) local usedcoverage={} + local shared={} for g1,c1 in next,classdef1 do if coverage[g1] then local l1=classlist[c1] @@ -17921,8 +18660,17 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly local first=offsets[1] local second=offsets[2] if first or second then - hash[paired]={ first,second or nil } - else + local s1=shared[first] + if s1==nil then + s1={} + shared[first]=s1 + end + local s2=s1[second] + if s2==nil then + s2={ first,second or nil } + s1[second]=s2 + end + hash[paired]=s2 end end end @@ -17931,6 +18679,7 @@ function gposhandlers.pair(f,fontdata,lookupid,lookupoffset,offset,glyphs,nofgly end end return { + shared=shared and true or nil, format="pair", coverage=usedcoverage, } @@ -19255,6 +20004,8 @@ function readers.cpal(f,fontdata,specification) fontdata.colorpalettes=palettes end end +local compress=gzip and gzip.compress +local compressed=compress and gzip.compressed function readers.svg(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"svg",specification.glyphs) if tableoffset then @@ -19276,10 +20027,14 @@ function readers.svg(f,fontdata,specification) for i=1,nofentries do local entry=entries[i] setposition(f,entry.offset) + local data=readstring(f,entry.length) + if compressed and not compressed(data) then + data=compress(data) + end entries[i]={ first=entry.first, last=entry.last, - data=readstring(f,entry.length) + data=data } end fontdata.svgshapes=entries @@ -19316,6 +20071,7 @@ function readers.sbix(f,fontdata,specification) end end) local glyphs={} + local delayed=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 or fonts.handlers.typethree for i=1,nofstrikes do local strike=strikes[i] local strikeppem=strike.ppem @@ -19332,13 +20088,25 @@ function readers.sbix(f,fontdata,specification) local datasize=nextoffset-glyphoffset if datasize>0 then setposition(f,strikeoffset+glyphoffset) + local x=readshort(f) + local y=readshort(f) + local tag=readtag(f) + local size=datasize-8 + local data=nil + local offset=nil + if delayed then + offset=getposition(f) + data=nil + else + data=readstring(f,size) + size=nil + end shapes[i]={ - x=readshort(f), - y=readshort(f), - tag=readtag(f), - data=readstring(f,datasize-8), - ppem=strikeppem, - ppi=strikeppi, + x=x, + y=y, + o=offset, + s=size, + data=data, } done=done+1 if done==nofglyphs then @@ -19517,29 +20285,46 @@ do end local default={ width=0,height=0 } local glyphs=fontdata.glyphs + local delayed=CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 or fonts.handlers.typethree for index,subtable in sortedhash(shapes) do if type(subtable)=="table" then local data=nil + local size=nil local metrics=default local format=subtable.format local offset=subtable.offsets[index] setposition(f,offset) if format==17 then metrics=getsmallmetrics(f) - data=readstring(f,readulong(f)) + size=true elseif format==18 then metrics=getbigmetrics(f) - data=readstring(f,readulong(f)) + size=true elseif format==19 then metrics=subtable.metrics - data=readstring(f,readulong(f)) + size=true + else + end + if size then + size=readulong(f) + if delayed then + offset=getposition(f) + data=nil + else + offset=nil + data=readstring(f,size) + size=nil + end else + offset=nil end local x=metrics.width local y=metrics.height shapes[index]={ x=x, y=y, + o=offset, + s=size, data=data, } local glyph=glyphs[index] @@ -20541,6 +21326,9 @@ local function checklookups(fontdata,missing,nofmissing) end end end +local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000 +local puafirst=0xE000 +local pualast=0xF8FF local function unifymissing(fontdata) if not fonts.mappings then require("font-map") @@ -20551,18 +21339,19 @@ local function unifymissing(fontdata) resources.unicodes=unicodes for unicode,d in next,fontdata.descriptions do if unicode<privateoffset then - local name=d.name - if name then - unicodes[name]=unicode + if unicode>=puafirst and unicode<=pualast then + else + local name=d.name + if name then + unicodes[name]=unicode + end end + else end end fonts.mappings.addtounicode(fontdata,fontdata.filename,checklookups) resources.unicodes=nil end -local firstprivate=fonts.privateoffsets and fonts.privateoffsets.textbase or 0xF0000 -local puafirst=0xE000 -local pualast=0xF8FF local function unifyglyphs(fontdata,usenames) local private=fontdata.private or privateoffset local glyphs=fontdata.glyphs @@ -21222,16 +22011,30 @@ function readers.pack(data) if kind=="gpos_pair" then local c=step.coverage if c then - if step.format=="pair" then + if step.format~="pair" then + for g1,d1 in next,c do + c[g1]=pack_normal(d1) + end + elseif step.shared then + local shared={} for g1,d1 in next,c do for g2,d2 in next,d1 do - local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end - local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end + if not shared[d2] then + local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end + local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end + shared[d2]=true + end end end + if pass==2 then + step.shared=nil + end else for g1,d1 in next,c do - c[g1]=pack_normal(d1) + for g2,d2 in next,d1 do + local f=d2[1] if f and f~=true then d2[1]=pack_indexed(f) end + local s=d2[2] if s and s~=true then d2[2]=pack_indexed(s) end + end end end end @@ -22517,11 +23320,12 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_d local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.107 +otf.version=3.111 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.pngcache=containers.define("fonts","png",otf.version,true) otf.pdfcache=containers.define("fonts","pdf",otf.version,true) +otf.mpscache=containers.define("fonts","mps",otf.version,true) otf.svgenabled=false otf.pngenabled=false local otfreaders=otf.readers @@ -22879,6 +23683,7 @@ local function copytotfm(data,cache_id) parameters.ascender=abs(metadata.ascender or 0) parameters.descender=abs(metadata.descender or 0) parameters.units=units + parameters.vheight=metadata.defaultvheight properties.space=spacer properties.encodingbytes=2 properties.format=data.format or formats.otf @@ -23205,7 +24010,7 @@ if not modules then modules={} end modules ['font-oto']={ local concat,unpack=table.concat,table.unpack local insert,remove=table.insert,table.remove local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring,rawget=type,next,tonumber,tostring,rawget +local type,next,tonumber,tostring=type,next,tonumber,tostring local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end) local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end) local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) @@ -23703,7 +24508,7 @@ local getboth=nuts.getboth local getdisc=nuts.getdisc local setdisc=nuts.setdisc local setoffsets=nuts.setoffsets -local ischar=nuts.is_char +local ischar=nuts.ischar local getkern=nuts.getkern local setkern=nuts.setkern local setlink=nuts.setlink @@ -25134,7 +25939,7 @@ local getprop=nuts.getprop local setprop=nuts.setprop local getsubtype=nuts.getsubtype local getchar=nuts.getchar -local ischar=nuts.is_char +local ischar=nuts.ischar local end_of_math=nuts.end_of_math local nodecodes=nodes.nodecodes local disc_code=nodecodes.disc @@ -25543,7 +26348,6 @@ registertracker("otf.actions","otf.substitutions","otf.positions") registertracker("otf.sample","otf.steps","otf.substitutions","otf.positions","otf.analyzing") registertracker("otf.sample.silent","otf.steps=silent","otf.substitutions","otf.positions","otf.analyzing") local nuts=nodes.nuts -local getfield=nuts.getfield local getnext=nuts.getnext local setnext=nuts.setnext local getprev=nuts.getprev @@ -25551,8 +26355,6 @@ local setprev=nuts.setprev local getboth=nuts.getboth local setboth=nuts.setboth local getid=nuts.getid -local getattr=nuts.getattr -local setattr=nuts.setattr local getprop=nuts.getprop local setprop=nuts.setprop local getsubtype=nuts.getsubtype @@ -25561,11 +26363,14 @@ local getchar=nuts.getchar local setchar=nuts.setchar local getdisc=nuts.getdisc local setdisc=nuts.setdisc +local getreplace=nuts.getreplace local setlink=nuts.setlink local getcomponents=nuts.getcomponents local setcomponents=nuts.setcomponents local getwidth=nuts.getwidth -local ischar=nuts.is_char +local getattr=nuts.getattr +local getglyphdata=nuts.getglyphdata +local ischar=nuts.ischar local isglyph=nuts.isglyph local usesfont=nuts.uses_font local insert_node_after=nuts.insert_after @@ -25576,6 +26381,7 @@ local find_node_tail=nuts.tail local flush_node_list=nuts.flush_list local flush_node=nuts.flush_node local end_of_math=nuts.end_of_math +local start_of_par=nuts.start_of_par local setmetatable=setmetatable local setmetatableindex=table.setmetatableindex local nextnode=nuts.traversers.node @@ -27137,7 +27943,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) if keepdisc then keepdisc=false lookaheaddisc=current - local replace=getfield(current,"replace") + local replace=getreplace(current) if not replace then sweepoverflow=true sweepnode=current @@ -27209,7 +28015,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) if notmatchpre[current]~=notmatchreplace[current] then lookaheaddisc=current end - local replace=getfield(current,"replace") + local replace=getreplace(current) while replace and i<s do if getid(replace)==glyph_code then i=i+1 @@ -27253,7 +28059,7 @@ local function chaindisk(head,start,dataset,sequence,rlmode,skiphash,ck) if notmatchpost[current]~=notmatchreplace[current] then backtrackdisc=current end - local replace=getfield(current,"replace") + local replace=getreplace(current) while replace and i>1 do if getid(replace)==glyph_code then i=i-1 @@ -28057,7 +28863,7 @@ local function testrun(disc,t_run,c_run,...) end local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true) local renewed=false - if (post or replace) and prev then + if (post or replace) then if post then setlink(posttail,next) else @@ -28168,7 +28974,7 @@ local function c_run_single(head,font,attr,lookupcache,step,dataset,sequence,rlm if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then local lookupmatch=lookupcache[char] @@ -28202,7 +29008,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end local startnext=getnext(start) if not a or (a==attr) then @@ -28217,7 +29023,7 @@ local function t_run_single(start,stop,font,attr,lookupcache) end while getid(s)==disc_code do ss=getnext(s) - s=getfield(s,"replace") + s=getreplace(s) if not s then s=ss ss=nil @@ -28244,12 +29050,13 @@ local function t_run_single(start,stop,font,attr,lookupcache) end while getid(s)==disc_code do ss=getnext(s) - s=getfield(s,"replace") + s=getreplace(s) if not s then s=ss ss=nil end end +lookupmatch=lg else break end @@ -28277,7 +29084,7 @@ end local function k_run_single(sub,injection,last,font,attr,lookupcache,step,dataset,sequence,rlmode,skiphash,handler) local a if attr then - a=getattr(sub,0) + a=getglyphdata(sub) end if not a or (a==attr) then for n in nextnode,sub do @@ -28311,7 +29118,7 @@ local function c_run_multiple(head,font,attr,steps,nofsteps,dataset,sequence,rlm if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then for i=1,nofsteps do @@ -28352,7 +29159,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) if char then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end local startnext=getnext(start) if not a or (a==attr) then @@ -28370,7 +29177,7 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) end while getid(s)==disc_code do ss=getnext(s) - s=getfield(s,"replace") + s=getreplace(s) if not s then s=ss ss=nil @@ -28397,12 +29204,13 @@ local function t_run_multiple(start,stop,font,attr,steps,nofsteps) end while getid(s)==disc_code do ss=getnext(s) - s=getfield(s,"replace") + s=getreplace(s) if not s then s=ss ss=nil end end +lookupmatch=lg else break end @@ -28430,7 +29238,7 @@ end local function k_run_multiple(sub,injection,last,font,attr,steps,nofsteps,dataset,sequence,rlmode,skiphash,handler) local a if attr then - a=getattr(sub,0) + a=getglyphdata(sub) end if not a or (a==attr) then for n in nextnode,sub do @@ -28544,7 +29352,7 @@ do checkstep(head) end local initialrl=0 - if getid(head)==localpar_code and getsubtype(head)==0 then + if getid(head)==localpar_code and start_of_par(head) then initialrl=pardirstate(head) elseif direction==1 or direction=="TRT" then initialrl=-1 @@ -28581,7 +29389,7 @@ do if m then local a if attr then - a=getattr(start,0) + a=getglyphdata(start) end if not a or (a==attr) then for i=m[1],m[2] do @@ -28625,7 +29433,7 @@ do if lookupmatch then local a if attr then - if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + if getglyphdata(start)==attr and (not attribute or getprop(start,a_state)==attribute) then a=true end elseif not attribute or getprop(start,a_state)==attribute then @@ -28681,7 +29489,7 @@ do if m then local a if attr then - if getattr(start,0)==attr and (not attribute or getprop(start,a_state)==attribute) then + if getglyphdata(start)==attr and (not attribute or getprop(start,a_state)==attribute) then a=true end elseif not attribute or getprop(start,a_state)==attribute then @@ -28876,19 +29684,27 @@ registerotffeature { plug=otf.pluginprocessor, } } +local function markinitializer(tfmdata,value) + local properties=tfmdata.properties + properties.checkmarks=value +end +registerotffeature { + name="checkmarks", + description="check mark widths", + default=true, + initializers={ + node=markinitializer, + }, +} otf.handlers=handlers +if context then + +--removed + +else +end local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.exit() end -local tag="kern" -if fontfeatures then - function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr) - local features=fontfeatures[font] - local enabled=features and features.spacekern and features[tag] - if enabled then - setspacekerns(font,sequence) - end - return head,enabled - end -else +local tag="kern" function handlers.trigger_space_kerns(head,dataset,sequence,initialrl,font,attr) local shared=fontdata[font].shared local features=shared and shared.features @@ -28898,7 +29714,6 @@ else end return head,enabled end -end local function hasspacekerns(data) local resources=data.resources local sequences=resources.sequences @@ -29083,18 +29898,6 @@ registerotffeature { node=spaceinitializer, }, } -local function markinitializer(tfmdata,value) - local properties=tfmdata.properties - properties.checkmarks=value -end -registerotffeature { - name="checkmarks", - description="check mark widths", - default=true, - initializers={ - node=markinitializer, - }, -} end -- closure @@ -29107,7 +29910,7 @@ if not modules then modules={} end modules ['font-osd']={ copyright="TAT Zetwerk / PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local insert,imerge,copy=table.insert,table.imerge,table.copy +local insert,imerge,copy,tohash=table.insert,table.imerge,table.copy,table.tohash local next,type=next,type local report=logs.reporter("otf","devanagari") fonts=fonts or {} @@ -29132,7 +29935,7 @@ local setprev=nuts.setprev local setchar=nuts.setchar local getprop=nuts.getprop local setprop=nuts.setprop -local ischar=nuts.is_char +local ischar=nuts.ischar local insert_node_after=nuts.insert_after local copy_node=nuts.copy local remove_node=nuts.remove @@ -29153,6 +29956,7 @@ local s_half=states.half local s_pref=states.pref local s_blwf=states.blwf local s_pstf=states.pstf +local s_init=states.init local replace_all_nbsp=nil replace_all_nbsp=function(head) replace_all_nbsp=typesetters and typesetters.characters and typesetters.characters.replacenbspaces or function(head) @@ -29298,15 +30102,10 @@ local zw_char={ [c_zwj ]=true, } local dflt_true={ - dflt=true -} -local two_defaults={ - dev2=dflt_true, -} -local one_defaults={ - dev2=dflt_true, - deva=dflt_true, + dflt=true, } +local two_defaults={} +local one_defaults={} local false_flags={ false,false,false,false } local sequence_reorder_matras={ features={ dv01=two_defaults }, @@ -29335,7 +30134,7 @@ local sequence_reorder_reph={ } } local sequence_reorder_pre_base_reordering_consonants={ - features={ dv03=two_defaults }, + features={ dv03=one_defaults }, flags=false_flags, name="dv03_reorder_pre_base_reordering_consonants", order={ "dv03" }, @@ -29371,6 +30170,7 @@ local basic_shaping_forms={ rkrf=true, rphf=true, vatu=true, + locl=true, } local valid={ abvs=true, @@ -29394,6 +30194,7 @@ local valid={ psts=true, haln=true, calt=true, + locl=true, } local scripts={} local scripts_one={ "deva","mlym","beng","gujr","guru","knda","orya","taml","telu" } @@ -29404,7 +30205,7 @@ for i=1,nofscripts do local two=scripts_two[i] scripts[one]=true scripts[two]=true - two_defaults[one]=dflt_true + two_defaults[two]=dflt_true one_defaults[one]=dflt_true one_defaults[two]=dflt_true end @@ -29420,31 +30221,79 @@ local function initializedevanagi(tfmdata) local gsubfeatures=resources.features.gsub local sequences=resources.sequences local sharedfeatures=tfmdata.shared.features + gsubfeatures["dv01"]=two_defaults + gsubfeatures["dv02"]=two_defaults + gsubfeatures["dv03"]=one_defaults + gsubfeatures["dv04"]=one_defaults + local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants) + local reorder_reph=copy(sequence_reorder_reph) + local reorder_matras=copy(sequence_reorder_matras) + local remove_joiners=copy(sequence_remove_joiners) local lastmatch=0 for s=1,#sequences do local features=sequences[s].features if features then for k,v in next,features do + if k=="locl" then + local steps=sequences[s].steps + local nofsteps=sequences[s].nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + for k,v in next,pre_mark do + local locl=coverage[k] + if locl then + if #locl>0 then + for j=1,#locl do + local ck=locl[j] + local f=ck[4] + local chainlookups=ck[6] + if chainlookups then + local chainlookup=chainlookups[f] + for j=1,#chainlookup do + local chainstep=chainlookup[j] + local steps=chainstep.steps + local nofsteps=chainstep.nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + locl=coverage[k] + end + end + end + end + end + end + if locl then + reorder_matras.steps[1].coverage[locl]=true + end + end + end + end + end + end if basic_shaping_forms[k] then - lastmatch=s + lastmatch=lastmatch+1 + if s~=lastmatch then + table.insert(sequences,lastmatch,table.remove(sequences,s)) + end end end end end local insertindex=lastmatch+1 - gsubfeatures["dv01"]=two_defaults - gsubfeatures["dv02"]=two_defaults - gsubfeatures["dv03"]=two_defaults - gsubfeatures["dv04"]=one_defaults - local reorder_pre_base_reordering_consonants=copy(sequence_reorder_pre_base_reordering_consonants) - local reorder_reph=copy(sequence_reorder_reph) - local reorder_matras=copy(sequence_reorder_matras) - local remove_joiners=copy(sequence_remove_joiners) + if tfmdata.properties.language then + dflt_true[tfmdata.properties.language]=true + end insert(sequences,insertindex,reorder_pre_base_reordering_consonants) insert(sequences,insertindex,reorder_reph) insert(sequences,insertindex,reorder_matras) insert(sequences,insertindex,remove_joiners) local blwfcache={} + local vatucache={} + local pstfcache={} local seqsubset={} local rephstep={ coverage={} @@ -29453,6 +30302,8 @@ local function initializedevanagi(tfmdata) reph=false, vattu=false, blwfcache=blwfcache, + vatucache=vatucache, + pstfcache=pstfcache, seqsubset=seqsubset, reorderreph=rephstep, } @@ -29467,17 +30318,89 @@ local function initializedevanagi(tfmdata) local features=sequence.features local has_rphf=features.rphf local has_blwf=features.blwf - if has_rphf and has_rphf.deva then + local has_vatu=features.vatu + local has_pstf=features.pstf + if has_rphf and has_rphf[script] then devanagari.reph=true - elseif has_blwf and has_blwf.deva then + elseif (has_blwf and has_blwf[script] ) or (has_vatu and has_vatu[script] ) then devanagari.vattu=true for i=1,nofsteps do local step=steps[i] local coverage=step.coverage if coverage then for k,v in next,coverage do - if not blwfcache[k] then - blwfcache[k]=v + for h,w in next,halant do + if v[h] then + if not blwfcache[k] then + blwfcache[k]=v + end + end + if has_vatu and has_vatu[script] and not vatucache[k] then + vatucache[k]=v + end + end + end + end + end + elseif has_pstf and has_pstf[script] then + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + for k,v in next,coverage do + if not pstfcache[k] then + pstfcache[k]=v + end + end + for k,v in next,ra do + local r=coverage[k] + if r then + local found=false + if #r>0 then + for j=1,#r do + local ck=r[j] + local f=ck[4] + local chainlookups=ck[6] + if chainlookups and chainlookups[f] then + local chainlookup=chainlookups[f] + for j=1,#chainlookup do + local chainstep=chainlookup[j] + local steps=chainstep.steps + local nofsteps=chainstep.nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + local h=coverage[k] + if h then + for k,v in next,h do + found=v and v.ligature + if found then + pre_base_reordering_consonants[found]=true + break + end + end + if found then + break + end + end + end + end + end + end + end + else + for k,v in next,r do + found=v and v.ligature + if found then + pre_base_reordering_consonants[found]=true + break + end + end + end + if found then + break + end end end end @@ -29489,17 +30412,53 @@ local function initializedevanagi(tfmdata) local step=steps[i] local coverage=step.coverage if coverage then - local reph=false + local reph,rephbase=false,false if kind=="rphf" then for k,v in next,ra do local r=coverage[k] if r then + rephbase=k local h=false - for k,v in next,halant do - local h=r[k] - if h then - reph=h.ligature or false - break + if #r>0 then + for j=1,#r do + local ck=r[j] + local f=ck[4] + local chainlookups=ck[6] + if chainlookups then + local chainlookup=chainlookups[f] + for j=1,#chainlookup do + local chainstep=chainlookup[j] + local steps=chainstep.steps + local nofsteps=chainstep.nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + local r=coverage[k] + if r then + for k,v in next,halant do + local h=r[k] + if h then + reph=h.ligature or false + break + end + end + if h then + break + end + end + end + end + end + end + end + else + for k,v in next,halant do + local h=r[k] + if h then + reph=h.ligature or false + break + end end end if reph then @@ -29508,7 +30467,7 @@ local function initializedevanagi(tfmdata) end end end - seqsubset[#seqsubset+1]={ kind,coverage,reph } + seqsubset[#seqsubset+1]={ kind,coverage,reph,rephbase } end end end @@ -29523,11 +30482,46 @@ local function initializedevanagi(tfmdata) local h=coverage[k] if h then local found=false - for k,v in next,h do - found=v and v.ligature - if found then - pre_base_reordering_consonants[k]=found - break + if #h>0 then + for j=1,#h do + local ck=h[j] + local f=ck[4] + local chainlookups=ck[6] + if chainlookups then + local chainlookup=chainlookups[f] + for j=1,#chainlookup do + local chainstep=chainlookup[j] + local steps=chainstep.steps + local nofsteps=chainstep.nofsteps + for i=1,nofsteps do + local step=steps[i] + local coverage=step.coverage + if coverage then + local h=coverage[k] + if h then + for k,v in next,h do + found=v and v.ligature + if found then + pre_base_reordering_consonants[found]=true + break + end + end + if found then + break + end + end + end + end + end + end + end + else + for k,v in next,h do + found=v and v.ligature + if found then + pre_base_reordering_consonants[found]=true + break + end end end if found then @@ -29540,27 +30534,17 @@ local function initializedevanagi(tfmdata) end end end - if script=="deva" then - sharedfeatures["dv04"]=true - elseif script=="dev2" then + if two_defaults[script] then sharedfeatures["dv01"]=true sharedfeatures["dv02"]=true sharedfeatures["dv03"]=true sharedfeatures["dv04"]=true - elseif script=="mlym" then - sharedfeatures["pstf"]=true - elseif script=="mlm2" then - sharedfeatures["pstf"]=true - sharedfeatures["pref"]=true + elseif one_defaults[script] then sharedfeatures["dv03"]=true - gsubfeatures ["dv03"]=two_defaults - insert(sequences,insertindex,sequence_reorder_pre_base_reordering_consonants) - elseif script=="taml" then sharedfeatures["dv04"]=true -sharedfeatures["pstf"]=true - elseif script=="tml2" then - else - report("todo: enable the right features for script %a",script) + end + if script=="mlym" or script=="taml" then + devanagari.left_matra_before_base=true end end end @@ -29593,6 +30577,8 @@ local function initialize_one(font,attr) reph=false, vattu=false, blwfcache={}, + vatucache={}, + pstfcache={}, } datasets.devanagari=devanagaridata local resources=tfmdata.resources @@ -29603,17 +30589,80 @@ local function initialize_one(font,attr) local kind=dataset[4] if kind=="rphf" then devanagaridata.reph=true - elseif kind=="blwf" then + elseif kind=="blwf" or kind=="vatu" then devanagaridata.vattu=true devanagaridata.blwfcache=devanagari.blwfcache + devanagaridata.vatucache=devanagari.vatucache + devanagaridata.pstfcache=devanagari.pstfcache + end + end + end + end + return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache,devanagaridata.vatucache,devanagaridata.pstfcache +end +local function contextchain(contexts,n) + local char=getchar(n) + for k=1,#contexts do + local ck=contexts[k] + local seq=ck[3] + local f=ck[4] + local l=ck[5] + if (l-f)==1 and seq[f+1][char] then + local ok=true + local c=n + for i=l+1,#seq do + c=getnext(c) + if not c or not seq[i][ischar(c)] then + ok=false + break + end + end + if ok then + c=getprev(n) + for i=1,f-1 do + c=getprev(c) + if not c or not seq[f-i][ischar(c)] then + ok=false + end + end + end + if ok then + return true + end + end + end + return false +end +local function order_matras(c) + local cn=getnext(c) + local char=getchar(cn) + while dependent_vowel[char] do + local next=getnext(cn) + local cc=c + local cchar=getchar(cc) + while cc~=cn do + if (above_mark[char] and (below_mark[cchar] or post_mark[cchar])) or (below_mark[char] and (post_mark[cchar])) then + local prev,next=getboth(cn) + if next then + setprev(next,prev) end + setnext(prev,next) + setnext(getprev(cc),cn) + setprev(cn,getprev(cc)) + setnext(cn,cc) + setprev(cc,cn) + break end + cc=getnext(cc) + cchar=getchar(cc) end + cn=next + char=getchar(cn) end - return devanagaridata.reph,devanagaridata.vattu,devanagaridata.blwfcache end local function reorder_one(head,start,stop,font,attr,nbspaces) - local reph,vattu,blwfcache=initialize_one(font,attr) + local reph,vattu,blwfcache,vatucache,pstfcache=initialize_one(font,attr) + local devanagari=fontdata[font].resources.devanagari local current=start local n=getnext(start) local base=nil @@ -29696,6 +30745,8 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) base=current elseif blwfcache[char] then setprop(current,a_state,s_blwf) + elseif pstfcache[char] then + setprop(current,a_state,s_pstf) else base=current end @@ -29764,7 +30815,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) end current=next end - if base~=stop and getprop(base,a_state) then + if base~=stop and getprop(base,a_state) then local next=getnext(base) if halant[getchar(next)] and not (next~=stop and getchar(getnext(next))==c_zwj) then setprop(base,a_state,unsetvalue) @@ -29792,6 +30843,16 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) n=getnext(n) ch=getchar(n) end + local tpm=twopart_mark[ch] + while tpm do + local extra=copy_node(n) + copyinjection(extra,n) + ch=tpm[1] + setchar(n,ch) + setchar(extra,tpm[2]) + head=insert_node_after(head,current,extra) + tpm=twopart_mark[ch] + end while c~=stop and dependent_vowel[ch] do c=n n=getnext(n) @@ -29815,9 +30876,44 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) local last=getnext(c) while cn~=last do if pre_mark[getchar(cn)] then - if bp then - setnext(bp,cn) + if devanagari.left_matra_before_base then + local prev,next=getboth(cn) + setlink(prev,next) + if cn==stop then + stop=getprev(cn) + end + if base==start then + if head==start then + head=cn + end + start=cn + end + setlink(getprev(base),cn) + setlink(cn,base) + cn=next + else + if bp then + setnext(bp,cn) + end + local prev,next=getboth(cn) + if next then + setprev(next,prev) + end + setnext(prev,next) + if cn==stop then + stop=prev + end + setprev(cn,bp) + setlink(cn,firstcons) + if firstcons==start then + if head==start then + head=cn + end + start=cn + end + cn=next end + elseif current~=base and dependent_vowel[getchar(cn)] then local prev,next=getboth(cn) if next then setprev(next,prev) @@ -29826,17 +30922,19 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) if cn==stop then stop=prev end - setprev(cn,bp) - setlink(cn,firstcons) - if firstcons==start then - if head==start then - head=cn - end - start=cn + setlink(b,cn,getnext(b)) + order_matras(cn) + cn=next + elseif current==base and dependent_vowel[getchar(cn)] then + local cnn=getnext(cn) + order_matras(cn) + cn=cnn + while cn~=last and dependent_vowel[getchar(cn)] do + cn=getnext(cn) end - break + else + cn=getnext(cn) end - cn=getnext(cn) end allreordered=c==stop current=getnext(c) @@ -29878,7 +30976,7 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) local cp=getprev(current) local cnsn=getnext(cns) setlink(cp,n) - setlink(cns,current) + setlink(cns,current) setlink(c,cnsn) if c==stop then stop=cp @@ -29894,6 +30992,13 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) if halant[getchar(next)] then cns=next end + if not vatucache[char] then + next=getnext(cns) + while dependent_vowel[getchar(next)] do + cns=next + next=getnext(cns) + end + end elseif char==c_nbsp then nbspaces=nbspaces+1 cns=current @@ -29901,6 +31006,13 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) if halant[getchar(next)] then cns=next end + if not vatucache[char] then + next=getnext(cns) + while dependent_vowel[getchar(next)] do + cns=next + next=getnext(cns) + end + end end end current=getnext(current) @@ -29908,6 +31020,9 @@ local function reorder_one(head,start,stop,font,attr,nbspaces) end if getchar(base)==c_nbsp then nbspaces=nbspaces-1 + if base==stop then + stop=getprev(stop) + end head=remove_node(head,base) flush_node(base) end @@ -29921,7 +31036,7 @@ function handlers.devanagari_reorder_matras(head,start) local char=ischar(current,startfont) local next=getnext(current) if char and getprop(current,a_syllabe)==startattr then - if halant[char] and not getprop(current,a_state) then + if halant[char] then if next then local char=ischar(next,startfont) if char and zw_char[char] and getprop(next,a_syllabe)==startattr then @@ -29943,6 +31058,7 @@ function handlers.devanagari_reorder_matras(head,start) end return head,start,true end +local rephbase={} function handlers.devanagari_reorder_reph(head,start) local current=getnext(start) local startnext=nil @@ -29950,44 +31066,29 @@ function handlers.devanagari_reorder_reph(head,start) local startfont=getfont(start) local startattr=getprop(start,a_syllabe) ::step_1:: - ::step_2:: - while current do - local char=ischar(current,startfont) - if char and getprop(current,a_syllabe)==startattr then - if halant[char] and not getprop(current,a_state) then - local next=getnext(current) - if next then - local nextchar=ischar(next,startfont) - if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then - current=next - next=getnext(current) - end - end - startnext=getnext(start) - head=remove_node(head,start) - setlink(start,next) - setlink(current,start) - start=startnext - startattr=getprop(start,a_syllabe) - break - end - current=getnext(current) - else - break - end + local char=ischar(start,startfont) + local rephbase=rephbase[startfont][char] + if char and after_subscript[rephbase] then + goto step_5 end - ::step_3:: - ::step_4:: - if not startnext then - current=getnext(start) + ::step_2:: + if char and not after_postscript[rephbase] then while current do local char=ischar(current,startfont) if char and getprop(current,a_syllabe)==startattr then - if getprop(current,a_state)==s_pstf then + if halant[char] then + local next=getnext(current) + if next then + local nextchar=ischar(next,startfont) + if nextchar and zw_char[nextchar] and getprop(next,a_syllabe)==startattr then + current=next + next=getnext(current) + end + end startnext=getnext(start) head=remove_node(head,start) - setlink(getprev(current),start) - setlink(start,current) + setlink(start,next) + setlink(current,start) start=startnext startattr=getprop(start,a_syllabe) break @@ -29998,6 +31099,63 @@ function handlers.devanagari_reorder_reph(head,start) end end end + ::step_3:: + if not startnext then + if char and after_main[rephbase] then + current=getnext(start) + while current do + local char=ischar(current,startfont) + if char and getprop(current,a_syllabe)==startattr then + if consonant[char] and not getprop(current,a_state)==s_pref then + startnext=getnext(start) + head=remove_node(head,start) + setlink(current,start) + setlink(start,getnext(current)) + start=startnext + startattr=getprop(start,a_syllabe) + break + end + current=getnext(current) + else + break + end + end + end + end + ::step_4:: + if not startnext then + if char and before_postscript[rephbase] then + current=getnext(start) + local c=nil + while current do + local char=ischar(current,startfont) + if char and getprop(current,a_syllabe)==startattr then + if getprop(current,a_state)==s_pstf then + startnext=getnext(start) + head=remove_node(head,start) + setlink(getprev(current),start) + setlink(start,current) + start=startnext + startattr=getprop(start,a_syllabe) + break + elseif not c and (vowel_modifier[char] or stress_tone_mark[char] ) then + c=current + end + current=getnext(current) + else + if c then + startnext=getnext(start) + head=remove_node(head,start) + setlink(getprev(c),start) + setlink(start,c) + start=startnext + startattr=getprop(start,a_syllabe) + end + break + end + end + end + end ::step_5:: if not startnext then current=getnext(start) @@ -30005,7 +31163,10 @@ function handlers.devanagari_reorder_reph(head,start) while current do local char=ischar(current,startfont) if char and getprop(current,a_syllabe)==startattr then - if not c and mark_above_below_post[char] and not after_subscript[char] then + local state=getprop(current,a_state) + if before_subscript[rephbase] and (state==s_blwf or state==s_pstf) then + c=current + elseif after_subscript[rephbase] and (state==s_pstf) then c=current end current=getnext(current) @@ -30045,63 +31206,64 @@ function handlers.devanagari_reorder_reph(head,start) end return head,start,true end +local reordered_pre_base_reordering_consonants={} function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) - local current=start - local startnext=nil - local startprev=nil + if reordered_pre_base_reordering_consonants[start] then + return head,start,true + end + local current=start local startfont=getfont(start) local startattr=getprop(start,a_syllabe) while current do local char=ischar(current,startfont) + local next=getnext(current) if char and getprop(current,a_syllabe)==startattr then - local next=getnext(current) - if halant[char] and not getprop(current,a_state) then + if halant[char] then if next then - local nextchar=ischar(next,startfont) - if nextchar and getprop(next,a_syllabe)==startattr then - if nextchar==c_zwnj or nextchar==c_zwj then - current=next - next=getnext(current) - end + local char=ischar(next,startfont) + if char and zw_char[char] and getprop(next,a_syllabe)==startattr then + current=next + next=getnext(current) end end - startnext=getnext(start) - removenode(start,start) + local startnext=getnext(start) + head=remove_node(head,start) setlink(start,next) setlink(current,start) + reordered_pre_base_reordering_consonants[start]=true start=startnext - break + return head,start,true end - current=next else break end + current=next end - if not startnext then - current=getnext(start) - startattr=getprop(start,a_syllabe) - while current do - local char=ischar(current,startfont) - if char and getprop(current,a_syllabe)==startattr then - if not consonant[char] and getprop(current,a_state) then - startnext=getnext(start) - removenode(start,start) - setlink(getprev(current),start) - setlink(start,current) - start=startnext - break - end - current=getnext(current) + local startattr=getprop(start,a_syllabe) + local current=getprev(start) + while current and getprop(current,a_syllabe)==startattr do + local char=ischar(current) + if (not dependent_vowel[char] and not getprop(current,a_state) or getprop(current,a_state)==s_init) then + startnext=getnext(start) + head=remove_node(head,start) + if current==head then + setlink(start,current) + head=start else - break + setlink(getprev(current),start) + setlink(start,current) end + reordered_pre_base_reordering_consonants[start]=true + start=startnext + break end + current=getprev(current) end return head,start,true end function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) local stop=getnext(start) - local font=getfont(start) + local font=getfont(start) local last=start while stop do local char=ischar(stop,font) @@ -30135,28 +31297,28 @@ local function initialize_two(font,attr) end local function reorder_two(head,start,stop,font,attr,nbspaces) local seqsubset,reorderreph=initialize_two(font,attr) - local reph=false local halfpos=nil local basepos=nil local subpos=nil local postpos=nil - local locl={} + reorderreph.coverage={} + rephbase[font]={} for i=1,#seqsubset do local subset=seqsubset[i] local kind=subset[1] local lookupcache=subset[2] if kind=="rphf" then - reph=subset[3] + reorderreph.coverage[subset[3]]=true + rephbase[font][subset[3]]=subset[4] local current=start local last=getnext(stop) while current~=last do if current~=stop then - local c=locl[current] or getchar(current) + local c=getchar(current) local found=lookupcache[c] if found then local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then + if found[getchar(next)] or contextchain(found,next) then local afternext=next~=stop and getnext(next) if afternext and zw_char[getchar(afternext)] then current=afternext @@ -30176,15 +31338,16 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local last=getnext(stop) while current~=last do if current~=stop then - local c=locl[current] or getchar(current) + local c=getchar(current) local found=lookupcache[c] if found then local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_pref) - setprop(next,a_state,s_pref) - current=next + if found[getchar(next)] or contextchain(found,next) then + if (not getprop(current,a_state) and not getprop(next,a_state)) then + setprop(current,a_state,s_pref) + setprop(next,a_state,s_pref) + current=next + end end end end @@ -30195,15 +31358,14 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local last=getnext(stop) while current~=last do if current~=stop then - local c=locl[current] or getchar(current) + local c=getchar(current) local found=lookupcache[c] if found then local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then + if found[getchar(next)] or contextchain(found,next) then if next~=stop and getchar(getnext(next))==c_zwnj then current=next - else + elseif (not getprop(current,a_state)) then setprop(current,a_state,s_half) if not halfpos then halfpos=current @@ -30215,21 +31377,22 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end current=getnext(current) end - elseif kind=="blwf" then + elseif kind=="blwf" or kind=="vatu" then local current=start local last=getnext(stop) while current~=last do if current~=stop then - local c=locl[current] or getchar(current) + local c=getchar(current) local found=lookupcache[c] if found then local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_blwf) - setprop(next,a_state,s_blwf) - current=next - subpos=current + if found[getchar(next)] or contextchain(found,next) then + if (not getprop(current,a_state) and not getprop(next,a_state)) then + setprop(current,a_state,s_blwf) + setprop(next,a_state,s_blwf) + current=next + subpos=current + end end end end @@ -30240,16 +31403,17 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local last=getnext(stop) while current~=last do if current~=stop then - local c=locl[current] or getchar(current) + local c=getchar(current) local found=lookupcache[c] if found then local next=getnext(current) - local n=locl[next] or getchar(next) - if found[n] then - setprop(current,a_state,s_pstf) - setprop(next,a_state,s_pstf) - current=next - postpos=current + if found[getchar(next)] or contextchain(found,next) then + if (not getprop(current,a_state) and not getprop(next,a_state)) then + setprop(current,a_state,s_pstf) + setprop(next,a_state,s_pstf) + current=next + postpos=current + end end end end @@ -30257,7 +31421,6 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end end end - reorderreph.coverage={ [reph]=true } local current,base,firstcons=start,nil,nil if getprop(start,a_state)==s_rphf then current=getnext(getnext(start)) @@ -30318,7 +31481,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) firstcons=current end local a=getprop(current,a_state) - if not (a==s_pref or a==s_blwf or a==s_pstf) then + if not (a==s_blwf or a==s_pstf or (a~=s_rphf and a~=s_blwf and ra[getchar(current)])) then base=current end end @@ -30335,7 +31498,7 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end return head,stop,nbspaces else - if getprop(base,a_state) then + if getprop(base,a_state) then setprop(base,a_state,unsetvalue) end basepos=base @@ -30353,34 +31516,59 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) local current=start local last=getnext(stop) while current~=last do - local char,target,cn=locl[current] or getchar(current),nil,getnext(current) + local char=getchar(current) + local target=nil + local cn=getnext(current) local tpm=twopart_mark[char] - if tpm then + while tpm do local extra=copy_node(current) copyinjection(extra,current) char=tpm[1] setchar(current,char) setchar(extra,tpm[2]) head=insert_node_after(head,current,extra) + tpm=twopart_mark[char] end if not moved[current] and dependent_vowel[char] then - if pre_mark[char] then + if pre_mark[char] then moved[current]=true local prev,next=getboth(current) setlink(prev,next) if current==stop then stop=getprev(current) end - if halfpos==start then + local pos + if before_main[char] then + pos=basepos + else + pos=halfpos + end + local ppos=getprev(pos) + while ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) do + if getprop(ppos,a_state)==s_pref then + pos=ppos + end + ppos=getprev(ppos) + end + local ppos=getprev(pos) + while ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) and halant[ischar(ppos)] do + ppos=getprev(ppos) + if ppos and getprop(ppos,a_syllabe)==getprop(pos,a_syllabe) and consonant[ischar(ppos)] then + pos=ppos + ppos=getprev(ppos) + else + break + end + end + if pos==start then if head==start then head=current end start=current end - setlink(getprev(halfpos),current) - setlink(current,halfpos) - halfpos=current - elseif above_mark[char] then + setlink(getprev(pos),current) + setlink(current,pos) + elseif above_mark[char] then target=basepos if subpos==basepos then subpos=current @@ -30389,13 +31577,23 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) postpos=current end basepos=current - elseif below_mark[char] then + elseif below_mark[char] then target=subpos if postpos==subpos then postpos=current end subpos=current - elseif post_mark[char] then + elseif post_mark[char] then + local n=getnext(postpos) + while n do + local v=ischar(n,font) + if nukta[v] or stress_tone_mark[v] or vowel_modifier[v] then + postpos=n + else + break + end + n=getnext(n) + end target=postpos postpos=current end @@ -30414,7 +31612,35 @@ local function reorder_two(head,start,stop,font,attr,nbspaces) end current=cn end - local current,c=start,nil + local current=getnext(start) + local last=getnext(stop) + while current~=last do + local char=getchar(current) + local cn=getnext(current) + if halant[char] and ra[ischar(cn)] and getprop(cn,a_state)~=s_rphf and getprop(cn,a_state)~=s_blwf then + if after_main[ischar(cn)] then + local prev=getprev(current) + local next=getnext(cn) + local bpn=getnext(basepos) + while bpn and dependent_vowel[ischar(bpn)] do + basepos=bpn + bpn=getnext(bpn) + end + if basepos~=prev then + setlink(prev,next) + setlink(cn,getnext(basepos)) + setlink(basepos,current) + if cn==stop then + stop=prev + end + cn=next + end + end + end + current=cn + end + local current=start + local c=nil while current~=stop do local char=getchar(current) if halant[char] or stress_tone_mark[char] then @@ -30533,7 +31759,25 @@ local function analyze_next_chars_one(c,font,variant) if not v then return c end - if dependent_vowel[v] then + local already_pre_mark + local already_above_mark + local already_below_mark + local already_post_mark + while dependent_vowel[v] do + local vowels=twopart_mark[v] or { v } + for k,v in next,vowels do + if pre_mark[v] and not already_pre_mark then + already_pre_mark=true + elseif above_mark[v] and not already_above_mark then + already_above_mark=true + elseif below_mark[v] and not already_below_mark then + already_below_mark=true + elseif post_mark[v] and not already_post_mark then + already_post_mark=true + else + return c + end + end c=getnext(c) n=getnext(c) if not n then @@ -30699,7 +31943,25 @@ local function analyze_next_chars_two(c,font) end end else - if dependent_vowel[v] then + local already_pre_mark + local already_above_mark + local already_below_mark + local already_post_mark + while dependent_vowel[v] do + local vowels=twopart_mark[v] or { v } + for k,v in next,vowels do + if pre_mark[v] and not already_pre_mark then + already_pre_mark=true + elseif above_mark[v] and not already_above_mark then + already_above_mark=true + elseif below_mark[v] and not already_below_mark then + already_below_mark=true + elseif post_mark[v] and not already_post_mark then + already_post_mark=true + else + return c + end + end c=n n=getnext(c) if not n then @@ -30766,6 +32028,7 @@ local function method_one(head,font,attr) local start=true local done=false local nbspaces=0 + local syllabe=0 while current do local char=ischar(current,font) if char then @@ -30902,6 +32165,15 @@ local function method_one(head,font,attr) end end if syllablestart~=syllableend then + if syllableend then + syllabe=syllabe+1 + local c=syllablestart + local n=getnext(syllableend) + while c~=n do + setprop(c,a_syllabe,syllabe) + c=getnext(c) + end + end head,current,nbspaces=reorder_one(head,syllablestart,syllableend,font,attr,nbspaces) current=getnext(current) end @@ -30940,6 +32212,20 @@ local function method_one(head,font,attr) if nbspaces>0 then head=replace_all_nbsp(head) end + current=head + local n=0 + while current do + local char=ischar(current,font) + if char then + if n==0 and not getprop(current,a_state) then + setprop(current,a_state,s_init) + end + n=n+1 + else + n=0 + end + current=getnext(current) + end return head,done end local function method_two(head,font,attr) @@ -31008,7 +32294,7 @@ local function method_two(head,font,attr) end if not syllableend and show_syntax_errors then local char=ischar(current,font) - if char and not getprop(current,a_state) then + if char and not getprop(current,a_state) then local mark=mark_four[char] if mark then head,current=inject_syntax_error(head,current,char) @@ -31021,6 +32307,20 @@ local function method_two(head,font,attr) if nbspaces>0 then head=replace_all_nbsp(head) end + current=head + local n=0 + while current do + local char=ischar(current,font) + if char then + if n==0 and not getprop(current,a_state) then + setprop(current,a_state,s_init) + end + n=n+1 + else + n=0 + end + current=getnext(current) + end return head,done end for i=1,nofscripts do @@ -31039,9 +32339,13 @@ if not modules then modules={} end modules ['font-ocl']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } +if CONTEXTLMTXMODE and CONTEXTLMTXMODE>0 then + return +end local tostring,tonumber,next=tostring,tonumber,next local round,max=math.round,math.round -local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash +local gsub,find=string.gsub,string.find +local sortedkeys,sortedhash,concat=table.sortedkeys,table.sortedhash,table.concat local setmetatableindex=table.setmetatableindex local formatters=string.formatters local tounicode=fonts.mappings.tounicode @@ -31051,6 +32355,7 @@ local rightcommand=helpers.commands.right local leftcommand=helpers.commands.left local downcommand=helpers.commands.down local otf=fonts.handlers.otf +local otfregister=otf.features.register local f_color=formatters["%.3f %.3f %.3f rg"] local f_gray=formatters["%.3f g"] if context then @@ -31107,7 +32412,7 @@ end local start={ "pdf","mode","font" } local push={ "pdf","page","q" } local pop={ "pdf","page","Q" } -local function initialize(tfmdata,kind,value) +local function initializeoverlay(tfmdata,kind,value) if value then local resources=tfmdata.resources local palettes=resources.colorpalettes @@ -31149,52 +32454,39 @@ local function initialize(tfmdata,kind,value) local s=#colorlist local goback=w~=0 and leftcommand[w] or nil local t={ - start, - not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) } + not u and actualb or { "pdf","page",(getactualtext(tounicode(u))) }, + push, } local n=2 local l=nil - local f=false for i=1,s do local entry=colorlist[i] local v=colorvalues[entry.class] or default if v and l~=v then - if f then - n=n+1 t[n]=pop - end - n=n+1 t[n]=push - f=true n=n+1 t[n]=v l=v - else - if f then - n=n+1 t[n]=pop - end - f=false - l=nil end n=n+1 t[n]=charcommand[entry.slot] if s>1 and i<s and goback then n=n+1 t[n]=goback end end - if f then - n=n+1 t[n]=pop - end + n=n+1 t[n]=pop n=n+1 t[n]=actuale character.commands=t end end end + return true end end end -fonts.handlers.otf.features.register { +otfregister { name="colr", description="color glyphs", manipulators={ - base=initialize, - node=initialize, + base=initializeoverlay, + node=initializeoverlay, } } do @@ -31203,32 +32495,17 @@ do local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] local hashed={} local cache={} - if epdf then - local openpdf=epdf.openMemStream - function otf.storepdfdata(pdf) - local done=hashed[pdf] - if not done then - nofstreams=nofstreams+1 - local o,n=openpdf(pdf,#pdf,f_name(nofstreams)) - cache[n]=o - done=f_used(n) - hashed[pdf]=done - end - return done - end - else - local openpdf=pdfe.new - function otf.storepdfdata(pdf) - local done=hashed[pdf] - if not done then - nofstreams=nofstreams+1 - local f=f_name(nofstreams) - local n=openpdf(pdf,#pdf,f) - done=f_used(n) - hashed[pdf]=done - end - return done + local openpdf=pdfe.new + function otf.storepdfdata(pdf) + local done=hashed[pdf] + if not done then + nofstreams=nofstreams+1 + local f=f_name(nofstreams) + local n=openpdf(pdf,#pdf,f) + done=f_used(n) + hashed[pdf]=done end + return done end end local function pdftovirtual(tfmdata,pdfshapes,kind) @@ -31260,14 +32537,20 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) local data=nil local dx=nil local dy=nil + local scale=1 if typ=="table" then data=pdf.data - dx=pdf.dx or 0 - dy=pdf.dy or 0 + dx=pdf.x or pdf.dx or 0 + dy=pdf.y or pdf.dy or 0 + scale=pdf.scale or 1 elseif typ=="string" then data=pdf dx=0 dy=0 + elseif typ=="number" then + data=pdf + dx=0 + dy=0 end if data then local bt=unicode and getactualtext(unicode) @@ -31276,9 +32559,9 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) local dp=character.depth or 0 character.commands={ not unicode and actualb or { "pdf","page",(getactualtext(unicode)) }, - downcommand[dp+dy*hfactor], - rightcommand[dx*hfactor], - vfimage(wd,ht,dp,data,name), + downcommand [dp+dy*hfactor], + rightcommand[ dx*hfactor], + vfimage(scale*wd,ht,dp,data,pdfshapes.filename or ""), actuale, } character[kind]=true @@ -31312,24 +32595,26 @@ do name="otfsvg", program="inkscape", method="pipeto", - template="--shell > temp-otf-svg-shape.log", + template="--export-area-drawing --shell > temp-otf-svg-shape.log", reporter=report_svg, } if not runner then runner=function() - return io.open("inkscape --shell > temp-otf-svg-shape.log","w") + return io.popen("inkscape --export-area-drawing --shell > temp-otf-svg-shape.log","w") end end - function otfsvg.topdf(svgshapes) + function otfsvg.topdf(svgshapes,tfmdata) local pdfshapes={} local inkscape=runner() if inkscape then + local descriptions=tfmdata.descriptions local nofshapes=#svgshapes local f_svgfile=formatters["temp-otf-svg-shape-%i.svg"] local f_pdffile=formatters["temp-otf-svg-shape-%i.pdf"] local f_convert=formatters["%s --export-pdf=%s\n"] local filterglyph=otfsvg.filterglyph local nofdone=0 + local processed={} report_svg("processing %i svg containers",nofshapes) statistics.starttiming() for i=1,nofshapes do @@ -31341,24 +32626,51 @@ do local pdffile=f_pdffile(index) savedata(svgfile,data) inkscape:write(f_convert(svgfile,pdffile)) - pdfshapes[index]=true + processed[index]=true nofdone=nofdone+1 - if nofdone%100==0 then - report_svg("%i shapes processed",nofdone) + if nofdone%25==0 then + report_svg("%i shapes submitted",nofdone) end end end end + if nofdone%25~=0 then + report_svg("%i shapes submitted",nofdone) + end + report_svg("processing can be going on for a while") inkscape:write("quit\n") inkscape:close() report_svg("processing %i pdf results",nofshapes) - for index in next,pdfshapes do + for index in next,processed do local svgfile=f_svgfile(index) local pdffile=f_pdffile(index) - pdfshapes[index]=loaddata(pdffile) + local pdfdata=loaddata(pdffile) + if pdfdata and pdfdata~="" then + pdfshapes[index]={ + data=pdfdata, + } + end remove(svgfile) remove(pdffile) end + local characters=tfmdata.characters + for k,v in next,characters do + local d=descriptions[k] + local i=d.index + if i then + local p=pdfshapes[i] + if p then + local w=d.width + local l=d.boundingbox[1] + local r=d.boundingbox[3] + p.scale=(r-l)/w + p.x=l + end + end + end + if not next(pdfshapes) then + report_svg("there are no converted shapes, fix your setup") + end statistics.stoptiming() if statistics.elapsedseconds then report_svg("svg conversion time %s",statistics.elapsedseconds() or "-") @@ -31377,19 +32689,20 @@ local function initializesvg(tfmdata,kind,value) end local pdffile=containers.read(otf.pdfcache,hash) local pdfshapes=pdffile and pdffile.pdfshapes - if not pdfshapes or pdffile.timestamp~=timestamp then + if not pdfshapes or pdffile.timestamp~=timestamp or not next(pdfshapes) then local svgfile=containers.read(otf.svgcache,hash) local svgshapes=svgfile and svgfile.svgshapes - pdfshapes=svgshapes and otfsvg.topdf(svgshapes) or {} + pdfshapes=svgshapes and otfsvg.topdf(svgshapes,tfmdata,otf.pdfcache.writable,hash) or {} containers.write(otf.pdfcache,hash,{ pdfshapes=pdfshapes, timestamp=timestamp, }) end pdftovirtual(tfmdata,pdfshapes,"svg") + return true end end -fonts.handlers.otf.features.register { +otfregister { name="svg", description="svg glyphs", manipulators={ @@ -31472,9 +32785,10 @@ local function initializepng(tfmdata,kind,value) }) end pdftovirtual(tfmdata,pdfshapes,"png") + return true end end -fonts.handlers.otf.features.register { +otfregister { name="sbix", description="sbix glyphs", manipulators={ @@ -31482,7 +32796,7 @@ fonts.handlers.otf.features.register { node=initializepng, } } -fonts.handlers.otf.features.register { +otfregister { name="cblc", description="cblc glyphs", manipulators={ @@ -31490,6 +32804,11 @@ fonts.handlers.otf.features.register { node=initializepng, } } +if context then + +--removed + +end end -- closure @@ -31513,9 +32832,10 @@ local fonts=fonts local otf=fonts.handlers.otf local registerotffeature=otf.features.register local setmetatableindex=table.setmetatableindex -local checkmerge=fonts.helpers.checkmerge -local checkflags=fonts.helpers.checkflags -local checksteps=fonts.helpers.checksteps +local fonthelpers=fonts.helpers +local checkmerge=fonthelpers.checkmerge +local checkflags=fonthelpers.checkflags +local checksteps=fonthelpers.checksteps local normalized={ substitution="substitution", single="substitution", @@ -31637,6 +32957,7 @@ local function addfeature(data,feature,specifications) local done=0 local skip=0 local aglunicodes=false + local privateslot=fonthelpers.privateslot local specifications=validspecification(specifications,feature) if not specifications then return @@ -31659,6 +32980,12 @@ local function addfeature(data,feature,specifications) return u end end + if privateslot then + u=privateslot(code) + if u then + return u + end + end local u=lpegmatch(p,code) if u then return u @@ -31688,7 +33015,7 @@ local function addfeature(data,feature,specifications) replacement=replacement[1] end replacement=tounicode(replacement) - if replacement and descriptions[replacement] then + if replacement and (nocheck or descriptions[replacement]) then cover(coverage,unicode,replacement) done=done+1 else @@ -32058,7 +33385,6 @@ local function addfeature(data,feature,specifications) local featuretype=normalized[specification.type or "substitution"] or "substitution" local featureflags=specification.flags or noflags local nocheck=specification.nocheck - local futuresteps=specification.futuresteps local featureorder=specification.order or { feature } local featurechain=(featuretype=="chainsubstitution" or featuretype=="chainposition") and 1 or 0 local nofsteps=0 @@ -32255,7 +33581,7 @@ if not modules then modules={} end modules ['font-onr']={ license="see context related readme files" } local fonts,logs,trackers,resolvers=fonts,logs,trackers,resolvers -local next,type,tonumber,rawget,rawset=next,type,tonumber,rawget,rawset +local next,type,tonumber,rawset=next,type,tonumber,rawset local match,lower,gsub,strip,find=string.match,string.lower,string.gsub,string.strip,string.find local char,byte,sub=string.char,string.byte,string.sub local abs=math.abs @@ -32410,7 +33736,7 @@ do } }, } - fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams) + fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,"cff",streams,true) else lpegmatch(p_filternames,binary,1,filename) end @@ -33017,8 +34343,9 @@ local function copytotfm(data) local filename=constructors.checkedfilename(resources) local fontname=metadata.fontname or metadata.fullname local fullname=metadata.fullname or metadata.fontname - local endash=0x0020 + local endash=0x2013 local emdash=0x2014 + local space=0x0020 local spacer="space" local spaceunits=500 local monospaced=metadata.monospaced @@ -33029,26 +34356,32 @@ local function copytotfm(data) parameters.italicangle=italicangle parameters.charwidth=charwidth parameters.charxheight=charxheight + local d_endash=descriptions[endash] + local d_emdash=descriptions[emdash] + local d_space=descriptions[space] + if not d_space or d_space==0 then + d_space=d_endash + end + if d_space then + spaceunits,spacer=d_space.width or 0,"space" + end if properties.monospaced then - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width,"emdash" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" + if spaceunits==0 and d_emdash then + spaceunits,spacer=d_emdash.width or 0,"emdash" end else - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and charwidth then - spaceunits,spacer=charwidth,"charwidth" + if spaceunits==0 and d_endash then + spaceunits,spacer=d_emdash.width or 0,"endash" end end - spaceunits=tonumber(spaceunits) - if spaceunits<200 then + if spaceunits==0 and charwidth then + spaceunits,spacer=charwidth or 0,"charwidth" + end + if spaceunits==0 then + spaceunits=tonumber(spaceunits) or 500 + end + if spaceunits==0 then + spaceunits=500 end parameters.slant=0 parameters.space=spaceunits @@ -33496,7 +34829,7 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-tfm']={ +if not modules then modules={} end modules ['luatex-fonts-tfm']={ version=1.001, comment="companion to font-ini.mkiv", author="Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -33532,7 +34865,7 @@ local registertfmenhancer=tfmenhancers.register local charcommand=helpers.commands.char constructors.resolvevirtualtoo=false fonts.formats.tfm="type1" -fonts.formats.ofm="type1" +fonts.formats.ofm="type1" function tfm.setfeatures(tfmdata,features) local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) if okay then @@ -33541,191 +34874,156 @@ function tfm.setfeatures(tfmdata,features) return {} end end -local depth={} -local read_from_tfm,check_tfm do - local tfmreaders=context and tfm.readers - local loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - local loadtfm=font.read_tfm - local loadvf=font.read_vf - directives.register("fonts.tfm.builtin",function(v) - loadtfmvf=tfmreaders and tfmreaders.loadtfmvf - if v and loadtfm then - loadtfmvf=false - end - end) - read_from_tfm=function(specification) - local filename=specification.filename - local size=specification.size - depth[filename]=(depth[filename] or 0)+1 - if trace_defining then - report_defining("loading tfm file %a at size %s",filename,size) - end - local tfmdata - if loadtfmvf then - tfmdata=loadtfmvf(filename,size) - else - tfmdata=loadtfm(filename,size) +local depth={} +local loadtfm=font.read_tfm +local loadvf=font.read_vf +local function read_from_tfm(specification) + local filename=specification.filename + local size=specification.size + depth[filename]=(depth[filename] or 0)+1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata=loadtfm(filename,size) + if tfmdata then + local features=specification.features and specification.features.normal or {} + local features=constructors.checkedfeatures("tfm",features) + specification.features.normal=features + local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata=newtfmdata end - if tfmdata then - local features=specification.features and specification.features.normal or {} - local features=constructors.checkedfeatures("tfm",features) - specification.features.normal=features - local newtfmdata=(depth[filename]==1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata=newtfmdata - end - local resources=tfmdata.resources or {} - local properties=tfmdata.properties or {} - local parameters=tfmdata.parameters or {} - local shared=tfmdata.shared or {} - shared.features=features - shared.resources=resources - properties.name=tfmdata.name - properties.fontname=tfmdata.fontname - properties.psname=tfmdata.psname - properties.fullname=tfmdata.fullname - properties.filename=specification.filename - properties.format=tfmdata.format or fonts.formats.tfm - properties.usedbitmap=tfmdata.usedbitmap - tfmdata.properties=properties - tfmdata.resources=resources - tfmdata.parameters=parameters - tfmdata.shared=shared - shared.rawdata={ resources=resources } - shared.features=features - if newtfmdata then - if not resources.marks then - resources.marks={} - end - if not resources.sequences then - resources.sequences={} - end - if not resources.features then - resources.features={ - gsub={}, - gpos={}, - } - end - if not tfmdata.changed then - tfmdata.changed={} - end - if not tfmdata.descriptions then - tfmdata.descriptions=tfmdata.characters - end - otf.readers.addunicodetable(tfmdata) - tfmenhancers.apply(tfmdata,filename) - constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) - otf.readers.unifymissing(tfmdata) - fonts.mappings.addtounicode(tfmdata,filename) - tfmdata.tounicode=1 - local tounicode=fonts.mappings.tounicode - for unicode,v in next,tfmdata.characters do - local u=v.unicode - if u then - v.tounicode=tounicode(u) - end - end - if tfmdata.usedbitmap then - tfm.addtounicode(tfmdata) - end - end - shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil - if size<0 then - size=idiv(65536*-size,100) - end - parameters.factor=1 - parameters.units=1000 - parameters.size=size - parameters.slant=parameters.slant or parameters[1] or 0 - parameters.space=parameters.space or parameters[2] or 0 - parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 - parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 - parameters.x_height=parameters.x_height or parameters[5] or 0 - parameters.quad=parameters.quad or parameters[6] or 0 - parameters.extra_space=parameters.extra_space or parameters[7] or 0 - constructors.enhanceparameters(parameters) - properties.private=properties.private or tfmdata.private or privateoffset - if newtfmdata then - elseif loadtfmvf then - local fonts=tfmdata.fonts - if fonts then - for i=1,#fonts do - local font=fonts[i] - local id=font.id - if not id then - local name=font.name - local size=font.size - if name and size then - local data,id=constructors.readanddefine(name,size) - if id then - font.id=id - font.name=nil - font.size=nil - end - end - end - end - end - elseif constructors.resolvevirtualtoo then - fonts.loggers.register(tfmdata,file.suffix(filename),specification) - local vfname=findbinfile(specification.name,'ovf') - if vfname and vfname~="" then - local vfdata=loadvf(vfname,size) - if vfdata then - local chars=tfmdata.characters - for k,v in next,vfdata.characters do - chars[k].commands=v.commands - end - properties.virtualized=true - tfmdata.fonts=vfdata.fonts - tfmdata.type="virtual" - local fontlist=vfdata.fonts - local name=file.nameonly(filename) - for i=1,#fontlist do - local n=fontlist[i].name - local s=fontlist[i].size - local d=depth[filename] - s=constructors.scaled(s,vfdata.designsize) - if d>tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i]={ id=0 } - elseif (d>1) and (s>tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i]={ id=0 } - else - local t,id=constructors.readanddefine(n,s) - fontlist[i]={ id=id } - end + local resources=tfmdata.resources or {} + local properties=tfmdata.properties or {} + local parameters=tfmdata.parameters or {} + local shared=tfmdata.shared or {} + shared.features=features + shared.resources=resources + properties.name=tfmdata.name + properties.fontname=tfmdata.fontname + properties.psname=tfmdata.psname + properties.fullname=tfmdata.fullname + properties.filename=specification.filename + properties.format=tfmdata.format or fonts.formats.tfm + properties.usedbitmap=tfmdata.usedbitmap + tfmdata.properties=properties + tfmdata.resources=resources + tfmdata.parameters=parameters + tfmdata.shared=shared + shared.rawdata={ resources=resources } + shared.features=features + if newtfmdata then + if not resources.marks then + resources.marks={} + end + if not resources.sequences then + resources.sequences={} + end + if not resources.features then + resources.features={ + gsub={}, + gpos={}, + } + end + if not tfmdata.changed then + tfmdata.changed={} + end + if not tfmdata.descriptions then + tfmdata.descriptions=tfmdata.characters + end + otf.readers.addunicodetable(tfmdata) + tfmenhancers.apply(tfmdata,filename) + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + otf.readers.unifymissing(tfmdata) + fonts.mappings.addtounicode(tfmdata,filename) + tfmdata.tounicode=1 + local tounicode=fonts.mappings.tounicode + for unicode,v in next,tfmdata.characters do + local u=v.unicode + if u then + v.tounicode=tounicode(u) + end + end + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil + if size<0 then + size=idiv(65536*-size,100) + end + parameters.factor=1 + parameters.units=1000 + parameters.size=size + parameters.slant=parameters.slant or parameters[1] or 0 + parameters.space=parameters.space or parameters[2] or 0 + parameters.space_stretch=parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink=parameters.space_shrink or parameters[4] or 0 + parameters.x_height=parameters.x_height or parameters[5] or 0 + parameters.quad=parameters.quad or parameters[6] or 0 + parameters.extra_space=parameters.extra_space or parameters[7] or 0 + constructors.enhanceparameters(parameters) + properties.private=properties.private or tfmdata.private or privateoffset + if newtfmdata then + elseif constructors.resolvevirtualtoo then + fonts.loggers.register(tfmdata,file.suffix(filename),specification) + local vfname=findbinfile(specification.name,'ovf') + if vfname and vfname~="" then + local vfdata=loadvf(vfname,size) + if vfdata then + local chars=tfmdata.characters + for k,v in next,vfdata.characters do + chars[k].commands=v.commands + end + properties.virtualized=true + tfmdata.fonts=vfdata.fonts + tfmdata.type="virtual" + local fontlist=vfdata.fonts + local name=file.nameonly(filename) + for i=1,#fontlist do + local n=fontlist[i].name + local s=fontlist[i].size + local d=depth[filename] + s=constructors.scaled(s,vfdata.designsize) + if d>tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i]={ id=0 } + elseif (d>1) and (s>tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i]={ id=0 } + else + local t,id=constructors.readanddefine(n,s) + fontlist[i]={ id=id } end end end end - properties.haskerns=true - properties.hasligatures=true - properties.hasitalics=true - resources.unicodes={} - resources.lookuptags={} - depth[filename]=depth[filename]-1 - return tfmdata - else - depth[filename]=depth[filename]-1 end + properties.haskerns=true + properties.hasligatures=true + properties.hasitalics=true + resources.unicodes={} + resources.lookuptags={} + depth[filename]=depth[filename]-1 + return tfmdata + else + depth[filename]=depth[filename]-1 end - check_tfm=function(specification,fullname) - local foundname=findbinfile(fullname,'tfm') or "" - if foundname=="" then - foundname=findbinfile(fullname,'ofm') or "" - end - if foundname=="" then - foundname=fonts.names.getfilename(fullname,"tfm") or "" - end - if foundname~="" then - specification.filename=foundname - specification.format="ofm" - return read_from_tfm(specification) - elseif trace_defining then - report_defining("loading tfm with name %a fails",specification.name) - end +end +local function check_tfm(specification,fullname) + local foundname=findbinfile(fullname,'tfm') or "" + if foundname=="" then + foundname=findbinfile(fullname,'ofm') or "" + end + if foundname=="" then + foundname=fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname~="" then + specification.filename=foundname + specification.format="ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) end end readers.check_tfm=check_tfm @@ -34120,7 +35418,6 @@ local variants=allocate() specifiers.variants=variants definers.methods=definers.methods or {} local internalized=allocate() -local lastdefined=nil local loadedfonts=constructors.loadedfonts local designsizes=constructors.designsizes local resolvefile=fontgoodies and fontgoodies.filenames and fontgoodies.filenames.resolve or function(s) return s end @@ -34381,9 +35678,6 @@ function constructors.readanddefine(name,size) end return fontdata[id],id end -function definers.current() - return lastdefined -end function definers.registered(hash) local id=internalized[hash] return id,id and fontdata[id] @@ -34434,7 +35728,6 @@ function definers.read(specification,size,id) end end end - lastdefined=tfmdata or id if not tfmdata then report_defining("unknown font %a, loading aborted",specification.name) elseif trace_defining and type(tfmdata)=="table" then @@ -34450,7 +35743,9 @@ end function font.getfont(id) return fontdata[id] end -callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") +if not context then + callbacks.register('define_font',definers.read,"definition of fonts (tfmdata preparation)") +end end -- closure diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua new file mode 100644 index 00000000000..0b6e09a8f95 --- /dev/null +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts-tfm.lua @@ -0,0 +1,654 @@ +if not modules then modules = { } end modules ['luatex-fonts-tfm'] = { + version = 1.001, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is the generic tfm/vf loader. There are no fundamental differences with +-- the one used in ConTeXt but we save some byte(codes) this way. + +local next, type = next, type +local match, format = string.match, string.format +local concat, sortedhash = table.concat, table.sortedhash +local idiv = number.idiv + +local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) +local trace_features = false trackers.register("tfm.features", function(v) trace_features = v end) + +local report_defining = logs.reporter("fonts","defining") +local report_tfm = logs.reporter("fonts","tfm loading") + +local findbinfile = resolvers.findbinfile +local setmetatableindex = table.setmetatableindex + +local fonts = fonts +local handlers = fonts.handlers +local helpers = fonts.helpers +local readers = fonts.readers +local constructors = fonts.constructors +local encodings = fonts.encodings + +local tfm = constructors.handlers.tfm +tfm.version = 1.000 +tfm.maxnestingdepth = 5 +tfm.maxnestingsize = 65536*1024 + +local otf = fonts.handlers.otf +local otfenhancers = otf.enhancers + +local tfmfeatures = constructors.features.tfm +local registertfmfeature = tfmfeatures.register + +local tfmenhancers = constructors.enhancers.tfm +local registertfmenhancer = tfmenhancers.register + +local charcommand = helpers.commands.char + +constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua + +fonts.formats.tfm = "type1" -- we need to have at least a value here +fonts.formats.ofm = "type1" -- we need to have at least a value here + +function tfm.setfeatures(tfmdata,features) + local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) + if okay then + return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm) + else + return { } -- will become false + end +end + +local depth = { } -- table.setmetatableindex("number") + +local loadtfm = font.read_tfm +local loadvf = font.read_vf + +local function read_from_tfm(specification) + local filename = specification.filename + local size = specification.size + depth[filename] = (depth[filename] or 0) + 1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata = loadtfm(filename,size) + if tfmdata then + + local features = specification.features and specification.features.normal or { } + local features = constructors.checkedfeatures("tfm",features) + specification.features.normal = features + + -- If reencode returns a new table, we assume that we're doing something + -- special. An 'auto' reencode picks up its vector from the pfb file. + + local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata = newtfmdata + end + + local resources = tfmdata.resources or { } + local properties = tfmdata.properties or { } + local parameters = tfmdata.parameters or { } + local shared = tfmdata.shared or { } + -- + shared.features = features + shared.resources = resources + -- + properties.name = tfmdata.name -- todo: fallback + properties.fontname = tfmdata.fontname -- todo: fallback + properties.psname = tfmdata.psname -- todo: fallback + properties.fullname = tfmdata.fullname -- todo: fallback + properties.filename = specification.filename -- todo: fallback + properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing + properties.usedbitmap = tfmdata.usedbitmap + -- + tfmdata.properties = properties + tfmdata.resources = resources + tfmdata.parameters = parameters + tfmdata.shared = shared + -- + shared.rawdata = { resources = resources } + shared.features = features + -- + -- The next branch is only entered when we have a proper encoded file i.e. + -- unicodes and such. It really nakes no sense to do feature juggling when + -- we have no names and unicodes. + -- + if newtfmdata then + -- + -- Some opentype processing assumes these to be present: + -- + if not resources.marks then + resources.marks = { } + end + if not resources.sequences then + resources.sequences = { } + end + if not resources.features then + resources.features = { + gsub = { }, + gpos = { }, + } + end + if not tfmdata.changed then + tfmdata.changed = { } + end + if not tfmdata.descriptions then + tfmdata.descriptions = tfmdata.characters + end + -- + -- It might be handy to have this: + -- + otf.readers.addunicodetable(tfmdata) + -- + -- We make a pseudo opentype font, e.g. kerns and ligatures etc: + -- + tfmenhancers.apply(tfmdata,filename) + -- + -- Now user stuff can kick in. + -- + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + -- + -- As that can also mess with names and such, we are now ready for finalizing + -- the unicode information. This is a different order that for instance type one + -- (afm) files. First we try to deduce unicodes from already present information. + -- + otf.readers.unifymissing(tfmdata) + -- + -- Next we fill in the gaps, based on names from teh agl. Probably not much will + -- happen here. + -- + fonts.mappings.addtounicode(tfmdata,filename) + -- + -- The tounicode data is passed to the backend that constructs the vectors for us. + -- + tfmdata.tounicode = 1 + local tounicode = fonts.mappings.tounicode + for unicode, v in next, tfmdata.characters do + local u = v.unicode + if u then + v.tounicode = tounicode(u) + end + end + -- + -- However, when we use a bitmap font those vectors can't be constructed because + -- that information is not carried with those fonts (there is no name info, nor + -- proper index info, nor unicodes at that end). So, we provide it ourselves. + -- + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) + end + end + -- + shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil + -- + if size < 0 then + size = idiv(65536 * -size,100) + end + parameters.factor = 1 -- already scaled + parameters.units = 1000 -- just in case + parameters.size = size + parameters.slant = parameters.slant or parameters[1] or 0 + parameters.space = parameters.space or parameters[2] or 0 + parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink = parameters.space_shrink or parameters[4] or 0 + parameters.x_height = parameters.x_height or parameters[5] or 0 + parameters.quad = parameters.quad or parameters[6] or 0 + parameters.extra_space = parameters.extra_space or parameters[7] or 0 + -- + constructors.enhanceparameters(parameters) -- official copies for us + -- + properties.private = properties.private or tfmdata.private or privateoffset + -- + if newtfmdata then + -- + -- We do nothing as we assume flat tfm files. It would become real messy + -- otherwise and I don't have something for testing on my system anyway. + -- + elseif constructors.resolvevirtualtoo then + fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here + local vfname = findbinfile(specification.name, 'ovf') + if vfname and vfname ~= "" then + local vfdata = loadvf(vfname,size) + if vfdata then + local chars = tfmdata.characters + for k,v in next, vfdata.characters do + chars[k].commands = v.commands + end + properties.virtualized = true + tfmdata.fonts = vfdata.fonts + tfmdata.type = "virtual" -- else nested calls with cummulative scaling + local fontlist = vfdata.fonts + local name = file.nameonly(filename) + for i=1,#fontlist do + local n = fontlist[i].name + local s = fontlist[i].size + local d = depth[filename] + s = constructors.scaled(s,vfdata.designsize) + if d > tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i] = { id = 0 } + elseif (d > 1) and (s > tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i] = { id = 0 } + else + local t, id = constructors.readanddefine(n,s) + fontlist[i] = { id = id } + end + end + end + end + end + -- + properties.haskerns = true + properties.hasligatures = true + properties.hasitalics = true + resources.unicodes = { } + resources.lookuptags = { } + -- + depth[filename] = depth[filename] - 1 + -- + return tfmdata + else + depth[filename] = depth[filename] - 1 + end +end + +local function check_tfm(specification,fullname) -- we could split up like afm/otf + local foundname = findbinfile(fullname, 'tfm') or "" + if foundname == "" then + foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context + end + if foundname == "" then + foundname = fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) + end +end + +readers.check_tfm = check_tfm + +function readers.tfm(specification) + local fullname = specification.filename or "" + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + fullname = specification.name .. "." .. forced + else + fullname = specification.name + end + end + return check_tfm(specification,fullname) +end + +readers.ofm = readers.tfm + +-- The reencoding acts upon the 'reencode' feature which can have values 'auto' or +-- an enc file. You can also specify a 'pfbfile' feature (but it defaults to the +-- tfm filename) and a 'bitmap' feature. When no enc file is givven (auto) we will +-- get the vectors from the pfb file. + +do + + local outfiles = { } + + local tfmcache = table.setmetatableindex(function(t,tfmdata) + local id = font.define(tfmdata) + t[tfmdata] = id + return id + end) + + local encdone = table.setmetatableindex("table") + + function tfm.reencode(tfmdata,specification) + + local features = specification.features + + if not features then + return + end + + local features = features.normal + + if not features then + return + end + + local tfmfile = file.basename(tfmdata.name) + local encfile = features.reencode -- or features.enc + local pfbfile = features.pfbfile -- or features.pfb + local bitmap = features.bitmap -- or features.pk + + if not encfile then + return + end + + local pfbfile = outfiles[tfmfile] + + if pfbfile == nil then + if bitmap then + pfbfile = false + elseif type(pfbfile) ~= "string" then + pfbfile = tfmfile + end + if type(pfbfile) == "string" then + pfbfile = file.addsuffix(pfbfile,"pfb") + -- pdf.mapline(tfmfile .. "<" .. pfbfile) + report_tfm("using type1 shapes from %a for %a",pfbfile,tfmfile) + else + report_tfm("using bitmap shapes for %a",tfmfile) + pfbfile = false -- use bitmap + end + outfiles[tfmfile] = pfbfile + end + + local encoding = false + local vector = false + + if type(pfbfile) == "string" then + local pfb = constructors.handlers.pfb + if pfb and pfb.loadvector then + local v, e = pfb.loadvector(pfbfile) + if v then + vector = v + end + if e then + encoding = e + end + end + end + if type(encfile) == "string" and encfile ~= "auto" then + encoding = fonts.encodings.load(file.addsuffix(encfile,"enc")) + if encoding then + encoding = encoding.vector + end + end + if not encoding then + report_tfm("bad encoding for %a, quitting",tfmfile) + return + end + + local unicoding = fonts.encodings.agl and fonts.encodings.agl.unicodes + local virtualid = tfmcache[tfmdata] + local tfmdata = table.copy(tfmdata) -- good enough for small fonts + local characters = { } + local originals = tfmdata.characters + local indices = { } + local parentfont = { "font", 1 } + local private = tfmdata.privateoffset or constructors.privateoffset + local reported = encdone[tfmfile][encfile] + + -- create characters table + + local backmap = vector and table.swapped(vector) + local done = { } -- prevent duplicate + + for index, name in sortedhash(encoding) do -- predictable order + local unicode = unicoding[name] + local original = originals[index] + if original then + if unicode then + original.unicode = unicode + else + unicode = private + private = private + 1 + if not reported then + report_tfm("glyph %a in font %a with encoding %a gets unicode %U",name,tfmfile,encfile,unicode) + end + end + characters[unicode] = original + indices[index] = unicode + original.name = name -- so one can lookup weird names + if backmap then + original.index = backmap[name] + else -- probably bitmap + original.commands = { parentfont, charcommand[index] } -- or "slot" + original.oindex = index + end + done[name] = true + elseif not done[name] then + report_tfm("bad index %a in font %a with name %a",index,tfmfile,name) + end + end + + encdone[tfmfile][encfile] = true + + -- redo kerns and ligatures + + for k, v in next, characters do + local kerns = v.kerns + if kerns then + local t = { } + for k, v in next, kerns do + local i = indices[k] + if i then + t[i] = v + end + end + v.kerns = next(t) and t or nil + end + local ligatures = v.ligatures + if ligatures then + local t = { } + for k, v in next, ligatures do + local i = indices[k] + if i then + t[i] = v + v.char = indices[v.char] + end + end + v.ligatures = next(t) and t or nil + end + end + + -- wrap up + + tfmdata.fonts = { { id = virtualid } } + tfmdata.characters = characters + tfmdata.fullname = tfmdata.fullname or tfmdata.name + tfmdata.psname = file.nameonly(pfbfile or tfmdata.name) + tfmdata.filename = pfbfile + tfmdata.encodingbytes = 2 + -- tfmdata.format = bitmap and "type3" or "type1" + tfmdata.format = "type1" + tfmdata.tounicode = 1 + tfmdata.embedding = "subset" + tfmdata.usedbitmap = bitmap and virtualid + tfmdata.private = private + + return tfmdata + end + +end + +-- This code adds a ToUnicode vector for bitmap fonts. We don't bother about +-- ranges because we have small fonts. it works ok with acrobat but fails with +-- the other viewers (they get confused by the bitmaps I guess). + +do + + local template = [[ +/CIDInit /ProcSet findresource begin + 12 dict begin + begincmap + /CIDSystemInfo << /Registry (TeX) /Ordering (bitmap-%s) /Supplement 0 >> def + /CMapName /TeX-bitmap-%s def + /CMapType 2 def + 1 begincodespacerange + <00> <FF> + endcodespacerange + %s beginbfchar +%s + endbfchar + endcmap +CMapName currentdict /CMap defineresource pop end +end +end +]] + + local flushstreamobject = lpdf and lpdf.flushstreamobject -- context + local setfontattributes = lpdf and lpdf.setfontattributes -- context + + if not flushstreamobject then + flushstreamobject = function(data) + return pdf.obj { immediate = true, type = "stream", string = data } -- generic + end + end + + if not setfontattributes then + setfontattributes = function(id,data) + return pdf.setfontattributes(id,data) -- generic + end + end + + function tfm.addtounicode(tfmdata) + local id = tfmdata.usedbitmap + local map = { } + local char = { } -- no need for range, hardly used + for k, v in next, tfmdata.characters do + local index = v.oindex + local tounicode = v.tounicode + if index and tounicode then + map[index] = tounicode + end + end + for k, v in sortedhash(map) do + char[#char+1] = format("<%02X> <%s>",k,v) + end + char = concat(char,"\n") + local stream = format(template,id,id,#char,char) + local reference = flushstreamobject(stream,nil,true) + setfontattributes(id,format("/ToUnicode %i 0 R",reference)) + end + +end + +-- Now we implement the regular features handlers. We need to convert the +-- tfm specific structures to opentype structures. In basemode they are +-- converted back so that is a bit of a waste but it's fast enough. + +do + + local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } + local noflags = { false, false, false, false } + + local function enhance_normalize_features(data) + local ligatures = setmetatableindex("table") + local kerns = setmetatableindex("table") + local characters = data.characters + for u, c in next, characters do + local l = c.ligatures + local k = c.kerns + if l then + ligatures[u] = l + for u, v in next, l do + l[u] = { ligature = v.char } + end + c.ligatures = nil + end + if k then + kerns[u] = k + for u, v in next, k do + k[u] = v -- { v, 0 } + end + c.kerns = nil + end + end + + for u, l in next, ligatures do + for k, v in next, l do + local vl = v.ligature + local dl = ligatures[vl] + if dl then + for kk, vv in next, dl do + v[kk] = vv -- table.copy(vv) + end + end + end + end + + local features = { + gpos = { }, + gsub = { }, + } + local sequences = { + -- only filled ones + } + if next(ligatures) then + features.gsub.liga = everywhere + data.properties.hasligatures = true + sequences[#sequences+1] = { + features = { + liga = everywhere, + }, + flags = noflags, + name = "s_s_0", + nofsteps = 1, + order = { "liga" }, + type = "gsub_ligature", + steps = { + { + coverage = ligatures, + }, + }, + } + end + if next(kerns) then + features.gpos.kern = everywhere + data.properties.haskerns = true + sequences[#sequences+1] = { + features = { + kern = everywhere, + }, + flags = noflags, + name = "p_s_0", + nofsteps = 1, + order = { "kern" }, + type = "gpos_pair", + steps = { + { + format = "kern", + coverage = kerns, + }, + }, + } + end + data.resources.features = features + data.resources.sequences = sequences + data.shared.resources = data.shared.resources or resources + end + + registertfmenhancer("normalize features", enhance_normalize_features) + registertfmenhancer("check extra features", otfenhancers.enhance) + +end + +-- As with type one (afm) loading, we just use the opentype ones: + +registertfmfeature { + name = "mode", + description = "mode", + initializers = { + base = otf.modeinitializer, + node = otf.modeinitializer, + } +} + +registertfmfeature { + name = "features", + description = "features", + default = true, + initializers = { + base = otf.basemodeinitializer, + node = otf.nodemodeinitializer, + }, + processors = { + node = otf.featuresprocessor, + } +} diff --git a/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua index 06fb682f3e5..9f45408b1b7 100644 --- a/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua +++ b/Master/texmf-dist/tex/generic/context/luatex/luatex-fonts.lua @@ -257,7 +257,9 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('font-vfc.lua') - -- This is the bulk of opentype code. + -- This is the bulk of opentype code. The color and variable font support (as for + -- emoji) can (and might) actually go away here because it has never been used + -- outside context so in retrospect there was no need for it being generic. loadmodule('font-otr.lua') loadmodule('font-oti.lua') @@ -283,7 +285,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then -- And for traditional TeX fonts. - loadmodule('font-tfm.lua') + loadmodule('luatex-fonts-tfm.lua') -- Some common code. |