5

As was suggested, I will rephrase my previous question, which is not confined in a coffin.

As @MartinScharrer rightly points out, I am asking how to optically align text at the margins after linebreaking, more specifically when you do not know in advance the content.

This is the case in templates, where the text is provided by a user.

Since TeX compose with boxes, the sidebearings are always there, but they become more noticeable when using large size fonts in title pages or posters.

Working with xelatex I solved this problem for single line sentences, but failed to do so with multiline paragraphs. (Again, text unknown in advance.)

Perfect alignment, single sentence, text unknown in advance.

perfect alignment, single sentence, text unknown in advance.

Variable right gaps in a multiple line title. variable right gaps in a multiple line title

The way I would like, (done by hand, known text)

the way I would like, (done by hand, known text)

    \documentclass{article}

    \RequirePackage{xcolor}
    \RequirePackage{xstring}

    %% scrapping sidebearing both L & R

    \newcommand\shaveLR[1]{% 
        \if\relax\detokenize{#1}\relax\else% check  empty
        \StrLeft{#1}{1}[\tempi]%    the first char
        \StrRight{#1}{1}[\tempii]%  the last char
        \kern-\XeTeXglyphbounds1 \the\XeTeXcharglyph\expandafter`\tempi% first char L un-kernig
        #1%  input string
        \kern-\XeTeXglyphbounds3 \the\XeTeXcharglyph\expandafter`\tempii% last char R un-kernig
        \fi}

        \newcommand{\hairlineiv}[1][green]{% 
        \leavevmode%
        \kern-0.1pt %
        \smash{\color{#1}\vrule height 4\baselineskip depth 5pt width 0.1pt}%
        \kern-0.1pt}

        \newcommand{\hairlinei}[1][red]{% 
        \leavevmode\kern-0.1pt %
        \smash{\color{#1}\vrule height 35pt depth 15pt width 0.1pt}%
        \kern-0.1pt}

    \newcommand{\byauthor}{}
    \newcommand{\longtitles}{}

    \begin{document}  
    \pagestyle{empty}   

    \renewcommand{\byauthor}{Your Name} % put your name here
    \renewcommand{\longtitles}{Long titles must be exactly align with the vertical green bar.}% the main title

    %%%% examples
    \newcommand{\thislongtitleR}{%
    \shaveLR{Long titles must be}\\%
    \shaveLR{exactly align with}\\%
    \shaveLR{the vertical green}\\%
    \shaveLR{bar.}}


    \Large \flushright
    Note the gap between\\ the red line and the 'e'.

    \vspace{\baselineskip}
    {\sffamily\fontsize{60}{60}\selectfont
     by \byauthor\hairlinei}
    \vspace{\baselineskip}

    No gap here after\\ zeroing the kern.

    \vspace{1\baselineskip}
    {\sffamily\fontsize{60}{60}\selectfont
        by \shaveLR{\byauthor}\hairlinei}
    \vspace{2\baselineskip}


    \newpage
    \Large \flushright The way it is:
    \vspace{1\baselineskip}
    \begin{minipage}{1.3\textwidth}
    \raggedleft\sffamily\fontsize{50}{60}\selectfont\bfseries \longtitles\hairlineiv\par
    \end{minipage}

    \vspace{2\baselineskip}
    \Large \flushright The way it should be:
    \vspace{1\baselineskip}

    \begin{minipage}{1.3\textwidth}
        \raggedleft\sffamily\fontsize{50}{60}\selectfont\bfseries \thislongtitleR\hairlineiv
    \end{minipage}

    \end{document}
  • 1
    Perhaps talk directly to the maintainers of xcoffins? They are after all the ones to implement your suggestions... – remco Apr 17 '18 at 18:52
  • 2
    github.com/latex3/latex3 or more precisely github.com/latex3/latex3/tree/master/l3experimental maybe open there a feature request issue? – user4686 Apr 17 '18 at 19:02
  • 1
    Please report feature requests or bug reports directly to the package authors. This is a question & answer side and your post does not fit into this scheme. – Martin Scharrer Apr 18 '18 at 11:21
  • isn't this more of an issue for microtype than xcoffins? to specify protrusion for the relevant characters to get better optical alignment at the margins? – David Carlisle Apr 18 '18 at 12:07
  • 1
    @MartinScharrer I fail to see why this is off topic, it is asking how to optically align text at the margins after linebreaking. The suggestion that it's xcoffins that does that is secondary. – David Carlisle Apr 18 '18 at 12:54
3

A LuaTeX solution:

In LuaTeX, you can use the post_linebreak_filter to intercept the broken lines and add some offsets. The sidebearings can be extracted from rawdata saved by luaotfload. After adding the offsets, the hboxes have to be repacked to determine the new glue settings.

To apply this to every vertical box in your document, add in your preamble

\usepackage{luacode}
\begin{luacode*}
  local function drop_sidebearing(head, groupcode)
    for n in node.traverse_id(node.id'hlist', head) do
      local char = node.has_glyph(n.head)
      if char then
        local f = font.getfont(char.font)
        if f.shared then
          local off = f.shared.rawdata.descriptions[char.char].boundingbox[1]*f.size/1000
          char.xadvance = char.xadvance - off
          char.xoffset = char.xoffset - off
        end
      end
      for ch in node.traverse_id(node.id'glyph', n.head) do
        char = ch
      end
      if char then
        local f = font.getfont(char.font)
        if f.shared then
          local desc = f.shared.rawdata.descriptions[char.char]
          char.xadvance = char.xadvance - (desc.width-desc.boundingbox[3])*f.size/1000
        end
      end
      local new_list = node.hpack(n.head, n.width, 'exactly')
      new_list.head = nil
      n.glue_order = new_list.glue_order 
      n.glue_set = new_list.glue_set
      n.glue_sign = new_list.glue_sign 
      node.free(new_list)
    end
    return true
  end
  luatexbase.add_to_callback('post_linebreak_filter', drop_sidebearing, 'Drop sidebearings after linebreaking')
\end{luacode*}

EDIT: The same code integrated into the original example with an added parameter \dropsidebearings. The code will only have an effect if \dropsidebearings is not 0 at the end of the paragraph.

\documentclass{article}

\RequirePackage{xcolor}
\RequirePackage{xstring}

\usepackage{luacode}
\newcount\dropsidebearings
\begin{luacode*}
  local function drop_sidebearing(head, groupcode)
    if tex.count['dropsidebearings'] == 0 then
      return true
    end
    for n in node.traverse_id(node.id'hlist', head) do
      local char = node.has_glyph(n.head)
      if char then
        local f = font.getfont(char.font)
        if f.shared then
          local off = f.shared.rawdata.descriptions[char.char].boundingbox[1]*f.size/1000
          char.xadvance = char.xadvance - off
          char.xoffset = char.xoffset - off
        end
      end
      for ch in node.traverse_id(node.id'glyph', n.head) do
        char = ch
      end
      if char then
        local f = font.getfont(char.font)
        if f.shared then
          local desc = f.shared.rawdata.descriptions[char.char]
          char.xadvance = char.xadvance - (desc.width-desc.boundingbox[3])*f.size/1000
        end
      end
      local new_list = node.hpack(n.head, n.width, 'exactly')
      new_list.head = nil
      n.glue_order = new_list.glue_order 
      n.glue_set = new_list.glue_set
      n.glue_sign = new_list.glue_sign 
      node.free(new_list)
    end
    return true
  end
  luatexbase.add_to_callback('post_linebreak_filter', drop_sidebearing, 'Drop sidebearings after linebreaking')
\end{luacode*}

\newcommand{\hairlineiv}[1][green]{% 
  \leavevmode%
  \kern-0.1pt %
  \smash{\color{#1}\vrule height 4\baselineskip depth 5pt width 0.1pt}%
  \kern-0.1pt
}

\newcommand{\hairlinei}[1][red]{% 
  \leavevmode\kern-0.1pt %
  \smash{\color{#1}\vrule height 35pt depth 15pt width 0.1pt}%
  \kern-0.1pt
}

\begin{document}  
\pagestyle{empty}   

\newcommand{\byauthor}{Your Name} % put your name here
\newcommand{\longtitles}{Long titles must be exactly align with the vertical green bar.}% the main title

\Large \flushright
Note the gap between\\ the red line and the 'e'.
\protrudechars=1

\vspace{\baselineskip}
{\sffamily\fontsize{60}{60}\selectfont
 by \byauthor\hairlinei}
\vspace{\baselineskip}

No gap here after\\ zeroing the kern.

\vspace{1\baselineskip}
{\sffamily\fontsize{60}{60}\selectfont
    \dropsidebearings=1
    by \byauthor\hairlinei\par}
\vspace{2\baselineskip}


\newpage
\Large \flushright The way it is:
\vspace{1\baselineskip}
\begin{minipage}{1.3\textwidth}
  \raggedleft\sffamily\fontsize{50}{60}\selectfont\bfseries \longtitles\hairlineiv\par
\end{minipage}

\vspace{2\baselineskip}
\Large \flushright The way it should be:
\vspace{1\baselineskip}

\begin{minipage}{1.3\textwidth}
  \dropsidebearings=1
  \raggedleft\sffamily\fontsize{50}{60}\selectfont\bfseries \longtitles\hairlineiv
\end{minipage}

\end{document}
  • It certainly works with LuaTex! Thank you Marcel. Now we only have to conquer XeLatex! Or move myself to LuaTex. I will mark your answer as satisfactory as soon as I check that it is possible to recompile safely some of my real life files. – Simon Dispa Apr 19 '18 at 19:46
  • (I can not claim that I understand how the invocation works.) – Simon Dispa Apr 19 '18 at 19:52
  • @ Marcel Krüger Thank you very much. So far everything works fine. While I start learning lua: the routine operates over the whole document (flawless). So you get right and left optical alignment on, perhaps, parts you might what to leave untouched. Is it possible to start and stop it, from an external switch? I know this question is beyond the scope of the original. – Simon Dispa Apr 20 '18 at 18:44
  • @SimonDispa I added an edit with a parameter to control this on a per paragraph level. – Marcel Krüger Apr 20 '18 at 20:28
  • @ Marcel Krüger Thank you again!. Just what I wanted. Perhaps you would like to comment on this solution. I found several question on sidebearing and/or side-bearing with LuaTeX as a limitation to jump to LuaTeX. (I am not allow to comment because I have not earn enough points.) tex.stackexchange.com/questions/45549/…. – Simon Dispa Apr 20 '18 at 21:34

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.