diff options
author | Hans Hagen <pragma@wxs.nl> | 2009-05-28 11:23:00 +0200 |
---|---|---|
committer | Hans Hagen <pragma@wxs.nl> | 2009-05-28 11:23:00 +0200 |
commit | 1d3090326210c6e6f7ec5432799ded25b75bba46 (patch) | |
tree | c5921203789ec669e6bccaba4bd56f9c072dc56b /tex/context/base/font-afm.lua | |
parent | 94d83f84758766511c5e324721e39fea6ab71dae (diff) | |
download | context-1d3090326210c6e6f7ec5432799ded25b75bba46.tar.gz |
beta 2009.05.28 11:23
Diffstat (limited to 'tex/context/base/font-afm.lua')
-rw-r--r-- | tex/context/base/font-afm.lua | 344 |
1 files changed, 196 insertions, 148 deletions
diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua index eef80c597..6cc227588 100644 --- a/tex/context/base/font-afm.lua +++ b/tex/context/base/font-afm.lua @@ -17,7 +17,11 @@ where we handles font encodings. Eventually font encoding goes away.</p> --ldx]]-- -local format = string.format +local trace_features = false trackers.register("afm.features", function(v) trace_features = v end) +local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end) +local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end) + +local format, match, gmatch, lower = string.format, string.match, string.gmatch, string.lower fonts = fonts or { } fonts.afm = fonts.afm or { } @@ -25,10 +29,9 @@ fonts.afm = fonts.afm or { } local afm = fonts.afm local tfm = fonts.tfm -afm.version = 1.30 -- incrementing this number one up will force a re-cache -afm.syncspace = true -- when true, nicer stretch values -afm.enhance_data = true -- best leave this set to true -afm.trace_features = false +afm.version = 1.400 -- incrementing this number one up will force a re-cache +afm.syncspace = true -- when true, nicer stretch values +afm.enhance_data = true -- best leave this set to true afm.features = { } afm.features.aux = { } afm.features.data = { } @@ -93,25 +96,25 @@ end local keys = { } -function keys.FontName (data,line) data.fullname = line:strip() end -function keys.ItalicAngle (data,line) data.italicangle = tonumber (line) end -function keys.IsFixedPitch(data,line) data.isfixedpitch = toboolean(line,true) end -function keys.CharWidth (data,line) data.charwidth = tonumber (line) end -function keys.XHeight (data,line) data.xheight = tonumber (line) end -function keys.Descender (data,line) data.descender = tonumber (line) end -function keys.Ascender (data,line) data.ascender = tonumber (line) end +function keys.FontName (data,line) data.metadata.fullname = line:strip() end +function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end +function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end +function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end +function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end +function keys.Descender (data,line) data.metadata.descender = tonumber (line) end +function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end function keys.Comment (data,line) -- Comment DesignSize 12 (pts) -- Comment TFM designsize: 12 (in points) - line = line:lower() - local designsize = line:match("designsize[^%d]*(%d+)") - if designsize then data.designsize = tonumber(designsize) end + line = lower(line) + local designsize = match(line,"designsize[^%d]*(%d+)") + if designsize then data.metadata.designsize = tonumber(designsize) end end local function get_charmetrics(data,charmetrics,vector) local characters = data.characters local chr, str, ind = { }, "", 0 - for k,v in charmetrics:gmatch("([%a]+) +(.-) *;") do + for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do if k == 'C' then if str ~= "" then characters[str] = chr end chr = { } @@ -128,10 +131,10 @@ local function get_charmetrics(data,charmetrics,vector) elseif k == 'N' then str = v elseif k == 'B' then - local llx, lly, urx, ury = v:match("^ *(.-) +(.-) +(.-) +(.-)$") + local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$") chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) } elseif k == 'L' then - local plus, becomes = v:match("^(.-) +(.-)$") + local plus, becomes = match(v,"^(.-) +(.-)$") if not chr.ligatures then chr.ligatures = { } end chr.ligatures[plus] = becomes end @@ -143,7 +146,7 @@ end local function get_kernpairs(data,kernpairs) local characters = data.characters - for one, two, value in kernpairs:gmatch("KPX +(.-) +(.-) +(.-)\n") do + for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do local chr = characters[one] if chr then if not chr.kerns then chr.kerns = { } end @@ -153,83 +156,85 @@ local function get_kernpairs(data,kernpairs) end local function get_variables(data,fontmetrics) - for key, rest in fontmetrics:gmatch("(%a+) *(.-)[\n\r]") do + for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do if keys[key] then keys[key](data,rest) end end end local function get_indexes(data,filename) - local trace = fonts.trace - local pfbname = input.find_file(file.removesuffix(filename)..".pfb","pfb") or "" + local pfbfile = file.replacesuffix(filename,"pfb") + local pfbname = resolvers.find_file(pfbfile,"pfb") or "" if pfbname == "" then - pfbname = input.find_file(file.removesuffix(file.basename(filename))..".pfb","pfb") or "" + pfbname = resolvers.find_file(file.basename(pfbfile),"pfb") or "" end if pfbname ~= "" then - data.luatex = data.luatex or { } data.luatex.filename = pfbname - local pfbblob = fontforge.open(pfbname) + local pfbblob = fontloader.open(pfbname) if pfbblob then local characters = data.characters - local pfbdata = fontforge.to_table(pfbblob) + local pfbdata = fontloader.to_table(pfbblob) --~ print(table.serialize(pfbdata)) if pfbdata then local glyphs = pfbdata.glyphs if glyphs then - if trace then + if trace_loading then logs.report("load afm","getting index data from %s",pfbname) end -- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0 - for index, glyph in pairs(glyphs) do + for index, glyph in next, glyphs do local name = glyph.name if name then local char = characters[name] if char then - if trace then + if trace_indexing then logs.report("load afm","glyph %s has index %s",name,index) end char.index = index end end end - elseif trace then + elseif trace_loading then logs.report("load afm","no glyph data in pfb file %s",pfbname) end - elseif trace then + elseif trace_loading then logs.report("load afm","no data in pfb file %s",pfbname) end - elseif trace then + fontloader.close(pfbblob) + elseif trace_loading then logs.report("load afm","invalid pfb file %s",pfbname) end - elseif trace then + elseif trace_loading then logs.report("load afm","no pfb file for %s",filename) end end function afm.read_afm(filename) - local ok, afmblob, size = input.loadbinfile(filename) -- has logging + local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging -- local ok, afmblob = true, file.readdata(filename) if ok and afmblob then local data = { - version = version or '0', characters = { }, - filename = file.removesuffix(file.basename(filename)) + metadata = { + version = version or '0', -- hm + filename = file.removesuffix(file.basename(filename)) + } } afmblob = afmblob:gsub("StartCharMetrics(.-)EndCharMetrics", function(charmetrics) - if fonts.trace then + if trace_loading then logs.report("load afm","loading char metrics") end get_charmetrics(data,charmetrics,vector) return "" end) afmblob = afmblob:gsub("StartKernPairs(.-)EndKernPairs", function(kernpairs) - if fonts.trace then + if trace_loading then logs.report("load afm","loading kern pairs") end get_kernpairs(data,kernpairs) return "" end) afmblob = afmblob:gsub("StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics) - if fonts.trace then + if trace_loading then logs.report("load afm","loading variables") end data.afmversion = version @@ -237,10 +242,11 @@ function afm.read_afm(filename) data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now return "" end) + data.luatex = { } get_indexes(data,filename) return data else - if fonts.trace then + if trace_loading then logs.report("load afm","no valid afm file %s",filename) end return nil @@ -254,50 +260,53 @@ way we can set them faster when defining a font.</p> --ldx]]-- function afm.load(filename) - local name = file.removesuffix(filename) - local data = containers.read(afm.cache(),name) - if data and data.verbose ~= fonts.verbose then - data = nil - end - local size = lfs.attributes(name,"size") or 0 - if data and data.size ~= size then - data = nil - end - if not data then - local foundname = input.find_file(filename,'afm') - if foundname and foundname ~= "" then - data = afm.read_afm(foundname) + -- hm, for some reasons not resolved yet + filename = resolvers.find_file(filename,'afm') or "" + if filename ~= "" then + local name = file.removesuffix(file.basename(filename)) + local data = containers.read(afm.cache(),name) + local size = lfs.attributes(filename,"size") or 0 + if not data or data.verbose ~= fonts.verbose or data.size ~= size then + logs.report("load afm", "reading %s",filename) + data = afm.read_afm(filename) if data then + -- data.luatex = data.luatex or { } + logs.report("load afm", "unifying %s",filename) afm.unify(data,filename) if afm.enhance_data then + logs.report("load afm", "add ligatures") afm.add_ligatures(data,'ligatures') -- easier this way + logs.report("load afm", "add tex-ligatures") afm.add_ligatures(data,'texligatures') -- easier this way + logs.report("load afm", "add extra kerns") afm.add_kerns(data) -- faster this way end - logs.report("load afm","file size: %s",size) data.size = size data.verbose = fonts.verbose - logs.report("load afm","saving: in cache") + logs.report("load afm","saving: %s in cache",name) data = containers.write(afm.cache(), name, data) + data = containers.read(afm.cache(),name) end end + return data + else + return nil end - return data end function afm.unify(data, filename) local unicodevector = fonts.enc.load('unicode').hash local glyphs, indices, unicodes, names = { }, { }, { }, { } local verbose, private = fonts.verbose, fonts.private - for name, blob in pairs(data.characters) do + for name, blob in next, data.characters do local code = unicodevector[name] -- or characters.name_to_unicode[name] if not code then - local u = name:match("^uni(%x+)$") + local u = match(name,"^uni(%x+)$") code = u and tonumber(u,16) if not code then code = private private = private + 1 - logs.report("afm glyph", "assigning private slot 0x%04X for unknown glyph name %s", code, name) + logs.report("afm glyph", "assigning private slot U+%04X for unknown glyph name %s", code, name) end end local index = blob.index @@ -319,14 +328,15 @@ function afm.unify(data, filename) blob.index = nil end end - data.luatex = { - filename = file.basename(filename), - unicodes = unicodes, -- name to unicode - indices = indices, -- unicode to index - names = names, -- name to index - } data.glyphs = glyphs data.characters = nil + local luatex = data.luatex + luatex.filename = luatex.filename or file.removesuffix(file.basename(filename)) + luatex.unicodes = unicodes -- name to unicode + luatex.indices = indices -- unicode to index + luatex.marks = { } -- todo + luatex.names = names -- name to index + luatex.private = private end --[[ldx-- @@ -335,15 +345,12 @@ and extra kerns. This saves quite some lookups later.</p> --ldx]]-- function afm.add_ligatures(afmdata,ligatures) - local glyphs = afmdata.glyphs - local luatex = afmdata.luatex - local indices = luatex.indices - local unicodes = luatex.unicodes - local names = luatex.names - for k,v in pairs(characters[ligatures]) do -- main characters table + local glyphs, luatex = afmdata.glyphs, afmdata.luatex + local indices, unicodes, names = luatex.indices, luatex.unicodes, luatex.names + for k,v in next, characters[ligatures] do -- main characters table local one = glyphs[names[k]] if one then - for _, b in pairs(v) do + for _, b in next, v do two, three = b[1], b[2] if two and three and names[two] and names[three] then local ol = one[ligatures] @@ -370,28 +377,42 @@ function afm.add_kerns(afmdata) local names = afmdata.luatex.names local uncomposed = characters.uncomposed local function do_it_left(what) - for index, glyph in pairs(glyphs) do - if glyph.kerns then - local k = { } - for complex, simple in pairs(uncomposed[what]) do - local ks = k[simple] - if ks and not k[complex] then - k[complex] = ks + for index, glyph in next, glyphs do + local kerns = glyph.kerns + if kerns then + local extrakerns = glyph.extrakerns or { } + for complex, simple in next, uncomposed[what] do + if names[compex] then + local ks = kerns[simple] + if ks and not kerns[complex] then + extrakerns[complex] = ks + end end end - if next(k) then - glyph.extrakerns = k + if next(extrakerns) then + glyph.extrakerns = extrakerns end end end end local function do_it_copy(what) - for complex, simple in pairs(uncomposed[what]) do + for complex, simple in next, uncomposed[what] do local c = glyphs[names[complex]] if c then -- optional local s = glyphs[names[simple]] - if s and s.kerns then - c.extrakerns = s.kerns -- ok ? no merge ? + if s then + if not c.kerns then + c.extrakerns = s.kerns or { } + end + if s.extrakerns then + local extrakerns = c.extrakerns or { } + for k, v in next, s.extrakerns do + extrakerns[k] = v + end + if next(extrakerns) then + s.extrakerns = extrakerns + end + end end end end @@ -413,12 +434,20 @@ end function afm.add_dimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name if data then - for index, glyph in pairs(data.glyphs) do + for index, glyph in next, data.glyphs do local bb = glyph.boundingbox if bb then local ht, dp = bb[4], -bb[2] - if ht ~= 0 then glyph.height = ht end - if dp ~= 0 then glyph.depth = dp end + if ht == 0 or ht < 0 then + -- no need to set it and no negative heights, nil == 0 + else + glyph.height = ht + end + if dp == 0 or dp < 0 then + -- no negative depths and no negative depths, nil == 0 + else + glyph.depth = dp + end end end end @@ -428,42 +457,48 @@ function afm.copy_to_tfm(data) if data then local glyphs = data.glyphs if glyphs then + local metadata, luatex = data.metadata, data.luatex + local unicodes, indices = luatex.unicodes, luatex.indices local characters, parameters, descriptions = { }, { }, { } - local unicodes = data.luatex.unicodes - local indices = data.luatex.indices - local tfm = { characters = characters, parameters = parameters, descriptions = descriptions } - for u, i in pairs(indices) do + local tfm = { + characters = characters, + parameters = parameters, + descriptions = descriptions, + indices = indices, + unicodes = unicodes, + luatex = luatex, + } + for u, i in next, indices do local d = glyphs[i] - characters[u] = { } -- not needed + characters[u] = { } descriptions[u] = d - d.index = i end - tfm.encodingbytes = data.encodingbytes or 2 - tfm.fullname = data.fullname - tfm.filename = data.filename - tfm.name = tfm.fullname -- data.name or tfm.fullname + tfm.encodingbytes = metadata.encodingbytes or 2 + tfm.fullname = metadata.fullname + tfm.filename = metadata.filename + tfm.name = tfm.fullname tfm.type = "real" tfm.units = 1000 - tfm.stretch = stretch - tfm.slant = slant + tfm.stretch = stretch -- nil + tfm.slant = slant -- nil tfm.direction = 0 tfm.boundarychar_label = 0 tfm.boundarychar = 65536 --~ tfm.false_boundarychar = 65536 -- produces invalid tfm in luatex - tfm.designsize = (data.designsize or 10)*65536 + tfm.designsize = (metadata.designsize or 10)*65536 local spaceunits = 500 tfm.spacer = "500 units" -- same as otf local endash, emdash = unicodes['space'], unicodes['emdash'] - if data.isfixedpitch then + if metadata.isfixedpitch then if descriptions[endash] then spaceunits, tfm.spacer = descriptions[endash].width, "space" end if not spaceunits and descriptions[emdash] then spaceunits, tfm.spacer = descriptions[emdash].width, "emdash" end - if not spaceunits and data.charwidth then - spaceunits, tfm.spacer = data.charwidth, "charwidth" + if not spaceunits and metadata.charwidth then + spaceunits, tfm.spacer = metadata.charwidth, "charwidth" end else if descriptions[endash] then @@ -472,8 +507,8 @@ function afm.copy_to_tfm(data) -- if not spaceunits and descriptions[emdash] then -- spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2" -- end - if not spaceunits and data.charwidth then - spaceunits, tfm.spacer = data.charwidth, "charwidth" + if not spaceunits and metadata.charwidth then + spaceunits, tfm.spacer = metadata.charwidth, "charwidth" end end -- @@ -484,25 +519,26 @@ function afm.copy_to_tfm(data) parameters.space_shrink = 333 parameters.x_height = 400 parameters.quad = 1000 - parameters.extra_space = 0 if spaceunits < 200 then -- todo: warning end - tfm.italicangle = data.italicangle - tfm.ascender = math.abs(data.ascender or 0) - tfm.descender = math.abs(data.descender or 0) - if data.italicangle then - parameters.slant = parameters.slant - math.round(math.tan(data.italicangle*math.pi/180)) + tfm.ascender = math.abs(metadata.ascender or 0) + tfm.descender = math.abs(metadata.descender or 0) + local italicangle = data.metadata.italicangle + if italicangle then + tfm.italicangle = italicangle + parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180)) end - if data.isfixedpitch then + if metadata.isfixedpitch then parameters.space_stretch = 0 parameters.space_shrink = 0 elseif afm.syncspace then parameters.space_stretch = spaceunits/2 parameters.space_shrink = spaceunits/3 end - if data.xheight and data.xheight > 0 then - parameters.x_height = data.xheight + parameters.extra_space = parameters.space_shrink + if metadata.xheight and metadata.xheight > 0 then + parameters.x_height = metadata.xheight else -- same as otf local x = unicodes['x'] @@ -516,7 +552,7 @@ function afm.copy_to_tfm(data) end local fd = data.fontdimens if fd and fd[8] and fd[9] and fd[10] then -- math - for k,v in pairs(fd) do + for k,v in next, fd do parameters[k] = v end end @@ -543,47 +579,59 @@ end function afm.set_features(tfmdata) local shared = tfmdata.shared local afmdata = shared.afmdata - -- elsewhere: shared.features = fonts.define.check(shared.features,afm.features.default) local features = shared.features if not table.is_empty(features) then local mode = tfmdata.mode or fonts.mode - local fi = fonts.initializers[mode] - if fi and fi.afm then - local function initialize(list) -- using tex lig and kerning + local initializers = fonts.initializers + local fi = initializers[mode] + local fiafm = fi and fi.afm + if fiafm then + local lists = { + fonts.triggers, + afm.features.list, + fonts.manipulators, + } + for l=1,3 do + local list = lists[l] if list then - for _, f in ipairs(list) do + for i=1,#list do + local f = list[i] local value = features[f] - if value and fi.afm[f] then -- brr - if afm.trace_features then + if value and fiafm[f] then -- brr + if trace_features then logs.report("define afm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown') end - fi.afm[f](tfmdata,value) + fiafm[f](tfmdata,value) mode = tfmdata.mode or fonts.mode - fi = fonts.initializers[mode] + fiafm = initializers[mode].afm end end end end - initialize(fonts.triggers) - initialize(afm.features.list) - initialize(fonts.manipulators) end local fm = fonts.methods[mode] - if fm and fm.afm then - local function register(list) -- node manipulations + local fmafm = fm and fm.afm + if fmfm then + local lists = { + afm.features.list, + } + local sp = shared.processors + for l=1,1 do + local list = lists[l] if list then - for _, f in ipairs(list) do - if features[f] and fm.afm[f] then -- brr - if not shared.processors then -- maybe also predefine - shared.processors = { fm.afm[f] } + for i=1,#list do + local f = list[i] + if features[f] and fmafm[f] then -- brr + if not sp then + sp = { fmafm[f] } + shared.processors = sp else - shared.processors[#shared.processors+1] = fm.afm[f] + sp[#sp+1] = fmafm[f] end end end end end - register(afm.features.list) end end end @@ -598,21 +646,21 @@ end function afm.afm_to_tfm(specification) local afmname = specification.filename or specification.name - local encoding, filename = afmname:match("^(.-)%-(.*)$") -- context: encoding-name.* + local encoding, filename = match(afmname,"^(.-)%-(.*)$") -- context: encoding-name.* if encoding and filename and fonts.enc.known[encoding] then tfm.set_normal_feature(specification,'encoding',encoding) -- will go away - if fonts.trace then + if trace_loading then logs.report("load afm","stripping encoding prefix from filename %s",afmname) end afmname = filename - elseif specification.forced == "afm" then - if fonts.trace then + elseif specification.forced == "afm" or specification.format == "afm" then -- move this one up + if trace_loading then logs.report("load afm","forcing afm format for %s",afmname) end else - local tfmname = input.findbinfile(afmname,"ofm") or "" + local tfmname = resolvers.findbinfile(afmname,"ofm") or "" if tfmname ~= "" then - if fonts.trace then + if trace_loading then logs.report("load afm","fallback from afm to tfm for %s",afmname) end afmname = "" @@ -638,7 +686,7 @@ function afm.afm_to_tfm(specification) tfmdata.shared.features = features afm.set_features(tfmdata) end - elseif fonts.trace then + elseif trace_loading then logs.report("load afm","no (valid) afm file found with name %s",afmname) end tfmdata = containers.write(tfm.cache(),cache_id,tfmdata) @@ -677,8 +725,8 @@ function tfm.read_from_afm(specification) end if filename then tfmtable.encodingbytes = 2 - tfmtable.filename = input.findbinfile(filename,"") or filename - tfmtable.fullname = afmdata.fontname or afmdata.fullname + tfmtable.filename = resolvers.findbinfile(filename,"") or filename + tfmtable.fullname = afmdata.metadata.fontname or afmdata.metadata.fullname tfmtable.format = 'type1' tfmtable.name = afmdata.luatex.filename or tfmtable.fullname end @@ -701,7 +749,7 @@ function afm.features.prepare_ligatures(tfmdata,ligatures,value) local luatex = afmdata.luatex local unicodes = luatex.unicodes local descriptions = tfmdata.descriptions - for u, chr in pairs(tfmdata.characters) do + for u, chr in next, tfmdata.characters do local d = descriptions[u] local l = d[ligatures] if l then @@ -710,7 +758,7 @@ function afm.features.prepare_ligatures(tfmdata,ligatures,value) ligatures = { } chr.ligatures = ligatures end - for k, v in pairs(l) do + for k, v in next, l do local uk, uv = unicodes[k], unicodes[v] if uk and uv then ligatures[uk] = { @@ -730,7 +778,7 @@ function afm.features.prepare_kerns(tfmdata,kerns,value) local luatex = afmdata.luatex local unicodes = luatex.unicodes local descriptions = tfmdata.descriptions - for u, chr in pairs(tfmdata.characters) do + for u, chr in next, tfmdata.characters do local d = descriptions[u] local newkerns = d[kerns] if newkerns then @@ -739,7 +787,7 @@ function afm.features.prepare_kerns(tfmdata,kerns,value) kerns = { } chr.kerns = kerns end - for k,v in pairs(newkerns) do + for k,v in next, newkerns do local uk = unicodes[k] if uk then kerns[uk] = v |