diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/letterspacing')
-rw-r--r-- | Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex b/Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex new file mode 100644 index 00000000000..488c46196b0 --- /dev/null +++ b/Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex @@ -0,0 +1,319 @@ +% Self-documenting file + +\ifx \Comment \Undefined + \long \def \Comment #1\EndComment {} +\else + \ifx \EndComment \Undefined + \def \EndComment + {\message {Error: \noexpand \EndComment encountered + without preceding \noexpand \Comment}} + \else %%% both defined; let's hope they're the right definitions! + \fi +\fi + +\Comment +This file, "letterspacing.tex", created by Philip Taylor of +Royal Holloway, University of London (P.Taylor@Rhul.Ac.Uk) for +Kaveh Bazargan of Focal Image (Kaveh@Focal.Demon.Co.Uk) may be +freely distributed provided that the following licence conditions +are honoured : +\EndComment + +\Comment % The Licence + Unlimited copying and redistribution of this file + is permitted so long as the file is not modified + in any way. + + Modifications may be made for private purposes (though + this is discouraged, as it could result in documents + typesetting differently on different systems) but if + such modifications are re-distributed, the modified + file must not be capable of being confused with the + original. In particular, this means + +(a) the filename (the portion before the extension, if any) + must not match any of : + + LETTERSPACE LETTER-SPACE + LETTERSPACING LETTER-SPACING + + regardless of case, and + +(b) the file must contain conditions identical to these, + except that the modifier/distributor may, if he or she + wishes, augment the list of proscribed filenames. +\EndComment + +\Comment +As far as is possible, `inaccessible' control sequences (i.e.~control sequences +containing one or more commercial-at$\,$s) are used to minimise the risk of +accidental collision with user-defined macros; however, the control sequences +used to access the natural dimensions of the text are required to be user +accessible, and therefore must contain only letters. +\EndComment + +%%% Open control sequences + +\newdimen \naturalwidth +\newdimen \naturaldepth +\newdimen \naturalheight + +\Comment +All control sequences defined hereafter are inaccessible to the casual user, +including the control sequence used to store the category code of commercial-at; +this catcode must be saved in order to be able to re-instate it at end of +module, as we have no idea in what context the module will be |\input|. Having +saved the catcode of commercial-at, we then change it to |11| (i.e.~that of a +letter) in order to allow it to be used in the cs-names which follow. +\EndComment + +%%% Concealed control sequences + +\expandafter \chardef + \csname \string @code\endcsname = + \the \catcode `\@ +\catcode `\@ = 11 + +\Comment +We will need a a box register in order to measure the natural dimensions of +the text, and a token-list register in which to save the tokens to be +letter-spaced. +\EndComment + +\newbox \l@tterspacebox +\newtoks \l@tterspacetoks + +\Comment +We will need to test whether a particular macro expands to a space, so we will +need another macro which does so expand with which to compare it; we will +also need a `more infinite' variant of |\hss|. +\EndComment + +\def \sp@ce { } +\def \hsss + {\hskip 0 pt plus 1 fill minus 1 fill\relax} + +\Comment +Many of the macros will used delimited parameter structures, typically +terminated by the reserved control sequence |\@nd|; we make this a synonym +for the empty macro (which expands to nothing), so that should it accidentally +get expanded there will be no side effects. We also define a brief synonym +for |\expandafter|, just to keep the individual lines of code reasonably short. +\EndComment + +\let \@nd = \empty +\let \@x = \expandafter + +\Comment +We will also need to compare a token which has been peeked at by |\futurelet| +with a space token; because of the difficulty of accessing such a space +token (which would usually be absorbed by a preceding control word), we +establish |\sp@cetoken| as a synonym. The code to achieve this is messy, +because of the very difficulty just outlined, and so we `waste' a control +sequence |\t@mp|; we then return this to the pool of undefined tokens. +\EndComment + +\let \sp@cetoken = \relax +\edef \t@mp {\let \sp@cetoken = \sp@ce} +\t@mp \let \t@mp = \undefined + +\Comment +The user-level macro |\letterspace| has exactly the same syntax as that for +|\hbox| and |\vbox|, as explained in the introduction; the delimited parameter +structure for this macro ensures that everything up to the open brace which +delimits the beginning of the text to be letter-spaced is absorbed as parameter +to the macro, and the brace-delimited text which follows is then assigned to the +token-list register |\l@tterspacetoks|; |\afterassignment| is used to regain +control once the assignment is complete. +\EndComment + +%%% Primary (user-level) macro + +\def \letterspace #1#% + {\def \hb@xmodifier {#1}% + \afterassignment \l@tterspace + \l@tterspacetoks = + } + +\Comment +Control then passes to |\l@tterspace|, which starts by setting an |\hbox| +containing the text to be typeset; the dimensions of this box (and therefore +of the text) are then saved in the open control sequences previously declared, +and the |\hbox| becomes of no further interest. + +A new |\hbox| is now created, in which the same text, but this time +letter-spaced, will be set; the box starts and ends with |\hss| glue so that if +only a single character is to be letter-spaced, it will be centered in the box. +If two or more characters are to be letter-spaced, they will be separated by +|\hsss| glue, previously declared, which by virtue of its greater degree of +infinity will completely override the |\hss| glue at the beginning and end; +thus the first and last characters will be set flush with the edges of the box. + +The actual mechanism by which letter-spacing takes place is not yet apparent, +but it will be seen that it is crucially dependent on the definition of +|\l@tt@rspace|, which is expanded as the box is being set; the |\@x| +(|\expandafter|) causes the actual tokens stored in |\l@tterspacetoks| to be +made available as parameter to |\l@tt@rspace| rather than the token-list +register itself, as it is these tokens on which |\l@tt@rspace| will operate. +The |\@nd| terminates the parameter list, and the |{}| which immediately +precedes it ensures that that there is always a null element at the end of the +list: without this, the braces which are needed to protect an accent/character +pair would be lost if such a pair formed the final element of the list, at the +point where they are passed as the second (delimited) parameter to |\p@rtiti@n|; +by definition, <TeX> removes the outermost pair of braces from both simple and +delimited parameters during parameter substitution if such braces form the first +and last tokens of the parameter, and thus if a brace-delimited group ever +becomes the second element of a two-element list, the braces will be irrevocably +lost. The |{}| ensure that such a situation can never occur. +\EndComment + +%%% Secondary (implementation-level) macro + +\def \l@tterspace + {\setbox \l@tterspacebox = \hbox + {\the \l@tterspacetoks}% + \naturalwidth = \wd \l@tterspacebox + \naturaldepth = \dp \l@tterspacebox + \naturalheight = \ht \l@tterspacebox + \hbox \hb@xmodifier + \bgroup + \hss + \@x \l@tt@rspace + \the \l@tterspacetoks {}\@nd + \hss + \egroup + } + +\Comment +The next macro is |\l@tt@rspace|, which forms the crux of the entire operation. +The text to be letter-spaced is passed as parameter to this macro, and the +first step is to check whether there is, in fact, any such text; this is +necessary both to cope with pathological usage (e.g.~|\letterspace {}|), and to +provide an exit route, as the macro uses tail-recursion to apply itself +iteratively to the `tail' of the text to be letter-spaced; when no elements +remain, the macro must exit. + +Once the presence of text has been ensured, the token-list representing +this text is partitioned into a head (the first element), and the tail +(the remainder); at each iteration, only the head is considered, although +if the tail is empty (i.e.~the end of the list has been reached), special +action is taken. + +If the first element is a space, it is treated specially by surrounding it +with two globs of |\hsss| glue, to provide extra stretchability when compared +to the single glob of |\hsss| glue which will separate consecutive non-space +tokens; otherwise, the element itself is yielded, followed by a single glob +of |\hsss| glue. This glue is suppressed if the element is the last of the +list, to ensure that the last token aligns with the edge of the box. + +When the first element has been dealt with, the macro uses tail +recursion to apply itself to the remaining elements (i.e.~to the tail); +|\@x| (|\expandafter|) is again used to ensure that the tail is expanded +into its component tokens before being passed as parameter. +\EndComment + +%%% Tertiary (implementation-level) macro + +\def \l@tt@rspace #1\@nd + {\ifx \@nd #1\@nd + \let \n@xt = \relax + \else + \p@rtition #1\@nd + \ifx \h@ad \sp@ce \hsss \h@ad \hsss + \else + \h@ad + \ifx \t@il \@nd \else \hsss \fi + \fi + \@x \def \@x \n@xt \@x + {\@x \l@tt@rspace \t@il \@nd}% + \fi + \n@xt + } + +\Comment +The operation of token-list partitioning is conceptually simple: one passes the +token list as parameter text to a macro defined to take two parameters, the +first simple and the second delimited; the first element of the list will be +split off as parameter-1, and the remaining material passed as parameter-2. +Unfortunately this na\"\i ve approach fails when the first element is a bare +space, as the semantics of <TeX> prevent such a space from ever being passed as +a simple parameter (it could be passed as a delimited parameter, but as one +does not know what token follows the space, defining an appropriate delimiter +structure would be tricky if not impossible). The technique used here relies +upon the adjunct macro |\m@kespacexplicit|, which replaces a leading bare space +by a space protected by braces; such spaces may legitimately be passed as simple +parameters. Once that operation has been completed, the re-constructed token +list is passed to |\p@rtiti@n|, which actually performs the partitioning as +above; again |\@x| (|\expandafter|) is used to expand |\b@dy| (the +re-constructed token list) into its component elements before being passed as +parameter text. +\EndComment + +%%% Adjunct macros -- list partitioning + +\def \p@rtition #1\@nd + {\m@kespacexplicit #1\@nd + \@x \p@rtiti@n \b@dy \@nd + } + +\def \p@rtiti@n #1#2\@nd + {\def \h@ad {#1}% + \def \t@il {#2}% + } + +\Comment +The operation of making a space explicit relies on prescience: the code needs +to know what token starts the token list before it knows how to proceed. +Prescience in <TeX> is usually accomplished by |\futurelet|, and this code +is no exception: |\futurelet| here causes |\h@ad| to be |\let| equal to +the leading token, and control is then ceded to |\m@kesp@cexplicit|. + +The latter compares |\h@ad| with |\sp@cetoken| (remember the convolutions we +had to go through to get |\sp@cetoken| correctly defined in the first place), +and if they match (i.e.~if the leading token is a space), then |\b@dy| +(the control sequence through which the results of this operation will +be returned) is defined to expand to a protected space (a space surrounded by +braces), followed by the remainder of the elements; if they do not match +(i.e.~if the leading token is \stress {not} a space), then |\b@dy| is simply +defined to be the original token list, unmodified. If the leading token +\stress {was} a space, it must be replaced by a protected space: this is +accomplished by |\pr@tectspace|. + +The |\pr@tectspace| macro uses a delimited parameter structure, as do most +of the other macros in this suite, but the structure used here is unique, +in that the initial delimiter is a space. Thus, when a token-list starting +with a space is passed as parameter text, that space is regarded as matching +the space in the delimiter structure and removed; the expansion of the macro +is therefore the tokens remaining once the leading space has been removed, +preceded by a protected space |{ }|. +\EndComment + +%%% Adjunct macros -- <space>... -> {<space>}... + +\def \m@kespacexplicit #1\@nd + {\futurelet \h@ad \m@kesp@cexplicit #1\@nd} + +\def \m@kesp@cexplicit #1\@nd + {\ifx \h@ad \sp@cetoken + \@x \def \@x \b@dy + \@x {\pr@tectspace #1\@nd}% + \else + \def \b@dy {#1}% + \fi + }% + +\@x \def \@x \pr@tectspace \sp@ce #1\@nd {{ }#1} + +\Comment +The final step is to re-instate the category code of commercial-at. +\EndComment + +%%% re-instate category code of commercial-at + +\catcode `\@ = \the \@code + +\Comment +Thus letter-spacing is accomplished. The author hopes both that the code will +be found useful and that the explanation which accompanies it will be found +informative and interesting. +\EndComment |