While preparing a font for Luatex, the fontloader also sets up some
extra tables inside the font structure that contain the unprocessed
data as returned by fontloader.open()
.
Among these is the glyph data:
For every glyph in the font there is some additional information that is
not contained in the characters
array since it is unnecessary for
Luatex to render a font.
For instance, this is a dump of the information about the glyph a:
table={
["boundingbox"]={ 45, -10, 432, 460 },
["depth"]=10,
["height"]=460,
["index"]=9,
["name"]="a",
["slookups"]={
["as_l_1_s"]={ 63209, 63329 },
["ss_cyrl_l_18_s"]=63209,
["ss_cyrl_l_44_s"]=63329,
["ss_grek_l_17_s"]=63209,
["ss_grek_l_43_s"]=63329,
["ss_l_16_s"]=63209,
["ss_l_37_s"]=63209,
["ss_l_42_s"]=63329,
},
["width"]=512,
}
There we find everything we need to calculate the sidebearings in the
boundingbox
array:
The first value is the left sidebearing.
The third value is the bbox width.
(Dimensions are in hundredths of a TeX point.)
packagedata = packagedata or { }
packagedata.sidebearings = { }
local sidebearings = packagedata.sidebearings
local utfbyte = utf.byte
local texsprint = tex.sprint
local get_sidebearings = function (id, char)
local tfmdata = font.getfont (id)
if not (tfmdata and tfmdata.shared) then
return 0, 0
end
local descriptions = tfmdata.shared.rawdata.descriptions
local glyphdata = descriptions [char]
if not glyphdata then
--- font lacks the glyph
return 0, 0
end
local boundingbox = glyphdata.boundingbox
local lside = boundingbox [1] or 0
local wd = boundingbox [3] or glyphdata.width
local rside = glyphdata.width - wd
inspect (glyphdata)
return lside / 100, rside /100
end
local sidebearings = function (id, char, left)
char = utfbyte (char)
local lside, rside = get_sidebearings (id, char)
if left then
texsprint (tostring (lside), "pt")
else
texsprint (tostring (rside), "pt")
end
end
packagedata.sidebearings.left = function (char)
return sidebearings (font.current (), char, true)
end
packagedata.sidebearings.right = function (char)
return sidebearings (font.current (), char, false)
end
Now we can wrap those functions on the TeX end like so:
\def \lsidebearing #1{%
\directlua {packagedata.sidebearings.left [[#1]]}%
}
\def \rsidebearing #1{%
\directlua {packagedata.sidebearings.right [[#1]]}%
}
These can be used just like \XeTeXglyphbounds
with the argument 1 and 3
respectively.
For comparison, here is a test file that runs with both Xetex and Luatex:
\ifdefined \directlua
\input luaotfload.sty
\directlua {require "sidebearings"}
\def \lsidebearing #1{%
\directlua {packagedata.sidebearings.left [[#1]]}%
}
\def \rsidebearing #1{%
\directlua {packagedata.sidebearings.right [[#1]]}%
}
\font \mainfont = "file:Iwona-Regular.otf"
\else
\def \lsidebearing #1{\the \XeTeXglyphbounds1 \the \XeTeXcharglyph`#1}
\def \rsidebearing #1{\the \XeTeXglyphbounds3 \the \XeTeXcharglyph`#1}
\font \mainfont = "[Iwona-Regular.otf]"
\fi
\mainfont
\def \test #1{[#1] left: \lsidebearing {#1}, right: \rsidebearing {#1}\par}
\test a
\test b
\test y
\test z
\test а
\test б
\test ю
\test я
\bye
Convenience gist of the files.