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 Answer 1

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.

10
  • Thank you, now I understand more. I think these examples should be in the luaotfload documentation. Aug 27, 2022 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? Aug 27, 2022 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. Aug 28, 2022 at 7: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? Aug 28, 2022 at 7: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? Aug 28, 2022 at 7:48

You must log in to answer this question.

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