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-otr.lua | |
parent | 8f5c555274eb48fcaaa3d7f340ee77710846fb7e (diff) | |
download | context-8e0089484acf80066e7393b1245d59dda211be09.tar.gz |
2017-03-20 17:38:00
Diffstat (limited to 'tex/context/base/mkiv/font-otr.lua')
-rw-r--r-- | tex/context/base/mkiv/font-otr.lua | 747 |
1 files changed, 412 insertions, 335 deletions
diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 43a059bb9..eab33f8b6 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -75,12 +75,13 @@ local setmetatableindex = table.setmetatableindex local formatters = string.formatters local sortedkeys = table.sortedkeys local sortedhash = table.sortedhash -local stripstring = string.strip +local stripstring = string.nospaces local utf16_to_utf8_be = utf.utf16_to_utf8_be local report = logs.reporter("otf reader") local trace_cmap = false -- only for checking issues +local trace_cmap_detail = false -- only for checking issues fonts = fonts or { } local handlers = fonts.handlers or { } @@ -703,6 +704,34 @@ local panosewidths = { -- We implement a reader per table. +-- helper + +local helpers = { } +readers.helpers = helpers + +local function gotodatatable(f,fontdata,tag,criterium) + if criterium and f then + local datatable = fontdata.tables[tag] + if datatable then + local tableoffset = datatable.offset + setposition(f,tableoffset) + return tableoffset + end + end +end + +local function setvariabledata(fontdata,tag,data) + local variabledata = fontdata.variabledata + if variabledata then + variabledata[tag] = data + else + fontdata.variabledata = { [tag] = data } + end +end + +helpers.gotodatatable = gotodatatable +helpers.setvariabledata = setvariabledata + -- The name table is probably the first one to load. After all this one provides -- useful information about what we deal with. The complication is that we need -- to filter the best one available. @@ -718,14 +747,13 @@ local platformnames = { } function readers.name(f,fontdata,specification) - local datatable = fontdata.tables.name - if datatable then - setposition(f,datatable.offset) + local tableoffset = gotodatatable(f,fontdata,"name",true) + if tableoffset then local format = readushort(f) local nofnames = readushort(f) local offset = readushort(f) -- we can also provide a raw list as extra, todo as option - local start = datatable.offset + offset + local start = tableoffset + offset local namelists = { unicode = { }, windows = { }, @@ -748,25 +776,15 @@ function readers.name(f,fontdata,specification) if encoding and language then local index = readushort(f) local name = reservednames[index] - if name then - namelist[#namelist+1] = { - platform = platform, - encoding = encoding, - language = language, - name = name, - length = readushort(f), - offset = start + readushort(f), - } - else -namelist[#namelist+1] = { - platform = platform, - encoding = encoding, - language = language, - length = readushort(f), - offset = start + readushort(f), -} --- skipshort(f,2) - end + namelist[#namelist+1] = { + platform = platform, + encoding = encoding, + language = language, + name = name, + index = index, + length = readushort(f), + offset = start + readushort(f), + } else skipshort(f,3) end @@ -803,6 +821,7 @@ namelist[#namelist+1] = { for i=1,#namelist do local name = namelist[i] local nametag = name.name + local index = name.index if not done[nametag or i] then local encoding = name.encoding local language = name.language @@ -824,7 +843,7 @@ namelist[#namelist+1] = { language = language, } end - extras[i-1] = content + extras[index] = content done[nametag or i] = true end end @@ -896,9 +915,8 @@ end -- properties table afterwards. readers["os/2"] = function(f,fontdata) - local datatable = fontdata.tables["os/2"] - if datatable then - setposition(f,datatable.offset) + local tableoffset = gotodatatable(f,fontdata,"os/2",true) + if tableoffset then local version = readushort(f) local windowsmetrics = { version = version, @@ -957,9 +975,8 @@ readers["os/2"] = function(f,fontdata) end readers.head = function(f,fontdata) - local datatable = fontdata.tables.head - if datatable then - setposition(f,datatable.offset) + local tableoffset = gotodatatable(f,fontdata,"head",true) + if tableoffset then local fontheader = { version = readfixed(f), revision = readfixed(f), @@ -990,68 +1007,60 @@ end -- variables are not used but nofmetrics is quite important. readers.hhea = function(f,fontdata,specification) - if specification.details then - local datatable = fontdata.tables.hhea - if datatable then - setposition(f,datatable.offset) - fontdata.horizontalheader = { - version = readfixed(f), -- two ushorts: major minor - ascender = readfword(f), - descender = readfword(f), - linegap = readfword(f), - maxadvancewidth = readufword(f), - minleftsidebearing = readfword(f), - minrightsidebearing = readfword(f), - maxextent = readfword(f), - caretsloperise = readshort(f), - caretsloperun = readshort(f), - caretoffset = readshort(f), - reserved_1 = readshort(f), - reserved_2 = readshort(f), - reserved_3 = readshort(f), - reserved_4 = readshort(f), - metricdataformat = readshort(f), - nofmetrics = readushort(f), - } - else - fontdata.horizontalheader = { - nofmetrics = 0, - } - end + local tableoffset = gotodatatable(f,fontdata,"hhea",specification.details) + if tableoffset then + fontdata.horizontalheader = { + version = readfixed(f), -- two ushorts: major minor + ascender = readfword(f), + descender = readfword(f), + linegap = readfword(f), + maxadvancewidth = readufword(f), + minleftsidebearing = readfword(f), + minrightsidebearing = readfword(f), + maxextent = readfword(f), + caretsloperise = readshort(f), + caretsloperun = readshort(f), + caretoffset = readshort(f), + reserved_1 = readshort(f), + reserved_2 = readshort(f), + reserved_3 = readshort(f), + reserved_4 = readshort(f), + metricdataformat = readshort(f), + nofmetrics = readushort(f), + } + else + fontdata.horizontalheader = { + nofmetrics = 0, + } end end readers.vhea = function(f,fontdata,specification) - if specification.details then - local datatable = fontdata.tables.vhea - if datatable then - setposition(f,datatable.offset) - local version = readfixed(f) - fontdata.verticalheader = { - version = version, - ascender = readfword(f), - descender = readfword(f), - linegap = readfword(f), - maxadvanceheight = readufword(f), - mintopsidebearing = readfword(f), - minbottomsidebearing = readfword(f), - maxextent = readfword(f), - caretsloperise = readshort(f), - caretsloperun = readshort(f), - caretoffset = readshort(f), - reserved_1 = readshort(f), - reserved_2 = readshort(f), - reserved_3 = readshort(f), - reserved_4 = readshort(f), - metricdataformat = readshort(f), - nofmetrics = readushort(f), - } --- inspect(fontdata.verticalheader) - else - fontdata.verticalheader = { - nofmetrics = 0, - } - end + local tableoffset = gotodatatable(f,fontdata,"vhea",specification.details) + if tableoffset then + fontdata.verticalheader = { + version = readfixed(f), + ascender = readfword(f), + descender = readfword(f), + linegap = readfword(f), + maxadvanceheight = readufword(f), + mintopsidebearing = readfword(f), + minbottomsidebearing = readfword(f), + maxextent = readfword(f), + caretsloperise = readshort(f), + caretsloperun = readshort(f), + caretoffset = readshort(f), + reserved_1 = readshort(f), + reserved_2 = readshort(f), + reserved_3 = readshort(f), + reserved_4 = readshort(f), + metricdataformat = readshort(f), + nofmetrics = readushort(f), + } + else + fontdata.verticalheader = { + nofmetrics = 0, + } end end @@ -1061,44 +1070,40 @@ end -- fontdata.maximumprofile can be bad readers.maxp = function(f,fontdata,specification) - if specification.details then - local datatable = fontdata.tables.maxp - if datatable then - setposition(f,datatable.offset) - local version = readfixed(f) - local nofglyphs = readushort(f) - fontdata.nofglyphs = nofglyphs - if version == 0.5 then - fontdata.maximumprofile = { - version = version, - nofglyphs = nofglyphs, - } - return - elseif version == 1.0 then - fontdata.maximumprofile = { - version = version, - nofglyphs = nofglyphs, - points = readushort(f), - contours = readushort(f), - compositepoints = readushort(f), - compositecontours = readushort(f), - zones = readushort(f), - twilightpoints = readushort(f), - storage = readushort(f), - functiondefs = readushort(f), - instructiondefs = readushort(f), - stackelements = readushort(f), - sizeofinstructions = readushort(f), - componentelements = readushort(f), - componentdepth = readushort(f), - } - return - end + local tableoffset = gotodatatable(f,fontdata,"maxp",specification.details) + if tableoffset then + local version = readfixed(f) + local nofglyphs = readushort(f) + fontdata.nofglyphs = nofglyphs + if version == 0.5 then + fontdata.maximumprofile = { + version = version, + nofglyphs = nofglyphs, + } + elseif version == 1.0 then + fontdata.maximumprofile = { + version = version, + nofglyphs = nofglyphs, + points = readushort(f), + contours = readushort(f), + compositepoints = readushort(f), + compositecontours = readushort(f), + zones = readushort(f), + twilightpoints = readushort(f), + storage = readushort(f), + functiondefs = readushort(f), + instructiondefs = readushort(f), + stackelements = readushort(f), + sizeofinstructions = readushort(f), + componentelements = readushort(f), + componentdepth = readushort(f), + } + else + fontdata.maximumprofile = { + version = version, + nofglyphs = 0, + } end - fontdata.maximumprofile = { - version = version, - nofglyphs = 0, - } end end @@ -1106,86 +1111,78 @@ end -- course). readers.hmtx = function(f,fontdata,specification) - if specification.glyphs then - local datatable = fontdata.tables.hmtx - if datatable then - setposition(f,datatable.offset) - local horizontalheader = fontdata.horizontalheader - local nofmetrics = horizontalheader.nofmetrics - local glyphs = fontdata.glyphs - local nofglyphs = fontdata.nofglyphs - local width = 0 -- advance - local leftsidebearing = 0 - for i=0,nofmetrics-1 do - local glyph = glyphs[i] - width = readshort(f) - leftsidebearing = readshort(f) - if width ~= 0 then - glyph.width = width - end - -- if leftsidebearing ~= 0 then - -- glyph.lsb = leftsidebearing - -- end + local tableoffset = gotodatatable(f,fontdata,"hmtx",specification.glyphs) + if tableoffset then + local horizontalheader = fontdata.horizontalheader + local nofmetrics = horizontalheader.nofmetrics + local glyphs = fontdata.glyphs + local nofglyphs = fontdata.nofglyphs + local width = 0 -- advance + local leftsidebearing = 0 + for i=0,nofmetrics-1 do + local glyph = glyphs[i] + width = readshort(f) + leftsidebearing = readshort(f) + if width ~= 0 then + glyph.width = width end - -- The next can happen in for instance a monospace font or in a cjk font - -- with fixed widths. - for i=nofmetrics,nofglyphs-1 do - local glyph = glyphs[i] - if width ~= 0 then - glyph.width = width - end - -- if leftsidebearing ~= 0 then - -- glyph.lsb = leftsidebearing - -- end + -- if leftsidebearing ~= 0 then + -- glyph.lsb = leftsidebearing + -- end + end + -- The next can happen in for instance a monospace font or in a cjk font + -- with fixed widths. + for i=nofmetrics,nofglyphs-1 do + local glyph = glyphs[i] + if width ~= 0 then + glyph.width = width end + -- if leftsidebearing ~= 0 then + -- glyph.lsb = leftsidebearing + -- end end + -- hm, there can be a lsb here end end readers.vmtx = function(f,fontdata,specification) - if specification.glyphs then - local datatable = fontdata.tables.vmtx - if datatable then - setposition(f,datatable.offset) - local verticalheader = fontdata.verticalheader - local nofmetrics = verticalheader.nofmetrics - local glyphs = fontdata.glyphs - local nofglyphs = fontdata.nofglyphs - local vheight = 0 - local vdefault = verticalheader.ascender + verticalheader.descender - local topsidebearing = 0 - for i=0,nofmetrics-1 do - local glyph = glyphs[i] - vheight = readshort(f) - topsidebearing = readshort(f) - if vheight ~= 0 and vheight ~= vdefault then - glyph.vheight = vheight - end - -- if topsidebearing ~= 0 then - -- glyph.tsb = topsidebearing - -- end + local tableoffset = gotodatatable(f,fontdata,"vmtx",specification.glyphs) + if tableoffset then + local verticalheader = fontdata.verticalheader + local nofmetrics = verticalheader.nofmetrics + local glyphs = fontdata.glyphs + local nofglyphs = fontdata.nofglyphs + local vheight = 0 + local vdefault = verticalheader.ascender + verticalheader.descender + local topsidebearing = 0 + for i=0,nofmetrics-1 do + local glyph = glyphs[i] + vheight = readshort(f) + topsidebearing = readshort(f) + if vheight ~= 0 and vheight ~= vdefault then + glyph.vheight = vheight end - -- The next can happen in for instance a monospace font or in a cjk font - -- with fixed heights. - for i=nofmetrics,nofglyphs-1 do - local glyph = glyphs[i] - if vheight ~= 0 and vheight ~= vdefault then - glyph.vheight = vheight - end - -- if topsidebearing ~= 0 then - -- glyph.tsb = topsidebearing - -- end + -- if topsidebearing ~= 0 then + -- glyph.tsb = topsidebearing + -- end + end + -- The next can happen in for instance a monospace font or in a cjk font + -- with fixed heights. + for i=nofmetrics,nofglyphs-1 do + local glyph = glyphs[i] + if vheight ~= 0 and vheight ~= vdefault then + glyph.vheight = vheight end + -- if topsidebearing ~= 0 then + -- glyph.tsb = topsidebearing + -- end end end end readers.vorg = function(f,fontdata,specification) if specification.glyphs then - local datatable = fontdata.tables.vorg - if datatable then - report("todo: %s","vorg") - end + -- reportskippedtable("vorg") end end @@ -1194,9 +1191,8 @@ end -- description is somewhat fuzzy but it is a hybrid with overloads. readers.post = function(f,fontdata,specification) - local datatable = fontdata.tables.post - if datatable then - setposition(f,datatable.offset) + local tableoffset = gotodatatable(f,fontdata,"post",true) + if tableoffset then local version = readfixed(f) fontdata.postscript = { version = version, @@ -1225,7 +1221,7 @@ readers.post = function(f,fontdata,specification) for i=0,nofglyphs-1 do local nameindex = readushort(f) if nameindex >= 258 then - maxnames = maxnames + 1 + maxnames = maxnames + 1 nameindex = nameindex - 257 indices[nameindex] = i else @@ -1238,7 +1234,7 @@ readers.post = function(f,fontdata,specification) report("quit post name fetching at %a of %a: %s",i,maxnames,"no index") break else - local length = readbyte(f) + local length = readbyte(f) if length > 0 then glyphs[mapping].name = readstring(f,length) else @@ -1365,7 +1361,7 @@ formatreaders[4] = function(f,fontdata,offset) elseif offset == 0xFFFF then -- bad encoding elseif offset == 0 then - if trace_cmap then + if trace_cmap_detail then report("format 4.%i segment %2i from %C upto %C at index %H",1,segment,startchar,endchar,(startchar + delta) % 65536) end for unicode=startchar,endchar do @@ -1398,7 +1394,7 @@ formatreaders[4] = function(f,fontdata,offset) end else local shift = (segment-nofsegments+offset/2) - startchar - if trace_cmap then + if trace_cmap_detail then report("format 4.%i segment %2i from %C upto %C at index %H",0,segment,startchar,endchar,(startchar + delta) % 65536) end for unicode=startchar,endchar do @@ -1448,7 +1444,7 @@ formatreaders[6] = function(f,fontdata,offset) local count = readushort(f) local stop = start+count-1 local nofdone = 0 - if trace_cmap then + if trace_cmap_detail then report("format 6 from %C to %C",2,start,stop) end for unicode=start,stop do @@ -1485,7 +1481,7 @@ formatreaders[12] = function(f,fontdata,offset) local first = readulong(f) local last = readulong(f) local index = readulong(f) - if trace_cmap then + if trace_cmap_detail then report("format 12 from %C to %C starts at index %i",first,last,index) end for unicode=first,last do @@ -1529,7 +1525,7 @@ formatreaders[13] = function(f,fontdata,offset) local last = readulong(f) local index = readulong(f) if first < privateoffset then - if trace_cmap then + if trace_cmap_detail then report("format 13 from %C to %C get index %i",first,last,index) end local glyph = glyphs[index] @@ -1635,76 +1631,82 @@ local function checkcmap(f,fontdata,records,platform,encoding,format) local p = platforms[platform] local e = encodings[p] local n = reader(f,fontdata,data) or 0 - report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n) + if trace_cmap then + report("cmap checked: platform %i (%s), encoding %i (%s), format %i, new unicodes %i",platform,p,encoding,e and e[encoding] or "?",format,n) + end return n end function readers.cmap(f,fontdata,specification) - if specification.glyphs then - local datatable = fontdata.tables.cmap - if datatable then - local tableoffset = datatable.offset - setposition(f,tableoffset) - local version = readushort(f) - local noftables = readushort(f) - local records = { } - local unicodecid = false - local variantcid = false - local variants = { } - local duplicates = fontdata.duplicates or { } - fontdata.duplicates = duplicates - for i=1,noftables do - local platform = readushort(f) - local encoding = readushort(f) - local offset = readulong(f) - local record = records[platform] - if not record then - records[platform] = { - [encoding] = { - offsets = { offset }, - formats = { }, - } + local tableoffset = gotodatatable(f,fontdata,"cmap",specification.glyphs) + if tableoffset then + local version = readushort(f) + local noftables = readushort(f) + local records = { } + local unicodecid = false + local variantcid = false + local variants = { } + local duplicates = fontdata.duplicates or { } + fontdata.duplicates = duplicates + for i=1,noftables do + local platform = readushort(f) + local encoding = readushort(f) + local offset = readulong(f) + local record = records[platform] + if not record then + records[platform] = { + [encoding] = { + offsets = { offset }, + formats = { }, + } + } + else + local subtables = record[encoding] + if not subtables then + record[encoding] = { + offsets = { offset }, + formats = { }, } else - local subtables = record[encoding] - if not subtables then - record[encoding] = { - offsets = { offset }, - formats = { }, - } - else - local offsets = subtables.offsets - offsets[#offsets+1] = offset - end + local offsets = subtables.offsets + offsets[#offsets+1] = offset end end + end + if trace_cmap then report("found cmaps:") - for platform, record in sortedhash(records) do - local p = platforms[platform] - local e = encodings[p] - local sp = supported[platform] - local ps = p or "?" + end + for platform, record in sortedhash(records) do + local p = platforms[platform] + local e = encodings[p] + local sp = supported[platform] + local ps = p or "?" + if trace_cmap then if sp then report(" platform %i: %s",platform,ps) else report(" platform %i: %s (unsupported)",platform,ps) end - for encoding, subtables in sortedhash(record) do - local se = sp and sp[encoding] - local es = e and e[encoding] or "?" + end + for encoding, subtables in sortedhash(record) do + local se = sp and sp[encoding] + local es = e and e[encoding] or "?" + if trace_cmap then if se then report(" encoding %i: %s",encoding,es) else report(" encoding %i: %s (unsupported)",encoding,es) end - local offsets = subtables.offsets - local formats = subtables.formats - for i=1,#offsets do - local offset = tableoffset + offsets[i] - setposition(f,offset) - formats[readushort(f)] = offset - end - record[encoding] = formats + end + local offsets = subtables.offsets + local formats = subtables.formats + for i=1,#offsets do + local offset = tableoffset + offsets[i] + setposition(f,offset) + formats[readushort(f)] = offset + end + record[encoding] = formats + if trace_cmap then local list = sortedkeys(formats) for i=1,#list do if not (se and se[list[i]]) then @@ -1714,27 +1716,27 @@ function readers.cmap(f,fontdata,specification) report(" formats: % t",list) end end - -- - local ok = false - for i=1,#sequence do - local si = sequence[i] - local sp, se, sf = si[1], si[2], si[3] - if checkcmap(f,fontdata,records,sp,se,sf) > 0 then - ok = true - end - end - if not ok then - report("no useable unicode cmap found") + end + -- + local ok = false + for i=1,#sequence do + local si = sequence[i] + local sp, se, sf = si[1], si[2], si[3] + if checkcmap(f,fontdata,records,sp,se,sf) > 0 then + ok = true end - -- - fontdata.cidmaps = { - version = version, - noftables = noftables, - records = records, - } - else - fontdata.cidmaps = { } end + if not ok then + report("no useable unicode cmap found") + end + -- + fontdata.cidmaps = { + version = version, + noftables = noftables, + records = records, + } + else + fontdata.cidmaps = { } end end @@ -1778,42 +1780,39 @@ end -- can also be available. Todo: we need a 'fake' lookup for this (analogue to ff). function readers.kern(f,fontdata,specification) - if specification.kerns then - local datatable = fontdata.tables.kern - if datatable then - setposition(f,datatable.offset) - local version = readushort(f) - local noftables = readushort(f) - for i=1,noftables do - local version = readushort(f) - local length = readushort(f) - local coverage = readushort(f) - -- bit 8-15 of coverage: format 0 or 2 - local format = bit32.rshift(coverage,8) -- is this ok? - if format == 0 then - local nofpairs = readushort(f) - local searchrange = readushort(f) - local entryselector = readushort(f) - local rangeshift = readushort(f) - local kerns = { } - local glyphs = fontdata.glyphs - for i=1,nofpairs do - local left = readushort(f) - local right = readushort(f) - local kern = readfword(f) - local glyph = glyphs[left] - local kerns = glyph.kerns - if kerns then - kerns[right] = kern - else - glyph.kerns = { [right] = kern } - end + local tableoffset = gotodatatable(f,fontdata,"kern",specification.kerns) + if tableoffset then + local version = readushort(f) + local noftables = readushort(f) + for i=1,noftables do + local version = readushort(f) + local length = readushort(f) + local coverage = readushort(f) + -- bit 8-15 of coverage: format 0 or 2 + local format = bit32.rshift(coverage,8) -- is this ok? + if format == 0 then + local nofpairs = readushort(f) + local searchrange = readushort(f) + local entryselector = readushort(f) + local rangeshift = readushort(f) + local kerns = { } + local glyphs = fontdata.glyphs + for i=1,nofpairs do + local left = readushort(f) + local right = readushort(f) + local kern = readfword(f) + local glyph = glyphs[left] + local kerns = glyph.kerns + if kerns then + kerns[right] = kern + else + glyph.kerns = { [right] = kern } end - elseif format == 2 then - report("todo: kern classes") - else - report("todo: kerns") end + elseif format == 2 then + report("todo: kern classes") + else + report("todo: kerns") end end end @@ -1847,7 +1846,7 @@ end -- some properties in order to read following tables. When details is true we also -- initialize the glyphs data. -local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo) +local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames) local fontdata = sub and maindata.subfonts and maindata.subfonts[sub] or maindata local names = fontdata.names local info = nil @@ -1872,6 +1871,25 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo) if not familyname then familyname = family end if not subfamilyname then subfamilyname = subfamily end end + if platformnames then + platformnames = fontdata.platformnames + end + if instancenames then + local variabledata = fontdata.variabledata + if variabledata then + local instances = variabledata and variabledata.instances + if instances then + instancenames = { } + for i=1,#instances do + instancenames[i] = lower(stripstring(instances[i].subfamily)) + end + else + instancenames = nil + end + else + instancenames = nil + end + end info = { -- we inherit some inconsistencies/choices from ff subfontindex = fontdata.subfontindex or sub or 0, -- filename = filename, @@ -1902,7 +1920,8 @@ local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo) capheight = metrics.capheight, -- not always present and probably crap ascender = metrics.typoascender, descender = metrics.typodescender, - platformnames = platformnames and fontdata.platformnames or nil, + platformnames = platformnames or nil, + instancenames = instancenames or nil, } if metricstoo then local keys = { @@ -1960,6 +1979,7 @@ local function loadtables(f,specification,offset) entryselector = readushort(f), -- not needed rangeshift = readushort(f), -- not needed tables = tables, + foundtables = false, } for i=1,fontdata.noftables do local tag = lower(stripstring(readstring(f,4))) @@ -1975,7 +1995,8 @@ local function loadtables(f,specification,offset) length = length, } end - if tables.cff then + fontdata.foundtables = sortedkeys(tables) + if tables.cff or tables.cff2 then fontdata.format = "opentype" else fontdata.format = "truetype" @@ -1996,23 +2017,35 @@ local function prepareglyps(fontdata) fontdata.mapping = { } end -local function readtable(tag,f,fontdata,specification) +local function readtable(tag,f,fontdata,specification,...) local reader = readers[tag] if reader then -- local t = os.clock() - reader(f,fontdata,specification) + reader(f,fontdata,specification,...) -- report("reading table %a took %0.4f seconds",tag,os.clock()-t) end end +local variablefonts_supported = context and true or false + local function readdata(f,offset,specification) + local fontdata = loadtables(f,specification,offset) + if specification.glyphs then prepareglyps(fontdata) end - -- + + if not variablefonts_supported then + specification.instance = nil + specification.variable = nil + specification.factors = nil + end + + fontdata.temporary = { } + readtable("name",f,fontdata,specification) - -- + local askedname = specification.askedname if askedname then local fullname = getname(fontdata,"fullname") or "" @@ -2022,7 +2055,35 @@ local function readdata(f,offset,specification) return -- keep searching end end - -- + + readtable("stat",f,fontdata,specification) + readtable("avar",f,fontdata,specification) + readtable("fvar",f,fontdata,specification) + + if variablefonts_supported then + + if not specification.factors then + local instance = specification.instance + if type(instance) == "string" then + local factors = helpers.getfactors(fontdata,instance) + specification.factors = factors + fontdata.factors = factors + fontdata.instance = instance + report("user instance: %s, factors: % t",instance,factors) + end + end + if not fontdata.factors then + if fontdata.variabledata then + local factors = helpers.getfactors(fontdata,true) + specification.factors = factors + fontdata.factors = factors + fontdata.instance = instance + report("font instance: %s, factors: % t",instance,factors) + end + end + + end + readtable("os/2",f,fontdata,specification) readtable("head",f,fontdata,specification) readtable("maxp",f,fontdata,specification) @@ -2032,32 +2093,35 @@ local function readdata(f,offset,specification) readtable("vmtx",f,fontdata,specification) readtable("vorg",f,fontdata,specification) readtable("post",f,fontdata,specification) + + readtable("mvar",f,fontdata,specification) + readtable("hvar",f,fontdata,specification) + readtable("vvar",f,fontdata,specification) + + readtable("gdef",f,fontdata,specification) + readtable("cff" ,f,fontdata,specification) + readtable("cff2",f,fontdata,specification) + readtable("cmap",f,fontdata,specification) - readtable("loca",f,fontdata,specification) - readtable("glyf",f,fontdata,specification) + readtable("loca",f,fontdata,specification) -- maybe load it in glyf + readtable("glyf",f,fontdata,specification) -- loads gvar + readtable("colr",f,fontdata,specification) readtable("cpal",f,fontdata,specification) readtable("svg" ,f,fontdata,specification) + readtable("kern",f,fontdata,specification) - readtable("gdef",f,fontdata,specification) readtable("gsub",f,fontdata,specification) readtable("gpos",f,fontdata,specification) + readtable("math",f,fontdata,specification) - -- - -- there are no proper fonts yet: - -- - readtable("fvar",f,fontdata,specification) -- probably - readtable("hvar",f,fontdata,specification) - readtable("vvar",f,fontdata,specification) - readtable("mvar",f,fontdata,specification) -- probably - readtable("vorg",f,fontdata,specification) - -- + fontdata.locations = nil fontdata.tables = nil fontdata.cidmaps = nil fontdata.dictionaries = nil - -- fontdata.cff = nil + -- fontdata.cff = nil return fontdata end @@ -2132,7 +2196,7 @@ local function loadfontdata(specification) end end -local function loadfont(specification,n) +local function loadfont(specification,n,instance) if type(specification) == "string" then specification = { filename = specification, @@ -2147,6 +2211,7 @@ local function loadfont(specification,n) -- true or number: subfont = n or true, tounicode = false, + instance = instance } end -- if shapes only then @@ -2162,6 +2227,10 @@ local function loadfont(specification,n) if specification.platformnames then specification.platformnames = true -- not really used any more end + if specification.instance or instance then + specification.variable = true + specification.instance = specification.instance or instance + end local function message(str) report("fatal error in file %a: %s\n%s",specification.filename,str,debug.traceback()) end @@ -2173,11 +2242,14 @@ end -- we need even less, but we can have a 'detail' variant -function readers.loadshapes(filename,n) +function readers.loadshapes(filename,n,instance,streams) local fontdata = loadfont { filename = filename, shapes = true, + streams = streams, + variable = true, subfont = n, + instance = instance, } if fontdata then -- easier on luajit but still we can hit the 64 K stack constants issue @@ -2202,7 +2274,7 @@ function readers.loadshapes(filename,n) } end -function readers.loadfont(filename,n) +function readers.loadfont(filename,n,instance) local fontdata = loadfont { filename = filename, glyphs = true, @@ -2212,9 +2284,9 @@ function readers.loadfont(filename,n) -- kerns = true, -- globalkerns = true, -- only for testing, e.g. cambria has different gpos and kern subfont = n, + instance = instance, } if fontdata then - -- return { tableversion = tableversion, creator = "context mkiv", @@ -2224,11 +2296,13 @@ function readers.loadfont(filename,n) descriptions = fontdata.descriptions, format = fontdata.format, goodies = { }, - metadata = getinfo(fontdata,n,false,false,true), -- no platformnames here ! + metadata = getinfo(fontdata,n,false,false,true,true), -- no platformnames here ! properties = { hasitalics = fontdata.hasitalics or false, maxcolorclass = fontdata.maxcolorclass, hascolor = fontdata.hascolor or false, + instance = fontdata.instance, + factors = fontdata.factors, }, resources = { -- filename = fontdata.filename, @@ -2247,7 +2321,8 @@ function readers.loadfont(filename,n) mathconstants = fontdata.mathconstants, colorpalettes = fontdata.colorpalettes, svgshapes = fontdata.svgshapes, - variable = fontdata.variable, + variabledata = fontdata.variabledata, + foundtables = fontdata.foundtables, }, } end @@ -2259,6 +2334,7 @@ function readers.getinfo(filename,specification) -- string, nil|number|table local subfont = nil local platformnames = false local rawfamilynames = false + local instancenames = true if type(specification) == "table" then subfont = tonumber(specification.subfont) platformnames = specification.platformnames @@ -2270,20 +2346,21 @@ function readers.getinfo(filename,specification) -- string, nil|number|table filename = filename, details = true, platformnames = platformnames, + instancenames = true, -- rawfamilynames = rawfamilynames, } if fontdata then local subfonts = fontdata.subfonts if not subfonts then - return getinfo(fontdata,nil,platformnames,rawfamilynames) + return getinfo(fontdata,nil,platformnames,rawfamilynames,false,instancenames) elseif not subfont then local info = { } for i=1,#subfonts do - info[i] = getinfo(fontdata,i,platformnames,rawfamilynames) + info[i] = getinfo(fontdata,i,platformnames,rawfamilynames,false,instancenames) end return info elseif subfont >= 1 and subfont <= #subfonts then - return getinfo(fontdata,subfont,platformnames,rawfamilynames) + return getinfo(fontdata,subfont,platformnames,rawfamilynames,false,instancenames) else return { filename = filename, |