summaryrefslogtreecommitdiff
path: root/luaotfload-auxiliary.lua
diff options
context:
space:
mode:
authorPhilipp Gesang <phg42.2a@gmail.com>2014-02-12 07:50:06 +0100
committerPhilipp Gesang <phg42.2a@gmail.com>2014-02-12 07:50:06 +0100
commit9138da7d4a53d65bc15f3a5dc73fd373db40bdf7 (patch)
tree702093c750d81aa2e8810f484627b51d6b485c27 /luaotfload-auxiliary.lua
parentffa5a347f68805e218c61c344c0b8a895c4bb8db (diff)
downloadluaotfload-9138da7d4a53d65bc15f3a5dc73fd373db40bdf7.tar.gz
[*] move source files to ./src
Diffstat (limited to 'luaotfload-auxiliary.lua')
-rw-r--r--luaotfload-auxiliary.lua783
1 files changed, 0 insertions, 783 deletions
diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
deleted file mode 100644
index 716af98..0000000
--- a/luaotfload-auxiliary.lua
+++ /dev/null
@@ -1,783 +0,0 @@
-#!/usr/bin/env texlua
------------------------------------------------------------------------
--- FILE: luaotfload-auxiliary.lua
--- DESCRIPTION: part of luaotfload
--- REQUIREMENTS: luaotfload 2.5
--- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
--- VERSION: 2.5
--- MODIFIED: 2014-01-02 21:24:25+0100
------------------------------------------------------------------------
---
-
---- this file addresses issue #24
---- https://github.com/lualatex/luaotfload/issues/24#
-
-luaotfload = luaotfload or {}
-luaotfload.aux = luaotfload.aux or { }
-
-local aux = luaotfload.aux
-local log = luaotfload.log
-local report = log.report
-local fonthashes = fonts.hashes
-local identifiers = fonthashes.identifiers
-
-local fontid = font.id
-local texsprint = tex.sprint
-
-local dofile = dofile
-local getmetatable = getmetatable
-local setmetatable = setmetatable
-local utf8 = unicode.utf8
-local stringlower = string.lower
-local stringformat = string.format
-local stringgsub = string.gsub
-local stringbyte = string.byte
-local stringfind = string.find
-local tablecopy = table.copy
-
------------------------------------------------------------------------
---- font patches
------------------------------------------------------------------------
-
---- https://github.com/khaledhosny/luaotfload/issues/54
-
-local rewrite_fontname = function (tfmdata, specification)
- tfmdata.name = [["]] .. specification .. [["]]
-end
-
-local rewriting = false
-
-local start_rewrite_fontname = function ()
- if rewriting == false then
- luatexbase.add_to_callback (
- "luaotfload.patch_font",
- rewrite_fontname,
- "luaotfload.rewrite_fontname")
- rewriting = true
- report ("log", 0, "aux",
- "start rewriting tfmdata.name field")
- end
-end
-
-aux.start_rewrite_fontname = start_rewrite_fontname
-
-local stop_rewrite_fontname = function ()
- if rewriting == true then
- luatexbase.remove_fromt_callback
- ("luaotfload.patch_font", "luaotfload.rewrite_fontname")
- rewriting = false
- report ("log", 0, "aux",
- "stop rewriting tfmdata.name field")
- end
-end
-
-aux.stop_rewrite_fontname = stop_rewrite_fontname
-
-
---[[doc--
-This sets two dimensions apparently relied upon by the unicode-math
-package.
---doc]]--
-
-local set_sscale_dimens = function (fontdata)
- local mathconstants = fontdata.MathConstants
- local parameters = fontdata.parameters
- if mathconstants then
- parameters[10] = mathconstants.ScriptPercentScaleDown or 70
- parameters[11] = mathconstants.ScriptScriptPercentScaleDown or 50
- end
- return fontdata
-end
-
-luatexbase.add_to_callback(
- "luaotfload.patch_font",
- set_sscale_dimens,
- "luaotfload.aux.set_sscale_dimens")
-
---- fontobj -> int
-local lookup_units = function (fontdata)
- local metadata = fontdata.shared and fontdata.shared.rawdata.metadata
- if metadata and metadata.units_per_em then
- return metadata.units_per_em
- elseif fontdata.parameters and fontdata.parameters.units then
- return fontdata.parameters.units
- elseif fontdata.units then --- v1.x
- return fontdata.units
- end
- return 1000
-end
-
---[[doc--
-This callback corrects some values of the Cambria font.
---doc]]--
---- fontobj -> unit
-local patch_cambria_domh = function (fontdata)
- local mathconstants = fontdata.MathConstants
- if mathconstants and fontdata.psname == "CambriaMath" then
- --- my test Cambria has 2048
- local units_per_em = fontdata.units_per_em or lookup_units(fontdata)
- local sz = fontdata.parameters.size or fontdata.size
- local mh = 2800 / units_per_em * sz
- if mathconstants.DisplayOperatorMinHeight < mh then
- mathconstants.DisplayOperatorMinHeight = mh
- end
- end
-end
-
-luatexbase.add_to_callback(
- "luaotfload.patch_font",
- patch_cambria_domh,
- "luaotfload.aux.patch_cambria_domh")
-
---[[doc--
-
-Comment from fontspec:
-
- “Here we patch fonts tfm table to emulate \XeTeX's \cs{fontdimen8},
- which stores the caps-height of the font. (Cf.\ \cs{fontdimen5} which
- stores the x-height.)
-
- Falls back to measuring the glyph if the font doesn't contain the
- necessary information.
- This needs to be extended for fonts that don't contain an `X'.”
-
---doc]]--
-
-local set_capheight = function (fontdata)
- local shared = fontdata.shared
- local parameters = fontdata.parameters
- local capheight
- if shared and shared.rawdata.metadata.pfminfo then
- local units_per_em = parameters.units
- local size = parameters.size
- local os2_capheight = shared.rawdata.metadata.pfminfo.os2_capheight
-
- if os2_capheight > 0 then
- capheight = os2_capheight / units_per_em * size
- else
- local X8 = stringbyte"X"
- if fontdata.characters[X8] then
- capheight = fontdata.characters[X8].height
- else
- capheight = parameters.ascender / units_per_em * size
- end
- end
- else
- local X8 = stringbyte"X"
- if fontdata.characters[X8] then
- capheight = fontdata.characters[X8].height
- end
- end
- if capheight then
- --- is this legit? afaics there’s nothing else on the
- --- array part of that table
- fontdata.parameters[8] = capheight
- end
-end
-
-luatexbase.add_to_callback(
- "luaotfload.patch_font",
- set_capheight,
- "luaotfload.aux.set_capheight")
-
------------------------------------------------------------------------
---- glyphs and characters
------------------------------------------------------------------------
-
-local agl = fonts.encodings.agl
-
---- int -> int -> bool
-local font_has_glyph = function (font_id, codepoint)
- local fontdata = fonts.hashes.identifiers[font_id]
- if fontdata then
- if fontdata.characters[codepoint] ~= nil then return true end
- end
- return false
-end
-
-aux.font_has_glyph = font_has_glyph
-
---- undocumented
-
-local raw_slot_of_name = function (font_id, glyphname)
- local fontdata = font.fonts[font_id]
- if fontdata.type == "virtual" then --- get base font for glyph idx
- local codepoint = agl.unicodes[glyphname]
- local glyph = fontdata.characters[codepoint]
- if fontdata.characters[codepoint] then
- return codepoint
- end
- end
- return false
-end
-
---[[doc--
-
- This one is approximately “name_to_slot” from the microtype package;
- note that it is all about Adobe Glyph names and glyph slots in the
- font. The names and values may diverge from actual Unicode.
-
- http://www.adobe.com/devnet/opentype/archives/glyph.html
-
- The “unsafe” switch triggers a fallback lookup in the raw fonts
- table. As some of the information is stored as references, this may
- have unpredictable side-effects.
-
---doc]]--
-
---- int -> string -> bool -> (int | false)
-local slot_of_name = function (font_id, glyphname, unsafe)
- local fontdata = identifiers[font_id]
- if fontdata then
- local unicode = fontdata.resources.unicodes[glyphname]
- if unicode then
- if type(unicode) == "number" then
- return unicode
- else
- return unicode[1] --- for multiple components
- end
--- else
--- --- missing
- end
- elseif unsafe == true then -- for Robert
- return raw_slot_of_name(font_id, glyphname)
- end
- return false
-end
-
-aux.slot_of_name = slot_of_name
-
---[[doc--
-
- Inverse of above; not authoritative as to my knowledge the official
- inverse of the AGL is the AGLFN. Maybe this whole issue should be
- dealt with in a separate package that loads char-def.lua and thereby
- solves the problem for the next couple decades.
-
- http://partners.adobe.com/public/developer/en/opentype/aglfn13.txt
-
---doc]]--
-
-local indices
-
---- int -> (string | false)
-local name_of_slot = function (codepoint)
- if not indices then --- this will load the glyph list
- local unicodes = agl.unicodes
- indices = table.swapped(unicodes)
- end
- local glyphname = indices[codepoint]
- if glyphname then
- return glyphname
- end
- return false
-end
-
-aux.name_of_slot = name_of_slot
-
---[[doc--
-
- In Context, characters.data is where the data from char-def.lua
- resides. The file is huge (>3.7 MB as of 2013) and not part of the
- isolated font loader. Nevertheless, we include a partial version
- generated by the mkcharacters script that contains only the
- a subset of the fields of each character defined.
-
- Currently, these are (compare the mkcharacters script!)
-
- · "direction"
- · "mirror"
- · "category"
- · "textclass"
-
- The directional information is required for packages like Simurgh [0]
- to work correctly. In an early stage [1] it was necessary to load
- further files from Context directly, including the full blown version
- of char-def. Since we have no use for most of the so imported
- functionality, the required parts have been isolated and are now
- instated along with luaotfload-characters.lua. We can extend the set
- of imported features easily should it not be enough.
-
- [0] https://github.com/persian-tex/simurgh
- [1] http://tex.stackexchange.com/a/132301/14066
-
---doc]]--
-
-characters = characters or { } --- should be created in basics-gen
-characters.data = nil
-local chardef = "luaotfload-characters"
-
-do
- local setmetatableindex = function (t, f)
- local mt = getmetatable (t)
- if mt then
- mt.__index = f
- else
- setmetatable (t, { __index = f })
- end
- end
-
- --- there are some special tables for each field that provide access
- --- to fields of the character table by means of a metatable
-
- local mkcharspecial = function (characters, tablename, field)
-
- local chardata = characters.data
-
- if chardata then
- local newspecial = { }
- characters [tablename] = newspecial --> e.g. “characters.data.mirrors”
-
- local idx = function (t, char)
- local c = chardata [char]
- if c then
- local m = c [field] --> e.g. “mirror”
- if m then
- t [char] = m
- return m
- end
- end
- newspecial [char] = false
- return char
- end
-
- setmetatableindex (newspecial, idx)
- end
-
- end
-
- local mkcategories = function (characters) -- different from the others
-
- local chardata = characters.data
-
- setmetatable (characters, { __index = function (t, char)
- if char then
- local c = chardata [char]
- c = c.category or char
- t [char] = c
- return c
- end
- end})
-
- end
-
- local load_failed = false
- local chardata --> characters.data; loaded on demand
-
- local load_chardef = function ()
-
- report ("both", 1, "aux", "Loading character metadata from %s.", chardef)
- chardata = dofile (kpse.find_file (chardef, "lua"))
-
- if chardata == nil then
- warning ("Could not load %s; continuing \z
- with empty character table.",
- chardef)
- chardata = { }
- load_failed = true
- end
-
- characters = { } --- nuke metatable
- characters.data = chardata
-
- --- institute some of the functionality from char-ini.lua
-
- mkcharspecial (characters, "mirrors", "mirror")
- mkcharspecial (characters, "directions", "direction")
- mkcharspecial (characters, "textclasses", "textclass")
- mkcategories (characters)
-
- end
-
- local charindex = function (t, k)
- if chardata == nil and load_failed ~= true then
- load_chardef ()
- end
-
- return characters [k]
- end
-
- setmetatableindex (characters, charindex)
-
-end
-
------------------------------------------------------------------------
---- features / scripts / languages
------------------------------------------------------------------------
---- lots of arrowcode ahead
-
---[[doc--
-This function, modeled after “check_script()” from fontspec, returns
-true if in the given font, the script “asked_script” is accounted for in at
-least one feature.
---doc]]--
-
---- int -> string -> bool
-local provides_script = function (font_id, asked_script)
- asked_script = stringlower(asked_script)
- if font_id and font_id > 0 then
- local fontdata = identifiers[font_id].shared.rawdata
- if fontdata then
- local fontname = fontdata.metadata.fontname
- local features = fontdata.resources.features
- for method, featuredata in next, features do
- --- where method: "gpos" | "gsub"
- for feature, data in next, featuredata do
- if data[asked_script] then
- report ("log", 1, "aux",
- "font no %d (%s) defines feature %s for script %s",
- font_id, fontname, feature, asked_script)
- return true
- end
- end
- end
- report ("log", 0, "aux",
- "font no %d (%s) defines no feature for script %s",
- font_id, fontname, asked_script)
- end
- end
- report ("log", 0, "aux", "no font with id %d", font_id)
- return false
-end
-
-aux.provides_script = provides_script
-
---[[doc--
-This function, modeled after “check_language()” from fontspec, returns
-true if in the given font, the language with tage “asked_language” is
-accounted for in the script with tag “asked_script” in at least one
-feature.
---doc]]--
-
---- int -> string -> string -> bool
-local provides_language = function (font_id, asked_script, asked_language)
- asked_script = stringlower(asked_script)
- asked_language = stringlower(asked_language)
- if font_id and font_id > 0 then
- local fontdata = identifiers[font_id].shared.rawdata
- if fontdata then
- local fontname = fontdata.metadata.fontname
- local features = fontdata.resources.features
- for method, featuredata in next, features do
- --- where method: "gpos" | "gsub"
- for feature, data in next, featuredata do
- local scriptdata = data[asked_script]
- if scriptdata and scriptdata[asked_language] then
- report ("log", 1, "aux",
- "font no %d (%s) defines feature %s "
- .. "for script %s with language %s",
- font_id, fontname, feature,
- asked_script, asked_language)
- return true
- end
- end
- end
- report ("log", 0, "aux",
- "font no %d (%s) defines no feature "
- .. "for script %s with language %s",
- font_id, fontname, asked_script, asked_language)
- end
- end
- report ("log", 0, "aux", "no font with id %d", font_id)
- return false
-end
-
-aux.provides_language = provides_language
-
---[[doc--
-We strip the syntax elements from feature definitions (shouldn’t
-actually be there in the first place, but who cares ...)
---doc]]--
-
-local lpeg = require"lpeg"
-local C, P, S = lpeg.C, lpeg.P, lpeg.S
-local lpegmatch = lpeg.match
-
-local sign = S"+-"
-local rhs = P"=" * P(1)^0 * P(-1)
-local strip_garbage = sign^-1 * C((1 - rhs)^1)
-
---s = "+foo" --> foo
---ss = "-bar" --> bar
---sss = "baz" --> baz
---t = "foo=bar" --> foo
---tt = "+bar=baz" --> bar
---ttt = "-baz=true" --> baz
---
---print(lpeg.match(strip_garbage, s))
---print(lpeg.match(strip_garbage, ss))
---print(lpeg.match(strip_garbage, sss))
---print(lpeg.match(strip_garbage, t))
---print(lpeg.match(strip_garbage, tt))
---print(lpeg.match(strip_garbage, ttt))
-
---[[doc--
-This function, modeled after “check_feature()” from fontspec, returns
-true if in the given font, the language with tag “asked_language” is
-accounted for in the script with tag “asked_script” in feature
-“asked_feature”.
---doc]]--
-
---- int -> string -> string -> string -> bool
-local provides_feature = function (font_id, asked_script,
- asked_language, asked_feature)
- asked_script = stringlower(asked_script)
- asked_language = stringlower(asked_language)
- asked_feature = lpegmatch(strip_garbage, asked_feature)
-
- if font_id and font_id > 0 then
- local fontdata = identifiers[font_id].shared.rawdata
- if fontdata then
- local features = fontdata.resources.features
- local fontname = fontdata.metadata.fontname
- for method, featuredata in next, features do
- --- where method: "gpos" | "gsub"
- local feature = featuredata[asked_feature]
- if feature then
- local scriptdata = feature[asked_script]
- if scriptdata and scriptdata[asked_language] then
- report ("log", 1, "aux",
- "font no %d (%s) defines feature %s "
- .. "for script %s with language %s",
- font_id, fontname, asked_feature,
- asked_script, asked_language)
- return true
- end
- end
- end
- report ("log", 0, "aux",
- "font no %d (%s) does not define feature %s for script %s with language %s",
- font_id, fontname, asked_feature, asked_script, asked_language)
- end
- end
- report ("log", 0, "aux", "no font with id %d", font_id)
- return false
-end
-
-aux.provides_feature = provides_feature
-
------------------------------------------------------------------------
---- font dimensions
------------------------------------------------------------------------
-
---- int -> string -> int
-local get_math_dimension = function (font_id, dimenname)
- if type(font_id) == "string" then
- font_id = fontid(font_id) --- safeguard
- end
- local fontdata = identifiers[font_id]
- local mathdata = fontdata.mathparameters
- if mathdata then
- return mathdata[dimenname] or 0
- end
- return 0
-end
-
-aux.get_math_dimension = get_math_dimension
-
---- int -> string -> unit
-local sprint_math_dimension = function (font_id, dimenname)
- if type(font_id) == "string" then
- font_id = fontid(font_id)
- end
- local dim = get_math_dimension(font_id, dimenname)
- texsprint(luatexbase.catcodetables["latex-package"], dim, "sp")
-end
-
-aux.sprint_math_dimension = sprint_math_dimension
-
------------------------------------------------------------------------
---- extra database functions
------------------------------------------------------------------------
-
-local namesresolve = fonts.names.resolve
-local namesscan_dir = fonts.names.scan_dir
-
---[====[-- TODO -> port this to new db model
-
---- local directories -------------------------------------------------
-
---- migrated from luaotfload-database.lua
---- https://github.com/lualatex/luaotfload/pull/61#issuecomment-17776975
-
---- string -> (int * int)
-local scan_external_dir = function (dir)
- local old_names, new_names = names.data()
- if not old_names then
- old_names = load_names()
- end
- new_names = tablecopy(old_names)
- local n_scanned, n_new = scan_dir(dir, old_names, new_names)
- --- FIXME
- --- This doesn’t seem right. If a db update is triggered after this
- --- point, then the added fonts will be saved along with it --
- --- which is not as “temporarily” as it should be. (This should be
- --- addressed during a refactoring of names_resolve().)
- names.data = new_names
- return n_scanned, n_new
-end
-
-aux.scan_external_dir = scan_external_dir
-
---]====]--
-
-aux.scan_external_dir = function ()
- print "ERROR: scan_external_dir() is not implemented"
-end
-
---- db queries --------------------------------------------------------
-
---- https://github.com/lualatex/luaotfload/issues/74
---- string -> (string * int)
-local resolve_fontname = function (name)
- local foundname, subfont, success = namesresolve(nil, nil, {
- name = name,
- lookup = "name",
- optsize = 0,
- specification = "name:" .. name,
- })
- if success then
- return foundname, subfont
- end
- return false, false
-end
-
-aux.resolve_fontname = resolve_fontname
-
---- string list -> (string * int)
-local resolve_fontlist
-resolve_fontlist = function (names, n)
- if not n then
- return resolve_fontlist(names, 1)
- end
- local this = names[n]
- if this then
- local foundname, subfont = resolve_fontname(this)
- if foundname then
- return foundname, subfont
- end
- return resolve_fontlist(names, n+1)
- end
- return false, false
-end
-
-aux.resolve_fontlist = resolve_fontlist
-
---- loaded fonts ------------------------------------------------------
-
---- just a proof of concept
-
---- fontobj -> string list -> (string list) list
-local get_font_data get_font_data = function (tfmdata, keys, acc, n)
- if not acc then
- return get_font_data(tfmdata, keys, {}, 1)
- end
- local key = keys[n]
- if key then
- local val = tfmdata[key]
- if val then
- acc[#acc+1] = val
- else
- acc[#acc+1] = false
- end
- return get_font_data(tfmdata, keys, acc, n+1)
- end
- return acc
-end
-
---[[doc--
-
- The next one operates on the fonts.hashes.identifiers table.
- It returns a list containing tuples of font ids and the
- contents of the fields specified in the first argument.
- Font table entries that were created indirectly -- e.g. by
- \letterspacefont or during font expansion -- will not be
- listed.
-
---doc]]--
-
-local default_keys = { "fullname" }
-
---- string list -> (int * string list) list
-local get_loaded_fonts get_loaded_fonts = function (keys, acc, lastid)
- if not acc then
- if not keys then
- keys = default_keys
- end
- return get_loaded_fonts(keys, {}, lastid)
- end
- local id, tfmdata = next(identifiers, lastid)
- if id then
- local data = get_font_data(tfmdata, keys)
- acc[#acc+1] = { id, data }
- return get_loaded_fonts (keys, acc, id)
- end
- return acc
-end
-
-aux.get_loaded_fonts = get_loaded_fonts
-
---- Raw access to the font.* namespace is unsafe so no documentation on
---- this one.
-local get_raw_fonts = function ( )
- local res = { }
- for i, v in font.each() do
- if v.filename then
- res[#res+1] = { i, v }
- end
- end
- return res
-end
-
-aux.get_raw_fonts = get_raw_fonts
-
------------------------------------------------------------------------
---- font parameters
------------------------------------------------------------------------
---- analogy of font-hsh
-
-fonthashes.parameters = fonthashes.parameters or { }
-fonthashes.quads = fonthashes.quads or { }
-
-local parameters = fonthashes.parameters or { }
-local quads = fonthashes.quads or { }
-
-setmetatable(parameters, { __index = function (t, font_id)
- local tfmdata = identifiers[font_id]
- if not tfmdata then --- unsafe; avoid
- tfmdata = font.fonts[font_id]
- end
- if tfmdata and type(tfmdata) == "table" then
- local fontparameters = tfmdata.parameters
- t[font_id] = fontparameters
- return fontparameters
- end
- return nil
-end})
-
---[[doc--
-
- Note that the reason as to why we prefer functions over table indices
- is that functions are much safer against unintended manipulation.
- This justifies the overhead they cost.
-
---doc]]--
-
---- int -> (number | false)
-local get_quad = function (font_id)
- local quad = quads[font_id]
- if quad then
- return quad
- end
- local fontparameters = parameters[font_id]
- if fontparameters then
- local quad = fontparameters.quad or 0
- quads[font_id] = quad
- return quad
- end
- return false
-end
-
-aux.get_quad = get_quad
-
--- vim:tw=71:sw=2:ts=2:expandtab