diff options
author | Hans Hagen <pragma@wxs.nl> | 2017-03-20 18:51:53 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2017-03-20 18:51:53 +0100 |
commit | 8e0089484acf80066e7393b1245d59dda211be09 (patch) | |
tree | a444a174ea8de55816cb4a9c3def00fb4521e7d8 /tex/context/base/mkiv/font-shp.lua | |
parent | 8f5c555274eb48fcaaa3d7f340ee77710846fb7e (diff) | |
download | context-8e0089484acf80066e7393b1245d59dda211be09.tar.gz |
2017-03-20 17:38:00
Diffstat (limited to 'tex/context/base/mkiv/font-shp.lua')
-rw-r--r-- | tex/context/base/mkiv/font-shp.lua | 232 |
1 files changed, 215 insertions, 17 deletions
diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 92ff70127..9447af94c 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -6,17 +6,19 @@ if not modules then modules = { } end modules ['font-shp'] = { license = "see context related readme files" } +local tonumber = tonumber local concat = table.concat -local load, tonumber = load, tonumber +local formatters = string.formatters -local otf = fonts.handlers.otf -local afm = fonts.handlers.afm +local otf = fonts.handlers.otf +local afm = fonts.handlers.afm -local hashes = fonts.hashes -local identifiers = hashes.identifiers +local hashes = fonts.hashes +local identifiers = hashes.identifiers -local version = 0.006 -local cache = containers.define("fonts", "shapes", version, true) +local version = 0.007 +local shapescache = containers.define("fonts", "shapes", version, true) +local streamscache = containers.define("fonts", "streams", version, true) -- shapes (can be come a separate file at some point) @@ -128,7 +130,19 @@ end -- todo: loaders per format -local function load(filename,sub) +local readers = otf.readers +local cleanname = readers.helpers.cleanname + +local function makehash(filename,sub,instance) + local name = cleanname(file.basename(filename)) + if instance then + return formatters["%s-%s-%s"](name,sub or 0,cleanname(instance)) + else + return formatters["%s-%s"] (name,sub or 0) + end +end + +local function loadoutlines(cache,filename,sub,instance) local base = file.basename(filename) local name = file.removesuffix(base) local kind = file.suffix(filename) @@ -140,13 +154,10 @@ local function load(filename,sub) -- fonts.formats if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then - local hash = containers.cleanname(base) -- including suffix - if sub then - hash = hash .. "-" .. sub - end + local hash = makehash(filename,sub,instance) data = containers.read(cache,hash) if not data or data.time ~= time or data.size ~= size then - data = otf.readers.loadshapes(filename,sub) + data = readers.loadshapes(filename,sub,instance) if data then data.size = size data.format = data.format or (kind == "otf" and "opentype") or "truetype" @@ -185,9 +196,196 @@ local function load(filename,sub) return data end +local function loadstreams(cache,filename,sub,instance) + local base = file.basename(filename) + local name = file.removesuffix(base) + local kind = file.suffix(filename) + local attr = lfs.attributes(filename) + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 + local sub = tonumber(sub) + + -- fonts.formats + + if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then + local hash = makehash(filename,sub,instance) + data = containers.read(cache,hash) + if not data or data.time ~= time or data.size ~= size then + data = readers.loadshapes(filename,sub,instance,true) + if data then + local glyphs = data.glyphs + local streams = { } + if glyphs then + for i=0,#glyphs do + streams[i] = glyphs[i].stream or "" + end + end + data.streams = streams + data.glyphs = nil + data.size = size + data.format = data.format or (kind == "otf" and "opentype") or "truetype" + data.time = time + containers.write(cache,hash,data) + data = containers.read(cache,hash) -- frees old mem + end + end + else + data = { + filename = filename, + size = 0, + time = time, + format = "unknown", + glyphs = { } + } + end + return data +end + +local loadedshapes = { } +local loadedstreams = { } + +local function loadoutlinedata(fontdata,streams) + local properties = fontdata.properties + local filename = properties.filename + local subindex = fontdata.subindex + local instance = properties.instance + local hash = makehash(filename,subindex,instance) + local loaded = loadedshapes[hash] + if not loaded then + loaded = loadoutlines(shapescache,filename,subindex,instance) + loadedshapes[hash] = loaded + end + return loaded +end + hashes.shapes = table.setmetatableindex(function(t,k) - local d = identifiers[k] - local v = load(d.properties.filename,d.subindex) - t[k] = v - return v + local f = identifiers[k] + if f then + return loadoutlinedata(f) + end end) + +local function loadstreamdata(fontdata,streams) + local properties = fontdata.properties + local filename = properties.filename + local subindex = fontdata.subindex + local instance = properties.instance + local hash = makehash(filename,subindex,instance) + local loaded = loadedstreams[hash] + if not loaded then + loaded = loadstreams(streamscache,filename,subindex,instance) + loadedstreams[hash] = loaded + end + return loaded +end + +hashes.streams = table.setmetatableindex(function(t,k) + local f = identifiers[k] + if f then + return loadstreamdata(f,true) + end +end) + +otf.loadoutlinedata = loadoutlinedata -- not public +otf.loadstreamdata = loadstreamdata -- not public +otf.loadshapes = loadshapes + +-- experimental code, for me only ... unsupported + +local f_c = string.formatters["%F %F %F %F %F %F c"] +local f_l = string.formatters["%F %F l"] +local f_m = string.formatters["%F %F m"] + +local function segmentstopdf(segments,factor,bt,et) + local t = { } + local n = #segments + for i=1,n do + local s = segments[i] + local m = #s + local w = s[m] + if w == "c" then + t[i] = f_c(s[1]*factor,s[2]*factor,s[3]*factor,s[4]*factor,s[5]*factor,s[6]*factor) + elseif w == "l" then + t[i] = f_l(s[1]*factor,s[2]*factor) + elseif w == "m" then + t[i] = f_m(s[1]*factor,s[2]*factor) + else + t[i] = "" + end + end + t[n+1] = "h f" -- B* + if bt and et then + t[0] = bt + t[n+2] = et + return concat(t,"\n",0,n+2) + else + return concat(t,"\n") + end +end + +local function addvariableshapes(tfmdata,key,value) + if value then + local shapes = otf.loadoutlinedata(tfmdata) + if not shapes then + return + end + local glyphs = shapes.glyphs + if not glyphs then + return + end + local characters = tfmdata.characters + local parameters = tfmdata.parameters + local hfactor = parameters.hfactor * (7200/7227) + local factor = hfactor / 65536 + local getactualtext = otf.getactualtext + for unicode, char in next, characters do + if not char.commands then + local shape = glyphs[char.index] + if shape then + local segments = shape.segments + if segments then + -- we need inline in order to support color + local bt, et = getactualtext(char.tounicode or char.unicode or unicode) + char.commands = { + { "special", "pdf:" .. segmentstopdf(segments,factor,bt,et) } + } + end + end + end + end + end +end + +otf.features.register { + name = "variableshapes", -- enforced for now + description = "variable shapes", + manipulators = { + base = addvariableshapes, + node = addvariableshapes, + } +} + +-- In the end it is easier to just provide the new charstring (cff) and points (ttdf). First +-- of all we already have the right information so there is no need to patch the already complex +-- backend code (we only need to make sure the cff is valid). Also, I prototyped support for +-- these fonts using (converted to) normal postscript shapes, a functionality that was already +-- present for a while for metafun. This solution even permits us to come up with usage of such +-- fonts in unexpected ways. It also opens the road to shapes generated with metafun includes +-- as real cff (or ttf) shapes instead of virtual in-line shapes. +-- +-- This is probably a prelude to writing a complete backend font inclusion plugin in lua. After +-- all I already have most info. For this we just need to pass a list of used glyphs (or analyze +-- them ourselves). + +local streams = fonts.hashes.streams + +callback.register("glyph_stream_provider",function(id,index,mode) + if id > 0 then + local streams = streams[id].streams + -- print(id,index,streams[index]) + if streams then + return streams[index] or "" + end + end + return "" + end) |