5

Please look at the following MWE:

\documentclass[20pt]{extarticle}
\usepackage{unicode-math}
\usepackage{luacode}

%% Works: change width of \begin{luacode} local function newwidth(tfmdata) tfmdata.shared.rawdata.descriptions[119891].width=3000 end fonts.constructors.features.otf.register{ name = 'width', description = 'Overwrite width values', initializers = { base = newwidth, }, } \end{luacode}

%% Does not work: math accent horizontal position of \begin{luacode} local function newacc(tfmdata) tfmdata.shared.rawdata.descriptions[119891].math.accent=900 end fonts.constructors.features.otf.register{ name = 'acc', description = 'Overwrite accent values', initializers = { base = newacc, }, } \end{luacode}

%% Does not work: change bounding box of \begin{luacode} local function newbbox(tfmdata) tfmdata.shared.rawdata.descriptions[119891].boundingbox={ -400, 0, 600, 0 } end fonts.constructors.features.otf.register{ name = 'bbox', description = 'Overwrite boundingbox values', initializers = { base = newbbox, }, } \end{luacode}

\setmathfont{Latin Modern Math}[math-style=literal, RawFeature={+width;+bbox;+acc}]

\begin{document}

$$ \hat $$% Sorry for $$, I usually use Plain TeX.

\end{document}

I changed succesfully width of (unicode 119891, mathematical italic small f), but I cannot change its sidebearings (bounding box) and its horizontal math accent position.

How to do that properly?

enter image description here

Edit: Somewhere I saw tfmdata.shared.rawdata.descriptions and somewhere tfmdata.characters. Could someome explain the difference please? When to use the former, when the latter?

1 Answers1

5

I guess we should start at the end:

Somewhere I saw tfmdata.shared.rawdata.descriptions and somewhere tfmdata.characters. Could someome explain the difference please? When to use the former, when the latter?

Never change anything in tfmdata.shared.rawdata. As the name indicates it's raw data not affected by any selected features and is shared by different TeX level fonts. So if you change it in your custom feature and then load the font once with and once without your feature your change might affect both. Or not. Depending on the order, implementation defined internals about when stuff gets shared or not, the version of all affected components and the phase of the moon. (Ok, the last one is unlikely but I can't guarantee that it can't happen...) Also relying on the rawdata misses anything changed by other features.

So instead things should be changed in tfmdata.characters. Now if you set simething there in initializers it doesn't have much effect since it gets overwritten by the rawdata. The initializers are more for initialization, argument parsing and setting up dynamic processors, actual character manipulation is done in manipulators. Attention: manipulators run, in contrast to initializers, after scaling the font. So you have to scale your changes too.

Therefore changing the width would be better done with

local function newwidth(tfmdata)
  tfmdata.characters[119891].width=3000 * tfmdata.parameters.factor
end
fonts.constructors.features.otf.register{
    name = 'width',
    description = 'Overwrite width values',
    manipulators = {
        base = newwidth,
    },
}

This way you can also change the accent position:

    local function newacc(tfmdata)
      tfmdata.characters[119891].top_accent = 900 * tfmdata.parameters.factor
    end
    fonts.constructors.features.otf.register{
        name = 'acc',
        description = 'Overwrite accent values',
        manipulators = {
            base = newacc,
        },
    }

Overwriting the bounding box on the other hand doesn't really make much sense because the bounding box is a physical property of how the glyph looks. It's informational and isn't used anywhere except to determine the initial height/depth/italic which happens before the initializers, so at the point your code runs it isn't accessed anymore. What are you actually trying to archive by changing it?

If you want to move the glyph horizontally relative to the origin, you can use virtual font commands to apply an offset. This effectively changes the sidebearings:

  local function moveright(tfmdata)
    tfmdata.characters[119891].commands={
      {'right', 900 * tfmdata.parameters.factor},
      {'char', 119891}
    }
  end
  fonts.constructors.features.otf.register{
      name = 'moveright',
      manipulators = {
        base = moveright,
      },
  }

If you want to move the glyph to the left, you still use the 'right' command but just use a negative amount. There is no 'left' command. You can also use 'down' for vertical adjustments.

  • Thank you, now I understand more. I think these examples should be in the luaotfload documentation. – Weißer Kater Aug 27 '22 at 23:18
  • I would like to change the bounding box, that means the sidebearings of a letter. It is a matter of taste, but I think the sidebearinges of the `` (mathematical small italic f) and of some other letters are to large in some fonts. Do you know how to change the sidebearings in luaotfload? – Weißer Kater Aug 27 '22 at 23:22
  • @WeißerKater In a glyph, the advance width (TeX's width) is the sum of three components: The left sidebearing, the width of the actually drawn glyph parts and the right sidebearing. Since we normally don't change the drawn glyph, you can't control the sidebearings independent from the width and can't change the width without changing the sidebearings. In practice this means that you already change the right sidebearing when changing the width. – Marcel Krüger Aug 28 '22 at 07:44
  • Therefore having the separate option to change sidebearings leads to issues. What do you want to happen when you set the sidebearings in a way that they (together with the drawn glyph width) don't match the width? Scale the glyph? Fail? – Marcel Krüger Aug 28 '22 at 07:45
  • To make this more practical, assume that a glyph has a (advance) width of 1000 units and has 10 units sidebearing in each side. So the bounding box is 980 units wide. If you change this to 2000 units width and 0 sidebearings, how do you want the output to look? – Marcel Krüger Aug 28 '22 at 07:48
  • You are right, of course. My examples were rather silly; I only wanted to see if they have an effect since I do not understand all the luaotfload code. And yes, the right sidebearing is controlled by the width. So there is only one question left: Is it possible to change (increase, decrease) the left sidebearing? Do you know a solution? – Weißer Kater Aug 28 '22 at 08:52
  • @WeißerKater I added something about moving the glyph origin which should have the effect you are looking for. – Marcel Krüger Aug 28 '22 at 09:41
  • Thank you very much, this is exactly what I looked for. Can I ask you some other questions about character manipulation (maybe in another thread)? Sorry if I am disturbing you. – Weißer Kater Aug 28 '22 at 10:17
  • @WeißerKater If you have further question just open a new question and ask it. If I (or someone else) will answer it is hard to say without seeing the question. – Marcel Krüger Aug 28 '22 at 11:57
  • OK, the is a new question: https://tex.stackexchange.com/questions/655436/luatex-how-to-slant-extend-or-embolden-only-some-characters-of-a-font-not-the – Weißer Kater Aug 28 '22 at 12:24