diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-ext.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-ext.lua | 539 |
1 files changed, 450 insertions, 89 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ext.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ext.lua index 965b6e6dc26..f9db5e0d9c0 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-ext.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-ext.lua @@ -7,9 +7,9 @@ if not modules then modules = { } end modules ['font-ext'] = { } local next, type, tonumber = next, type, tonumber -local formatters = string.formatters -local byte = string.byte +local byte, find, formatters = string.byte, string.find, string.formatters local utfchar = utf.char +local sortedhash, sortedkeys, sort = table.sortedhash, table.sortedkeys, table.sort local context = context local fonts = fonts @@ -37,8 +37,12 @@ local registerafmfeature = handlers.afm.features.register local fontdata = hashes.identifiers local fontproperties = hashes.properties +local constructors = fonts.constructors +local getprivate = constructors.getprivate + local allocate = utilities.storage.allocate local settings_to_array = utilities.parsers.settings_to_array +local settings_to_hash = utilities.parsers.settings_to_hash local getparameters = utilities.parsers.getparameters local gettexdimen = tex.getdimen local family_font = node.family_font @@ -46,6 +50,13 @@ local family_font = node.family_font local setmetatableindex = table.setmetatableindex local implement = interfaces.implement +local variables = interfaces.variables + + +local v_background = variables.background +local v_frame = variables.frame +local v_empty = variables.empty +local v_none = variables.none -- -- -- -- -- -- -- shared @@ -122,7 +133,6 @@ local function initializeexpansion(tfmdata,value) shrink = 10 * shrink, step = 10 * step, factor = factor, - auto = true, } local data = characters and characters.data for i, chr in next, tfmdata.characters do @@ -397,15 +407,6 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) end end end - local parameters = tfmdata.parameters - local protrusion = tfmdata.protrusion - if not protrusion then - parameters.protrusion = { - auto = true - } - else - protrusion.auto = true - end end -- The opbd test is just there because it was discussed on the context development list. However, @@ -435,7 +436,6 @@ local function initializeprotrusion(tfmdata,value) factor = factor, left = left, right = right, - auto = true, } for i, chr in next, tfmdata.characters do local v, pl, pr = vector[i], nil, nil @@ -645,32 +645,41 @@ local function manipulatedimensions(tfmdata,key,value) local parameters = tfmdata.parameters local emwidth = parameters.quad local exheight = parameters.xheight - local width = 0 - local height = 0 - local depth = 0 + local newwidth = false + local newheight = false + local newdepth = false if value == "strut" then - height = gettexdimen("strutht") - depth = gettexdimen("strutdp") + newheight = gettexdimen("strutht") + newdepth = gettexdimen("strutdp") + elseif value == "mono" then + newwidth = emwidth else local spec = settings_to_array(value) - width = (spec[1] or 0) * emwidth - height = (spec[2] or 0) * exheight - depth = (spec[3] or 0) * exheight + newwidth = tonumber(spec[1]) + newheight = tonumber(spec[2]) + newdepth = tonumber(spec[3]) + if newwidth then newwidth = newwidth * emwidth end + if newheight then newheight = newheight * exheight end + if newdepth then newdepth = newdepth * exheight end end - if width > 0 then - local resources = tfmdata.resources + if newwidth or newheight or newdepth then local additions = { } - local private = resources.private for unicode, old_c in next, characters do - local oldwidth = old_c.width + local oldwidth = old_c.width + local oldheight = old_c.height + local olddepth = old_c.depth + local width = newwidth or oldwidth or 0 + local height = newheight or oldheight or 0 + local depth = newdepth or olddepth or 0 if oldwidth ~= width then -- Defining the tables in one step is more efficient -- than adding fields later. - private = private + 1 + local private = getprivate(tfmdata) local new_c local commands = { { "right", (width - oldwidth) / 2 }, { "slot", 1, private }, + -- { "slot", 0, private }, } if height > 0 then if depth > 0 then @@ -703,13 +712,12 @@ local function manipulatedimensions(tfmdata,key,value) end setmetatableindex(new_c,old_c) characters[unicode] = new_c - additions[private] = old_c + additions[private] = old_c end end for k, v in next, additions do characters[k] = v end - resources.private = private elseif height > 0 and depth > 0 then for unicode, old_c in next, characters do old_c.height = height @@ -739,6 +747,53 @@ local dimensions_specification = { registerotffeature(dimensions_specification) registerafmfeature(dimensions_specification) +-------------------------------------------------------------------------------------------------------------- + +-- local function fakemonospace(tfmdata) +-- local resources = tfmdata.resources +-- local gposfeatures = resources.features.gpos +-- local characters = tfmdata.characters +-- local descriptions = tfmdata.descriptions +-- local sequences = resources.sequences +-- local coverage = { } +-- local units = tfmdata.shared.rawdata.metadata.units +-- for k, v in next, characters do +-- local w = descriptions[k].width +-- local d = units - w +-- coverage[k] = { -d/2, 0, units, 0 } +-- end +-- local f = { dflt = { dflt = true } } +-- local s = #sequences + 1 +-- local t = { +-- features = { fakemono = f }, +-- flags = { false, false, false, false }, +-- index = s, +-- name = "p_s_" .. s, +-- nofsteps = 1, +-- order = { "fakemono" }, +-- skiphash = false, +-- type = "gpos_single", +-- steps = { +-- { +-- format = "single", +-- coverage = coverage, +-- } +-- } +-- } +-- gposfeatures["fakemono"] = f +-- sequences[s] = t +-- end +-- +-- fonts.constructors.features.otf.register { +-- name = "fakemono", +-- description = "fake monospaced", +-- initializers = { +-- node = fakemonospace, +-- }, +-- } + +-------------------------------------------------------------------------------------------------------------- + -- for zhichu chen (see mailing list archive): we might add a few more variants -- in due time -- @@ -748,79 +803,175 @@ registerafmfeature(dimensions_specification) -- -- \definecolor[DummyColor][s=.75,t=.5,a=1] {\DummyColor test} \nopdfcompression -- --- local gray = { "special", "pdf: /Tr1 gs .75 g" } --- local black = { "special", "pdf: /Tr0 gs 0 g" } +-- local gray = { "pdf", "origin", "/Tr1 gs .75 g" } +-- local black = { "pdf", "origin", "/Tr0 gs 0 g" } --- sort of obsolete as we now have \showglyphs + +-- boundingbox={yes|background|frame|empty|<color>} local push = { "push" } local pop = { "pop" } -local gray = { "special", "pdf: .75 g" } -local black = { "special", "pdf: 0 g" } -local downcache = { } -- handy for huge cjk fonts -local rulecache = { } -- handy for huge cjk fonts +----- gray = { "pdf", "origin", ".75 g .75 G" } +----- black = { "pdf", "origin", "0 g 0 G" } +----- gray = { "pdf", ".75 g" } +----- black = { "pdf", "0 g" } -setmetatableindex(downcache,function(t,d) - local v = { "down", d } - t[d] = v +-- local bp = number.dimenfactors.bp +-- +-- local downcache = setmetatableindex(function(t,d) +-- local v = { "down", d } +-- t[d] = v +-- return v +-- end) +-- +-- local backcache = setmetatableindex(function(t,h) +-- local h = h * bp +-- local v = setmetatableindex(function(t,w) +-- -- local v = { "rule", h, w } +-- local v = { "pdf", "origin", formatters["0 0 %.6F %.6F re F"](w*bp,h) } +-- t[w] = v +-- return v +-- end) +-- t[h] = v +-- return v +-- end) +-- +-- local forecache = setmetatableindex(function(t,h) +-- local h = h * bp +-- local v = setmetatableindex(function(t,w) +-- local v = { "pdf", "origin", formatters["%.6F w 0 0 %.6F %.6F re S"](0.25*65536*bp,w*bp,h) } +-- t[w] = v +-- return v +-- end) +-- t[h] = v +-- return v +-- end) + +local bp = number.dimenfactors.bp +local r = 16384 * bp -- 65536 // 4 + +local backcache = setmetatableindex(function(t,h) + local h = h * bp + local v = setmetatableindex(function(t,d) + local d = d * bp + local v = setmetatableindex(function(t,w) + local v = { "pdf", "origin", formatters["%.6F w 0 %.6F %.6F %.6F re f"](r,-d,w*bp,h+d) } + t[w] = v + return v + end) + t[d] = v + return v + end) + t[h] = v return v end) -setmetatableindex(rulecache,function(t,h) - local v = { } - t[h] = v - setmetatableindex(v,function(t,w) - local v = { "rule", h, w } - t[w] = v +local forecache = setmetatableindex(function(t,h) + local h = h * bp + local v = setmetatableindex(function(t,d) + local d = d * bp + local v = setmetatableindex(function(t,w) + -- the frame goes through the boundingbox + -- local v = { "pdf", "origin", formatters["[] 0 d 0 J %.6F w %.6F %.6F %.6F re S"](r,-d,w*bp,h+d) } + local v = { "pdf", "origin", formatters["[] 0 d 0 J %.6F w %.6F %.6F %.6F %.6F re S"](r,r/2,-d+r/2,w*bp-r,h+d-r) } + t[w] = v + return v + end) + t[d] = v return v end) + t[h] = v return v end) +local startcolor = nil +local stopcolor = nil + local function showboundingbox(tfmdata,key,value) if value then - local vfspecials = backends.pdf.tables.vfspecials - local gray = vfspecials and (vfspecials.rulecolors[value] or vfspecials.rulecolors.palegray) or gray + if not backcolors then + local vfspecials = backends.pdf.tables.vfspecials + startcolor = vfspecials.startcolor + stopcolor = vfspecials.stopcolor + end local characters = tfmdata.characters - local resources = tfmdata.resources local additions = { } - local private = resources.private + local rulecache = backcache + local showchar = true + local color = "palegray" + if type(value) == "string" then + value = settings_to_array(value) + for i=1,#value do + local v = value[i] + if v == v_frame then + rulecache = forecache + elseif v == v_background then + rulecache = backcache + elseif v == v_empty then + showchar = false + elseif v == v_none then + color = nil + else + color = v + end + end + end + local gray = color and startcolor(color) or nil + local black = gray and stopcolor or nil for unicode, old_c in next, characters do - private = private + 1 - local width = old_c.width or 0 - local height = old_c.height or 0 - local depth = old_c.depth or 0 - local new_c - if depth == 0 then - new_c = { - width = width, - height = height, - commands = { - push, - gray, - rulecache[height][width], - black, - pop, - { "slot", 1, private }, - } - } - else - new_c = { - width = width, - height = height, - depth = depth, - commands = { - push, - downcache[depth], - gray, - rulecache[height+depth][width], - black, - pop, - { "slot", 1, private }, - } + local private = getprivate(tfmdata) + local width = old_c.width or 0 + local height = old_c.height or 0 + local depth = old_c.depth or 0 + local char = showchar and { "slot", 1, private } or nil -- { "slot", 0, private } + -- local new_c + -- if depth == 0 then + -- new_c = { + -- width = width, + -- height = height, + -- commands = { + -- push, + -- gray, + -- rulecache[height][width], + -- black, + -- pop, + -- char, + -- } + -- } + -- else + -- new_c = { + -- width = width, + -- height = height, + -- depth = depth, + -- commands = { + -- push, + -- downcache[depth], + -- gray, + -- rulecache[height+depth][width], + -- black, + -- pop, + -- char, + -- } + -- } + -- end + local rule = rulecache[height][depth][width] + local new_c = { + width = width, + height = height, + depth = depth, + commands = gray and { + -- push, + gray, + rule, + black, + -- pop, + char, + } or { + rule, + char, } - end + } setmetatableindex(new_c,old_c) characters[unicode] = new_c additions[private] = old_c @@ -828,7 +979,6 @@ local function showboundingbox(tfmdata,key,value) for k, v in next, additions do characters[k] = v end - resources.private = private end end @@ -884,6 +1034,58 @@ registerotffeature { -- -- end +do + + local P, lpegpatterns, lpegmatch = lpeg.P, lpeg.patterns, lpeg.match + + local amount, stretch, shrink, extra + + local factor = lpegpatterns.unsigned + local space = lpegpatterns.space + local pattern = ( + (factor / function(n) amount = tonumber(n) or amount end) + + (P("+") + P("plus" )) * space^0 * (factor / function(n) stretch = tonumber(n) or stretch end) + + (P("-") + P("minus")) * space^0 * (factor / function(n) shrink = tonumber(n) or shrink end) + + ( P("extra")) * space^0 * (factor / function(n) extra = tonumber(n) or extra end) + + space^1 + )^1 + + local function initialize(tfmdata,key,value) + local characters = tfmdata.characters + local parameters = tfmdata.parameters + if type(value) == "string" then + local emwidth = parameters.quad + amount, stretch, shrink, extra = 0, 0, 0, false + lpegmatch(pattern,value) + if not extra then + if shrink ~= 0 then + extra = shrink + elseif stretch ~= 0 then + extra = stretch + else + extra = amount + end + end + parameters.space = amount * emwidth + parameters.space_stretch = stretch * emwidth + parameters.space_shrink = shrink * emwidth + parameters.extra_space = extra * emwidth + end + end + + -- 1.1 + 1.2 - 1.3 minus 1.4 plus 1.1 extra 1.4 -- last one wins + + registerotffeature { + name = "spacing", + description = "space settings", + manipulators = { + base = initialize, + node = initialize, + } + } + +end + -- -- historic stuff, move from font-ota (handled differently, typo-rep) -- -- local delete_node = nodes.delete @@ -1069,7 +1271,7 @@ local function getprivatecharornode(tfmdata,name) local font = properties.id local slot = getprivateslot(font,name) if slot then - -- todo: set current attribibutes + -- todo: set current attributes local char = tfmdata.characters[slot] local tonode = char.tonode if tonode then @@ -1121,7 +1323,7 @@ do end end - fonts.constructors.newfeatures.otf.register { + constructors.newfeatures.otf.register { name = "extraprivates", description = "extra privates", default = true, @@ -1257,21 +1459,21 @@ do -- another hack for a crappy font local function additalictowidth(tfmdata,key,value) local characters = tfmdata.characters - local resources = tfmdata.resources local additions = { } - local private = resources.private for unicode, old_c in next, characters do -- maybe check for math local oldwidth = old_c.width local olditalic = old_c.italic if olditalic and olditalic ~= 0 then - private = private + 1 + local private = getprivate(tfmdata) local new_c = { width = oldwidth + olditalic, height = old_c.height, depth = old_c.depth, commands = { - { "slot", 1, private }, + -- { "slot", 1, private }, + -- { "slot", 0, private }, + { "char", private }, { "right", olditalic }, }, } @@ -1283,7 +1485,6 @@ do -- another hack for a crappy font for k, v in next, additions do characters[k] = v end - resources.private = private end registerotffeature { @@ -1345,3 +1546,163 @@ do } end + +do + + -- This is a rather special test-only feature that I added for the sake of testing + -- Idris's husayni. We wanted to know if uniscribe obeys the order of lookups in a + -- font, in spite of what the description of handling arabic suggests. And indeed, + -- mixed-in lookups of other features (like all these ss* in husayni) are handled + -- the same in context as in uniscribe. If one sets reorderlookups=arab then we sort + -- according to the "assumed" order so e.g. the ss* move to after the standard + -- features. The observed difference in rendering is an indication that uniscribe is + -- quite faithful to the font (while e.g. tests with the hb plugin demonstrate some + -- interference, apart from some hard coded init etc expectations). Anyway, it means + -- that we're okay with the (generic) node processor. A pitfall is that in context + -- we can actually control more, so we can trigger an analyze pass with e.g. + -- dflt/dflt while the libraries depend on the script settings for that. Uniscribe + -- probably also parses the string and when seeing arabic will follow a different + -- code path, although it seems to treat all features equal. + + local trace_reorder = trackers.register("fonts.reorderlookups",function(v) trace_reorder = v end) + local report_reorder = logs.reporter("fonts","reorder") + + local vectors = { } + + vectors.arab = { + gsub = { + ccmp = 1, + isol = 2, + fina = 3, + medi = 4, + init = 5, + rlig = 6, + rclt = 7, + calt = 8, + liga = 9, + dlig = 10, + cswh = 11, + mset = 12, + }, + gpos = { + curs = 1, + kern = 2, + mark = 3, + mkmk = 4, + }, + } + + function otf.reorderlookups(tfmdata,vector) + local order = vectors[vector] + if not order then + return + end + local oldsequences = tfmdata.resources.sequences + if oldsequences then + local sequences = { } + for i=1,#oldsequences do + sequences[i] = oldsequences[i] + end + for i=1,#sequences do + local s = sequences[i] + local features = s.features + local kind = s.type + local index = s.index + if features then + local when + local what + for feature in sortedhash(features) do + if not what then + what = find(kind,"^gsub") and "gsub" or "gpos" + end + local newwhen = order[what][feature] + if not newwhen then + -- skip + elseif not when then + when = newwhen + elseif newwhen < when then + when = newwhen + end + end + s.ondex = s.index + s.index = i + s.what = what == "gsub" and 1 or 2 + s.when = when or 99 + else + s.ondex = s.index + s.index = i + s.what = 1 + s.when = 99 + end + end + sort(sequences,function(a,b) + local what_a = a.what + local what_b = b.what + if what_a ~= what_b then + return a.index < b.index + end + local when_a = a.when + local when_b = b.when + if when_a == when_b then + return a.index < b.index + else + return when_a < when_b + end + end) + local swapped = 0 + for i=1,#sequences do + local sequence = sequences[i] + local features = sequence.features + if features then + local index = sequence.index + if index ~= i then + swapped = swapped + 1 + end + if trace_reorder then + if swapped == 1 then + report_reorder() + report_reorder("start swapping lookups in font %!font:name!",tfmdata) + report_reorder() + report_reorder("gsub order: % t",table.swapped(order.gsub)) + report_reorder("gpos order: % t",table.swapped(order.gpos)) + report_reorder() + end + report_reorder("%03i : lookup %03i, type %s, sorted %2i, moved %s, % t", + i,index,sequence.what == 1 and "gsub" or "gpos",sequence.when or 99, + (index > i and "-") or (index < i and "+") or "=",sortedkeys(features)) + end + end + sequence.what = nil + sequence.when = nil + sequence.index = sequence.ondex + end + if swapped > 0 then + if trace_reorder then + report_reorder() + report_reorder("stop swapping lookups, %i lookups swapped",swapped) + report_reorder() + end +-- tfmdata.resources.sequences = sequences + tfmdata.shared.reorderedsequences = sequences + end + end + end + + -- maybe delay till ra is filled + + local function reorderlookups(tfmdata,key,value) + if value then + otf.reorderlookups(tfmdata,value) + end + end + + registerotffeature { + name = "reorderlookups", + description = "reorder lookups", + manipulators = { + base = reorderlookups, + node = reorderlookups, + } + } + +end |