summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex')
-rw-r--r--Master/texmf-dist/tex/generic/letterspacing/letterspacing.tex319
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