diff options
18 files changed, 1059 insertions, 465 deletions
diff --git a/scripts/mkimport b/scripts/mkimport index b3c71fe..08537d7 100755 --- a/scripts/mkimport +++ b/scripts/mkimport @@ -196,11 +196,9 @@ local imports = { { name = "fonts-demo-vf-1" , ours = nil , kind = kind_ignored }, { name = "fonts-enc" , ours = nil , kind = kind_merged }, { name = "fonts-ext" , ours = nil , kind = kind_merged }, - { name = "fonts-inj" , ours = nil , kind = kind_merged }, { name = "fonts-lua" , ours = nil , kind = kind_merged }, { name = "fonts-merged" , ours = "reference" , kind = kind_essential }, { name = "fonts-ota" , ours = nil , kind = kind_merged }, - { name = "fonts-otn" , ours = nil , kind = kind_merged }, { name = "fonts" , ours = nil , kind = kind_merged }, { name = "fonts" , ours = nil , kind = kind_tex }, { name = "fonts-syn" , ours = nil , kind = kind_ignored }, @@ -230,10 +228,12 @@ local imports = { { name = "font-con" , ours = "font-con" , kind = kind_merged }, { name = "font-def" , ours = "font-def" , kind = kind_merged }, { name = "font-ini" , ours = "font-ini" , kind = kind_merged }, + { name = "font-inj" , ours = "font-inj" , kind = kind_merged }, { name = "font-map" , ours = "font-map" , kind = kind_merged }, { name = "font-otb" , ours = "font-otb" , kind = kind_merged }, { name = "font-otf" , ours = "font-otf" , kind = kind_merged }, { name = "font-oti" , ours = "font-oti" , kind = kind_merged }, + { name = "font-otn" , ours = "font-otn" , kind = kind_merged }, { name = "font-otp" , ours = "font-otp" , kind = kind_merged }, { name = "font-tfm" , ours = "font-tfm" , kind = kind_merged }, { name = "l-boolean" , ours = "l-boolean" , kind = kind_lualibs }, @@ -282,9 +282,9 @@ local package = { --- [24] font-oti.lua --- [25] font-otf.lua --- [26] font-otb.lua ---- [27] luatex-fonts-inj.lua +--- [27] font-inj.lua --- [28] luatex-fonts-ota.lua ---- [29] luatex-fonts-otn.lua +--- [30] font-otn.lua --- [30] font-otp.lua --- [31] luatex-fonts-lua.lua --- [32] font-def.lua @@ -336,9 +336,9 @@ local package = { "font-oti", "font-otf", "font-otb", - "fonts-inj", + "font-inj", "fonts-ota", - "fonts-otn", + "font-otn", "font-otp", "fonts-lua", "font-def", diff --git a/scripts/mkstatus b/scripts/mkstatus index 4b36a9d..c5ded0d 100755 --- a/scripts/mkstatus +++ b/scripts/mkstatus @@ -101,11 +101,11 @@ local names = { { miscdir, "fontloader-fonts-demo-vf-1.lua", }, { miscdir, "fontloader-fonts-enc.lua", }, { miscdir, "fontloader-fonts-ext.lua", }, - { miscdir, "fontloader-fonts-inj.lua", }, + { miscdir, "fontloader-font-inj.lua", }, { miscdir, "fontloader-fonts.lua", }, { miscdir, "fontloader-fonts-lua.lua", }, { miscdir, "fontloader-fonts-ota.lua", }, - { miscdir, "fontloader-fonts-otn.lua", }, + { miscdir, "fontloader-font-otn.lua", }, { miscdir, "fontloader-fonts-syn.lua", }, { miscdir, "fontloader-fonts-tfm.lua", }, { miscdir, "fontloader-font-tfm.lua", }, @@ -164,7 +164,9 @@ local git_info = function () --io.write "\n" local desc = readpipe (describecmd) if not desc then die "cannot parse git information" end - local desc = string.explode (string.fullstrip (desc), "/")[2] + desc = string.fullstrip (desc) + local desc = string.explode (desc, "/")[2] or desc + if not desc then die "cannot parse sanitized git information" end local data = readpipe (logcmd) if data and type (data) == "string" and data ~= "" then data = load (data) diff --git a/src/fontloader/misc/fontloader-basics-nod.lua b/src/fontloader/misc/fontloader-basics-nod.lua index 39400a3..78f1b17 100644 --- a/src/fontloader/misc/fontloader-basics-nod.lua +++ b/src/fontloader/misc/fontloader-basics-nod.lua @@ -51,17 +51,23 @@ nodes = { } nodes.pool = { } nodes.handlers = { } -local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end -local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end -local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" } -local disccodes = { [0] = "discretionary", "explicit", "automatic", "regular", "first", "second" } - -for i=0,#glyphcodes do glyphcodes[glyphcodes[i]] = i end -for i=0,#disccodes do disccodes [disccodes [i]] = i end +local nodecodes = { } +local glyphcodes = node.subtypes("glyph") +local disccodes = node.subtypes("disc") + +for k, v in next, node.types() do + v = string.gsub(v,"_","") + nodecodes[k] = v + nodecodes[v] = k +end +for i=0,#glyphcodes do + glyphcodes[glyphcodes[i]] = i +end +for i=0,#disccodes do + disccodes[disccodes[i]] = i +end nodes.nodecodes = nodecodes -nodes.whatcodes = whatcodes -nodes.whatsitcodes = whatcodes nodes.glyphcodes = glyphcodes nodes.disccodes = disccodes @@ -140,7 +146,6 @@ nodes.slide = node.slide nodes.vpack = node.vpack nodes.first_glyph = node.first_glyph -nodes.first_character = node.first_character nodes.has_glyph = node.has_glyph or node.first_glyph nodes.current_attr = node.current_attr @@ -178,20 +183,33 @@ nodes.tonut = tonut nuts.tonode = tonode nuts.tonut = tonut - local getfield = direct.getfield local setfield = direct.setfield nuts.getfield = getfield nuts.setfield = setfield nuts.getnext = direct.getnext +nuts.setnext = direct.setnext nuts.getprev = direct.getprev +nuts.setprev = direct.setprev +nuts.getboth = direct.getboth +nuts.setboth = direct.setboth nuts.getid = direct.getid -nuts.getattr = getfield +nuts.getattr = direct.get_attribute or direct.has_attribute or getfield nuts.setattr = setfield nuts.getfont = direct.getfont +nuts.setfont = direct.setfont nuts.getsubtype = direct.getsubtype +nuts.setsubtype = direct.setsubtype or function(n,s) setfield(n,"subtype",s) end nuts.getchar = direct.getchar +nuts.setchar = direct.setchar +nuts.getdisc = direct.getdisc +nuts.setdisc = direct.setdisc +nuts.setlink = direct.setlink +nuts.getlist = direct.getlist +nuts.setlist = direct.setlist or function(n,l) setfield(n,"list",l) end +nuts.getleader = direct.getleader +nuts.setleader = direct.setleader or function(n,l) setfield(n,"leader",l) end nuts.insert_before = direct.insert_before nuts.insert_after = direct.insert_after @@ -206,6 +224,9 @@ nuts.is_node = direct.is_node nuts.end_of_math = direct.end_of_math nuts.traverse = direct.traverse nuts.traverse_id = direct.traverse_id +nuts.traverse_char = direct.traverse_char +nuts.ligaturing = direct.ligaturing +nuts.kerning = direct.kerning nuts.getprop = nuts.getattr nuts.setprop = nuts.setattr diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua index 55d7793..e5bf9e9 100644 --- a/src/fontloader/misc/fontloader-font-con.lua +++ b/src/fontloader/misc/fontloader-font-con.lua @@ -682,6 +682,8 @@ function constructors.scale(tfmdata,specification) if isunicode then chr.unicode = isunicode chr.tounicode = tounicode(isunicode) + -- in luatex > 0.85 we can do this: + -- chr.tounicode = isunicode end if hasquality then -- we could move these calculations elsewhere (saves calculations) diff --git a/src/fontloader/misc/fontloader-fonts-inj.lua b/src/fontloader/misc/fontloader-font-inj.lua index 36781f7..8937021 100644 --- a/src/fontloader/misc/fontloader-fonts-inj.lua +++ b/src/fontloader/misc/fontloader-font-inj.lua @@ -74,7 +74,6 @@ local nofregisteredkerns = 0 local nofregisteredpairs = 0 local nofregisteredmarks = 0 local nofregisteredcursives = 0 ------ markanchors = { } -- one base can have more marks local keepregisteredcounts = false function injections.keepcounts() @@ -91,10 +90,41 @@ end -- We need to make sure that a possible metatable will not kick in unexpectedly. +-- function injections.reset(n) +-- local p = rawget(properties,n) +-- if p and rawget(p,"injections") then +-- p.injections = nil +-- end +-- end + +-- function injections.copy(target,source) +-- local sp = rawget(properties,source) +-- if sp then +-- local tp = rawget(properties,target) +-- local si = rawget(sp,"injections") +-- if si then +-- si = fastcopy(si) +-- if tp then +-- tp.injections = si +-- else +-- propertydata[target] = { +-- injections = si, +-- } +-- end +-- else +-- if tp then +-- tp.injections = nil +-- end +-- end +-- end +-- end + function injections.reset(n) local p = rawget(properties,n) - if p and rawget(p,"injections") then - p.injections = nil + if p then + p.injections = false -- { } + else + properties[n] = false -- { injections = { } } end end @@ -112,10 +142,17 @@ function injections.copy(target,source) injections = si, } end + elseif tp then + tp.injections = false -- { } else - if tp then - tp.injections = nil - end + properties[target] = { injections = { } } + end + else + local tp = rawget(properties,target) + if tp then + tp.injections = false -- { } + else + properties[target] = false -- { injections = { } } end end end @@ -367,10 +404,11 @@ local function show(n,what,nested,symbol) local markx = i.markx or 0 local marky = i.marky or 0 local markdir = i.markdir or 0 - local markbase = i.markbase or 0 -- will be markbasenode + local markbase = i.markbase or 0 local cursivex = i.cursivex or 0 local cursivey = i.cursivey or 0 local ligaindex = i.ligaindex or 0 + local cursbase = i.cursiveanchor local margin = nested and 4 or 2 -- if rightkern ~= 0 or yoffset ~= 0 then @@ -382,7 +420,13 @@ local function show(n,what,nested,symbol) report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no") end if cursivex ~= 0 or cursivey ~= 0 then - report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + if cursbase then + report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey) + else + report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + end + elseif cursbase then + report_injections("%w%s curs: base",margin,symbol) end if ligaindex ~= 0 then report_injections("%w%s liga: index %i",margin,symbol,ligaindex) diff --git a/src/fontloader/misc/fontloader-font-map.lua b/src/fontloader/misc/fontloader-font-map.lua index b645d9a..dc3f499 100644 --- a/src/fontloader/misc/fontloader-font-map.lua +++ b/src/fontloader/misc/fontloader-font-map.lua @@ -74,6 +74,71 @@ end local f_single = formatters["%04X"] local f_double = formatters["%04X%04X"] +-- 0.684 0.661 0,672 0.650 : cache at lua end (more mem) +-- 0.682 0,672 0.698 0.657 : no cache (moderate mem i.e. lua strings) +-- 0.644 0.647 0.655 0.645 : convert in c (less mem in theory) + +-- local tounicodes = table.setmetatableindex(function(t,unicode) +-- local s +-- if unicode < 0x10000 then +-- s = f_single(unicode) +-- elseif unicode < 0x1FFFFFFFFF then +-- s = f_double(floor(unicode/1024),unicode%1024+0xDC00) +-- else +-- s = false +-- end +-- t[unicode] = s +-- return s +-- end) +-- +-- local function tounicode16(unicode,name) +-- local s = tounicodes[unicode] +-- if s then +-- return s +-- else +-- report_fonts("can't convert %a in %a into tounicode",unicode,name) +-- end +-- end +-- +-- local function tounicode16sequence(unicodes,name) +-- local t = { } +-- for l=1,#unicodes do +-- local u = unicodes[l] +-- local s = tounicodes[u] +-- if s then +-- t[l] = s +-- else +-- report_fonts ("can't convert %a in %a into tounicode",u,name) +-- return +-- end +-- end +-- return concat(t) +-- end +-- +-- local function tounicode(unicode,name) +-- if type(unicode) == "table" then +-- local t = { } +-- for l=1,#unicode do +-- local u = unicode[l] +-- local s = tounicodes[u] +-- if s then +-- t[l] = s +-- else +-- report_fonts ("can't convert %a in %a into tounicode",u,name) +-- return +-- end +-- end +-- return concat(t) +-- else +-- local s = tounicodes[unicode] +-- if s then +-- return s +-- else +-- report_fonts("can't convert %a in %a into tounicode",unicode,name) +-- end +-- end +-- end + local function tounicode16(unicode,name) if unicode < 0x10000 then return f_single(unicode) @@ -126,7 +191,6 @@ local function tounicode(unicode,name) end end - local function fromunicode16(str) if #str == 4 then return tonumber(str,16) diff --git a/src/fontloader/misc/fontloader-font-otf.lua b/src/fontloader/misc/fontloader-font-otf.lua index f709e70..0471c17 100644 --- a/src/fontloader/misc/fontloader-font-otf.lua +++ b/src/fontloader/misc/fontloader-font-otf.lua @@ -58,7 +58,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.819 -- beware: also sync font-mis.lua and in mtx-fonts +otf.version = 2.820 -- beware: also sync font-mis.lua and in mtx-fonts otf.cache = containers.define("fonts", "otf", otf.version, true) local hashes = fonts.hashes @@ -296,7 +296,8 @@ local ordered_enhancers = { "expand lookups", -- a temp hack awaiting the lua loader --- "check extra features", -- after metadata and duplicates +--[[phg-- PATCH: Next line restores font features --phg]]-- + "check extra features", -- after metadata and duplicates "cleanup tables", @@ -600,7 +601,9 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone applyruntimefixes(filename,data) end enhance("add dimensions",data,filename,nil,false) +--[[phg-- This was hand-patched to restore the fontloader enhance("check extra features",data,filename) +--phg]]-- if trace_sequences then showfeatureorder(data,filename) end @@ -2959,7 +2962,7 @@ otf.coverup = { kern = justset, }, register = function(coverage,lookuptype,format,feature,n,descriptions,resources) - local name = formatters["ctx_%s_%s"](feature,n) + local name = formatters["ctx_%s_%s_%s"](feature,lookuptype,n) -- we can have a mix of types if lookuptype == "kern" then resources.lookuptypes[name] = "position" else @@ -2973,7 +2976,6 @@ otf.coverup = { else description.slookups = { [name] = c } end --- inspect(feature,description) end return name end diff --git a/src/fontloader/misc/fontloader-font-oti.lua b/src/fontloader/misc/fontloader-font-oti.lua index 06c2a42..bacd001 100644 --- a/src/fontloader/misc/fontloader-font-oti.lua +++ b/src/fontloader/misc/fontloader-font-oti.lua @@ -13,9 +13,11 @@ local constructors = fonts.constructors local otf = constructors.newhandler("otf") local otffeatures = constructors.newfeatures("otf") -local otftables = otf.tables local registerotffeature = otffeatures.register +local otftables = otf.tables or { } +otf.tables = otftables + local allocate = utilities.storage.allocate registerotffeature { @@ -89,3 +91,68 @@ registerotffeature { } } +-- here (as also in generic + +otftables.featuretypes = allocate { + gpos_single = "position", + gpos_pair = "position", + gpos_cursive = "position", + gpos_mark2base = "position", + gpos_mark2ligature = "position", + gpos_mark2mark = "position", + gpos_context = "position", + gpos_contextchain = "position", + gsub_single = "substitution", + gsub_multiple = "substitution", + gsub_alternate = "substitution", + gsub_ligature = "substitution", + gsub_context = "substitution", + gsub_contextchain = "substitution", + gsub_reversecontextchain = "substitution", + gsub_reversesub = "substitution", +} + +function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts) + if featuretype == "position" then + local default = scripts.dflt + if default then + if autoscript == "position" or autoscript == true then + return default + else + report_otf("script feature %s not applied, enable default positioning") + end + else + -- no positioning at all + end + elseif featuretype == "substitution" then + local default = scripts.dflt + if default then + if autoscript == "substitution" or autoscript == true then + return default + end + end + end +end + +function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages) + if featuretype == "position" then + local default = languages.dflt + if default then + if autolanguage == "position" or autolanguage == true then + return default + else + report_otf("language feature %s not applied, enable default positioning") + end + else + -- no positioning at all + end + elseif featuretype == "substitution" then + local default = languages.dflt + if default then + if autolanguage == "substitution" or autolanguage == true then + return default + end + end + end +end + diff --git a/src/fontloader/misc/fontloader-fonts-otn.lua b/src/fontloader/misc/fontloader-font-otn.lua index 7fafadb..b48aea7 100644 --- a/src/fontloader/misc/fontloader-fonts-otn.lua +++ b/src/fontloader/misc/fontloader-font-otn.lua @@ -132,7 +132,7 @@ results in different tables.</p> -- gpos_context ok -- -- gpos_contextchain ok -- -- --- todo: contextpos and contextsub and class stuff +-- todo: contextpos -- -- actions: -- @@ -212,7 +212,9 @@ local tonut = nuts.tonut local getfield = nuts.getfield local setfield = nuts.setfield local getnext = nuts.getnext +local setnext = nuts.setnext local getprev = nuts.getprev +local setprev = nuts.setprev local getid = nuts.getid local getattr = nuts.getattr local setattr = nuts.setattr @@ -220,7 +222,9 @@ local getprop = nuts.getprop local setprop = nuts.setprop local getfont = nuts.getfont local getsubtype = nuts.getsubtype +local setsubtype = nuts.setsubtype local getchar = nuts.getchar +local setchar = nuts.setchar local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after @@ -243,7 +247,6 @@ local wildcard = "*" local default = "dflt" local nodecodes = nodes.nodecodes -local whatcodes = nodes.whatcodes local glyphcodes = nodes.glyphcodes local disccodes = nodes.disccodes @@ -251,9 +254,9 @@ local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue local disc_code = nodecodes.disc local math_code = nodecodes.math +local dir_code = nodecodes.dir +local localpar_code = nodecodes.localpar -local dir_code = whatcodes.dir -local localpar_code = whatcodes.localpar local discretionary_code = disccodes.discretionary local ligature_code = glyphcodes.ligature @@ -412,8 +415,8 @@ local function flattendisk(head,disc) if replace then if next then local tail = find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) end return replace, replace elseif next then @@ -427,17 +430,17 @@ local function flattendisk(head,disc) if replace then local tail = find_node_tail(replace) if next then - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) end - setfield(prev,"next",replace) - setfield(replace,"prev",prev) + setnext(prev,replace) + setprev(replace,prev) return head, replace else if next then - setfield(next,"prev",prev) + setprev(next,prev) end - setfield(prev,"next",next) + setnext(prev,next) return head, next end end @@ -451,14 +454,14 @@ local function appenddisc(disc,list) local ptail = find_node_tail(post) local rtail = find_node_tail(replace) if post then - setfield(ptail,"next",phead) - setfield(phead,"prev",ptail) + setnext(ptail,phead) + setprev(phead,ptail) else setfield(disc,"post",phead) end if replace then - setfield(rtail,"next",rhead) - setfield(rhead,"prev",rtail) + setnext(rtail,rhead) + setprev(rhead,rtail) else setfield(disc,"replace",rhead) end @@ -472,24 +475,24 @@ local function markstoligature(kind,lookupname,head,start,stop,char) else local prev = getprev(start) local next = getnext(stop) - setfield(start,"prev",nil) - setfield(stop,"next",nil) + setprev(start,nil) + setnext(stop,nil) local base = copy_glyph(start) if head == start then head = base end resetinjection(base) - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) + setchar(base,char) + setsubtype(base,ligature_code) setfield(base,"components",start) if prev then - setfield(prev,"next",base) + setnext(prev,base) end if next then - setfield(next,"prev",base) + setprev(next,base) end - setfield(base,"next",next) - setfield(base,"prev",prev) + setnext(base,next) + setprev(base,prev) return head, base end end @@ -528,7 +531,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end if start == stop and getchar(start) == char then resetinjection(start) - setfield(start,"char",char) + setchar(start,char) return head, start end -- needs testing (side effects): @@ -541,24 +544,24 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local prev = getprev(start) local next = getnext(stop) local comp = start - setfield(start,"prev",nil) - setfield(stop,"next",nil) + setprev(start,nil) + setnext(stop,nil) local base = copy_glyph(start) if start == head then head = base end resetinjection(base) - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) + setchar(base,char) + setsubtype(base,ligature_code) setfield(base,"components",comp) -- start can have components ... do we need to flush? if prev then - setfield(prev,"next",base) + setnext(prev,base) end if next then - setfield(next,"prev",base) + setprev(next,base) end - setfield(base,"prev",prev) - setfield(base,"next",next) + setprev(base,prev) + setnext(base,next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -602,8 +605,8 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end else -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks - local discprev = getfield(discfound,"prev") - local discnext = getfield(discfound,"next") + local discprev = getprev(discfound) + local discnext = getnext(discfound) if discprev and discnext then -- we assume normalization in context, and don't care about generic ... especially -- \- can give problems as there we can have a negative char but that won't match @@ -612,34 +615,34 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local post = getfield(discfound,"post") local replace = getfield(discfound,"replace") if not replace then -- todo: signal simple hyphen - local prev = getfield(base,"prev") + local prev = getprev(base) local copied = copy_node_list(comp) - setfield(discnext,"prev",nil) -- also blocks funny assignments - setfield(discprev,"next",nil) -- also blocks funny assignments + setprev(discnext,nil) -- also blocks funny assignments + setnext(discprev,nil) -- also blocks funny assignments if pre then - setfield(discprev,"next",pre) - setfield(pre,"prev",discprev) + setnext(discprev,pre) + setprev(pre,discprev) end pre = comp if post then local tail = find_node_tail(post) - setfield(tail,"next",discnext) - setfield(discnext,"prev",tail) - setfield(post,"prev",nil) + setnext(tail,discnext) + setprev(discnext,tail) + setprev(post,nil) else post = discnext end - setfield(prev,"next",discfound) - setfield(discfound,"prev",prev) - setfield(discfound,"next",next) - setfield(next,"prev",discfound) - setfield(base,"next",nil) - setfield(base,"prev",nil) + setnext(prev,discfound) + setprev(discfound,prev) + setnext(discfound,next) + setprev(next,discfound) + setnext(base,nil) + setprev(base,nil) setfield(base,"components",copied) setfield(discfound,"pre",pre) setfield(discfound,"post",post) setfield(discfound,"replace",base) - setfield(discfound,"subtype",discretionary_code) + setsubtype(discfound,discretionary_code) base = prev -- restart end end @@ -651,7 +654,7 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) local nofmultiples = #multiple if nofmultiples > 0 then resetinjection(start) - setfield(start,"char",multiple[1]) + setchar(start,multiple[1]) if nofmultiples > 1 then local sn = getnext(start) for k=2,nofmultiples do -- todo: use insert_node @@ -662,13 +665,13 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) -- end local n = copy_node(start) -- ignore components resetinjection(n) - setfield(n,"char",multiple[k]) - setfield(n,"prev",start) - setfield(n,"next",sn) + setchar(n,multiple[k]) + setprev(n,start) + setnext(n,sn) if sn then - setfield(sn,"prev",n) + setprev(sn,n) end - setfield(start,"next",n) + setnext(start,n) start = n end end @@ -720,7 +723,7 @@ function handlers.gsub_single(head,start,kind,lookupname,replacement) logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) end resetinjection(start) - setfield(start,"char",replacement) + setchar(start,replacement) return head, start, true end @@ -732,7 +735,7 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment) end resetinjection(start) - setfield(start,"char",choice) + setchar(start,choice) else if trace_alternatives then logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment) @@ -830,7 +833,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else -- weird but happens (in some arabic font) resetinjection(start) - setfield(start,"char",lig) + setchar(start,lig) if trace_ligatures then logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end @@ -1207,7 +1210,7 @@ function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,loo logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) end resetinjection(start) - setfield(start,"char",replacement) + setchar(start,replacement) return head, start, true else return head, start, false @@ -1238,7 +1241,7 @@ as less as needed but that would also make the code even more messy.</p> -- repeat -- start x x m x x stop => start m -- local next = getnext(start) -- if not marks[getchar(next)] then --- local components = getfield(next,"components") +-- local components = getnext(next,"components") -- if components then -- probably not needed -- flush_node_list(components) -- end @@ -1291,7 +1294,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) end resetinjection(current) - setfield(current,"char",replacement) + setchar(current,replacement) end end return head, start, true @@ -1368,7 +1371,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment) end resetinjection(start) - setfield(start,"char",choice) + setchar(start,choice) else if trace_alternatives then logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment) @@ -1936,13 +1939,13 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku local tail = nil if prev then tail = prev - setfield(current,"prev",sweepnode) + setprev(current,sweepnode) else tail = find_node_tail(head) end - setfield(sweepnode,"next",current) - setfield(head,"prev",nil) - setfield(tail,"next",nil) + setnext(sweepnode,current) + setprev(head,nil) + setnext(tail,nil) appenddisc(sweepnode,head) end end @@ -2036,12 +2039,12 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku cprev = getprev(cprev) end - setfield(lookaheaddisc,"prev",cprev) + setprev(lookaheaddisc,cprev) if cprev then - setfield(cprev,"next",lookaheaddisc) + setnext(cprev,lookaheaddisc) end - setfield(cf,"prev",nil) - setfield(cl,"next",nil) + setprev(cf,nil) + setnext(cl,nil) if startishead then head = lookaheaddisc end @@ -2064,13 +2067,13 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku new, cnew, ok = chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) end if pre then - setfield(cl,"next",pre) - setfield(pre,"prev",cl) + setnext(cl,pre) + setprev(pre,cl) end if replace then local tail = find_node_tail(new) - setfield(tail,"next",replace) - setfield(replace,"prev",tail) + setnext(tail,replace) + setprev(replace,tail) end setfield(lookaheaddisc,"pre",cf) -- also updates tail setfield(lookaheaddisc,"replace",new) -- also updates tail @@ -2092,11 +2095,11 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku cnext = getnext(cnext) end if cnext then - setfield(cnext,"prev",backtrackdisc) + setprev(cnext,backtrackdisc) end - setfield(backtrackdisc,"next",cnext) - setfield(cf,"prev",nil) - setfield(cl,"next",nil) + setnext(backtrackdisc,cnext) + setprev(cf,nil) + setnext(cl,nil) local replace = getfield(backtrackdisc,"replace") local post = getfield(backtrackdisc,"post") local new = copy_node_list(cf) @@ -2116,15 +2119,15 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku end if post then local tail = find_node_tail(post) - setfield(tail,"next",cf) - setfield(cf,"prev",tail) + setnext(tail,cf) + setprev(cf,tail) else post = cf end if replace then local tail = find_node_tail(replace) - setfield(tail,"next",new) - setfield(new,"prev",tail) + setnext(tail,new) + setprev(new,tail) else replace = new end @@ -2700,26 +2703,49 @@ otf.chainhandlers = { verbose = verbose_handle_contextchain, } +local handle_contextchain = nil + +-- normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) + +function chained_contextchain(head,start,stop,...) + local steps = currentlookup.steps + local nofsteps = currentlookup.nofsteps + if nofsteps > 1 then + reportmoresteps(dataset,sequence) + end + return handle_contextchain(head,start,...) +end + function otf.setcontextchain(method) if not method or method == "normal" or not otf.chainhandlers[method] then - if handlers.contextchain then -- no need for a message while making the format + if handle_contextchain then -- no need for a message while making the format logwarning("installing normal contextchain handler") end - handlers.contextchain = normal_handle_contextchain + handle_contextchain = normal_handle_contextchain else logwarning("installing contextchain handler %a",method) local handler = otf.chainhandlers[method] - handlers.contextchain = function(...) + handle_contextchain = function(...) return handler(currentfont,...) -- hm, get rid of ... end end - handlers.gsub_context = handlers.contextchain - handlers.gsub_contextchain = handlers.contextchain - handlers.gsub_reversecontextchain = handlers.contextchain - handlers.gpos_contextchain = handlers.contextchain - handlers.gpos_context = handlers.contextchain + + handlers.gsub_context = handle_contextchain + handlers.gsub_contextchain = handle_contextchain + handlers.gsub_reversecontextchain = handle_contextchain + handlers.gpos_contextchain = handle_contextchain + handlers.gpos_context = handle_contextchain + + handlers.contextchain = handle_contextchain + end +chainprocs.gsub_context = chained_contextchain +chainprocs.gsub_contextchain = chained_contextchain +chainprocs.gsub_reversecontextchain = chained_contextchain +chainprocs.gpos_contextchain = chained_contextchain +chainprocs.gpos_context = chained_contextchain + otf.setcontextchain() local missing = { } -- we only report once @@ -2759,20 +2785,33 @@ end) -- fonts.hashes.lookups = lookuphashes -local autofeatures = fonts.analyzers.features -- was: constants +local autofeatures = fonts.analyzers.features +local featuretypes = otf.tables.featuretypes +local defaultscript = otf.features.checkeddefaultscript +local defaultlanguage = otf.features.checkeddefaultlanguage -local function initialize(sequence,script,language,enabled) +local function initialize(sequence,script,language,enabled,autoscript,autolanguage) local features = sequence.features if features then local order = sequence.order if order then - for i=1,#order do -- - local kind = order[i] -- + local featuretype = featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind = order[i] local valid = enabled[kind] if valid then - local scripts = features[kind] -- - local languages = scripts[script] or scripts[wildcard] - if languages and (languages[language] or languages[wildcard]) then + local scripts = features[kind] + local languages = scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled = languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then return { valid, autofeatures[kind] or false, sequence, kind } end end @@ -2785,11 +2824,13 @@ local function initialize(sequence,script,language,enabled) end function otf.dataset(tfmdata,font) -- generic variant, overloaded in context - local shared = tfmdata.shared - local properties = tfmdata.properties - local language = properties.language or "dflt" - local script = properties.script or "dflt" - local enabled = shared.features + local shared = tfmdata.shared + local properties = tfmdata.properties + local language = properties.language or "dflt" + local script = properties.script or "dflt" + local enabled = shared.features + local autoscript = enabled and enabled.autoscript + local autolanguage = enabled and enabled.autolanguage local res = resolved[font] if not res then res = { } @@ -2808,7 +2849,7 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context rs[language] = rl local sequences = tfmdata.resources.sequences for s=1,#sequences do - local v = enabled and initialize(sequences[s],script,language,enabled) + local v = enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) if v then rl[#rl+1] = v end @@ -2856,11 +2897,11 @@ local function kernrun(disc,run) -- go on elseif prev then local nest = getprev(pre) - setfield(pre,"prev",prev) - setfield(prev,"next",pre) + setprev(pre,prev) + setnext(prev,pre) run(prevmarks,"preinjections") - setfield(pre,"prev",nest) - setfield(prev,"next",disc) + setprev(pre,nest) + setnext(prev,disc) else run(pre,"preinjections") end @@ -2869,48 +2910,48 @@ local function kernrun(disc,run) -- go on elseif next then local tail = find_node_tail(post) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) run(post,"postinjections",next) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) else run(post,"postinjections") end -- if not replace and prev and next then -- this should be already done by discfound - setfield(prev,"next",next) - setfield(next,"prev",prev) + setnext(prev,next) + setprev(next,prev) run(prevmarks,"injections",next) - setfield(prev,"next",disc) - setfield(next,"prev",disc) + setnext(prev,disc) + setprev(next,disc) elseif prev and next then local tail = find_node_tail(replace) local nest = getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setprev(replace,prev) + setnext(prev,replace) + setnext(tail,next) + setprev(next,tail) run(prevmarks,"replaceinjections",next) - setfield(replace,"prev",nest) - setfield(prev,"next",disc) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setprev(replace,nest) + setnext(prev,disc) + setnext(tail,nil) + setprev(next,disc) elseif prev then local nest = getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) + setprev(replace,prev) + setnext(prev,replace) run(prevmarks,"replaceinjections") - setfield(replace,"prev",nest) - setfield(prev,"next",disc) + setprev(replace,nest) + setnext(prev,disc) elseif next then local tail = find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) run(replace,"replaceinjections",next) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) else run(replace,"replaceinjections") end @@ -2967,21 +3008,21 @@ local function testrun(disc,trun,crun) -- use helper -- only look ahead local tail = find_node_tail(replace) -- local nest = getprev(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) if trun(replace,next) then setfield(disc,"replace",nil) -- beware, side effects of nest so first - setfield(prev,"next",replace) - setfield(replace,"prev",prev) - setfield(next,"prev",tail) - setfield(tail,"next",next) - setfield(disc,"prev",nil) - setfield(disc,"next",nil) + setnext(prev,replace) + setprev(replace,prev) + setprev(next,tail) + setnext(tail,next) + setprev(disc,nil) + setnext(disc,nil) flush_node_list(disc) return replace -- restart else - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) end else -- weird case @@ -3003,11 +3044,11 @@ local function discrun(disc,drun,krun) report_run("disc") -- will be more detailed end if next and prev then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) + setnext(prev,next) + -- setprev(next,prev) drun(prev) - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) + setnext(prev,disc) + -- setprev(next,disc) end -- local pre = getfield(disc,"pre") @@ -3015,11 +3056,11 @@ local function discrun(disc,drun,krun) -- go on elseif prev then local nest = getprev(pre) - setfield(pre,"prev",prev) - setfield(prev,"next",pre) + setprev(pre,prev) + setnext(prev,pre) krun(prev,"preinjections") - setfield(pre,"prev",nest) - setfield(prev,"next",disc) + setprev(pre,nest) + setnext(prev,disc) else krun(pre,"preinjections") end @@ -3319,6 +3360,41 @@ local function featuresprocessor(head,font,attr) end elseif id == math_code then start = getnext(end_of_math(start)) + elseif id == dir_code then + local dir = getfield(start,"dir") + if dir == "+TLT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = 1 + elseif dir == "+TRT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = -1 + elseif dir == "-TLT" or dir == "-TRT" then + topstack = topstack - 1 + rlmode = dirstack[topstack] == "+TRT" and -1 or 1 + else + rlmode = rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + start = getnext(start) + elseif id == localpar_code then + local dir = getfield(start,"dir") + if dir == "TRT" then + rlparmode = -1 + elseif dir == "TLT" then + rlparmode = 1 + else + rlparmode = 0 + end + -- one might wonder if the par dir should be looked at, so we might as well drop the next line + rlmode = rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + start = getnext(start) else start = getnext(start) end @@ -3554,6 +3630,40 @@ local function featuresprocessor(head,font,attr) end elseif id == math_code then start = getnext(end_of_math(start)) + elseif id == dir_code then + local dir = getfield(start,"dir") + if dir == "+TLT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = 1 + elseif dir == "+TRT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = -1 + elseif dir == "-TLT" or dir == "-TRT" then + topstack = topstack - 1 + rlmode = dirstack[topstack] == "+TRT" and -1 or 1 + else + rlmode = rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + start = getnext(start) + elseif id == localpar_code then + local dir = getfield(start,"dir") + if dir == "TRT" then + rlparmode = -1 + elseif dir == "TLT" then + rlparmode = 1 + else + rlparmode = 0 + end + rlmode = rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + start = getnext(start) else start = getnext(start) end @@ -3723,10 +3833,10 @@ local function split(replacement,original) return result end -local valid = { - coverage = { chainsub = true, chainpos = true, contextsub = true }, +local valid = { -- does contextpos work? + coverage = { chainsub = true, chainpos = true, contextsub = true, contextpos = true }, reversecoverage = { reversesub = true }, - glyphs = { chainsub = true, chainpos = true }, + glyphs = { chainsub = true, chainpos = true, contextsub = true, contextpos = true }, } local function prepare_contextchains(tfmdata) @@ -3784,7 +3894,10 @@ local function prepare_contextchains(tfmdata) sequence[nofsequences] = after[n] end end +--[[phg-- Hard patch: This crashes, see https://github.com/lualatex/luaotfload/issues/303 if sequence[1] then +--phg]]-- + if sequence[start] then -- Replacements only happen with reverse lookups as they are single only. We -- could pack them into current (replacement value instead of true) and then -- use sequence[start] instead but it's somewhat ugly. diff --git a/src/fontloader/misc/fontloader-fonts-def.lua b/src/fontloader/misc/fontloader-fonts-def.lua index 0c2f0db..f0941ec 100644 --- a/src/fontloader/misc/fontloader-fonts-def.lua +++ b/src/fontloader/misc/fontloader-fonts-def.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['luatex-font-def'] = { +if not modules then modules = { } end modules ['luatex-fonts-def'] = { version = 1.001, comment = "companion to luatex-*.tex", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", diff --git a/src/fontloader/misc/fontloader-fonts-ota.lua b/src/fontloader/misc/fontloader-fonts-ota.lua index f083fe0..256ead5 100644 --- a/src/fontloader/misc/fontloader-fonts-ota.lua +++ b/src/fontloader/misc/fontloader-fonts-ota.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['font-otx'] = { +if not modules then modules = { } end modules ['luatex-fonts-ota'] = { version = 1.001, comment = "companion to font-otf.lua (analysing)", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -24,7 +24,6 @@ local methods = allocate() analyzers.initializers = initializers analyzers.methods = methods -analyzers.useunicodemarks = false local a_state = attributes.private('state') @@ -98,8 +97,9 @@ local features = { pstf = s_pstf, } -analyzers.states = states -analyzers.features = features +analyzers.states = states +analyzers.features = features +analyzers.useunicodemarks = false -- todo: analyzers per script/lang, cross font, so we need an font id hash -> script -- e.g. latin -> hyphenate, arab -> 1/2/3 analyze -- its own namespace @@ -117,7 +117,10 @@ function analyzers.setstate(head,font) local char = getchar(current) local d = descriptions[char] if d then - if d.class == "mark" or (useunicodemarks and categories[char] == "mn") then + if d.class == "mark" then + done = true + setprop(current,a_state,s_mark) + elseif useunicodemarks and categories[char] == "mn" then done = true setprop(current,a_state,s_mark) elseif n == 0 then @@ -136,7 +139,9 @@ function analyzers.setstate(head,font) first, last, n = nil, nil, 0 end elseif id == disc_code then - -- always in the middle + -- always in the middle .. it doesn't make much sense to assign a property + -- here ... we might at some point decide to flag the components when present + -- but even then it's kind of bogus setprop(current,a_state,s_medi) last = current else -- finish @@ -213,17 +218,6 @@ registerotffeature { methods.latn = analyzers.setstate --- This info eventually can go into char-def and we will have a state --- table for generic then (unicode recognized all states but in practice --- only has only --- --- isolated : isol --- final : isol_fina --- medial : isol_fina_medi_init --- --- so in practice, without analyzer it's rather useless info which is --- why having it in char-def makes only sense for special purposes (like) --- like tracing cq. visualizing. local tatweel = 0x0640 local zwnj = 0x200C @@ -344,8 +338,6 @@ local medial = { -- isol_fina_medi_init local arab_warned = { } --- todo: gref - local function warning(current,what) local char = getchar(current) if not arab_warned[char] then diff --git a/src/fontloader/misc/fontloader-fonts.lua b/src/fontloader/misc/fontloader-fonts.lua index f18ba35..2e34fb8 100644 --- a/src/fontloader/misc/fontloader-fonts.lua +++ b/src/fontloader/misc/fontloader-fonts.lua @@ -215,9 +215,11 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('font-oti.lua') loadmodule('font-otf.lua') loadmodule('font-otb.lua') - loadmodule('luatex-fonts-inj.lua') -- normally the same as font-inj.lua + ----------('luatex-fonts-inj.lua') -- normally the same as font-inj.lua / beware loadmodule is parsed + loadmodule('font-inj.lua') loadmodule('luatex-fonts-ota.lua') - loadmodule('luatex-fonts-otn.lua') -- normally the same as font-otn.lua + ----------('luatex-fonts-otn.lua') -- normally the same as font-otn.lua / beware loadmodule is parsed + loadmodule('font-otn.lua') loadmodule('font-otp.lua') loadmodule('luatex-fonts-lua.lua') loadmodule('font-def.lua') -- this code (stripped) might end up in luatex-fonts-def.lua diff --git a/src/fontloader/misc/fontloader-languages.lua b/src/fontloader/misc/fontloader-languages.lua index 1ea8c1f..cecd60c 100644 --- a/src/fontloader/misc/fontloader-languages.lua +++ b/src/fontloader/misc/fontloader-languages.lua @@ -16,28 +16,33 @@ function languages.loadpatterns(tag) if not loaded[tag] then loaded[tag] = 0 local filename = kpse.find_file("lang-" .. tag .. ".lua") - if filename and filename == "" then - print("<unknown language file for: " .. tag .. ">") + if not filename or filename == "" then + texio.write("<unknown language file for: " .. tag .. ">") else local whatever = loadfile(filename) if type(whatever) == "function" then whatever = whatever() if type(whatever) == "table" then + texio.write("<language file: " .. tag .. ">") local characters = whatever.patterns.characters or "" local patterns = whatever.patterns.data or "" local exceptions = whatever.exceptions.data or "" - local language = lang.new() for b in string.utfvalues(characters) do + -- what about uppercase +-- lang.sethjcode(b,b) tex.setlccode(b,b) end + local language = lang.new() lang.patterns(language, patterns) lang.hyphenation(language, exceptions) loaded[tag] = lang.id(language) else - print("<invalid language table: " .. tag .. ">") + texio.write("<invalid language table: " .. tag .. ">") + os.exit() end else - print("<invalid language file: " .. tag .. ">") + texio.write("<invalid language file: " .. tag .. ">") + os.exit() end end end diff --git a/src/fontloader/misc/fontloader-languages.tex b/src/fontloader/misc/fontloader-languages.tex index 9778da3..a087b30 100644 --- a/src/fontloader/misc/fontloader-languages.tex +++ b/src/fontloader/misc/fontloader-languages.tex @@ -8,6 +8,8 @@ %D Cf. discussion on \CONTEXT\ list: +% \savinghyphcodes1 + \directlua { dofile(kpse.find_file("luatex-languages.lua","tex")) } diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua index ae36617..46de1d0 100644 --- a/src/fontloader/runtime/fontloader-reference.lua +++ b/src/fontloader/runtime/fontloader-reference.lua @@ -1,6 +1,6 @@ --- merged file : luatex-fonts-merged.lua --- parent file : luatex-fonts.lua --- merge date : 11/19/15 19:13:15 +-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua +-- parent file : c:/data/develop/context/sources/luatex-fonts.lua +-- merge date : 12/21/15 16:29:15 do -- begin closure to overcome local limits and interference @@ -3901,15 +3901,21 @@ end nodes={} nodes.pool={} nodes.handlers={} -local nodecodes={} for k,v in next,node.types () do nodecodes[string.gsub(v,"_","")]=k end -local whatcodes={} for k,v in next,node.whatsits() do whatcodes[string.gsub(v,"_","")]=k end -local glyphcodes={ [0]="character","glyph","ligature","ghost","left","right" } -local disccodes={ [0]="discretionary","explicit","automatic","regular","first","second" } -for i=0,#glyphcodes do glyphcodes[glyphcodes[i]]=i end -for i=0,#disccodes do disccodes [disccodes [i]]=i end +local nodecodes={} +local glyphcodes=node.subtypes("glyph") +local disccodes=node.subtypes("disc") +for k,v in next,node.types() do + v=string.gsub(v,"_","") + nodecodes[k]=v + nodecodes[v]=k +end +for i=0,#glyphcodes do + glyphcodes[glyphcodes[i]]=i +end +for i=0,#disccodes do + disccodes[disccodes[i]]=i +end nodes.nodecodes=nodecodes -nodes.whatcodes=whatcodes -nodes.whatsitcodes=whatcodes nodes.glyphcodes=glyphcodes nodes.disccodes=disccodes local free_node=node.free @@ -3973,7 +3979,6 @@ nodes.traverse_id=node.traverse_id nodes.slide=node.slide nodes.vpack=node.vpack nodes.first_glyph=node.first_glyph -nodes.first_character=node.first_character nodes.has_glyph=node.has_glyph or node.first_glyph nodes.current_attr=node.current_attr nodes.do_ligature_n=node.do_ligature_n @@ -4002,13 +4007,27 @@ local setfield=direct.setfield nuts.getfield=getfield nuts.setfield=setfield nuts.getnext=direct.getnext +nuts.setnext=direct.setnext nuts.getprev=direct.getprev +nuts.setprev=direct.setprev +nuts.getboth=direct.getboth +nuts.setboth=direct.setboth nuts.getid=direct.getid -nuts.getattr=getfield +nuts.getattr=direct.get_attribute or direct.has_attribute or getfield nuts.setattr=setfield nuts.getfont=direct.getfont +nuts.setfont=direct.setfont nuts.getsubtype=direct.getsubtype +nuts.setsubtype=direct.setsubtype or function(n,s) setfield(n,"subtype",s) end nuts.getchar=direct.getchar +nuts.setchar=direct.setchar +nuts.getdisc=direct.getdisc +nuts.setdisc=direct.setdisc +nuts.setlink=direct.setlink +nuts.getlist=direct.getlist +nuts.setlist=direct.setlist or function(n,l) setfield(n,"list",l) end +nuts.getleader=direct.getleader +nuts.setleader=direct.setleader or function(n,l) setfield(n,"leader",l) end nuts.insert_before=direct.insert_before nuts.insert_after=direct.insert_after nuts.delete=direct.delete @@ -4022,6 +4041,9 @@ nuts.is_node=direct.is_node nuts.end_of_math=direct.end_of_math nuts.traverse=direct.traverse nuts.traverse_id=direct.traverse_id +nuts.traverse_char=direct.traverse_char +nuts.ligaturing=direct.ligaturing +nuts.kerning=direct.kerning nuts.getprop=nuts.getattr nuts.setprop=nuts.setattr local new_nut=direct.new @@ -7048,8 +7070,9 @@ local fonts=fonts local constructors=fonts.constructors local otf=constructors.newhandler("otf") local otffeatures=constructors.newfeatures("otf") -local otftables=otf.tables local registerotffeature=otffeatures.register +local otftables=otf.tables or {} +otf.tables=otftables local allocate=utilities.storage.allocate registerotffeature { name="features", @@ -7113,6 +7136,64 @@ registerotffeature { node=setscript, } } +otftables.featuretypes=allocate { + gpos_single="position", + gpos_pair="position", + gpos_cursive="position", + gpos_mark2base="position", + gpos_mark2ligature="position", + gpos_mark2mark="position", + gpos_context="position", + gpos_contextchain="position", + gsub_single="substitution", + gsub_multiple="substitution", + gsub_alternate="substitution", + gsub_ligature="substitution", + gsub_context="substitution", + gsub_contextchain="substitution", + gsub_reversecontextchain="substitution", + gsub_reversesub="substitution", +} +function otffeatures.checkeddefaultscript(featuretype,autoscript,scripts) + if featuretype=="position" then + local default=scripts.dflt + if default then + if autoscript=="position" or autoscript==true then + return default + else + report_otf("script feature %s not applied, enable default positioning") + end + else + end + elseif featuretype=="substitution" then + local default=scripts.dflt + if default then + if autoscript=="substitution" or autoscript==true then + return default + end + end + end +end +function otffeatures.checkeddefaultlanguage(featuretype,autolanguage,languages) + if featuretype=="position" then + local default=languages.dflt + if default then + if autolanguage=="position" or autolanguage==true then + return default + else + report_otf("language feature %s not applied, enable default positioning") + end + else + end + elseif featuretype=="substitution" then + local default=languages.dflt + if default then + if autolanguage=="substitution" or autolanguage==true then + return default + end + end + end +end end -- closure @@ -7156,7 +7237,7 @@ local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.819 +otf.version=2.820 otf.cache=containers.define("fonts","otf",otf.version,true) local hashes=fonts.hashes local definers=fonts.definers @@ -9492,7 +9573,7 @@ otf.coverup={ kern=justset, }, register=function(coverage,lookuptype,format,feature,n,descriptions,resources) - local name=formatters["ctx_%s_%s"](feature,n) + local name=formatters["ctx_%s_%s_%s"](feature,lookuptype,n) if lookuptype=="kern" then resources.lookuptypes[name]="position" else @@ -10224,8 +10305,10 @@ function injections.resetcounts() end function injections.reset(n) local p=rawget(properties,n) - if p and rawget(p,"injections") then - p.injections=nil + if p then + p.injections=false + else + properties[n]=false end end function injections.copy(target,source) @@ -10242,10 +10325,17 @@ function injections.copy(target,source) injections=si, } end + elseif tp then + tp.injections=false else - if tp then - tp.injections=nil - end + properties[target]={ injections={} } + end + else + local tp=rawget(properties,target) + if tp then + tp.injections=false + else + properties[target]=false end end end @@ -10480,10 +10570,11 @@ local function show(n,what,nested,symbol) local markx=i.markx or 0 local marky=i.marky or 0 local markdir=i.markdir or 0 - local markbase=i.markbase or 0 + local markbase=i.markbase or 0 local cursivex=i.cursivex or 0 local cursivey=i.cursivey or 0 local ligaindex=i.ligaindex or 0 + local cursbase=i.cursiveanchor local margin=nested and 4 or 2 if rightkern~=0 or yoffset~=0 then report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset) @@ -10494,7 +10585,13 @@ local function show(n,what,nested,symbol) report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no") end if cursivex~=0 or cursivey~=0 then - report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + if cursbase then + report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey) + else + report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey) + end + elseif cursbase then + report_injections("%w%s curs: base",margin,symbol) end if ligaindex~=0 then report_injections("%w%s liga: index %i",margin,symbol,ligaindex) @@ -11177,7 +11274,7 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['font-otx']={ +if not modules then modules={} end modules ['luatex-fonts-ota']={ version=1.001, comment="companion to font-otf.lua (analysing)", author="Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -11194,7 +11291,6 @@ local initializers=allocate() local methods=allocate() analyzers.initializers=initializers analyzers.methods=methods -analyzers.useunicodemarks=false local a_state=attributes.private('state') local nuts=nodes.nuts local tonut=nuts.tonut @@ -11250,6 +11346,7 @@ local features={ } analyzers.states=states analyzers.features=features +analyzers.useunicodemarks=false function analyzers.setstate(head,font) local useunicodemarks=analyzers.useunicodemarks local tfmdata=fontdata[font] @@ -11263,7 +11360,10 @@ function analyzers.setstate(head,font) local char=getchar(current) local d=descriptions[char] if d then - if d.class=="mark" or (useunicodemarks and categories[char]=="mn") then + if d.class=="mark" then + done=true + setprop(current,a_state,s_mark) + elseif useunicodemarks and categories[char]=="mn" then done=true setprop(current,a_state,s_mark) elseif n==0 then @@ -11612,7 +11712,9 @@ local tonut=nuts.tonut local getfield=nuts.getfield local setfield=nuts.setfield local getnext=nuts.getnext +local setnext=nuts.setnext local getprev=nuts.getprev +local setprev=nuts.setprev local getid=nuts.getid local getattr=nuts.getattr local setattr=nuts.setattr @@ -11620,7 +11722,9 @@ local getprop=nuts.getprop local setprop=nuts.setprop local getfont=nuts.getfont local getsubtype=nuts.getsubtype +local setsubtype=nuts.setsubtype local getchar=nuts.getchar +local setchar=nuts.setchar local insert_node_before=nuts.insert_before local insert_node_after=nuts.insert_after local delete_node=nuts.delete @@ -11639,15 +11743,14 @@ local zwj=0x200D local wildcard="*" local default="dflt" local nodecodes=nodes.nodecodes -local whatcodes=nodes.whatcodes local glyphcodes=nodes.glyphcodes local disccodes=nodes.disccodes local glyph_code=nodecodes.glyph local glue_code=nodecodes.glue local disc_code=nodecodes.disc local math_code=nodecodes.math -local dir_code=whatcodes.dir -local localpar_code=whatcodes.localpar +local dir_code=nodecodes.dir +local localpar_code=nodecodes.localpar local discretionary_code=disccodes.discretionary local ligature_code=glyphcodes.ligature local privateattribute=attributes.private @@ -11767,8 +11870,8 @@ local function flattendisk(head,disc) if replace then if next then local tail=find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) end return replace,replace elseif next then @@ -11782,17 +11885,17 @@ local function flattendisk(head,disc) if replace then local tail=find_node_tail(replace) if next then - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) end - setfield(prev,"next",replace) - setfield(replace,"prev",prev) + setnext(prev,replace) + setprev(replace,prev) return head,replace else if next then - setfield(next,"prev",prev) + setprev(next,prev) end - setfield(prev,"next",next) + setnext(prev,next) return head,next end end @@ -11805,14 +11908,14 @@ local function appenddisc(disc,list) local ptail=find_node_tail(post) local rtail=find_node_tail(replace) if post then - setfield(ptail,"next",phead) - setfield(phead,"prev",ptail) + setnext(ptail,phead) + setprev(phead,ptail) else setfield(disc,"post",phead) end if replace then - setfield(rtail,"next",rhead) - setfield(rhead,"prev",rtail) + setnext(rtail,rhead) + setprev(rhead,rtail) else setfield(disc,"replace",rhead) end @@ -11823,24 +11926,24 @@ local function markstoligature(kind,lookupname,head,start,stop,char) else local prev=getprev(start) local next=getnext(stop) - setfield(start,"prev",nil) - setfield(stop,"next",nil) + setprev(start,nil) + setnext(stop,nil) local base=copy_glyph(start) if head==start then head=base end resetinjection(base) - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) + setchar(base,char) + setsubtype(base,ligature_code) setfield(base,"components",start) if prev then - setfield(prev,"next",base) + setnext(prev,base) end if next then - setfield(next,"prev",base) + setprev(next,base) end - setfield(base,"next",next) - setfield(base,"prev",prev) + setnext(base,next) + setprev(base,prev) return head,base end end @@ -11868,7 +11971,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end if start==stop and getchar(start)==char then resetinjection(start) - setfield(start,"char",char) + setchar(start,char) return head,start end local components=getfield(start,"components") @@ -11877,24 +11980,24 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local prev=getprev(start) local next=getnext(stop) local comp=start - setfield(start,"prev",nil) - setfield(stop,"next",nil) + setprev(start,nil) + setnext(stop,nil) local base=copy_glyph(start) if start==head then head=base end resetinjection(base) - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) + setchar(base,char) + setsubtype(base,ligature_code) setfield(base,"components",comp) if prev then - setfield(prev,"next",base) + setnext(prev,base) end if next then - setfield(next,"prev",base) + setprev(next,base) end - setfield(base,"prev",prev) - setfield(base,"next",next) + setprev(base,prev) + setnext(base,next) if not discfound then local deletemarks=markflag~="mark" local components=start @@ -11934,41 +12037,41 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun start=getnext(start) end else - local discprev=getfield(discfound,"prev") - local discnext=getfield(discfound,"next") + local discprev=getprev(discfound) + local discnext=getnext(discfound) if discprev and discnext then local pre=getfield(discfound,"pre") local post=getfield(discfound,"post") local replace=getfield(discfound,"replace") if not replace then - local prev=getfield(base,"prev") + local prev=getprev(base) local copied=copy_node_list(comp) - setfield(discnext,"prev",nil) - setfield(discprev,"next",nil) + setprev(discnext,nil) + setnext(discprev,nil) if pre then - setfield(discprev,"next",pre) - setfield(pre,"prev",discprev) + setnext(discprev,pre) + setprev(pre,discprev) end pre=comp if post then local tail=find_node_tail(post) - setfield(tail,"next",discnext) - setfield(discnext,"prev",tail) - setfield(post,"prev",nil) + setnext(tail,discnext) + setprev(discnext,tail) + setprev(post,nil) else post=discnext end - setfield(prev,"next",discfound) - setfield(discfound,"prev",prev) - setfield(discfound,"next",next) - setfield(next,"prev",discfound) - setfield(base,"next",nil) - setfield(base,"prev",nil) + setnext(prev,discfound) + setprev(discfound,prev) + setnext(discfound,next) + setprev(next,discfound) + setnext(base,nil) + setprev(base,nil) setfield(base,"components",copied) setfield(discfound,"pre",pre) setfield(discfound,"post",post) setfield(discfound,"replace",base) - setfield(discfound,"subtype",discretionary_code) + setsubtype(discfound,discretionary_code) base=prev end end @@ -11979,19 +12082,19 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) local nofmultiples=#multiple if nofmultiples>0 then resetinjection(start) - setfield(start,"char",multiple[1]) + setchar(start,multiple[1]) if nofmultiples>1 then local sn=getnext(start) for k=2,nofmultiples do local n=copy_node(start) resetinjection(n) - setfield(n,"char",multiple[k]) - setfield(n,"prev",start) - setfield(n,"next",sn) + setchar(n,multiple[k]) + setprev(n,start) + setnext(n,sn) if sn then - setfield(sn,"prev",n) + setprev(sn,n) end - setfield(start,"next",n) + setnext(start,n) start=n end end @@ -12039,7 +12142,7 @@ function handlers.gsub_single(head,start,kind,lookupname,replacement) logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) end resetinjection(start) - setfield(start,"char",replacement) + setchar(start,replacement) return head,start,true end function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence) @@ -12050,7 +12153,7 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment) end resetinjection(start) - setfield(start,"char",choice) + setchar(start,choice) else if trace_alternatives then logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment) @@ -12144,7 +12247,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) end else resetinjection(start) - setfield(start,"char",lig) + setchar(start,lig) if trace_ligatures then logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end @@ -12471,7 +12574,7 @@ function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,loo logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) end resetinjection(start) - setfield(start,"char",replacement) + setchar(start,replacement) return head,start,true else return head,start,false @@ -12503,7 +12606,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) end resetinjection(current) - setfield(current,"char",replacement) + setchar(current,replacement) end end return head,start,true @@ -12561,7 +12664,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment) end resetinjection(start) - setfield(start,"char",choice) + setchar(start,choice) else if trace_alternatives then logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment) @@ -13056,13 +13159,13 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku local tail=nil if prev then tail=prev - setfield(current,"prev",sweepnode) + setprev(current,sweepnode) else tail=find_node_tail(head) end - setfield(sweepnode,"next",current) - setfield(head,"prev",nil) - setfield(tail,"next",nil) + setnext(sweepnode,current) + setprev(head,nil) + setnext(tail,nil) appenddisc(sweepnode,head) end end @@ -13150,12 +13253,12 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku startishead=cf==head cprev=getprev(cprev) end - setfield(lookaheaddisc,"prev",cprev) + setprev(lookaheaddisc,cprev) if cprev then - setfield(cprev,"next",lookaheaddisc) + setnext(cprev,lookaheaddisc) end - setfield(cf,"prev",nil) - setfield(cl,"next",nil) + setprev(cf,nil) + setnext(cl,nil) if startishead then head=lookaheaddisc end @@ -13177,13 +13280,13 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku new,cnew,ok=chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) end if pre then - setfield(cl,"next",pre) - setfield(pre,"prev",cl) + setnext(cl,pre) + setprev(pre,cl) end if replace then local tail=find_node_tail(new) - setfield(tail,"next",replace) - setfield(replace,"prev",tail) + setnext(tail,replace) + setprev(replace,tail) end setfield(lookaheaddisc,"pre",cf) setfield(lookaheaddisc,"replace",new) @@ -13201,11 +13304,11 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku cnext=getnext(cnext) end if cnext then - setfield(cnext,"prev",backtrackdisc) + setprev(cnext,backtrackdisc) end - setfield(backtrackdisc,"next",cnext) - setfield(cf,"prev",nil) - setfield(cl,"next",nil) + setnext(backtrackdisc,cnext) + setprev(cf,nil) + setnext(cl,nil) local replace=getfield(backtrackdisc,"replace") local post=getfield(backtrackdisc,"post") local new=copy_node_list(cf) @@ -13225,15 +13328,15 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku end if post then local tail=find_node_tail(post) - setfield(tail,"next",cf) - setfield(cf,"prev",tail) + setnext(tail,cf) + setprev(cf,tail) else post=cf end if replace then local tail=find_node_tail(replace) - setfield(tail,"next",new) - setfield(new,"prev",tail) + setnext(tail,new) + setprev(new,tail) else replace=new end @@ -13761,25 +13864,40 @@ otf.chainhandlers={ normal=normal_handle_contextchain, verbose=verbose_handle_contextchain, } +local handle_contextchain=nil +function chained_contextchain(head,start,stop,...) + local steps=currentlookup.steps + local nofsteps=currentlookup.nofsteps + if nofsteps>1 then + reportmoresteps(dataset,sequence) + end + return handle_contextchain(head,start,...) +end function otf.setcontextchain(method) if not method or method=="normal" or not otf.chainhandlers[method] then - if handlers.contextchain then + if handle_contextchain then logwarning("installing normal contextchain handler") end - handlers.contextchain=normal_handle_contextchain + handle_contextchain=normal_handle_contextchain else logwarning("installing contextchain handler %a",method) local handler=otf.chainhandlers[method] - handlers.contextchain=function(...) + handle_contextchain=function(...) return handler(currentfont,...) end end - handlers.gsub_context=handlers.contextchain - handlers.gsub_contextchain=handlers.contextchain - handlers.gsub_reversecontextchain=handlers.contextchain - handlers.gpos_contextchain=handlers.contextchain - handlers.gpos_context=handlers.contextchain + handlers.gsub_context=handle_contextchain + handlers.gsub_contextchain=handle_contextchain + handlers.gsub_reversecontextchain=handle_contextchain + handlers.gpos_contextchain=handle_contextchain + handlers.gpos_context=handle_contextchain + handlers.contextchain=handle_contextchain end +chainprocs.gsub_context=chained_contextchain +chainprocs.gsub_contextchain=chained_contextchain +chainprocs.gsub_reversecontextchain=chained_contextchain +chainprocs.gpos_contextchain=chained_contextchain +chainprocs.gpos_context=chained_contextchain otf.setcontextchain() local missing={} local function logprocess(...) @@ -13807,19 +13925,32 @@ setmetatableindex(lookuphashes,function(t,font) t[font]=lookuphash return lookuphash end) -local autofeatures=fonts.analyzers.features -local function initialize(sequence,script,language,enabled) +local autofeatures=fonts.analyzers.features +local featuretypes=otf.tables.featuretypes +local defaultscript=otf.features.checkeddefaultscript +local defaultlanguage=otf.features.checkeddefaultlanguage +local function initialize(sequence,script,language,enabled,autoscript,autolanguage) local features=sequence.features if features then local order=sequence.order if order then - for i=1,#order do - local kind=order[i] + local featuretype=featuretypes[sequence.type or "unknown"] + for i=1,#order do + local kind=order[i] local valid=enabled[kind] if valid then - local scripts=features[kind] - local languages=scripts[script] or scripts[wildcard] - if languages and (languages[language] or languages[wildcard]) then + local scripts=features[kind] + local languages=scripts and ( + scripts[script] or + scripts[wildcard] or + (autoscript and defaultscript(featuretype,autoscript,scripts)) + ) + local enabled=languages and ( + languages[language] or + languages[wildcard] or + (autolanguage and defaultlanguage(featuretype,autolanguage,languages)) + ) + if enabled then return { valid,autofeatures[kind] or false,sequence,kind } end end @@ -13835,6 +13966,8 @@ function otf.dataset(tfmdata,font) local language=properties.language or "dflt" local script=properties.script or "dflt" local enabled=shared.features + local autoscript=enabled and enabled.autoscript + local autolanguage=enabled and enabled.autolanguage local res=resolved[font] if not res then res={} @@ -13852,7 +13985,7 @@ function otf.dataset(tfmdata,font) rs[language]=rl local sequences=tfmdata.resources.sequences for s=1,#sequences do - local v=enabled and initialize(sequences[s],script,language,enabled) + local v=enabled and initialize(sequences[s],script,language,enabled,autoscript,autolanguage) if v then rl[#rl+1]=v end @@ -13882,57 +14015,57 @@ local function kernrun(disc,run) if not pre then elseif prev then local nest=getprev(pre) - setfield(pre,"prev",prev) - setfield(prev,"next",pre) + setprev(pre,prev) + setnext(prev,pre) run(prevmarks,"preinjections") - setfield(pre,"prev",nest) - setfield(prev,"next",disc) + setprev(pre,nest) + setnext(prev,disc) else run(pre,"preinjections") end if not post then elseif next then local tail=find_node_tail(post) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) run(post,"postinjections",next) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) else run(post,"postinjections") end if not replace and prev and next then - setfield(prev,"next",next) - setfield(next,"prev",prev) + setnext(prev,next) + setprev(next,prev) run(prevmarks,"injections",next) - setfield(prev,"next",disc) - setfield(next,"prev",disc) + setnext(prev,disc) + setprev(next,disc) elseif prev and next then local tail=find_node_tail(replace) local nest=getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setprev(replace,prev) + setnext(prev,replace) + setnext(tail,next) + setprev(next,tail) run(prevmarks,"replaceinjections",next) - setfield(replace,"prev",nest) - setfield(prev,"next",disc) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setprev(replace,nest) + setnext(prev,disc) + setnext(tail,nil) + setprev(next,disc) elseif prev then local nest=getprev(replace) - setfield(replace,"prev",prev) - setfield(prev,"next",replace) + setprev(replace,prev) + setnext(prev,replace) run(prevmarks,"replaceinjections") - setfield(replace,"prev",nest) - setfield(prev,"next",disc) + setprev(replace,nest) + setnext(prev,disc) elseif next then local tail=find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) run(replace,"replaceinjections",next) - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) else run(replace,"replaceinjections") end @@ -13979,21 +14112,21 @@ local function testrun(disc,trun,crun) local prev=getprev(disc) if prev then local tail=find_node_tail(replace) - setfield(tail,"next",next) - setfield(next,"prev",tail) + setnext(tail,next) + setprev(next,tail) if trun(replace,next) then setfield(disc,"replace",nil) - setfield(prev,"next",replace) - setfield(replace,"prev",prev) - setfield(next,"prev",tail) - setfield(tail,"next",next) - setfield(disc,"prev",nil) - setfield(disc,"next",nil) + setnext(prev,replace) + setprev(replace,prev) + setprev(next,tail) + setnext(tail,next) + setprev(disc,nil) + setnext(disc,nil) flush_node_list(disc) return replace else - setfield(tail,"next",nil) - setfield(next,"prev",disc) + setnext(tail,nil) + setprev(next,disc) end else end @@ -14011,19 +14144,19 @@ local function discrun(disc,drun,krun) report_run("disc") end if next and prev then - setfield(prev,"next",next) + setnext(prev,next) drun(prev) - setfield(prev,"next",disc) + setnext(prev,disc) end local pre=getfield(disc,"pre") if not pre then elseif prev then local nest=getprev(pre) - setfield(pre,"prev",prev) - setfield(prev,"next",pre) + setprev(pre,prev) + setnext(prev,pre) krun(prev,"preinjections") - setfield(pre,"prev",nest) - setfield(prev,"next",disc) + setprev(pre,nest) + setnext(prev,disc) else krun(pre,"preinjections") end @@ -14281,6 +14414,40 @@ local function featuresprocessor(head,font,attr) end elseif id==math_code then start=getnext(end_of_math(start)) + elseif id==dir_code then + local dir=getfield(start,"dir") + if dir=="+TLT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=1 + elseif dir=="+TRT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=-1 + elseif dir=="-TLT" or dir=="-TRT" then + topstack=topstack-1 + rlmode=dirstack[topstack]=="+TRT" and -1 or 1 + else + rlmode=rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + start=getnext(start) + elseif id==localpar_code then + local dir=getfield(start,"dir") + if dir=="TRT" then + rlparmode=-1 + elseif dir=="TLT" then + rlparmode=1 + else + rlparmode=0 + end + rlmode=rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + start=getnext(start) else start=getnext(start) end @@ -14501,6 +14668,40 @@ local function featuresprocessor(head,font,attr) end elseif id==math_code then start=getnext(end_of_math(start)) + elseif id==dir_code then + local dir=getfield(start,"dir") + if dir=="+TLT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=1 + elseif dir=="+TRT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=-1 + elseif dir=="-TLT" or dir=="-TRT" then + topstack=topstack-1 + rlmode=dirstack[topstack]=="+TRT" and -1 or 1 + else + rlmode=rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + start=getnext(start) + elseif id==localpar_code then + local dir=getfield(start,"dir") + if dir=="TRT" then + rlparmode=-1 + elseif dir=="TLT" then + rlparmode=1 + else + rlparmode=0 + end + rlmode=rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + start=getnext(start) else start=getnext(start) end @@ -14636,10 +14837,10 @@ local function split(replacement,original) end return result end -local valid={ - coverage={ chainsub=true,chainpos=true,contextsub=true }, +local valid={ + coverage={ chainsub=true,chainpos=true,contextsub=true,contextpos=true }, reversecoverage={ reversesub=true }, - glyphs={ chainsub=true,chainpos=true }, + glyphs={ chainsub=true,chainpos=true,contextsub=true,contextpos=true }, } local function prepare_contextchains(tfmdata) local rawdata=tfmdata.shared.rawdata @@ -15952,7 +16153,7 @@ end -- closure do -- begin closure to overcome local limits and interference -if not modules then modules={} end modules ['luatex-font-def']={ +if not modules then modules={} end modules ['luatex-fonts-def']={ version=1.001, comment="companion to luatex-*.tex", author="Hans Hagen, PRAGMA-ADE, Hasselt NL", diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index c50e0cd..11d3101 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -15,7 +15,7 @@ luaotfload.aux = luaotfload.aux or { } local aux = luaotfload.aux local log = luaotfload.log -local report = log.report +local logreport = log.report local fonthashes = fonts.hashes local encodings = fonts.encodings local identifiers = fonthashes.identifiers @@ -54,8 +54,8 @@ local start_rewrite_fontname = function () rewrite_fontname, "luaotfload.rewrite_fontname") rewriting = true - report ("log", 1, "aux", - "start rewriting tfmdata.name field") + logreport ("log", 1, "aux", + "start rewriting tfmdata.name field") end end @@ -66,8 +66,8 @@ local stop_rewrite_fontname = function () luatexbase.remove_from_callback ("luaotfload.patch_font", "luaotfload.rewrite_fontname") rewriting = false - report ("log", 1, "aux", - "stop rewriting tfmdata.name field") + logreport ("log", 1, "aux", + "stop rewriting tfmdata.name field") end end @@ -393,7 +393,7 @@ do local load_chardef = function () - report ("both", 1, "aux", "Loading character metadata from %s.", chardef) + logreport ("both", 1, "aux", "Loading character metadata from %s.", chardef) chardata = dofile (kpse.find_file (chardef, "lua")) if chardata == nil then @@ -452,18 +452,18 @@ local provides_script = function (font_id, asked_script) --- where method: "gpos" | "gsub" for feature, data in next, featuredata do if data[asked_script] then - report ("log", 1, "aux", - "font no %d (%s) defines feature %s for script %s", - font_id, fontname, feature, asked_script) + logreport ("log", 1, "aux", + "font no %d (%s) defines feature %s for script %s", + font_id, fontname, feature, asked_script) return true end end end - report ("log", 0, "aux", - "font no %d (%s) defines no feature for script %s", - font_id, fontname, asked_script) + logreport ("log", 0, "aux", + "font no %d (%s) defines no feature for script %s", + font_id, fontname, asked_script) end - report ("log", 0, "aux", "no font with id %d", font_id) + logreport ("log", 0, "aux", "no font with id %d", font_id) return false end @@ -491,21 +491,21 @@ local provides_language = function (font_id, asked_script, asked_language) for feature, data in next, featuredata do local scriptdata = data[asked_script] if scriptdata and scriptdata[asked_language] then - report ("log", 1, "aux", - "font no %d (%s) defines feature %s " - .. "for script %s with language %s", - font_id, fontname, feature, - asked_script, asked_language) + logreport ("log", 1, "aux", + "font no %d (%s) defines feature %s " + .. "for script %s with language %s", + font_id, fontname, feature, + asked_script, asked_language) return true end end end - report ("log", 0, "aux", - "font no %d (%s) defines no feature " - .. "for script %s with language %s", - font_id, fontname, asked_script, asked_language) + logreport ("log", 0, "aux", + "font no %d (%s) defines no feature " + .. "for script %s with language %s", + font_id, fontname, asked_script, asked_language) end - report ("log", 0, "aux", "no font with id %d", font_id) + logreport ("log", 0, "aux", "no font with id %d", font_id) return false end @@ -564,20 +564,20 @@ local provides_feature = function (font_id, asked_script, if feature then local scriptdata = feature[asked_script] if scriptdata and scriptdata[asked_language] then - report ("log", 1, "aux", - "font no %d (%s) defines feature %s " - .. "for script %s with language %s", - font_id, fontname, asked_feature, - asked_script, asked_language) + logreport ("log", 1, "aux", + "font no %d (%s) defines feature %s " + .. "for script %s with language %s", + font_id, fontname, asked_feature, + asked_script, asked_language) return true end end end - report ("log", 0, "aux", - "font no %d (%s) does not define feature %s for script %s with language %s", - font_id, fontname, asked_feature, asked_script, asked_language) + logreport ("log", 0, "aux", + "font no %d (%s) does not define feature %s for script %s with language %s", + font_id, fontname, asked_feature, asked_script, asked_language) end - report ("log", 0, "aux", "no font with id %d", font_id) + logreport ("log", 0, "aux", "no font with id %d", font_id) return false end diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index d212df5..3f9d67a 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -941,6 +941,7 @@ local report_otf = logs.reporter("fonts","otf loading") --- start locals for addfeature() local utfbyte = unicode.utf8.byte +local utfchar = unicode.utf8.char local otf = handlers and handlers.otf --- filled in later during initialization @@ -1158,18 +1159,17 @@ local function current_addfeature(data,feature,specifications) end local askedfeatures = specification.features or everywhere local askedsteps = specifications.steps or specification.subtables or { specification.data } or { } - local defaulttype = specification.type or "substitution" + local featuretype = normalized[specification.type or "substitution"] or "substitution" local featureflags = specification.flags or noflags local featureorder = specification.order or { feature } local added = false local nofsteps = 0 local steps = { } for i=1,#askedsteps do - local list = askedsteps[i] - local coverage = { } - local cover = coveractions[featuretype] - local format = nil - local featuretype = normalized[list.type or defaulttype] or "substitution" + local list = askedsteps[i] + local coverage = { } + local cover = coveractions[featuretype] + local format = nil if not cover then -- unknown elseif featuretype == "substitution" then @@ -1355,11 +1355,8 @@ local function current_addfeature(data,feature,specifications) end end - ---[[ end snippet from font-otc.lua ]] -local tlig_order = { "tlig" } - local tlig_specification = { { type = "substitution", @@ -1370,7 +1367,7 @@ local tlig_specification = { [0x0060] = 0x2018, -- quoteright }, flags = noflags, - order = tlig_order, + order = { "tlig" }, prepend = true, }, { @@ -1390,7 +1387,7 @@ local tlig_specification = { [0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK }, flags = noflags, - order = tlig_order, + order = { "tlig" }, prepend = true, }, { @@ -1403,11 +1400,24 @@ local tlig_specification = { [0x00BF] = {0x003F, 0x0060}, -- questiondown }, flags = noflags, - order = tlig_order, + order = { "tlig" }, prepend = true, }, } +local tlig_specification = { + type = "substitution", + features = everywhere, + data = { + [0x0022] = 0x201D, -- quotedblright + [0x0027] = 0x2019, -- quoteleft + [0x0060] = 0x2018, -- quoteright + }, + flags = noflags, + order = { "tlig" }, + prepend = true, +} + local anum_arabic = { --- these are the same as in font-otc [0x0030] = 0x0660, [0x0031] = 0x0661, @@ -1466,9 +1476,65 @@ local anum_specification = { }, } +local rot13_specification = { + type = "substitution", + features = everywhere, + data = { + [65] = 78, [ 97] = 110, [78] = 65, [110] = 97, + [66] = 79, [ 98] = 111, [79] = 66, [111] = 98, + [67] = 80, [ 99] = 112, [80] = 67, [112] = 99, + [68] = 81, [100] = 113, [81] = 68, [113] = 100, + [69] = 82, [101] = 114, [82] = 69, [114] = 101, + [70] = 83, [102] = 115, [83] = 70, [115] = 102, + [71] = 84, [103] = 116, [84] = 71, [116] = 103, + [72] = 85, [104] = 117, [85] = 72, [117] = 104, + [73] = 86, [105] = 118, [86] = 73, [118] = 105, + [74] = 87, [106] = 119, [87] = 74, [119] = 106, + [75] = 88, [107] = 120, [88] = 75, [120] = 107, + [76] = 89, [108] = 121, [89] = 76, [121] = 108, + [77] = 90, [109] = 122, [90] = 77, [122] = 109, + }, + flags = noflags, + order = { "rot13" }, + prepend = true, +} + +local extrafeatures = { + tlig = { tlig_specification, "tex ligatures and substitutions" }, + anum = { anum_specification, "arabic numerals" }, + rot13 = { rot13_specification, "rot13" }, +} + +function add_otf_feature (name, specification) + if type (name) == "table" then + specification = name + name = specification.name + end + if type (name) == "string" then + extrafeatures[name] = specification + end +end + +otf.addfeature = add_otf_feature + +local install_extra_features = function (data, filename, raw) + for feature, specification in next, extrafeatures do + logreport ("both", 3, "features", + "register synthetic feature “%s” for %s font “%s”(%d)", + feature, + data.format, + tostring (data.metadata and data.metadata.fontname or "<unknown>"), + data.subfont or -1) + otf.features.register { name = feature, description = specification[2] } + otf.enhancers.addfeature (data, feature, specification[1]) + end +end + return { init = function () + logreport = luaotfload.log.report + if not fonts and fonts.handlers then logreport ("log", 0, "features", "OTF mechanisms missing -- did you forget to \z @@ -1478,41 +1544,13 @@ return { otf = fonts.handlers.otf - local extrafeatures = { - tlig = tlig_specification, - trep = { }, - anum = anum_specification, - } - --- hack for backwards compat with TL2014 loader - local addfeature = otf.version < 2.8 and current_addfeature - or ancient_addfeature + otf.enhancers.addfeature = otf.version < 2.8 and ancient_addfeature + or current_addfeature otf.enhancers.register ("check extra features", - function (data, filename, raw) - for feature, specification in next, extrafeatures do - logreport ("both", 3, "features", - "register synthetic feature “%s” for %s font “%s”(%d)", - feature, - data.format, - tostring (data.metadata and data.metadata.fontname or "<unknown>"), - data.subfont or -1) - addfeature (data, feature, specification) - end - end) - - logreport = luaotfload.log.report - if not fonts then - logreport ("log", 0, "features", - "OTF mechanisms missing -- did you forget to \z - load a font loader?") - return false - end + install_extra_features) - otf.features.register { - name = "anum", - description = "arabic digits", - } return true end } diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 895e32e..d471152 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -65,6 +65,43 @@ local logreport --- filled in after loading the log module --doc]]-- +local glyph_codes = + { [0] = "character" + , [1] = "glyph" + , [2] = "ligature" + , [3] = "ghost" + , [4] = "left" + , [5] = "right" + } + +local disc_codes = + { [0] = "discretionary" + , [1] = "explicit" + , [2] = "automatic" + , [3] = "regular" + , [4] = "first" + , [5] = "second" + } + +local node_types = { disc = disc_codes, glyph = glyph_codes } + +local luatex_stubs = function () + if not node.subtypes then + node.subtypes = function (t) return node_types [t] or { } end + local direct = node.direct + + local getfield = direct.getfield + local setfield = direct.setfield + + direct.setchar = direct.setchar or function (n, ...) setfield (n, "char", ...) end + direct.setprev = direct.setprev or function (n, ...) setfield (n, "prev", ...) end + direct.setnext = direct.setnext or function (n, ...) setfield (n, "next", ...) end + + direct.getchar = direct.getchar or function (n) getfield (n, "char") end + direct.getprev = direct.getprev or function (n) getfield (n, "prev") end + direct.getnext = direct.getnext or function (n) getfield (n, "next") end + end +end local init_early = function () @@ -82,6 +119,8 @@ local init_early = function () if not lualibs then error "this module requires Luaotfload" end if not luaotfload then error "this module requires Luaotfload" end + luatex_stubs () + --[[doc-- The logger needs to be in place prior to loading the fontloader due @@ -214,9 +253,9 @@ local context_modules = { { ctx, "font-oti" }, { ctx, "font-otf" }, { ctx, "font-otb" }, - { ltx, "luatex-fonts-inj" }, --> since 2014-01-07, replaces node-inj.lua + { ltx, "font-inj" }, { ltx, "luatex-fonts-ota" }, - { ltx, "luatex-fonts-otn" }, --> since 2014-01-07, replaces font-otn.lua + { ltx, "font-otn" }, { ctx, "font-otp" }, --> since 2013-04-23 { ltx, "luatex-fonts-lua" }, { ctx, "font-def" }, @@ -338,9 +377,9 @@ local init_main = function () load_fontloader_module "font-oti" load_fontloader_module "font-otf" load_fontloader_module "font-otb" - load_fontloader_module "fonts-inj" --> since 2014-01-07, replaces node-inj.lua + load_fontloader_module "font-inj" load_fontloader_module "fonts-ota" - load_fontloader_module "fonts-otn" --> since 2014-01-07, replaces font-otn.lua + load_fontloader_module "font-otn" load_fontloader_module "font-otp" --> since 2013-04-23 load_fontloader_module "fonts-lua" load_fontloader_module "font-def" |