if not modules then modules = { } end modules ['font-fbk'] = { version = 1.001, comment = "companion to font-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local cos, tan, rad, format = math.cos, math.tan, math.rad, string.format local utfbyte, utfchar = utf.byte, utf.char --[[ldx--

This is very experimental code!

--ldx]]-- local trace_combining_visualize = false trackers.register("fonts.composing.visualize", function(v) trace_combining_visualize = v end) local trace_combining_define = false trackers.register("fonts.composing.define", function(v) trace_combining_define = v end) trackers.register("fonts.combining", "fonts.composing.define") -- for old times sake (and manuals) trackers.register("fonts.combining.all", "fonts.composing.*") -- for old times sake (and manuals) local report_combining = logs.reporter("fonts","combining") local force_combining = false -- just for demo purposes (see mk) local allocate = utilities.storage.allocate local fonts = fonts local handlers = fonts.handlers local constructors = fonts.constructors local otf = handlers.otf local afm = handlers.afm local registerotffeature = otf.features.register local registerafmfeature = afm.features.register local unicodecharacters = characters.data local unicodefallbacks = characters.fallbacks local vf = handlers.vf local commands = vf.combiner.commands local push = vf.predefined.push local pop = vf.predefined.pop local force_composed = false local cache = { } -- we could make these weak local fraction = 0.15 -- 30 units for lucida local function composecharacters(tfmdata) -- this assumes that slot 1 is self, there will be a proper self some day local characters = tfmdata.characters local descriptions = tfmdata.descriptions local parameters = tfmdata.parameters local properties = tfmdata.properties local Xdesc = descriptions[utfbyte("X")] local xdesc = descriptions[utfbyte("x")] if Xdesc and xdesc then local scale = parameters.factor or 1 local deltaxheight = scale * (Xdesc.boundingbox[4] - xdesc.boundingbox[4]) local extraxheight = fraction * deltaxheight -- maybe use compose value local italicfactor = parameters.italicfactor or 0 local vfspecials = backends.tables.vfspecials --brr local red, green, blue, black if trace_combining_visualize then red = vfspecials.red green = vfspecials.green blue = vfspecials.blue black = vfspecials.black end local compose = fonts.goodies.getcompositions(tfmdata) if compose and trace_combining_visualize then report_combining("using compose information from goodies file") end local done = false for i, c in next, unicodecharacters do -- loop over all characters ... not that efficient but a specials hash takes memory if force_combining or not characters[i] then local s = c.specials if s and s[1] == 'char' then local chr = s[2] local charschr = characters[chr] if charschr then local cc = c.category if cc == 'll' or cc == 'lu' or cc == 'lt' then -- characters.is_letter[cc] local acc = s[3] local t = { } for k, v in next, charschr do if k ~= "commands" then t[k] = v end end local charsacc = characters[acc] --~ local ca = charsacc.category --~ if ca == "mn" then --~ -- mark nonspacing --~ elseif ca == "ms" then --~ -- mark spacing combining --~ elseif ca == "me" then --~ -- mark enclosing --~ else if not charsacc then -- fallback accents acc = unicodefallbacks[acc] charsacc = acc and characters[acc] end local chr_t = cache[chr] if not chr_t then chr_t = {"slot", 1, chr} cache[chr] = chr_t end if charsacc then if trace_combining_define then report_combining("composed %C, base %C, accent %C",i,chr,acc) end local acc_t = cache[acc] if not acc_t then acc_t = {"slot", 1, acc} cache[acc] = acc_t end local cb = descriptions[chr].boundingbox local ab = descriptions[acc].boundingbox -- todo: adapt height if cb and ab then local c_llx, c_lly, c_urx, c_ury = scale*cb[1], scale*cb[2], scale*cb[3], scale*cb[4] local a_llx, a_lly, a_urx, a_ury = scale*ab[1], scale*ab[2], scale*ab[3], scale*ab[4] local done = false if compose then local i_compose = compose[i] local i_anchored = i_compose and i_compose.anchored if i_anchored then local c_compose = compose[chr] local a_compose = compose[acc] local c_anchors = c_compose and c_compose.anchors local a_anchors = a_compose and a_compose.anchors if c_anchors and a_anchors then local c_anchor = c_anchors[i_anchored] local a_anchor = a_anchors[i_anchored] if c_anchor and a_anchor then local cx = c_anchor.x or 0 local cy = c_anchor.y or 0 local ax = a_anchor.x or 0 local ay = a_anchor.y or 0 local dx = cx - ax local dy = cy - ay if trace_combining_define then report_combining("building %C from %C and %C",i,chr,acc) report_combining(" boundingbox:") report_combining(" chr: %3i %3i %3i %3i",unpack(cb)) report_combining(" acc: %3i %3i %3i %3i",unpack(ab)) report_combining(" anchors:") report_combining(" chr: %3i %3i",cx,cy) report_combining(" acc: %3i %3i",ax,ay) report_combining(" delta:") report_combining(" %s: %3i %3i",i_anchored,dx,dy) end if trace_combining_visualize then t.commands = { push, {"right", scale*dx}, {"down",-scale*dy}, green, acc_t, black, pop, chr_t } -- t.commands = { -- push, {"right", scale*cx}, {"down", -scale*cy}, red, {"rule",10000,10000,10000}, pop, -- push, {"right", scale*ax}, {"down", -scale*ay}, blue, {"rule",10000,10000,10000}, pop, -- push, {"right", scale*dx}, {"down", -scale*dy}, green, acc_t, black, pop, chr_t -- } else t.commands = { push, {"right", scale*dx}, {"down",-scale*dy}, acc_t, pop, chr_t } end done = true end end end end if not done then -- can be sped up for scale == 1 local dx = (c_urx - a_urx - a_llx + c_llx)/2 local dd = (c_urx - c_llx)*italicfactor if a_ury < 0 then if trace_combining_visualize then t.commands = { push, {"right", dx-dd}, red, acc_t, black, pop, chr_t } else t.commands = { push, {"right", dx-dd}, acc_t, pop, chr_t } end elseif c_ury > a_lly then -- messy test local dy if compose then -- experimental: we could use sx but all that testing -- takes time and code dy = compose[i] if dy then dy = dy.dy end if not dy then dy = compose[acc] if dy then dy = dy and dy.dy end end if not dy then dy = compose.dy end if not dy then dy = - deltaxheight + extraxheight elseif dy > -1.5 and dy < 1.5 then -- we assume a fraction of (percentage) dy = - dy * deltaxheight else -- we assume fontunits (value smaller than 2 make no sense) dy = - dy * scale end else dy = - deltaxheight + extraxheight end if trace_combining_visualize then t.commands = { push, {"right", dx+dd}, {"down", dy}, green, acc_t, black, pop, chr_t } else t.commands = { push, {"right", dx+dd}, {"down", dy}, acc_t, pop, chr_t } end else if trace_combining_visualize then t.commands = { push, {"right", dx+dd}, blue, acc_t, black, pop, chr_t } else t.commands = { push, {"right", dx+dd}, acc_t, pop, chr_t } end end end else t.commands = { chr_t } -- else index mess end else if trace_combining_define then report_combining("%C becomes simplfied %C",i,chr) end t.commands = { chr_t } -- else index mess end done = true characters[i] = t local d = { } for k, v in next, descriptions[chr] do d[k] = v end descriptions[i] = d end end end end end if done then properties.virtualized = true end end end registerotffeature { name = "compose", description = "additional composed characters", manipulators = { base = composecharacters, node = composecharacters, } } registerafmfeature { name = "compose", description = "additional composed characters", manipulators = { base = composecharacters, node = composecharacters, } } vf.helpers.composecharacters = composecharacters -- This installs the builder into the regular virtual font builder, -- which only makes sense as demo. commands["compose.trace.enable"] = function() trace_combining_visualize = true end commands["compose.trace.disable"] = function() trace_combining_visualize = false end commands["compose.force.enable"] = function() force_combining = true end commands["compose.force.disable"] = function() force_combining = false end commands["compose.trace.set"] = function(g,v) if v[2] == nil then trace_combining_visualize = true else trace_combining_visualize = v[2] end end commands["compose.apply"] = function(g,v) composecharacters(g) end -- vf builder -- {'special', 'pdf: q ' .. s .. ' 0 0 '.. s .. ' 0 0 cm'}, -- {'special', 'pdf: q 1 0 0 1 ' .. -w .. ' ' .. -h .. ' cm'}, -- {'special', 'pdf: /Fm\XX\space Do'}, -- {'special', 'pdf: Q'}, -- {'special', 'pdf: Q'}, -- new and experimental local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } local noflags = { } local char_specification = { type = "ligature", features = everywhere, data = characters.splits.char, order = { "char-ligatures" }, flags = noflags, prepend = true, } local compat_specification = { type = "ligature", features = everywhere, data = characters.splits.compat, order = { "compat-ligatures" }, flags = noflags, prepend = true, } otf.addfeature("char-ligatures", char_specification) -- xlig (extra) otf.addfeature("compat-ligatures",compat_specification) -- plig (pseudo) registerotffeature { name = 'char-ligatures', description = 'unicode char specials to ligatures' } registerotffeature { name = 'compat-ligatures', description = 'unicode compat specials to ligatures' }