diff options
author | Hans Hagen <pragma@wxs.nl> | 2019-04-04 14:11:01 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2019-04-04 14:11:01 +0200 |
commit | 64f6e8fc0c6cb9254a6fe3db0b4ab31c51cf8524 (patch) | |
tree | 1b36a0b35f5b6d516d27fe817a27249d4c6d9c78 /tex/context/base/mkiv/font-tpk.lua | |
parent | 70a938c4934f042face9805fc4c392c0676b11d5 (diff) | |
download | context-64f6e8fc0c6cb9254a6fe3db0b4ab31c51cf8524.tar.gz |
2019-04-04 13:38:00
Diffstat (limited to 'tex/context/base/mkiv/font-tpk.lua')
-rw-r--r-- | tex/context/base/mkiv/font-tpk.lua | 1292 |
1 files changed, 1292 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/font-tpk.lua b/tex/context/base/mkiv/font-tpk.lua new file mode 100644 index 000000000..8f4b00b56 --- /dev/null +++ b/tex/context/base/mkiv/font-tpk.lua @@ -0,0 +1,1292 @@ + if not modules then modules = { } end modules ['font-tpk'] = { + version = 1.001, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The bitmap loader is more or less derived from the luatex version (taco) +-- which is derived from pdftex (thanh) who uses code from dvips (thomas) +-- adapted by piet ... etc. The tfm and vf readers are also derived from +-- luatex. All do things a bit more luaish and errors are of course mine. + +local next = next +local extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift +local idiv = number.idiv +local char = string.char +local concat, insert, remove, copy = table.concat, table.insert, table.remove, table.copy +local tobitstring = number.tobitstring +local formatters = string.formatters +local round = math.round + +local streams = utilities.streams +local openstream = streams.open +local streamsize = streams.size +local readcardinal1 = streams.readcardinal1 +local readcardinal2 = streams.readcardinal2 +local readcardinal3 = streams.readcardinal3 +local readcardinal4 = streams.readcardinal4 +local readinteger1 = streams.readinteger1 +local readinteger2 = streams.readinteger2 +local readinteger3 = streams.readinteger3 +local readinteger4 = streams.readinteger4 +local readbyte = streams.readbyte +local readbytes = streams.readbytes +local readstring = streams.readstring +local skipbytes = streams.skipbytes +local getposition = streams.getposition +local setposition = streams.setposition + +if not fonts then fonts = { handlers = { tfm = { } } } end + +local handlers = fonts.handlers +local tfm = handlers.tfm or { } +handlers.tfm = tfm +local readers = tfm.readers or { } +tfm.readers = readers + +tfm.version = 1.005 +tfm.cache = containers.define("fonts", "tfm", tfm.version, true) + +-- Performance is no real issue here so I didn't optimize too much. After +-- all, these files are small and we mostly use opentype or type1 fonts. + +do + + local function readbitmap(glyph,s,flagbyte) + + local inputbyte = 0 + local bitweight = 0 + local dynf = 0 + local remainder = 0 + local realfunc = nil + local repeatcount = 0 + + local function getnyb() -- can be inlined + if bitweight == 0 then + bitweight = 16 + inputbyte = readbyte(s) + return extract(inputbyte,4,4) + else + bitweight = 0 + return band(inputbyte,15) + end + end + + local function getbit() -- can be inlined + bitweight = rshift(bitweight,1) + if bitweight == 0 then -- actually we can check for 1 + inputbyte = readbyte(s) + bitweight = 128 + end + return band(inputbyte,bitweight) + end + + local function pkpackednum() + local i = getnyb(s) + if i == 0 then + repeat + j = getnyb() + i = i + 1 + until (j ~= 0) + if i > 3 then + return handlehuge(i,j) + else + for i=1,i do + j = j * 16 + getnyb() + end + return j - 15 + (13 - dynf) * 16 + dynf + end + elseif i <= dynf then + return i + elseif i < 14 then + return (i - dynf - 1) * 16 + getnyb() + dynf + 1 + elseif i == 14 then + repeatcount = pkpackednum() + else + repeatcount = 1 + end + return realfunc() + end + + local function rest() + if remainder < 0 then + remainder = -remainder + return 0 + elseif remainder > 4000 then + remainder = 4000 - remainder + return 4000 + elseif remainder > 0 then + local i = remainder + remainder = 0 + realfunc = pkpackednum + return i + else + -- error = "pk issue that shouldn't happen" + return 0 + end + end + + local function handlehuge(i,j) + while i ~= 0 do + j = lshift(j,4) + getnyb() + -- j = extract(j,8,4) + getnyb() + i = i - 1 + end + remainder = j - 15 + (13 - dynf) * 16 + dynf + realfunc = rest + return rest() + end + + local gpower = { [0] = + 0, 1, 3, 7, 15, 31, 63, 127, + 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535 + } + + local raster = { } + local r = 0 + glyph.stream = raster + + local xsize = glyph.xsize + local ysize = glyph.ysize + local word = 0 + local wordweight = 0 + local wordwidth = idiv(xsize + 15,16) + local rowsleft = 0 + local turnon = band(flagbyte,8) == 8 and true or false + local hbit = 0 + local count = 0 + -- + realfunc = pkpackednum + dynf = idiv(flagbyte,16) + -- + if dynf == 14 then + bitweight = 0 + for i=1,ysize do + word = 0 + wordweight = 32768 + for j=1,xsize do + if getbit() ~= 0 then + word = word + wordweight + end + wordweight = rshift(wordweight,1) + if wordweight == 0 then + r = r + 1 + raster[r] = word + word = 0 + wordweight = 32768 + end + end + if wordweight ~= 32768 then + r = r + 1 + raster[r] = word + end + end + else + rowsleft = ysize + hbit = xsize + repeatcount = 0 + wordweight = 16 + word = 0 + bitweight = 0 + while rowsleft > 0 do + count = realfunc() + while count ~= 0 do + if count < wordweight and count < hbit then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - count] + end + hbit = hbit - count + wordweight = wordweight - count + count = 0 + elseif count >= hbit and hbit <= wordweight then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - hbit] + end + r = r + 1 + raster[r] = word + for i=1,repeatcount*wordwidth do + r = r + 1 + raster[r] = raster[r - wordwidth] + end + rowsleft = rowsleft - repeatcount - 1 + repeatcount = 0 + word = 0 + wordweight = 16 + count = count - hbit + hbit = xsize + else + if turnon then + word = word + gpower[wordweight] + end + r = r + 1 + raster[r] = word + word = 0 + count = count - wordweight + hbit = hbit - wordweight + wordweight = 16 + end + end + turnon = not turnon + end + if rowsleft ~= 0 or hbit ~= xsize then + print("ERROR",rowsleft,hbit,xsize) + -- error = "error while unpacking, more bits than required" + end + end + + end + + function readers.showpk(glyph) + local xsize = glyph.xsize + local ysize = glyph.ysize + local stream = glyph.stream + local result = { } + local rr = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + r = 0 + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; rr[r] = tobitstring(b,16,16) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; rr[r] = tobitstring(b,16,16) + else + r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw) + end + result[y] = concat(rr) + end + return concat(result,"\n") + end + + local template = formatters [ [[ + %.3N 0 %i %i %i %i d1 + q + %i 0 0 %i %i %i cm + BI + /W %i + /H %i + /IM true + /BPC 1 + /D [1 0] + ID %t + EI + Q]] ] + + function readers.pktopdf(glyph,width) + local xsize = glyph.xsize or 0 + local ysize = glyph.ysize or 0 + local xoffset = glyph.xoffset or 0 + local yoffset = glyph.yoffset or 0 + local stream = glyph.stream + + local dpi = 1 + local newdpi = 1 + + local xdpi = dpi * xsize / newdpi + local ydpi = dpi * ysize / newdpi + + local llx = - xoffset + local lly = yoffset - ysize + 1 + local urx = llx + xsize + 1 + local ury = lly + ysize + + local result = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + else + r = r + 1 ; result[r] = char(extract(b,8,8)) + end + end + return + template(width,llx,lly,urx,ury,xdpi,ydpi,llx,lly,xsize,ysize,result), + llx, lly, urx, ury + end + + function readers.loadpk(filename) + local s = openstream(filename) + local preamble = readcardinal1(s) + local version = readcardinal1(s) + local comment = readstring(s,readcardinal1(s)) + local designsize = readcardinal4(s) + local checksum = readcardinal4(s) + local hppp = readcardinal4(s) + local vppp = readcardinal4(s) + if preamble ~= 247 or version ~= 89 or not vppp then + return { error = "invalid preamble" } + end + local glyphs = { } + local data = { + designsize = designsize, + comment = comment, + hppp = hppp, + vppp = vppp, + glyphs = glyphs, + } + while true do + local flagbyte = readcardinal1(s) + if flagbyte < 240 then + local c = band(flagbyte,7) + local length, index, width, pixels, xsize, ysize, xoffset, yoffset + if c >= 0 and c <= 3 then + length = band(flagbyte,7) * 256 + readcardinal1(s) - 3 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal1(s) + xsize = readcardinal1(s) + ysize = readcardinal1(s) + xoffset = readcardinal1(s) + yoffset = readcardinal1(s) + if xoffset > 127 then + xoffset = xoffset - 256 + end + if yoffset > 127 then + yoffset = yoffset - 256 + end + elseif c >= 4 and c <= 6 then + length = band(flagbyte,3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal2(s) + xsize = readcardinal2(s) + ysize = readcardinal2(s) + xoffset = readcardinal2(s) + yoffset = readcardinal2(s) + else -- 7 + length = readcardinal4(s) - 9 + index = readcardinal4(s) + width = readinteger4(s) + pixels = readcardinal4(s) + readcardinal4(s) + xsize = readcardinal4(s) + ysize = readcardinal4(s) + xoffset = readcardinal4(s) + yoffset = readcardinal4(s) + end + local glyph = { + index = index, + width = width, + pixels = pixels, + xsize = xsize, + ysize = ysize, + xoffset = xoffset, + yoffset = yoffset, + } + if length <= 0 then + data.error = "bad packet" + return data + end + readbitmap(glyph,s,flagbyte) + glyphs[index] = glyph + elseif flagbyte == 240 then + -- k[1] x[k] + skipbytes(s,readcardinal1(s)) + elseif flagbyte == 241 then + -- k[2] x[k] + skipbytes(s,readcardinal2(s)*2) + elseif flagbyte == 242 then + -- k[3] x[k] + skipbytes(s,readcardinal3(s)*3) + elseif flagbyte == 243 then + -- k[4] x[k] + skipbytes(s,readcardinal4(s)*4) -- readinteger4 + elseif flagbyte == 244 then + -- y[4] + skipbytes(s,4) + elseif flagbyte == 245 then + break + elseif flagbyte == 246 then + -- nop + else + data.error = "unknown pk command" + break + end + end + return data + end + +end + +do + + local leftboundary = -1 + local rightboundary = -2 + local boundarychar = 65536 + + function readers.loadtfm(filename) + local data + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + local s = openstream(filename) + if not s then + return someerror() + end + -- + local wide = false + local header = 0 + local max = 0 + local size = streamsize(s) + local glyphs = table.setmetatableindex(function(t,k) local v = { } t[k] = v return v end) + local parameters = { } + local direction = 0 + -- + local lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np + -- + lf = readcardinal2(s) + if lf ~= 0 then + header = 6 + max = 255 + wide = false + lh = readcardinal2(s) + bc = readcardinal2(s) + ec = readcardinal2(s) + nw = readcardinal2(s) + nh = readcardinal2(s) + nd = readcardinal2(s) + ni = readcardinal2(s) + nl = readcardinal2(s) + nk = readcardinal2(s) + ne = readcardinal2(s) + np = readcardinal2(s) + else + header = 14 + max = 65535 + wide = readcardinal4(s) == 0 + if not wide then + return someerror("invalid format") + end + lf = readcardinal4(s) + lh = readcardinal4(s) + bc = readcardinal4(s) + ec = readcardinal4(s) + nw = readcardinal4(s) + nh = readcardinal4(s) + nd = readcardinal4(s) + ni = readcardinal4(s) + nl = readcardinal4(s) + nk = readcardinal4(s) + ne = readcardinal4(s) + np = readcardinal4(s) + direction = readcardinal4(s) + end + if (bc > ec + 1) or (ec > max) then + return someerror("file is too small") + end + if bc > max then + bc, ec = 1, 0 + end + local nlw = (wide and 2 or 1) * nl + local neew = (wide and 2 or 1) * ne + local ncw = (wide and 2 or 1) * (ec - bc + 1) + if lf ~= (header + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np) then + return someerror("file is too small") + end + if nw == 0 or nh == 0 or nd == 0 or ni == 0 then + return someerror("no glyphs") + end + if lf * 4 > size then + return someerror("file is too small") + end + local slh = lh + if lh < 2 then + return someerror("file is too small") + end + local checksum = readcardinal4(s) + local designsize = readcardinal2(s) + designsize = designsize * 256 + readcardinal1(s) + designsize = designsize * 16 + rshift(readcardinal1(s),4) + if designsize < 0xFFFF then + return someerror("weird designsize") + end + -- + local alpha = 16 + local z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + local beta = idiv(256,alpha) + alpha = alpha * z + -- + local function readscaled() + local a, b, c, d = readbytes(s,4) + local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta) + if a == 0 then + return n + elseif a == 255 then + return n - alpha + else + return 0 + end + end + -- + local function readunscaled() + local a, b, c, d = readbytes(s,4) + if a > 127 then + a = a - 256 + end + return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4) + end + -- + while lh > 2 do -- can be one-liner + skipbytes(s,4) + lh = lh - 1 + end + local saved = getposition(s) + setposition(s,(header + slh + ncw) * 4 + 1) + local widths = { } for i=0,nw-1 do widths [i] = readscaled() end + local heights = { } for i=0,nh-1 do heights[i] = readscaled() end + local depths = { } for i=0,nd-1 do depths [i] = readscaled() end + local italics = { } for i=0,ni-1 do italics[i] = readscaled() end + if widths[0] ~= 0 or heights[0] ~= 0 or depths[0] ~= 0 then + return someerror("invalid dimensions") + end + -- + local blabel = nl + local bchar = boundarychar + -- + local ligatures = { } + if nl > 0 then + for i=0,nl-1 do + local a, b, c, d = readbytes(s,4) + ligatures[i] = { + skip = a, + nxt = b, + op = c, + rem = d, + } + if a > 128 then + if 256 * c + d >= nl then + return someerror("invalid ligature table") + end + if a == 255 and i == 0 then + bchar = b + end + else + if c < 128 then + -- whatever + elseif 256 * (c - 128) + d >= nk then + return someerror("invalid ligature table") + end + if (a < 128) and (i - 0 + a + 1 >= nl) then + return someerror("invalid ligature table") + end + end + if a == 255 then + blabel = 256 * c + d + end + end + end + local allkerns = { } + for i=0,nk-1 do + allkerns[i] = readscaled() + end + local extensibles = { } + for i=0,ne-1 do + extensibles[i] = wide and { + top = readcardinal2(s), + bot = readcardinal2(s), + mid = readcardinal2(s), + rep = readcardinal2(s), + } or { + top = readcardinal1(s), + bot = readcardinal1(s), + mid = readcardinal1(s), + rep = readcardinal1(s), + } + end + for i=1,np do + if i == 1 then + parameters[i] = readunscaled() + else + parameters[i] = readscaled() + end + end + for i=1,7 do + if not parameters[i] then + parameters[i] = 0 + end + end + -- + setposition(s,saved) + local extras = false + if blabel ~= nl then + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + -- if l.op >= 128 then + -- extras = true -- kern + -- else + extras = true -- ligature + -- end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + end + if extras then + local ligas = { } + local kerns = { } + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + kerns[nxt] = allkerns[256 * (op - 128) + rem] + else + ligas[nxt] = { type = op * 2 + 1, char = rem } + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break; + end + k = k + skip + 1 + end + end + if next(kerns) then + local glyph = glyphs[leftboundary] + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + local glyph = glyphs[leftboundary] + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + for i=bc,ec do + local glyph, width, height, depth, italic, tag, remainder + if wide then + width = readcardinal2(s) + height = readcardinal1(s) + depth = readcardinal1(s) + italic = readcardinal1(s) + tag = readcardinal1(s) + remainder = readcardinal2(s) + else + width = readcardinal1(s) + height = readcardinal1(s) + depth = extract(height,0,4) + height = extract(height,4,4) + italic = readcardinal1(s) + tag = extract(italic,0,2) + italic = extract(italic,2,6) + remainder = readcardinal1(s) + end + if width == 0 then + -- nothing + else + if width >= nw or height >= nh or depth >= nd or italic >= ni then + return someerror("invalid dimension index") + end + local extensible, nextinsize + if tag == 0 then + -- nothing special + else + local r = remainder + if tag == 1 then + if r >= nl then + return someerror("invalid ligature index") + end + elseif tag == 2 then + if r < bc or r > ec then + return someerror("invalid chain index") + end + while r < i do + local g = glyphs[r] + if g.tag ~= list_tag then + break + end + r = g.remainder + end + if r == i then + return someerror("cycles in chain") + end + nextinsize = r + elseif tag == 3 then + if r >= ne then + return someerror("bad extensible") + end + extensible = extensibles[r] -- remainder ? + remainder = 0 + end + end + glyphs[i] = { + width = widths [width], + height = heights[height], + depth = depths [depth], + italic = italics[italic], + tag = tag, + -- index = i, + remainder = remainder, + extensible = extensible, + next = nextinsize, + } + end + end + for i=bc,ec do + local glyph = glyphs[i] + if glyph.tag == 1 then + -- ligature + local k = glyph.remainder + local l = ligatures[k] + if l.skip > 128 then + k = 256 * l.op + l.rem + end + local ligas = { } + local kerns = { } + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + local kern = allkerns[256 * (op - 128) + rem] + if nxt == bchar then + kerns[rightboundary] = kern + end + kerns[nxt] = kern + else + local ligature = { type = op * 2 + 1, char = rem } + if nxt == bchar then + ligas[rightboundary] = ligature + end + ligas[nxt] = ligature -- shared + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + if next(kerns)then + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + end + -- + if bchar ~= boundarychar then + glyphs[rightboundary] = copy(glyphs[bchar]) + end + -- + -- for k, v in next, glyphs do + -- v.tag = nil + -- v.remainder = nil + -- end + -- + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + parameters = parameters, + designsize = designsize, + size = designsize, + direction = direction, + -- checksum = checksum, + -- embedding = "unknown", + -- encodingbytes = 0, + -- extend = 1000, + -- slant = 0, + -- squeeze = 0, + -- format = "unknown", + -- identity = "unknown", + -- mode = 0, + -- streamprovider = 0, + -- tounicode = 0, + -- type = "unknown", + -- units_per_em = 0, + -- used = false, + -- width = 0, + -- writingmode = "unknown", + } + end + +end + +do + + local push = { "push" } + local push = { "pop" } + + local w, x, y, z, f + local stack + local s, result, r + local alpha, beta, z + + local function scaled1() + local a = readbytes(s,1) + if a == 0 then + return 0 + elseif a == 255 then + return - alpha + else + return 0 -- error + end + end + + local function scaled2() + local a, b = readbytes(s,2) + local sw = idiv(b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled3() + local a, b, c = readbytes(s,3) + local sw = idiv(rshift(c*z,8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled4() + local a, b, c, d = readbytes(s,4) + local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function dummy() + end + + local actions = { + + [128] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } p = p + 1 end, + [129] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } p = p + 2 end, + [130] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal3(s) } p = p + 3 end, + [131] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } p = p + 4 end, + + [132] = function() + r = r + 1 + result[r] = { "rule", scaled4(), scaled4() } + p = p + 8 + end, + + [133] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } + r = r + 1 result[r] = pop + p = p + 1 + end, + [134] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 2 + end, + [135] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 3 + end, + [136] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } + r = r + 1 result[r] = pop + p = p + 4 + end, + + [137] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "rule", scaled4(), scaled4() } + r = r + 1 result[r] = pop + p = p + 8 + end, + + [138] = dummy, -- nop + [139] = dummy, -- bop + [140] = dummy, -- eop + + [141] = function() + insert(stack, { w, x, y, z }) + r = r + 1 + result[r] = push + end, + [142] = function() + local t = remove(stack) + if t then + w, x, y, z = t[1], t[2], t[3], t[4] + r = r + 1 + result[r] = pop + end + end, + + [143] = function() r = r + 1 result[r] = { "right", scaled1() } p = p + 1 end, + [144] = function() r = r + 1 result[r] = { "right", scaled2() } p = p + 2 end, + [145] = function() r = r + 1 result[r] = { "right", scaled3() } p = p + 3 end, + [146] = function() r = r + 1 result[r] = { "right", scaled4() } p = p + 4 end, + + [148] = function() w = scaled1() r = r + 1 result[r] = { "right", w } p = p + 1 end, + [149] = function() w = scaled2() r = r + 1 result[r] = { "right", w } p = p + 2 end, + [150] = function() w = scaled3() r = r + 1 result[r] = { "right", w } p = p + 3 end, + [151] = function() w = scaled4() r = r + 1 result[r] = { "right", w } p = p + 4 end, + + [153] = function() x = scaled1() r = r + 1 result[r] = { "right", x } p = p + 1 end, + [154] = function() x = scaled2() r = r + 1 result[r] = { "right", x } p = p + 2 end, + [155] = function() x = scaled3() r = r + 1 result[r] = { "right", x } p = p + 3 end, + [156] = function() x = scaled4() r = r + 1 result[r] = { "right", x } p = p + 4 end, + + [157] = function() r = r + 1 result[r] = { "down", scaled1() } p = p + 1 end, + [158] = function() r = r + 1 result[r] = { "down", scaled2() } p = p + 2 end, + [159] = function() r = r + 1 result[r] = { "down", scaled3() } p = p + 3 end, + [160] = function() r = r + 1 result[r] = { "down", scaled4() } p = p + 4 end, + + [162] = function() y = scaled1() r = r + 1 result[r] = { "down", y } p = p + 1 end, + [163] = function() y = scaled2() r = r + 1 result[r] = { "down", y } p = p + 2 end, + [164] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 3 end, + [165] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 4 end, + + [167] = function() z = scaled1() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [168] = function() z = scaled2() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [169] = function() z = scaled3() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [170] = function() z = scaled4() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + + [147] = function() r = r + 1 result[r] = { "right", w } end, + [152] = function() r = r + 1 result[r] = { "right", x } end, + [161] = function() r = r + 1 result[r] = { "down", y } end, + [166] = function() r = r + 1 result[r] = { "down", z } end, + + [235] = function() f = readcardinal1(s) p = p + 1 end, + [236] = function() f = readcardinal2(s) p = p + 3 end, + [237] = function() f = readcardinal3(s) p = p + 3 end, + [238] = function() f = readcardinal4(s) p = p + 4 end, + + [239] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 1 + n end, + [240] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 2 + n end, + [241] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 3 + n end, + [242] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 4 + n end, + + [250] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 1 + n end, + [251] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 2 + n end, + [252] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 3 + n end, + [253] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 4 + n end, + + } + + table.setmetatableindex(actions,function(t,cmd) + local v + if cmd >= 0 and cmd <= 127 then + v = function() + if f == 0 then + f = 1 + end + r = r + 1 ; result[r] = { "slot", f, cmd } + end + elseif cmd >= 171 and cmd <= 234 then + cmd = cmd - 170 + v = function() + r = r + 1 ; result[r] = { "font", cmd } + end + else + v = dummy + end + t[cmd] = v + return v + end) + + function readers.loadvf(filename,data) + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + s = openstream(filename) + if not s then + return someerror() + end + -- + local cmd = readcardinal1(s) + if cmd ~= 247 then + return someerror("bad preamble") + end + cmd = readcardinal1(s) + if cmd ~= 202 then + return someerror("bad version") + end + local header = readstring(s,readcardinal1(s)) + local checksum = readcardinal4(s) + local designsize = idiv(readcardinal4(s),16) + local fonts = data and data.fonts or { } + local glyphs = data and data.glyphs or { } + -- + alpha = 16 + z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + beta = idiv(256,alpha) + alpha = alpha * z + -- + cmd = readcardinal1(s) + while true do + local n + if cmd == 243 then + n = readcardinal1(s) + 1 + elseif cmd == 244 then + n = readcardinal2(s) + 1 + elseif cmd == 245 then + n = readcardinal3(s) + 1 + elseif cmd == 246 then + n = readcardinal4(s) + 1 + else + break + end + local checksum = skipbytes(s,4) + local size = scaled4() + local designsize = idiv(readcardinal4(s),16) + local pathlen = readcardinal1(s) + local namelen = readcardinal1(s) + local path = readstring(s,pathlen) + local name = readstring(s,namelen) + fonts[n] = { path = path, name = name, size = size } + cmd = readcardinal1(s) + end + local index = 0 + while cmd and cmd <= 242 do + local width = 0 + local length = 0 + local checksum = 0 + if cmd == 242 then + length = readcardinal4(s) + checksum = readcardinal4(s) + width = readcardinal4(s) + else + length = cmd + checksum = readcardinal1(s) + width = readcardinal3(s) + end + w, x, y, z, f = 0, 0, 0, 0, false + stack, result, r, p = { }, { }, 0, 0 + while p < length do + local cmd = readcardinal1(s) + p = p + 1 + actions[cmd]() + end + local glyph = glyphs[index] + if glyph then + glyph.width = width + glyph.commands = result + else + glyphs[index] = { + width = width, + commands = result, + } + end + index = index + 1 + if #stack > 0 then + -- error: more pushes than pops + end + if packet_length ~= 0 then + -- error: invalid packet length + end + cmd = readcardinal1(s) + end + if readcardinal1(s) ~= 248 then + -- error: no post + end + s, result, r = nil, nil, nil + if data then + data.glyphs = data.glyphs or glyphs + data.fonts = data.fonts or fonts + return data + else + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + designsize = designsize, + header = header, + fonts = fonts, + } + end + end + + -- the replacement loader (not sparse): + + function readers.loadtfmvf(tfmname,size) + local vfname = file.addsuffix(file.nameonly(tfmfile),"vf") + local tfmfile = tfmname + local vffile = resolvers.findbinfile(vfname,"ovf") + if tfmfile and tfmfile ~= "" then + if size < 0 then + size = idiv(65536 * -size,100) + end + local data = readers.loadtfm(tfmfile) + if data.error then + return data + end + if vffile and vffile ~= "" then + data = readers.loadvf(vffile,data) + if data.error then + return data + end + end + local designsize = data.designsize + local glyphs = data.glyphs + local parameters = data.parameters + local fonts = data.fonts + if size ~= designsize then + local factor = size / designsize + for index, glyph in next, glyphs do + if next(glyph) then + glyph.width = round(factor*glyph.width) + glyph.height = round(factor*glyph.height) + glyph.depth = round(factor*glyph.depth) + local italic = glyph.italic + if italic == 0 then + glyph.italic = nil + else + glyph.italic = round(factor*glyph.italic) + end + -- + local kerns = glyph.kerns + if kerns then + for index, kern in next, kerns do + kerns[index] = round(factor*kern) + end + end + -- + local commands = glyph.commands + if commands then + for i=1,#commands do + local c = commands[i] + local t = c[1] + if t == "down" or t == "right" then + c[2] = round(factor*c[2]) + elseif t == "rule" then + c[2] = round(factor*c[2]) + c[3] = round(factor*c[3]) + end + end + end + else + glyphs[index] = nil + end + end + for i=2,30 do + local p = parameters[i] + if p then + parameters[i] = round(factor*p) + else + break + end + end + if fonts then + for k, v in next, fonts do + v.size = round(factor*v.size) + end + end + else + for index, glyph in next, glyphs do + if next(glyph) then + if glyph.italic == 0 then + glyph.italic = nil + end + else + glyphs[index] = nil + end + end + end + -- + parameters.slant = parameters[1] + parameters.space = parameters[2] + parameters.space_stretch = parameters[3] + parameters.space_shrink = parameters[4] + parameters.x_height = parameters[5] + parameters.quad = parameters[6] + parameters.extra_space = parameters[7] + -- + for i=1,7 do + parameters[i] = nil -- so no danger for async + end + -- + data.characters = glyphs + data.glyphs = nil + data.size = size + -- + return data + end + end + +end + +-- inspect(readers.loadtfmvf(resolvers.find_file("mi-iwonari.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("texnansi-palatinonova-regular.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("cmex10.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("cmr10.tfm"))) +-- local t = readers.loadtfmvf("texnansi-lte50019.tfm") +-- inspect(t) |