summaryrefslogtreecommitdiff
path: root/texmf-dist/tex/harftex/base/harf-load.lua
diff options
context:
space:
mode:
Diffstat (limited to 'texmf-dist/tex/harftex/base/harf-load.lua')
-rw-r--r--texmf-dist/tex/harftex/base/harf-load.lua361
1 files changed, 0 insertions, 361 deletions
diff --git a/texmf-dist/tex/harftex/base/harf-load.lua b/texmf-dist/tex/harftex/base/harf-load.lua
deleted file mode 100644
index 8367ced0..00000000
--- a/texmf-dist/tex/harftex/base/harf-load.lua
+++ /dev/null
@@ -1,361 +0,0 @@
-local module = {
- name = "harf-load",
- description = "Harf font loading",
- version = "0.4.2",
- date = "2019-09-07",
- license = "GPL v2.0"
-}
-luatexbase.provides_module(module)
-
-local hb = require("harf-base")
-
-local hbfonts = hb.fonts
-local hbfonts = hbfonts or {}
-
-local cfftag = hb.Tag.new("CFF ")
-local cff2tag = hb.Tag.new("CFF2")
-local os2tag = hb.Tag.new("OS/2")
-local posttag = hb.Tag.new("post")
-local glyftag = hb.Tag.new("glyf")
-
-local function loadfont(spec)
- local path = spec.resolved or spec.name
- if not path then
- return nil
- end
-
- local index = spec.sub and spec.sub or 1
- local key = string.format("%s:%d", path, index)
- local data = hbfonts[key]
- if data then
- return data
- end
-
- local hbface = hb.Face.new(path, index - 1)
- local tags = hbface and hbface:get_table_tags()
- -- If the face has no table tags then it isn’t a valid SFNT font that
- -- HarfBuzz can handle.
- if tags then
- local hbfont = hb.Font.new(hbface)
- local upem = hbface:get_upem()
-
- -- The engine seems to use the font type to tell whether there is a CFF
- -- table or not, so we check for that here.
- local fonttype = nil
- local hasos2 = false
- local haspost = false
- for i = 1, #tags do
- local tag = tags[i]
- if tag == cfftag or tag == cff2tag then
- fonttype = "opentype"
- elseif tag == glyftag then
- fonttype = "truetype"
- elseif tag == os2tag then
- hasos2 = true
- elseif tag == posttag then
- haspost = true
- end
- end
-
- local fontextents = hbfont:get_h_extents()
- local ascender = fontextents and fontextents.ascender or upem * .8
- local descender = fontextents and fontextents.descender or upem * .2
-
- local gid = hbfont:get_nominal_glyph(0x0020)
- local space = gid and hbfont:get_glyph_h_advance(gid) or upem / 2
-
- local slant = 0
- if haspost then
- local post = hbface:get_table(posttag)
- local length = post:get_length()
- local data = post:get_data()
- if length >= 32 and string.unpack(">i4", data) <= 0x00030000 then
- local italicangle = string.unpack(">i4", data, 5) / 2^16
- if italicangle ~= 0 then
- slant = -math.tan(italicangle * math.pi / 180) * 65536.0
- end
- end
- end
-
- -- Load glyph metrics for all glyphs in the font. We used to do this on
- -- demand to make loading fonts faster, but hit many limitations inside
- -- the engine (mainly with shared backend fonts, where the engine would
- -- assume all fonts it decides to share load the same set of glyphs).
- --
- -- Getting glyph advances is fast enough, but glyph extents are slower
- -- especially in CFF fonts. We might want to have an option to ignore exact
- -- glyph extents and use font ascender and descender if this proved to be
- -- too slow.
- local glyphcount = hbface:get_glyph_count()
- local glyphs = {}
- for gid = 0, glyphcount - 1 do
- local width = hbfont:get_glyph_h_advance(gid)
- local height, depth, italic = nil, nil, nil
- local extents = hbfont:get_glyph_extents(gid)
- if extents then
- height = extents.y_bearing
- depth = extents.y_bearing + extents.height
- if extents.x_bearing < 0 then
- italic = -extents.x_bearing
- end
- end
- glyphs[gid] = {
- width = width,
- height = height or ascender,
- depth = -(depth or descender),
- italic = italic or 0,
- }
- end
-
- local unicodes = hbface:collect_unicodes()
- local characters = {}
- for _, uni in next, unicodes do
- characters[uni] = hbfont:get_nominal_glyph(uni)
- end
-
- local xheight, capheight = 0, 0
- if hasos2 then
- local os2 = hbface:get_table(os2tag)
- local length = os2:get_length()
- local data = os2:get_data()
- if length >= 96 and string.unpack(">H", data) > 1 then
- -- We don’t need much of the table, so we read from hard-coded offsets.
- xheight = string.unpack(">H", data, 87)
- capheight = string.unpack(">H", data, 89)
- end
- end
-
- if xheight == 0 then
- local gid = characters[120] -- x
- if gid then
- xheight = glyphs[gid].height
- else
- xheight = ascender / 2
- end
- end
-
- if capheight == 0 then
- local gid = characters[88] -- X
- if gid then
- capheight = glyphs[gid].height
- else
- capheight = ascender
- end
- end
-
- data = {
- face = hbface,
- font = hbfont,
- upem = upem,
- fonttype = fonttype,
- space = space,
- xheight = xheight,
- capheight = capheight,
- slant = slant,
- glyphs = glyphs,
- unicodes = characters,
- psname = hbface:get_name(hb.ot.NAME_ID_POSTSCRIPT_NAME),
- fullname = hbface:get_name(hb.ot.NAME_ID_FULL_NAME),
- haspng = hbface:ot_color_has_png(),
- loaded = {}, -- Cached loaded glyph data.
- }
-
- hbfonts[key] = data
- return data
- end
-end
-
--- Drop illegal characters from PS Name, per the spec
--- https://docs.microsoft.com/en-us/typography/opentype/spec/name#nid6
-local function sanitize(psname)
- local new = psname:gsub(".", function(c)
- local b = c:byte()
- if (b < 33 or b > 126)
- or c == "["
- or c == "]"
- or c == "("
- or c == ")"
- or c == "{"
- or c == "}"
- or c == "<"
- or c == ">"
- or c == "/"
- or c == "%"
- then
- return "-"
- end
- return c
- end)
- return new
-end
-
-local tlig = hb.texlig
-
-local function scalefont(data, spec)
- local size = spec.size
- local hbface = data.face
- local hbfont = data.font
- local upem = data.upem
- local space = data.space
-
- if size < 0 then
- size = -655.36 * size
- end
-
- -- Extract features (that we pass to HarfBuzz) from the rest of the options.
- -- Mostly a heuristic.
- local features = {}
- local options = {}
- local rawfeatures = spec.features and spec.features.raw or {}
- for key, val in next, rawfeatures do
- if key == "language" then val = hb.Language.new(val) end
- if key == "colr" then key = "palette" end
- if key == "tlig" then key = "texlig" end
- if key:len() == 4 then
- -- 4-letter options are likely font features, but not always, so we do
- -- some checks below. We put non feature options in the `options` dict.
- if val == true or val == false then
- val = (val and '+' or '-')..key
- features[#features + 1] = hb.Feature.new(val)
- elseif tonumber(val) then
- val = '+'..key..'='..tonumber(val) - 1
- features[#features + 1] = hb.Feature.new(val)
- else
- options[key] = val
- end
- else
- options[key] = val
- end
- end
-
- -- We shape in font units (at UPEM) and then scale output with the desired
- -- sfont size.
- local scale = size / upem
- hbfont:set_scale(upem, upem)
-
- -- Populate font’s characters table.
- local glyphs = data.glyphs
- local characters = {}
- for gid, glyph in next, glyphs do
- characters[hb.CH_GID_PREFIX + gid] = {
- index = gid,
- width = glyph.width * scale,
- height = glyph.height * scale,
- depth = glyph.depth * scale,
- italic = glyph.italic * scale,
- }
- end
-
- local unicodes = data.unicodes
- for uni, gid in next, unicodes do
- characters[uni] = characters[hb.CH_GID_PREFIX + gid]
- end
-
- -- Select font palette, we support `palette=index` option, and load the first
- -- one otherwise.
- local paletteidx = tonumber(options.palette) or 1
-
- -- Load CPAL palette from the font.
- local palette = nil
- if hbface:ot_color_has_palettes() and hbface:ot_color_has_layers() then
- local count = hbface:ot_color_palette_get_count()
- if paletteidx <= count then
- palette = hbface:ot_color_palette_get_colors(paletteidx)
- end
- end
-
- local letterspace = 0
- if options.letterspace then
- letterspace = tonumber(options.letterspace) / 100 * upem
- elseif options.kernfactor then
- letterspace = tonumber(options.kernfactor) * upem
- end
- space = space + letterspace
-
- local slantfactor = nil
- if options.slant then
- slantfactor = tonumber(options.slant) * 1000
- end
-
- local mode = nil
- local width = nil
- if options.embolden then
- mode = 2
- -- The multiplication by 7200.0/7227 is to undo the opposite conversion
- -- the engine is doing and make the final number written in the PDF file
- -- match XeTeX’s.
- width = (size * tonumber(options.embolden) / 6553.6) * (7200.0/7227)
- end
-
- local hscale = upem
- local extendfactor = nil
- if options.extend then
- extendfactor = tonumber(options.extend) * 1000
- hscale = hscale * tonumber(options.extend)
- end
-
- local vscale = upem
- local squeezefactor = nil
- if options.squeeze then
- squeezefactor = tonumber(options.squeeze) * 1000
- vscale = vscale * tonumber(options.squeeze)
- end
-
- if options.texlig then
- for char in next, characters do
- local ligatures = tlig[char]
- if ligatures then
- characters[char].ligatures = ligatures
- end
- end
- end
-
- return {
- name = spec.specification,
- filename = spec.resolved or spec.name,
- designsize = size,
- psname = sanitize(data.psname),
- fullname = data.fullname,
- index = (spec.sub and spec.sub or 1) - 1,
- size = size,
- units_per_em = upem,
- type = "real",
- embedding = "subset",
- tounicode = 1,
- nomath = true,
- format = data.fonttype,
- slant = slantfactor,
- mode = mode,
- width = width,
- extend = extendfactor,
- squeeze = squeezefactor,
- characters = characters,
- parameters = {
- slant = data.slant,
- space = space * scale,
- space_stretch = space * scale / 2,
- space_shrink = space * scale / 3,
- x_height = data.xheight * scale,
- quad = size,
- extra_space = space * scale / 3,
- [8] = data.capheight * scale, -- for XeTeX compatibility.
- },
- hb = {
- scale = scale,
- features = features,
- options = options,
- palette = palette,
- shared = data,
- letterspace = letterspace,
- hscale = hscale,
- vscale = vscale,
- },
- }
-end
-
-local function define_font(spec, size)
- local hbdata = loadfont(spec)
- return hbdata and scalefont(hbdata, spec)
-end
-
-return define_font