10

Someone gives me a box, and my goal is to know as much as possible about the amount of glue inside that box. I can assume that the box is not huge, but it may contain arbitrary stuff (so I cannot deconstruct the box using \unskip and friends).

For definiteness, say that the box \mybox was defined with \newbox\mybox then constructed using \setbox\mybox\hbox to 50pt{a b c}. To get the natural width of the box's contents, I can do \setbox0\hbox{\unhcopy\mybox}\showthe\wd0 (and I'll get 21.66669pt).

To know if the box contains infinite stretch I can typeset it inside a box of width \maxdimen and check for the badness (well, that's not entirely fool-proof, but should be ok), and similarly for infinite shrink.

What I'd be interested in is to know the stretch or shrink in the finite case. My feeling is that it should be possible to extract that by checking the \badness after \setbox0\hbox spread \somedim{\unhcopy\mybox} with various \somedim. Is this correct? Is there a more efficient approach?

  • 1
    You know s>0 (spread) and b<10000 (badness) and you need to calculate f (total stretch in the box). This can be done by f = root 3 of {100 s^3 \over b}. I mean that you are specialist for such type of calculations in TeX... – wipet Jul 12 '14 at 5:12
  • 1
    I suppose using \showbox and reading a copy of the log (with TeX) is cheating? – David Carlisle Jul 12 '14 at 7:29
  • @DavidCarlisle Given the goal, which would be to have a more clever method for math layout (where e.g., subscripts do not have to take their natural width), yes, reading the log is cheating. – Bruno Le Floch Jul 15 '14 at 12:43
2

Short answer: one can find the natural width of the box, the exact amount of stretch if it is finite (otherwise one can only say "it's infinite"), and similarly the exact amount of shrink if it is finite.

Let us assume for definiteness that \mybox is a horizontal box such as

\newbox\mybox
\setbox\mybox\hbox spread 5pt{Some text perhaps.}

To find its natural width, do \setbox0\hbox{\unhcopy\mybox}: then the answer is the width \wd0 of box 0.

We can only probe the amount of glue stretch or shrink by setting the box with a width different from its natural width, and testing the \badness. Setting the box to a width larger than its natural width probes the stretch component, and setting it to a width smaller than its natural width probes the shrink component. In both cases, if the corresponding component (stretch for larger widths, shrink for smaller widths) is infinite then the \badness will be zero, telling us nothing about the value or sign of that infinite component. I see no other way to probe such infinite values, so let's focus on the finite case.

The general formula for the badness is quite complicated: it involves in some cases the combination 100(t/s)^3 where t is the difference between the natural width of the box and the width that was asked for, and s is the amount of stretch (or shrink, if the box was squeezed). Fortunately, we can go by with only a very simple case. Our basic construction for testing the amount of stretch is \setbox0\hbox spread 1sp{\unhcopy\mybox\hskip 0pt plus -\stest} where \stest is a dimension that we will vary. The amount of stretch in this box is the amount in \mybox, minus \stest. If that is positive, then the box can stretch, and the \badness is not too big (as it turns out, 100 or less). Otherwise, the box is underfull, as it cannot stretch even by 1sp, and the \badness is 10000 (when testing the shrink, we get overfull boxes with a \badness of 1000000). We thus have a simple way to test whether the amount of stretch in \mybox is >\stest or <=\stest for any dimension \stest. The task is thus reduced to a dichotomy.

\hbadness=1000000
\hfuzz=\maxdimen
\newdimen\stest
\newdimen\smin
\newdimen\smax
\def\find#1#2#3{%
  \smin = -\maxdimen
  \smax = \maxdimen
  \loop
    \stest = \smin
    \advance \stest by \smax
    \divide \stest by 2 % now \stest=(\smin+\smax)/2 truncated to 0
    \ifdim \stest = \smax
      \advance \stest by -1sp % ensure that \smin<=\stest<\smax.
    \fi
    \setbox 0 = \hbox spread #2 1sp {%
      \unhcopy\mybox
      \hskip 0pt #3-\stest
    }%
    \ifnum \badness > 100 % (shrink/stretch in \mybox) <= \stest
      \smax = \stest
    \else
      \smin = \stest
      \advance \smin by 1sp
      % since ">\stest" implies ">=\stest+1sp"
    \fi
    % In both cases, the interval [\smin,\smax] becomes smaller.
  \ifdim\smin<\smax
  \repeat
  \ifdim\smin>\smax\BOOM\fi% cannot happen, I think
  \message{^^JThe #1 is
    \ifdim\smin=\maxdimen infinite\else\the\smin\fi.}% (\smin=\smax)
}
\setbox0\hbox{\unhcopy\mybox}
\message{^^JThe natural width is \the\wd0 .}
\find{stretch}{}{plus}
\find{shrink}{-}{minus}

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.