summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--luaotfload-auxiliary.lua406
-rw-r--r--luaotfload.dtx10
-rwxr-xr-xmkglyphlist6
-rw-r--r--tests/font_patch.tex6
-rw-r--r--tests/pln-aux-1.tex49
-rw-r--r--tests/pln-aux-2.tex102
-rw-r--r--tests/pln-aux-3.tex39
-rw-r--r--tests/pln-aux-4.tex41
8 files changed, 656 insertions, 3 deletions
diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
new file mode 100644
index 0000000..2cf1e00
--- /dev/null
+++ b/luaotfload-auxiliary.lua
@@ -0,0 +1,406 @@
+#!/usr/bin/env texlua
+-----------------------------------------------------------------------
+-- FILE: luaotfload-auxiliary.lua
+-- DESCRIPTION: part of luaotfload
+-- REQUIREMENTS: luaotfload 2.2
+-- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
+-- VERSION: 1.0
+-- CREATED: 2013-05-01 14:40:50+0200
+-----------------------------------------------------------------------
+--
+
+--- this file addresses issue #24
+--- https://github.com/lualatex/luaotfload/issues/24#
+
+luaotfload = luaotfload or {}
+luaotfload.aux = luaotfload.aux or { }
+
+config = config or { }
+config.luaotfload = config.luaotfload or { }
+
+local aux = luaotfload.aux
+local log = luaotfload.log
+local identifiers = fonts.hashes.identifiers
+
+local fontid = font.id
+local texsprint = tex.sprint
+
+local utf8 = unicode.utf8
+local stringlower = string.lower
+local stringformat = string.format
+local stringgsub = string.gsub
+local stringbyte = string.byte
+
+-----------------------------------------------------------------------
+--- font patches
+-----------------------------------------------------------------------
+
+--[[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]]--
+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 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
+-----------------------------------------------------------------------
+
+--- 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
+
+--- int -> bool
+local current_font_has_glyph = function (codepoint)
+ return font_has_glyph (font.current(), codepoint)
+end
+
+aux.current_font_has_glyph = current_font_has_glyph
+
+local do_if_glyph_else = function (chr, positive, negative)
+ local codepoint = tonumber(chr)
+ if not codepoint then codepoint = utf8.byte(chr) end
+ if current_font_has_glyph(codepoint) then
+ tex.sprint(positive)
+ else
+ tex.sprint(negative)
+ end
+end
+
+aux.do_if_glyph_else = do_if_glyph_else
+
+--[[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
+
+--doc]]--
+
+--- string -> (int | false)
+local slot_of_name = function (glyphname)
+ local fontdata = identifiers[font.current()]
+ if fontdata then
+ local unicode = fontdata.resources.unicodes[glyphname]
+ if unicode and type(unicode) == "number" then
+ return unicode
+ else
+ return unicode[1] --- for multiple components
+ end
+ 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 = fonts.encodings.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
+
+-----------------------------------------------------------------------
+--- 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
+ log(stringformat(
+ "font no %d (%s) defines feature %s for script %s",
+ font_id, fontname, feature, asked_script))
+ return true
+ end
+ end
+ end
+ log(stringformat(
+ "font no %d (%s) defines no feature for script %s",
+ font_id, fontname, asked_script))
+ end
+ end
+ log(stringformat("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
+ log(stringformat("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
+ log(stringformat(
+ "font no %d (%s) defines no feature for script %s with language %s",
+ font_id, fontname, asked_script, asked_language))
+ end
+ end
+ log(stringformat("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
+ log(stringformat("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
+ log(stringformat(
+ "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
+ log(stringformat("no font with id %d", font_id))
+ return false
+end
+
+aux.provides_feature = provides_feature
+
+-----------------------------------------------------------------------
+--- font dimensions
+-----------------------------------------------------------------------
+
+--- string -> string -> int
+local get_math_dimension = function (csname, dimenname)
+ local fontdata = identifiers[fontid(csname)]
+ local mathdata = fontdata.mathparameters
+ if mathdata then return mathdata[dimenname] or 0 end
+ return 0
+end
+
+aux.get_math_dimension = get_math_dimension
+
+--- string -> string -> unit
+local sprint_math_dimension = function (csname, dimenname)
+ local dim = get_math_dimension(csname, dimenname)
+ texsprint(luatexbase.catcodetables["latex-package"], dim)
+ texsprint(luatexbase.catcodetables["latex-package"], "sp")
+end
+
+aux.sprint_math_dimension = sprint_math_dimension
+
+-- vim:tw=71:sw=2:ts=2:expandtab
diff --git a/luaotfload.dtx b/luaotfload.dtx
index dd43990..fd71485 100644
--- a/luaotfload.dtx
+++ b/luaotfload.dtx
@@ -1226,6 +1226,11 @@ luaotfload.font_definer = "patch" --- | “generic” | “old”
local error, warning, info, log =
luatexbase.provides_module(luaotfload.module)
+luaotfload.error = error
+luaotfload.warning = warning
+luaotfload.info = info
+luaotfload.log = log
+
% \end{macrocode}
% We set the minimum version requirement for \LUATEX to v0.76,
% because the font loader requires recent features like direct
@@ -1542,7 +1547,6 @@ loadmodule"colors.lua" --- “font-clr”
% genuine \verb|name:| and \verb|file:| lookups of \LUATEX-Fonts.
% Another benefit is that we can now easily plug in or replace new lookup
% behaviors if necessary.
-%
% The name resolver remains untouched, but it calls
% \luafunction{fonts.names.resolve()} internally anyways (see
% \fileent{luaotfload-database.lua}).
@@ -1683,10 +1687,12 @@ elseif font_definer == "patch" then
1)
end
-loadmodule"features.lua" --- contains what was “font-ltx” and “font-otc”
+loadmodule"features.lua" --- contains what was “font-ltx” and “font-otc”
+loadmodule"auxiliary.lua" --- additionaly high-level functionality (new)
-- vim:tw=71:sw=4:ts=4:expandtab
+
% \end{macrocode}
%
% \iffalse
diff --git a/mkglyphlist b/mkglyphlist
index 9ee1528..d73a608 100755
--- a/mkglyphlist
+++ b/mkglyphlist
@@ -8,6 +8,12 @@
-- VERSION: 1.0
-- CREATED: 04/23/2013 12:42:17 PM CEST
-----------------------------------------------------------------------
+-- interesting thread on the Context list:
+-- http://www.ntg.nl/pipermail/ntg-context/2008/029057.html
+-----------------------------------------------------------------------
+
+
+-----------------------------------------------------------------------
-- config
-----------------------------------------------------------------------
local glyphfile = "./glyphlist.txt"
diff --git a/tests/font_patch.tex b/tests/font_patch.tex
index d41ff48..d3bba07 100644
--- a/tests/font_patch.tex
+++ b/tests/font_patch.tex
@@ -8,7 +8,11 @@
mc.DisplayOperatorMinHeight = 2800 / em * sz
end
end
- luatexbase.add_to_callback("luaotfload.patch_font", patch, "cambria.domh")
+ %% part of luaotfload-auxiliary
+ %luatexbase.add_to_callback(
+ %"luaotfload.patch_font",
+ %patch,
+ %"luaotfload.aux.patch_cambria_domh")
}
\font\4={name:Cambria Math:mode=base;script=math} at 10pt
diff --git a/tests/pln-aux-1.tex b/tests/pln-aux-1.tex
new file mode 100644
index 0000000..a504850
--- /dev/null
+++ b/tests/pln-aux-1.tex
@@ -0,0 +1,49 @@
+\input luaotfload.sty
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% usage for glyph tests
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\baselineskip=17.28pt
+
+\font\iwonaregular=name:iwona at 14.4pt
+\font\lmromanten=file:lmroman10-regular.otf at 14.4pt
+\font\cmuregular=file:cmunrm.otf at 14.4pt
+
+%% wrap tests in macros (could move to style file)
+\def\doifglyphelse#1#2#3{%
+ \directlua{
+ luaotfload.aux.do_if_glyph_else([[#1]], [[#2]], [[#3]])
+ }%
+}
+
+\def\doifglyph#1#2{\doifglyphelse{#1}{#2}{}}
+
+%% no otf font loaded yet, so both fail:
+first:
+\doifglyphelse{a}{true}{false}
+\doifglyph {a}{yep}
+
+%% load lm and try repeat:
+\lmromanten
+second:
+\doifglyphelse{a}{true}{false}
+\doifglyph {a}{yep}
+
+%% let’s test some more free fonts
+\def\checkglyphset{%
+ \doifglyphelse ö{ö}{nope}
+ \doifglyphelse п{п}{nope}
+ \doifglyphelse α{α}{nope}
+ \doifglyphelse Æ{Æ}{nope}
+ \doifglyphelse ą{ą}{nope}
+ \doifglyphelse ř{ř}{nope}
+ \doifglyphelse ˝{˝}{nope}
+ \doifglyphelse ѩ{ѩ}{nope}
+ \endgraf
+}
+
+\iwonaregular \checkglyphset
+\lmromanten \checkglyphset
+\cmuregular \checkglyphset
+
+\bye
diff --git a/tests/pln-aux-2.tex b/tests/pln-aux-2.tex
new file mode 100644
index 0000000..62192a5
--- /dev/null
+++ b/tests/pln-aux-2.tex
@@ -0,0 +1,102 @@
+\input luaotfload.sty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% script, features, and language
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\font\minionregular=file:MinionPro_Regular.otf at 9pt
+\font\biolinum=file:LinBiolinum_R.otf at 9pt
+\font\cmuregular=file:cmunrm.otf at 9pt
+
+%% (1) luaotfload.aux.provides_script(font_id, script)
+%% #1 defined font; #2 OT script tag
+\def\providesscript[#1][#2]{%
+ \bgroup#1%
+ let’s see whether \detokenize{#1} has script #2:
+ \directlua{
+ local aux = luaotfload.aux
+ local succ = aux.provides_script(font.current(), [[#2]])
+ if succ then tex.sprint"true" else tex.sprint"false" end
+ }%
+ \egroup
+ \endgraf%
+}
+
+\providesscript [\minionregular][latn]%% Latin
+\providesscript [\biolinum][latn]
+\providesscript [\cmuregular][latn]
+\providesscript [\minionregular][cyrl]%% Cyrillic
+\providesscript [\biolinum][cyrl]
+\providesscript [\cmuregular][cyrl]
+\providesscript [\minionregular][tibt]%% Tibetan
+\providesscript [\biolinum][tibt]
+\providesscript [\cmuregular][tibt]
+
+\hrule % --------------------------------------------------------------
+
+%% (2) luaotfload.aux.provides_language(font_id, script, language)
+%% #1 defined font; #2 OT script tag; #3 OT language tag
+\def\provideslanguage[#1][#2][#3]{%
+ \bgroup#1%
+ let’s see whether \detokenize{#1} supports language #3 for script #2:
+ \directlua{
+ local aux = luaotfload.aux
+ local succ = aux.provides_language(font.current(), [[#2]], [[#3]])
+ if succ then tex.sprint"true" else tex.sprint"false" end
+ }%
+ \egroup
+ \endgraf%
+}
+
+\provideslanguage [\minionregular][latn][nld]%% Latin/Dutch
+\provideslanguage [\biolinum][latn][nld]
+\provideslanguage [\cmuregular][latn][nld]
+\provideslanguage [\minionregular][latn][deu]%% Latin/German
+\provideslanguage [\biolinum][latn][deu]
+\provideslanguage [\cmuregular][latn][deu]
+\provideslanguage [\minionregular][cyrl][rus]%% Cyrillic/Russian
+\provideslanguage [\biolinum][cyrl][rus]
+\provideslanguage [\cmuregular][cyrl][rus]
+\provideslanguage [\minionregular][cyrl][klm]%% Cyrillic/Kalmyk
+\provideslanguage [\biolinum][cyrl][klm]
+\provideslanguage [\cmuregular][cyrl][klm]
+\provideslanguage [\minionregular][cyrl][srb]%% Cyrillic/Serbian
+\provideslanguage [\biolinum][cyrl][srb]
+\provideslanguage [\cmuregular][cyrl][srb]
+\provideslanguage [\minionregular][tibt][tib]%% Tibetan
+\provideslanguage [\biolinum][tibt][tib]
+\provideslanguage [\cmuregular][tibt][tib]
+
+\hrule % --------------------------------------------------------------
+
+%% (3) luaotfload.aux.provides_feature(
+%% font_id, script, language, feature)
+%% #1 defined font; #2 OT script tag;
+%% #3 OT language tag; #4 OT feature
+\def\providesfeature[#1][#2][#3][#4]{%this is getting ridiculous
+ \bgroup#1%
+ let’s see whether \detokenize{#1} supports feature #4 for the
+ combination of script #2 with language #3:
+ \directlua{
+ local aux = luaotfload.aux
+ local succ = aux.provides_feature(
+ font.current(), [[#2]], [[#3]], [[#4]])
+ if succ then tex.sprint"true" else tex.sprint"false" end
+ }%
+ \egroup
+ \endgraf%
+}
+
+\providesfeature [\minionregular][latn][nld][liga]%% Latin/Dutch
+\providesfeature [\biolinum][latn][nld][liga]
+\providesfeature [\cmuregular][latn][nld][liga]
+\providesfeature [\minionregular][latn][deu][liga]%% Latin/German
+\providesfeature [\biolinum][latn][deu][liga]
+\providesfeature [\cmuregular][latn][deu][liga]
+\providesfeature [\minionregular][cyrl][srb][liga]%% Cyrillic/Serbian
+\providesfeature [\biolinum][cyrl][srb][liga]
+\providesfeature [\cmuregular][cyrl][srb][liga]
+\providesfeature [\minionregular][tibt][tib][liga]%% Tibetan
+\providesfeature [\biolinum][tibt][tib][liga]
+\providesfeature [\cmuregular][tibt][tib][liga]
+
+\bye
diff --git a/tests/pln-aux-3.tex b/tests/pln-aux-3.tex
new file mode 100644
index 0000000..12a80cf
--- /dev/null
+++ b/tests/pln-aux-3.tex
@@ -0,0 +1,39 @@
+\input luaotfload.sty
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% math dimension getter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\font\xitsmath=file:xits-math.otf
+\font\cambriamath=file:cambria.ttc(1)
+
+\font\main=file:Iwona-Regular.otf at 12pt\main
+
+\directlua{
+ local aux = luaotfload.aux
+ local test_a = function (fontname, dimension)
+ tex.sprint(
+ "(", fontname, " (", dimension, " ",
+ aux.get_math_dimension(fontname, dimension),
+ [[))\endgraf ]])
+ end
+
+ local test_b = function (fontname, dimension)
+ aux.sprint_math_dimension(fontname, dimension)
+ tex.print[[\endgraf ]]
+ end
+
+ test_a("xitsmath", "AxisHeight")
+ test_a("xitsmath", "RadicalVerticalGap")
+ test_a("cambriamath", "StackTopShiftUp")
+ test_a("cambriamath", "FractionNumeratorGapMin")
+
+ test_b("xitsmath", "AxisHeight")
+ test_b("xitsmath", "RadicalVerticalGap")
+ test_b("cambriamath", "StackTopShiftUp")
+ test_b("cambriamath", "FractionNumeratorGapMin")
+}
+
+foo bar baz
+
+\bye
diff --git a/tests/pln-aux-4.tex b/tests/pln-aux-4.tex
new file mode 100644
index 0000000..80ffc0b
--- /dev/null
+++ b/tests/pln-aux-4.tex
@@ -0,0 +1,41 @@
+\input luaotfload.sty
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% unicode character mappings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\font\ptserifregular = file:PTF55F.ttf \ptserifregular
+
+%% here we map the function luaotfload.aux.name_of_slot
+%% on a short text, printing a list of letters, their
+%% code points and names (as specified in the Adobe
+%% Glyph List).
+
+\directlua{
+ local aux = luaotfload.aux
+ local cbk = function (str)
+ if string.match(str, "^EOF") then
+ luatexbase.remove_from_callback("process_input_buffer", "weird")
+ return [[the end!]]
+ end
+ local res = { }
+ for chr in string.utfcharacters(str) do
+ local val = unicode.utf8.byte(chr)
+ local line = chr .. " <> " .. tostring(val)
+ line = line .. " <> " .. (aux.name_of_slot(val) or "")
+ res[\string#res+1] = line
+ end
+ return table.concat(res, [[\endgraf]])
+ end
+
+ luatexbase.add_to_callback("process_input_buffer", cbk, "weird")
+}
+
+Я узнал что у меня
+Есть огромная семья
+И тропинка и лесок
+В поле каждый колосок
+
+EOF
+
+\bye