11

This question has been solved, in XeTeX, by this code:

\def\kright#1{\leavevmode #1\kern-\XeTeXglyphbounds3 \the\XeTeXcharglyph`#1 }
\def\kleft#1{\leavevmode \kern-\XeTeXglyphbounds1 \the\XeTeXcharglyph`#1 #1}

which allows me to align text more precisely to the ink by accessing the side-bearing measurements (\XeTeXglyphbounds1 and 3).

This XeTeX dependency is currently the only thing stopping me from moving to LuaTeX (mainly for microtype). Is an equivalent function available in LuaTeX, or planned?


After reading a bit more on microtype, could the equivalent effect be achieved by an appropriately-tailored set of character protrusions? That way, my move to LuaTeX might be a lot simpler.

1
  • A neat solution in LuaTeX is in tex.stackexchange.com/questions/470276/…. It inserts a negative kern node, before or after the glyph, derived from the bounding box 1 or 3 as required. It works AFTER the TeX line break finish its job, so you do not need to know in advance to which glyph to apply the shift, as happens in xetex. Jan 16, 2019 at 21:56

2 Answers 2

6

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

Typeset result

Convenience gist of the files.

1
8

Yes and no. When you load the font via the built-in fontloader library (which is very low level), you can access all the information of the font file. This includes the bounding box, as far as I can see (look at the section 4.4.5.1.2 "Glyph items" in the LuaTeX reference manual).

But normally you load the fonts via the fontspec / luaotfload packages, which discard that information and only keep what is needed for TeX.

I doubt that inclusion of that information is planned in the luaotfload package, which is based on ConTeXt's font loader.

8
  • Thanks, Patrick. A couple of supplementaries: (1) it looks rather "overloaded" for what I want to do; (2) I'm definitely a fontspec person; and (3) it only has data for left side-bearings, and then "only if nonzero and not equal to bounding box", which leads me to equate the bounding box with the TeX character box, which is definitely what I don't want -- I need to get close to the actual ink. Feb 23, 2012 at 19:06
  • 1
    @Brent.Longborough The bounding box should be the real "tight" box. It is calculated from the actual outlines of the fonts if the font does not contain the bbox info.
    – topskip
    Feb 23, 2012 at 20:08
  • I'm sure the bounding box is kept, but you may be looking at the wrong place (too late now, I'll try to find a definite answer in the morning if there wasn’t one by then). Feb 23, 2012 at 21:40
  • 1
    @Brent.Longborough: the side bearings can be seen as the differences between glyphs bounding box and the box TeX sees. Feb 23, 2012 at 21:42
  • 1
    Sorry for not providing an answer as promised, but you can get the bounding box from fonts.identifiers[id].shared.otfdata.descriptions[gid].boundingbox where id is the font number and gid is glyph id. Feb 26, 2012 at 23:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .