if not modules then modules = { } end modules ['good-mth'] = { 2 version = 1.000, 3 comment = "companion to font-lib.mkiv", 4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", 5 copyright = "PRAGMA ADE / ConTeXt Development Team", 6 license = "see context related readme files" 7} 8 9local type, next, tonumber, unpack = type, next, tonumber, unpack 10local ceil = math.ceil 11local match = string.match 12 13local fonts = fonts 14 15local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end) 16local report_goodies = logs.reporter("fonts","goodies") 17 18local registerotffeature = fonts.handlers.otf.features.register 19 20local fontgoodies = fonts.goodies or { } 21 22local fontcharacters = fonts.hashes.characters 23 24local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end) 25 26local report_math = logs.reporter("mathematics","initializing") 27 28local nuts = nodes.nuts 29 30local setlink = nuts.setlink 31 32local nodepool = nuts.pool 33 34local new_kern = nodepool.kern 35local new_glyph = nodepool.glyph 36local new_hlist = nodepool.hlist 37local new_vlist = nodepool.vlist 38 39local insertnodeafter = nuts.insertafter 40 41local helpers = fonts.helpers 42local upcommand = helpers.commands.up 43local rightcommand = helpers.commands.right 44local charcommand = helpers.commands.char 45local prependcommands = helpers.prependcommands 46 47-- experiment, we have to load the definitions immediately as they precede 48-- the definition so they need to be initialized in the typescript 49 50-- local function withscriptcode(tfmdata,unicode,data,action) 51-- if type(unicode) == "string" then 52-- local p, u = match(unicode,"^(.-):(.-)$") 53-- if u then 54-- u = tonumber(u) 55-- if u then 56-- local slots = fonts.helpers.mathscriptslots(tfmdata,u) 57-- if slots then 58-- if p == "*" then 59-- action(u,data) 60-- for i=1,#slots do 61-- action(slots[i],data) 62-- end 63-- else 64-- p = tonumber(p) 65-- if p then 66-- action(slots[p],data) 67-- end 68-- end 69-- end 70-- end 71-- end 72-- else 73-- action(unicode,data) 74-- end 75-- end 76 77-- local function finalize(tfmdata,feature,value) 78-- -- if tfmdata.mathparameters then -- funny, cambria text has this 79-- local goodies = tfmdata.goodies 80-- if goodies then 81-- local virtualized = mathematics.virtualized 82-- for i=1,#goodies do 83-- local goodie = goodies[i] 84-- local mathematics = goodie.mathematics 85-- local dimensions = mathematics and mathematics.dimensions 86-- if dimensions then 87-- if trace_defining then 88-- report_math("overloading dimensions in %a @ %p",tfmdata.properties.fullname,tfmdata.parameters.size) 89-- end 90-- local characters = tfmdata.characters 91-- local descriptions = tfmdata.descriptions 92-- local parameters = tfmdata.parameters 93-- local factor = parameters.factor 94-- local hfactor = parameters.hfactor 95-- local vfactor = parameters.vfactor 96-- local function overloadone(unicode,data) 97-- local character = characters[unicode] 98-- if not character then 99-- local c = virtualized[unicode] 100-- if c then 101-- character = characters[c] 102-- end 103-- end 104-- if character then 105-- local width = data.width 106-- local height = data.height 107-- local depth = data.depth 108-- if trace_defining and (width or height or depth) then 109-- report_math("overloading dimensions of %C, width %p, height %p, depth %p", 110-- unicode,width or 0,height or 0,depth or 0) 111-- end 112-- if width then character.width = width * hfactor end 113-- if height then character.height = height * vfactor end 114-- if depth then character.depth = depth * vfactor end 115-- -- 116-- local xoffset = data.xoffset 117-- local yoffset = data.yoffset 118-- if xoffset == "llx" then 119-- local d = descriptions[unicode] 120-- if d then 121-- xoffset = - d.boundingbox[1] * hfactor 122-- character.width = character.width + xoffset 123-- xoffset = rightcommand[xoffset] 124-- else 125-- xoffset = nil 126-- end 127-- elseif xoffset and xoffset ~= 0 then 128-- xoffset = rightcommand[xoffset * hfactor] 129-- else 130-- xoffset = nil 131-- end 132-- if yoffset and yoffset ~= 0 then 133-- yoffset = upcommand[yoffset * vfactor] 134-- else 135-- yoffset = nil 136-- end 137-- if xoffset or yoffset then 138-- local commands = character.commands 139-- if commands then 140-- prependcommands(commands,yoffset,xoffset) 141-- else 142-- local slot = charcommand[unicode] 143-- if xoffset and yoffset then 144-- character.commands = { xoffset, yoffset, slot } 145-- elseif xoffset then 146-- character.commands = { xoffset, slot } 147-- else 148-- character.commands = { yoffset, slot } 149-- end 150-- end 151-- end 152-- elseif trace_defining then 153-- report_math("no overloading dimensions of %C, not in font",unicode) 154-- end 155-- end 156-- local function overload(dimensions) 157-- for unicode, data in next, dimensions do 158-- withscriptcode(tfmdata,unicode,data,overloadone) 159-- end 160-- end 161-- if value == nil then 162-- value = { "default" } 163-- end 164-- if value == "all" or value == true then 165-- for name, value in next, dimensions do 166-- overload(value) 167-- end 168-- else 169-- if type(value) == "string" then 170-- value = utilities.parsers.settings_to_array(value) 171-- end 172-- if type(value) == "table" then 173-- for i=1,#value do 174-- local d = dimensions[value[i]] 175-- if d then 176-- overload(d) 177-- end 178-- end 179-- end 180-- end 181-- end 182-- end 183-- end 184-- end 185-- 186-- registerotffeature { 187-- name = "mathdimensions", 188-- description = "manipulate math dimensions", 189-- -- default = true, 190-- manipulators = { 191-- base = finalize, 192-- node = finalize, 193-- } 194-- } 195 196local function initialize(goodies) 197 local mathgoodies = goodies.mathematics 198 if mathgoodies then 199 local virtuals = mathgoodies.virtuals 200 local mapfiles = mathgoodies.mapfiles 201 local maplines = mathgoodies.maplines 202 if virtuals then 203 for name, specification in next, virtuals do 204 -- beware, they are all constructed ... we should be more selective 205 mathematics.makefont(name,specification,goodies) 206 end 207 end 208 if mapfiles then 209 for i=1,#mapfiles do 210 fonts.mappings.loadfile(mapfiles[i]) -- todo: backend function 211 end 212 end 213 if maplines then 214 for i=1,#maplines do 215 fonts.mappings.loadline(maplines[i]) -- todo: backend function 216 end 217 end 218 end 219end 220 221fontgoodies.register("mathematics", initialize) 222 223-- local enabled = false directives.register("fontgoodies.mathkerning",function(v) enabled = v end) 224 225-- local function initialize(tfmdata) 226-- -- if enabled and tfmdata.mathparameters then -- funny, cambria text has this 227-- if tfmdata.mathparameters then -- funny, cambria text has this 228-- local goodies = tfmdata.goodies 229-- if goodies then 230-- local characters = tfmdata.characters 231-- if characters[0x1D44E] then -- 119886 232-- -- we have at least an italic a 233-- for i=1,#goodies do 234-- local mathgoodies = goodies[i].mathematics 235-- if mathgoodies then 236-- local kerns = mathgoodies.kerns 237-- if kerns then 238-- local function kernone(unicode,data) 239-- local chardata = characters[unicode] 240-- if chardata and (not chardata.mathkerns or data.force) then 241-- chardata.mathkerns = data 242-- end 243-- end 244-- for unicode, data in next, kerns do 245-- withscriptcode(tfmdata,unicode,data,kernone) 246-- end 247-- return 248-- end 249-- end 250-- end 251-- else 252-- return -- no proper math font anyway 253-- end 254-- end 255-- end 256-- end 257-- 258-- registerotffeature { 259-- name = "mathkerns", 260-- description = "math kerns", 261-- -- default = true, 262-- initializers = { 263-- base = initialize, 264-- node = initialize, 265-- } 266-- } 267 268-- -- math italics (not really needed) 269-- -- 270-- -- it would be nice to have a \noitalics\font option 271-- 272-- local function initialize(tfmdata) 273-- local goodies = tfmdata.goodies 274-- if goodies then 275-- local shared = tfmdata.shared 276-- for i=1,#goodies do 277-- local mathgoodies = goodies[i].mathematics 278-- if mathgoodies then 279-- local mathitalics = mathgoodies.italics 280-- if mathitalics then 281-- local properties = tfmdata.properties 282-- if properties.setitalics then 283-- mathitalics = mathitalics[file.nameonly(properties.name)] or mathitalics 284-- if mathitalics then 285-- if trace_goodies then 286-- report_goodies("loading mathitalics for font %a",properties.name) 287-- end 288-- local corrections = mathitalics.corrections 289-- local defaultfactor = mathitalics.defaultfactor 290-- -- properties.mathitalic_defaultfactor = defaultfactor -- we inherit outer one anyway (name will change) 291-- if corrections then 292-- fontgoodies.registerpostprocessor(tfmdata, function(tfmdata) -- this is another tfmdata (a copy) 293-- -- better make a helper so that we have less code being defined 294-- local properties = tfmdata.properties 295-- local parameters = tfmdata.parameters 296-- local characters = tfmdata.characters 297-- properties.mathitalic_defaultfactor = defaultfactor 298-- properties.mathitalic_defaultvalue = defaultfactor * parameters.quad 299-- if trace_goodies then 300-- report_goodies("assigning mathitalics for font %a",properties.name) 301-- end 302-- local quad = parameters.quad 303-- local hfactor = parameters.hfactor 304-- for k, v in next, corrections do 305-- local c = characters[k] 306-- if c then 307-- if v > -1 and v < 1 then 308-- c.italic = v * quad 309-- else 310-- c.italic = v * hfactor 311-- end 312-- else 313-- report_goodies("invalid mathitalics entry %U for font %a",k,properties.name) 314-- end 315-- end 316-- end) 317-- end 318-- return -- maybe not as these can accumulate 319-- end 320-- end 321-- end 322-- end 323-- end 324-- end 325-- end 326-- 327-- registerotffeature { 328-- name = "mathitalics", 329-- description = "additional math italic corrections", 330-- -- default = true, 331-- initializers = { 332-- base = initialize, 333-- node = initialize, 334-- } 335-- } 336 337local function mathradicalaction(n,h,v,font,mchar,echar) 338 local characters = fontcharacters[font] 339 local mchardata = characters[mchar] 340 local echardata = characters[echar] 341 local ewidth = echardata.width 342 local mwidth = mchardata.width 343 local delta = h - ewidth 344 local glyph = new_glyph(font,echar) 345 local head = glyph 346 if delta > 0 then 347 local count = ceil(delta/mwidth) 348 local kern = (delta - count * mwidth) / count 349 for i=1,count do 350 local k = new_kern(kern) 351 local g = new_glyph(font,mchar) 352 setlink(k,head) 353 setlink(g,k) 354 head = g 355 end 356 end 357 local height = mchardata.height 358 local list = new_hlist(head) 359 local kern = new_kern(height-v) 360 list = setlink(kern,list) 361 local list = new_vlist(kern) 362 insertnodeafter(n,n,list) 363end 364 365local function mathhruleaction(n,h,v,font,bchar,mchar,echar) 366 local characters = fontcharacters[font] 367 local bchardata = characters[bchar] 368 local mchardata = characters[mchar] 369 local echardata = characters[echar] 370 local bwidth = bchardata.width 371 local mwidth = mchardata.width 372 local ewidth = echardata.width 373 local delta = h - ewidth - bwidth 374 local glyph = new_glyph(font,echar) 375 local head = glyph 376 if delta > 0 then 377 local count = ceil(delta/mwidth) 378 local kern = (delta - count * mwidth) / (count+1) 379 for i=1,count do 380 local k = new_kern(kern) 381 local g = new_glyph(font,mchar) 382 setlink(k,head) 383 setlink(g,k) 384 head = g 385 end 386 local k = new_kern(kern) 387 setlink(k,head) 388 head = k 389 end 390 local g = new_glyph(font,bchar) 391 setlink(g,head) 392 head = g 393 local height = mchardata.height 394 local list = new_hlist(head) 395 local kern = new_kern(height-v) 396 list = setlink(kern,list) 397 local list = new_vlist(kern) 398 insertnodeafter(n,n,list) 399end 400 401local function initialize(tfmdata) 402 local goodies = tfmdata.goodies 403 if goodies then 404 local resources = tfmdata.resources 405 local ruledata = { } 406 for i=1,#goodies do 407 local mathematics = goodies[i].mathematics 408 if mathematics then 409 local rules = mathematics.rules 410 if rules then 411 for tag, name in next, rules do 412 ruledata[tag] = name 413 end 414 end 415 end 416 end 417 if next(ruledata) then 418 local characters = tfmdata.characters 419 local unicodes = resources.unicodes 420 if characters and unicodes then 421 local mathruleactions = resources.mathruleactions 422 if not mathruleactions then 423 mathruleactions = { } 424 resources.mathruleactions = mathruleactions 425 end 426 -- 427 local mchar = unicodes[ruledata["radical.extender"] or false] 428 local echar = unicodes[ruledata["radical.end"] or false] 429 if mchar and echar then 430 mathruleactions.radicalaction = function(n,h,v,font) 431 mathradicalaction(n,h,v,font,mchar,echar) 432 end 433 end 434 -- 435 local bchar = unicodes[ruledata["hrule.begin"] or false] 436 local mchar = unicodes[ruledata["hrule.extender"] or false] 437 local echar = unicodes[ruledata["hrule.end"] or false] 438 if bchar and mchar and echar then 439 mathruleactions.hruleaction = function(n,h,v,font) 440 mathhruleaction(n,h,v,font,bchar,mchar,echar) 441 end 442 end 443 -- not that nice but we need to register it at the tex end 444 -- context.enablemathrules("\\fontclass") 445 end 446 end 447 end 448end 449 450registerotffeature { 451 name = "mathrules", 452 description = "check math rules", 453 default = true, 454 initializers = { 455 base = initialize, 456 node = initialize, 457 } 458} 459 |