Skip to content

Instantly share code, notes, and snippets.

@hmenke
Last active January 28, 2023 01:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hmenke/6e8ff7c90a5e5df3c4895f60059a2ef7 to your computer and use it in GitHub Desktop.
Save hmenke/6e8ff7c90a5e5df3c4895f60059a2ef7 to your computer and use it in GitHub Desktop.
Emulate XeTeX font primitives in LuaTeX
\ifdefined\directlua
\input XeTeXemulate.sty
\input luaotfload.sty
\XeTeXemulate
\fi
\font\1="[lmroman10-italic.otf]" at 10pt\1
\font\2=cmr10 at 10pt
\edef\x{\the\XeTeXfonttype\1}“\x”
\edef\x{\the\XeTeXfonttype\2}“\x”
\edef\x{\the\XeTeXversion}“\x”
\edef\x{\XeTeXrevision}“\x”
\edef\x{\char\XeTeXfirstfontchar\1}“\x”
\edef\x{\char\XeTeXfirstfontchar\2}“\x”
\edef\x{\char\XeTeXlastfontchar\1}“\x”
\edef\x{\char\XeTeXlastfontchar\2}“\x”
\edef\x{\XeTeXglyph150}“\x”
\edef\x{\the\XeTeXcountglyphs\1}“\x”
\edef\x{\the\XeTeXcountglyphs\2}“\x”
\edef\x{\XeTeXglyphname\1 150}“\x”
\edef\x{\the\XeTeXglyphindex"acircumflexgrave"\relax}“\x”
\edef\x{\the\XeTeXglyphindex"acircumflexgrave" }“\x”
\edef\x{\the\XeTeXcharglyph"00A5}“\x”
\edef\x{\the\XeTeXglyphbounds 1 \XeTeXcharglyph`f}“\x”
\edef\x{\the\XeTeXglyphbounds 2 \XeTeXcharglyph`f}“\x”
\edef\x{\the\XeTeXglyphbounds 3 \XeTeXcharglyph`f}“\x”
\edef\x{\the\XeTeXglyphbounds 4 \XeTeXcharglyph`f}“\x”
\edef\x{[\the\XeTeXglyphindex yen ] x}“\x”
\edef\x{[\the\XeTeXglyphindex "yen" ] x}“\x”
\edef\x{[\the\XeTeXglyphindex"yen"\relax] x }“\x”
\edef\x{[\the\XeTeXglyphindex"yen"] x }“\x”
\edef\x{[\the\XeTeXglyphindex "yen" *2]}“\x”
\edef\x{[\the\XeTeXglyphindex "yen"\relax*2]}“\x”
\edef\x{[\XeTeXglyphindex"yen"] }“\meaning\x”
\edef\x{[\XeTeXglyphindex] }“\meaning\x”
\bye
\ifcsname ProvidesPackage\endcsname
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{XeTeXemulate}[2018/09/03 v0.0 Emulate the XeTeX font primitives in LuaTeX]
\fi
\def\XeTeXemulate{%
\chardef\XeTeXversion=0
\def\XeTeXrevision{.99999}%
% Circumvent \outer error
\csname newcount\endcsname\XeTeXtracingfonts \XeTeXtracingfonts=0
\csname newcount\endcsname\XeTeXuseglyphmetrics \XeTeXuseglyphmetrics=1
%
\let\XeTeXmathcode\Umathcode
%
\protected\def\XeTeXfonttype{%
\directlua{
local fid = token.scan_int()
local tfmdata = font.getfont(fid)
local fonttype = tfmdata.format == "opentype" and 2 or 0
tex.print([[\numexpr]] .. fonttype .. [[\relax]])
}\fontid
}%
%
\protected\def\XeTeXfirstfontchar{%
\directlua{
local fid = token.scan_int()
local tfmdata = font.getfont(fid)
local min
for slot in pairs(tfmdata.characters) do
min = min and (slot < min and slot or min) or slot
end
tex.print([[\numexpr]] .. min .. [[\relax]])
}\fontid
}%
%
\protected\def\XeTeXlastfontchar{%
\directlua{
local fid = token.scan_int()
local tfmdata = font.getfont(fid)
local max
for slot in pairs(tfmdata.characters) do
max = max and (slot > max and slot < 2^16 and slot or max) or slot
end
tex.print([[\numexpr]] .. max .. [[\relax]])
}\fontid
}%
%
\def\XeTeXglyph{%
\directlua{
local index = token.scan_int()
local tfmdata = font.getfont(font.current())
if tfmdata.format \string~= "opentype" then
tex.error([[Cannot use \string\XeTeXglyph]] .. [[ with ]] ..
tfmdata.name .. [[; not a native platform font]])
end
for slot, char in pairs(tfmdata.characters) do
if char.index == index then
tex.print(utf.char(char.unicode))
return
end
end
}}%
%
\protected\def\XeTeXcountglyphs{%
\directlua{
local fid = token.scan_int()
local tfmdata = font.getfont(fid)
local count = 0
if tfmdata.format == "opentype" then
for _ in pairs(tfmdata.characters) do
count = count + 1
end
end
tex.print([[\numexpr]] .. count .. [[\relax]])
}\fontid
}%
%
\def\XeTeXglyphname{%
\directlua{
local fid = token.scan_int()
local index = token.scan_int()
local tfmdata = font.getfont(fid)
if tfmdata.format \string~= "opentype" then
tex.error([[Cannot use \string\XeTeXglyphname]] .. [[ with ]] ..
tfmdata.name .. [[; not a native platform font]])
end
local count = 0
for slot, char in pairs(tfmdata.shared.rawdata.descriptions) do
if char.index == index then
tex.print(char.name)
return
end
end
}\fontid
}%
%
\protected\def\XeTeXglyphindex{%
\directlua{
local k = string.gsub(token.scan_string(),'"','')
token.scan_keyword(' ') % remove optional space
local tfmdata = font.getfont(font.current())
if tfmdata.format \string~= "opentype" then
tex.error([[Cannot use \string\XeTeXglyphindex]] .. [[ with ]] ..
tfmdata.name .. [[; not a native platform font]])
end
local index = 0
for slot, char in pairs(tfmdata.shared.rawdata.descriptions) do
if char.name == k then
index = char.index
break
end
end
tex.print([[\numexpr]] .. index .. [[\relax]])
}}%
%
\protected\def\XeTeXcharglyph{%
\directlua{
local id = token.scan_int()
local tfmdata = font.getfont(font.current())
if tfmdata.format \string~= "opentype" then
tex.error([[Cannot use \string\XeTeXcharglyph]] .. [[ with ]] ..
tfmdata.name .. [[; not a native platform font]])
end
local index = tfmdata.characters[id].index
tex.print([[\numexpr]] .. index .. [[\relax]])
}}%
%
\protected\def\XeTeXglyphbounds{%
\directlua{
local edge = token.scan_int()
local slot = token.scan_int()
local tfmdata = font.getfont(font.current())
if tfmdata.format \string~= "opentype" then
tex.error([[Cannot use \string\XeTeXglyphname]] .. [[ with ]] ..
tfmdata.name .. [[; not a native platform font]])
end
for _,char in pairs(tfmdata.shared.rawdata.descriptions) do
if char and char.index == slot then
local bbox = char.boundingbox
local dimen = 0
if edge == 1 then
dimen = bbox and bbox[1] / 100 * 2^16 or 0
elseif edge == 2 then
dimen = tfmdata.characters[char.unicode].height
elseif edge == 3 then
dimen = bbox and (char.width - bbox[3]) / 100 * 2^16 or 0
elseif edge == 4 then
dimen = tfmdata.characters[char.unicode].depth
end
tex.print([[\dimexpr]] .. tex.round(dimen) .. [[sp\relax]])
break
end
end
}}%
}
\endinput
@hmenke
Copy link
Author

hmenke commented Jan 8, 2023

I'd actually rather reimplement the entire thing in pure Lua and expose the commands via token.set_lua. That makes them feel a lot more like actual primitives since they expand in a single step. That will need some expandafter magic for \fontid, but other than that should be straight-forward.

@hmenke
Copy link
Author

hmenke commented Jan 26, 2023

@kberry
Copy link

kberry commented Jan 28, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment