Skip to content

Instantly share code, notes, and snippets.

@hmenke hmenke/XeTeXemulate.sty
Last active Jan 16, 2019

Embed
What would you like to do?
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
@davidcarlisle

This comment has been minimized.

Copy link

commented Sep 3, 2018

currently

\typeout{YEN: \the\XeTeXglyphindex"yen" }

produces

YEN: 638\ignorespaces

in luatex as \ignorespaces isn't expandable, also it modifies the value of \count@ which may cause some surprises.

May I suggest


\documentclass{article}

\makeatletter
\ifx\directlua\@undefined\else

  \protected\def\XeTeXglyphindex"#1"{%
    \directlua{
      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 == "\luaescapestring{#1}" then
              index = char.index
              break
          end
      end
      tex.print([[\numexpr(]] .. index .. ')')
    }}%
%

\fi

\begin{document}

\typeout{YEN 1: [\the\XeTeXglyphindex"yen" ] x}
\typeout{YEN 2: [\the\XeTeXglyphindex"yen"\relax] x }% a bit weird (so emulation drops \relax)
\typeout{YEN 3: [\the\XeTeXglyphindex"yen"] x }% too weird to contemplate emulating
\typeout{YEN 4: [\XeTeXglyphindex"yen"] }
\typeout{YEN 5: [\XeTeXglyphindex] }

\end{document}

@davidcarlisle

This comment has been minimized.

Copy link

commented Sep 3, 2018

It may be better to add the \relax in the tex.print to prevent following tokens being takes as the numexpr, I added (..) but that would still gobble *2 etc. Also the " in xetex are actually optional, this works

\typeout{YEN 1b: [\the\XeTeXglyphindex yen ] x}

@davidcarlisle

This comment has been minimized.

Copy link

commented Sep 3, 2018

better emulation using token scanner

\documentclass{article}

\makeatletter
\ifx\directlua\@undefined\else

  \protected\def\XeTeXglyphindex"#1"{%
    \directlua{
      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 == "\luaescapestring{#1}" then
              index = char.index
              break
          end
      end
      tex.print([[\numexpr(]] .. index .. ')')
    }}%
%
  \protected\def\XeTeXglyphindex{%
    \directlua{
      local k = string.gsub(token.scan_string(),'"','')
      local sp = token.scan_keyword(' ')
      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]])
    }}%
%

\fi

\begin{document}

\typeout{YEN 0: [\the\XeTeXglyphindex yen ] x}
\typeout{YEN 1: [\the\XeTeXglyphindex "yen" ] x}
\typeout{YEN 2: [\the\XeTeXglyphindex"yen"\relax] x }
\typeout{YEN 3: [\the\XeTeXglyphindex"yen"] x }
\typeout{YEN 4: [\XeTeXglyphindex"yen"] }
\typeout{YEN 5: [\XeTeXglyphindex] }
\typeout{YEN 6: [\the\XeTeXglyphindex "yen" *2]}
\typeout{YEN 7: [\the\XeTeXglyphindex "yen"\relax*2]}
\end{document}

with xelatex


YEN 0: [638] x
YEN 1: [638] x
YEN 2: [638\relax ] x 
YEN 3: [0x 
YEN 4: [\XeTeXglyphindex "yen"] 
YEN 5: [\XeTeXglyphindex ] 
YEN 6: [638*2]
YEN 7: [638\relax *2]

with lualatex

YEN 0: [638] x
YEN 1: [638] x
YEN 2: [638\relax ] x 
YEN 3: [0x 
YEN 4: [\XeTeXglyphindex "yen"] 
YEN 5: [\XeTeXglyphindex ] 
YEN 6: [638*2]
YEN 7: [638\relax *2]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.