From d1c8ea4d4e53f7304a768048b1c718a30bd9e7f4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 8 Jul 2016 08:19:44 +0200 Subject: [fontloader] sync with Context as of 2016-07-14 --- src/fontloader/misc/fontloader-font-otj.lua | 73 +++++++++++---- src/fontloader/misc/fontloader-font-ots.lua | 137 ++++++++++++++++------------ src/fontloader/misc/fontloader-mplib.lua | 22 ++--- 3 files changed, 148 insertions(+), 84 deletions(-) (limited to 'src/fontloader/misc') diff --git a/src/fontloader/misc/fontloader-font-otj.lua b/src/fontloader/misc/fontloader-font-otj.lua index d1408fd..46b2ca8 100644 --- a/src/fontloader/misc/fontloader-font-otj.lua +++ b/src/fontloader/misc/fontloader-font-otj.lua @@ -36,7 +36,7 @@ local registertracker = trackers.register local trace_injections = false registertracker("fonts.injections", function(v) trace_injections = v end) local trace_marks = false registertracker("fonts.injections.marks", function(v) trace_marks = v end) local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end) -local trace_spaces = false registertracker("otf.spaces", function(v) trace_spaces = v end) +local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end) -- use_advance is just an experiment: it makes copying glyphs (instead of new_glyph) dangerous @@ -1092,6 +1092,10 @@ local function inject_everything(head,where) nofmarks = nofmarks + 1 marks[nofmarks] = current else +local yoffset = i.yoffset +if yoffset and yoffset ~= 0 then + setfield(current,"yoffset",yoffset) +end if hascursives then local cursivex = i.cursivex if cursivex then @@ -1144,10 +1148,10 @@ local function inject_everything(head,where) end end -- left|glyph|right - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(current,"yoffset",yoffset) - end +-- local yoffset = i.yoffset +-- if yoffset and yoffset ~= 0 then +-- setfield(current,"yoffset",yoffset) +-- end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then insert_node_before(head,current,newkern(leftkern)) @@ -1422,6 +1426,48 @@ function nodes.injections.setspacekerns(font,sequence) end end +local getthreshold + +if context then + + local threshold = 1 -- todo: add a few methods for context + local parameters = fonts.hashes.parameters + + directives.register("otf.threshold", function(v) threshold = tonumber(v) or 1 end) + + getthreshold = function(font) + local p = parameters[font] + local f = p.factor + local s = p.spacing + local t = threshold * (s and s.width or p.space or 0) - 2 + return t > 0 and t or 0, f + end + +else + + injections.threshold = 0 + + getthreshold = function(font) + local p = fontdata[font].parameters + local f = p.factor + local s = p.spacing + local t = injections.threshold * (s and s.width or p.space or 0) - 2 + return t > 0 and t or 0, f + end + +end + +injections.getthreshold = getthreshold + +function injections.isspace(n,threshold) + if getid(n) == glue_code then + local w = getfield(n,"width") + if threshold and w > threshold then -- was >= + return 32 + end + end +end + local function injectspaces(head) if not triggers then @@ -1438,18 +1484,11 @@ local function injectspaces(head) local rightkern = false local function updatefont(font,trig) - -- local resources = resources[font] - -- local spacekerns = resources.spacekerns - -- if spacekerns then - -- leftkerns = spacekerns.left - -- rightkerns = spacekerns.right - -- end leftkerns = trig.left rightkerns = trig.right - local par = fontdata[font].parameters -- fallback for generic - factor = par.factor - threshold = par.spacing.width - 1 -- get rid of rounding errors lastfont = font + threshold, + factor = getthreshold(font) end for n in traverse_id(glue_code,tonut(head)) do @@ -1469,7 +1508,7 @@ local function injectspaces(head) end end if prevchar then - local font = getfont(next) + local font = getfont(prev) local trig = triggers[font] if trig then if lastfont ~= font then @@ -1482,7 +1521,7 @@ local function injectspaces(head) end if leftkern then local old = getfield(n,"width") - if old >= threshold then + if old > threshold then if rightkern then local new = old + (leftkern + rightkern) * factor if trace_spaces then @@ -1501,7 +1540,7 @@ local function injectspaces(head) leftkern = false elseif rightkern then local old = getfield(n,"width") - if old >= threshold then + if old > threshold then local new = old + rightkern * factor if trace_spaces then report_spaces("[%p -> %p] %C",nextchar,old,new) diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua index d63d524..0f38508 100644 --- a/src/fontloader/misc/fontloader-font-ots.lua +++ b/src/fontloader/misc/fontloader-font-ots.lua @@ -134,12 +134,8 @@ local trace_discruns = false registertracker("otf.discruns", function(v local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end) -local quit_on_no_replacement = true -- maybe per font -local zwnjruns = true -local optimizekerns = true - -registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) -registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) +----- zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) +local optimizekerns = true local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") @@ -239,6 +235,7 @@ local cursonce = true local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers +local fontfeatures = fonthashes.features local otffeatures = fonts.constructors.features.otf local registerotffeature = otffeatures.register @@ -269,16 +266,8 @@ local notmatchreplace = { } local handlers = { } --- helper - -local function isspace(n) - if getid(n) == glue_code then - local w = getfield(n,"width") - if w >= threshold then - return 32 - end - end -end +local isspace = injections.isspace +local getthreshold = injections.getthreshold -- we use this for special testing and documentation @@ -605,7 +594,7 @@ end return head, base end -local function multiple_glyphs(head,start,multiple,ignoremarks) +local function multiple_glyphs(head,start,multiple,ignoremarks,what) local nofmultiples = #multiple if nofmultiples > 0 then resetinjection(start) @@ -613,17 +602,29 @@ local function multiple_glyphs(head,start,multiple,ignoremarks) if nofmultiples > 1 then local sn = getnext(start) for k=2,nofmultiples do --- untested: --- --- while ignoremarks and marks[getchar(sn)] then --- local sn = getnext(sn) --- end + -- untested: + -- + -- while ignoremarks and marks[getchar(sn)] then + -- local sn = getnext(sn) + -- end local n = copy_node(start) -- ignore components resetinjection(n) setchar(n,multiple[k]) insert_node_after(head,start,n) start = n end + if what == true then + -- we're ok + elseif what > 1 then + local m = multiple[nofmultiples] + for i=2,what do + local n = copy_node(start) -- ignore components + resetinjection(n) + setchar(n,m) + insert_node_after(head,start,n) + start = n + end + end end return head, start, true else @@ -705,7 +706,7 @@ function handlers.gsub_multiple(head,start,dataset,sequence,multiple) if trace_multiples then logprocess("%s: replacing %s by multiple %s",pref(dataset,sequence),gref(getchar(start)),gref(multiple)) end - return multiple_glyphs(head,start,multiple,sequence.flags[1]) + return multiple_glyphs(head,start,multiple,sequence.flags[1],dataset[1]) end function handlers.gsub_ligature(head,start,dataset,sequence,ligature) @@ -1237,7 +1238,7 @@ function chainprocs.gsub_multiple(head,start,stop,dataset,sequence,currentlookup if trace_multiples then logprocess("%s: replacing %s by multiple characters %s",cref(dataset,sequence),gref(startchar),gref(replacement)) end - return multiple_glyphs(head,start,replacement,sequence.flags[1]) + return multiple_glyphs(head,start,replacement,sequence.flags[1],dataset[1]) end return head, start, false end @@ -1262,7 +1263,7 @@ function chainprocs.gsub_alternate(head,start,stop,dataset,sequence,currentlooku end local kind = dataset[4] local what = dataset[1] - local value = what == true and tfmdata.shared.features[kind] or what + local value = what == true and tfmdata.shared.features[kind] or what -- todo: optimize in ctx local current = start while current do local currentchar = ischar(current) @@ -2295,16 +2296,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match prev = getprev(prev) - elseif seq[n][32] then + elseif seq[n][32] and isspace(prev,threshold) then n = n - 1 prev = getprev(prev) else match = false break end - elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces - n = n - 1 - prev = getprev(prev) -- was absent else match = false break @@ -2424,15 +2422,13 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) end -- maybe only if match current = getnext(current) - elseif seq[n][32] then -- brrr + elseif seq[n][32] and isspace(current,threshold) then n = n + 1 + current = getnext(current) else match = false break end - elseif seq[n][32] then - n = n + 1 - current = getnext(current) else match = false break @@ -2545,7 +2541,7 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode) if replacements then head, start, done = reversesub(head,start,last,dataset,sequence,replacements,rlmode) else - done = quit_on_no_replacement -- can be meant to be skipped / quite inconsistent in fonts + done = true if trace_contexts then logprocess("%s: skipping match",cref(dataset,sequence)) end @@ -2728,10 +2724,10 @@ local function kernrun(disc,k_run,font,attr,...) end end -- - if prev and (pre or replace) and not ischar(prev,font) then + if prev and not ischar(prev,font) then -- and (pre or replace) prev = false end - if next and (post or replace) and not ischar(next,font) then + if next and not ischar(next,font) then -- and (post or replace) next = false end -- @@ -3306,13 +3302,13 @@ local function featuresprocessor(head,font,attr) if nesting == 1 then - currentfont = font - tfmdata = fontdata[font] - descriptions = tfmdata.descriptions - characters = tfmdata.characters - marks = tfmdata.resources.marks - factor = tfmdata.parameters.factor - threshold = tfmdata.parameters.spacing.width or 65536*10 + currentfont = font + tfmdata = fontdata[font] + descriptions = tfmdata.descriptions + characters = tfmdata.characters + marks = tfmdata.resources.marks + threshold, + factor = getthreshold(font) elseif currentfont ~= font then @@ -3371,15 +3367,12 @@ local function featuresprocessor(head,font,attr) local nofsteps = sequence.nofsteps if not steps then -- this permits injection, watch the different arguments - local h, d, ok = handler(head,start,dataset,sequence,nil,nil,nil,0,font,attr) + local h, d, ok = handler(head,head,dataset,sequence,nil,nil,nil,0,font,attr) if ok then success = true if h then head = h end - if d then - start = d - end end elseif typ == "gsub_reversecontextchain" then -- this is a limited case, no special treatments like 'init' etc @@ -3596,12 +3589,29 @@ otf.handlers = handlers -- used in devanagari local setspacekerns = nodes.injections.setspacekerns if not setspacekerns then os.exit() end -function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) - -- if not setspacekerns then - -- setspacekerns = nodes.injections.setspacekerns - -- end - setspacekerns(font,sequence) - return head, start, true +if fontfeatures then + + function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) + local features = fontfeatures[font] + local enabled = features.spacekern == true and features.kern == true + if enabled then + setspacekerns(font,sequence) + end + return head, start, enabled + end + +else -- generic (no hashes) + + function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr) + local shared = fontdata[font].shared + local features = shared and shared.features + local enabled = features and features.spacekern == true and features.kern == true + if enabled then + setspacekerns(font,sequence) + end + return head, start, enabled + end + end local function hasspacekerns(data) @@ -3636,11 +3646,13 @@ otf.readers.registerextender { end } +-- we merge the lookups but we still honor the language / script + local function spaceinitializer(tfmdata,value) -- attr local resources = tfmdata.resources local spacekerns = resources and resources.spacekerns - if spacekerns == nil then - local properties = tfmdata.properties + local properties = tfmdata.properties + if value and spacekerns == nil then if properties and properties.hasspacekerns then local sequences = resources.sequences local left = { } @@ -3653,7 +3665,20 @@ local function spaceinitializer(tfmdata,value) -- attr if steps then local kern = sequence.features.kern if kern then - feat = feat or kern -- or maybe merge + if feat then + for script, languages in next, kern do + local f = feat[k] + if f then + for l in next, languages do + f[l] = true + end + else + feat[script] = languages + end + end + else + feat = kern + end for i=1,#steps do local step = steps[i] local coverage = step.coverage diff --git a/src/fontloader/misc/fontloader-mplib.lua b/src/fontloader/misc/fontloader-mplib.lua index fd6eb97..976bb59 100644 --- a/src/fontloader/misc/fontloader-mplib.lua +++ b/src/fontloader/misc/fontloader-mplib.lua @@ -352,7 +352,7 @@ else return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width end - local function concat(px, py) -- no tx, ty here + local function concatinated(px, py) -- no tx, ty here return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider end @@ -401,29 +401,29 @@ else for i=1,#path do pth = path[i] if not ith then - pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord)) + pdf_literalcode("%f %f m",concatinated(pth.x_coord,pth.y_coord)) elseif curved(ith,pth) then - local a, b = concat(ith.right_x,ith.right_y) - local c, d = concat(pth.left_x,pth.left_y) - pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord)) + local a, b = concatinated(ith.right_x,ith.right_y) + local c, d = concatinated(pth.left_x,pth.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(pth.x_coord, pth.y_coord)) else - pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord)) + pdf_literalcode("%f %f l",concatinated(pth.x_coord, pth.y_coord)) end ith = pth end if not open then local one = path[1] if curved(pth,one) then - local a, b = concat(pth.right_x,pth.right_y) - local c, d = concat(one.left_x,one.left_y) - pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord)) + local a, b = concatinated(pth.right_x,pth.right_y) + local c, d = concatinated(one.left_x,one.left_y) + pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concatinated(one.x_coord, one.y_coord)) else - pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord)) end elseif #path == 1 then -- special case .. draw point local one = path[1] - pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord)) + pdf_literalcode("%f %f l",concatinated(one.x_coord,one.y_coord)) end return t end -- cgit v1.2.3