When I'm writing a macro, I'm first thinking about user interface.
For your purpose, we suggest the macro \Capinsert which will be used before
paragraph:
\Capinsert First letter is scaled, this means F in this case.
User may insert a optional left material. We can use \optdef mentioned in
OPmac trick 0067 but the optional parameter is separated by brackets [] and
user can write \thefontscale[...] here (for example) and the brackets []
are not able to be nested. Thus, user can be confused. This is the reason
why I suggest to use {} as an optional parameter. For example:
\Capinsert {material llaped to the left} First letter is scaled ...
This decision needs little more macro programming:
\def\Capinsert{\def\leftCapmaterial{}\futurelet\next\CapinsertA}
\def\CapinsertA{\ifx\next\bgroup \expandafter\CapinsertB \else \expandafter\CapinsertC \fi}
\def\CapinsertB #1{\def\leftCapmaterial{#1}\CapinsertC}
\def\CapinsertC #1{...
\Capinsert checks by \futurelet if there is an open brace \bgroup. If
this is true, the \CapinsertB scans the optional parameter and saves it to
\leftCapmaterial macro. Else \CapinsertC is processed where the core of
the macro is realised.
Now, we suggest the way of data declaration. It may looks like:
\newdimen\ptem \ptem=.1em
\newdimen\Capsize \Capsize=44\ptem
\newdimen\Capabove \Capabove=8\ptem
\declCap {default} {0;0,0,0}
\declCap A {1;6,2,-2}
...
\declCap W {3;0,4,6}
...
First, the \ptem is declared here. It is 1pt when 10pt font is used. But
if user declares \typosise[12/14] before the data declaration (for example) and whole
document is scaled, then the unit used for letter correction is scaled too.
This is desired behavior. The \ptem means "pt unit dependent on em".
The \Capsize declares the size of the scaled letters. And \Capabove
declares the amount of raising scaled letters above the first baseline of
the paragraph. If it it zero then top of scaled letter is equal to the
first baseline.
The data about letters are declared in the way:
\declCap <letter> {protrude left; first line left, second line left, etc.}
The {default} data is used when the letter hasn't its own declaration. The
comma separated list can include arbitrary number of numbers. The corresponding number
of lines in the paragraph will be shifted. The numbers can include decimal
point, can be negative and they are expressed in \ptem units.
The macro code follows. The \declCap only saves data to the macro
with the name \cap:=<letter>. The \sxdef from OPmac is used here:
\def\declCap #1#2{\sxdef{cap:=#1}{#2}}
The \CapinsertC reads the letter to be scaled as #1 and does following:
\def\CapinsertC #1{\par
\isdefined{cap:=#1}\iftrue \edef\tmp{\csname cap:=#1\endcsname}%
\else \edef\tmp{\csname cap:=default\endcsname}\fi
\setbox0=\hbox{{\thefontsize[\expandafter\ignorept\the\Capsize]#1}}%
\expandafter \CapinsertD \tmp,,%
\noindent\kern-\firstlineindent
\rlap{\kern-\protrudeCap\ptem\llap{\leftCapmaterial}%
\vbox to0pt{\kern-\Capabove\box0\vss}}%
\kern\firstlineindent
}
The \tmp includes declared data or default. The \box0 includes the scaled
letter. The \thefontsize parameter needs the dimen without pt. So,
the \ignorept macro from OPmac removes the pt letters expanded by
\the primitive. The \Capinsert is executed followed by data and by two
commas. It prepares and executes \parshape primitive and saves the
indentation of the first line to the \firstlineindent.
The \noindent starts indented by \firslineindent. So, wee need to return
back by negative kern, to do \rlap{scaled letter} and to return
by \kern\firstindent. The scaled letter is realized by
\kern-\protrudeCap\ptem \llap{left material}\vbox{shifted \box0}
The last thing is to scan data prepared by the form
\CapinsertD protrude left; first line left, second line left, ... ,,%
This is done by:
\def\CapinsertD #1;{\tmpnum=1 \let\firstlineindent=\undefined
\def\parshapeparams{}\def\protrudeCap{#1}\CapinsertE}
\def\CapinsertE #1,{\ifx,#1,\parshape =\tmpnum \parshapeparams 0pt \hsize
\else
\advance\tmpnum by1
\tmpdim=\wd0 \advance\tmpdim by-#1\ptem \advance\tmpdim by-\protrudeCap\ptem
\edef\parshapeparams{\parshapeparams\the\tmpdim}%
\ifx\firstlineindent\undefined \let\firstlineindent\parshapeparams \fi
\advance\tmpdim by-\hsize \tmpdim=-\tmpdim
\edef\parshapeparams{\parshapeparams\the\tmpdim}%
\expandafter \CapinsertE \fi
}
First, \CapinsertD reads protrude left, save it to \protrudeCap. The
initial values of \tmpnum, \firstlineindent, \parshapeparams are set
here. The \CapinsertE reads line indentations in the loop. The loop ends
when #1 is empty, i. e. between the last two commas appended to the data.
The \tmpnum counts number of indented lines plus 1. The indentation is
calculated by \wd0 minus data-item minus protrude. The result is added
to the \parshapeparams. Next, the line width is calculated as \hsize
minus indentation and added to the parshapeparams too. When the loop ends,
we have \parshapeparams ready for \parshape primitive. Only \tmpnum is
prepended and 0pt \hsize is appended (this declares normal line).
Finally, the working example is here:
\input opmac
\input cs-schola
%\typosize[12/15]
%% macros
\def\declCap #1#2{\sxdef{cap:=#1}{#2}}
\def\Capinsert{\def\leftCapmaterial{}\futurelet\next\CapinsertA}
\def\CapinsertA{\ifx\next\bgroup \expandafter\CapinsertB \else \expandafter\CapinsertC \fi}
\def\CapinsertB #1{\def\leftCapmaterial{#1}\CapinsertC}
\def\CapinsertC #1{\par
\isdefined{cap:=#1}\iftrue \edef\tmp{\csname cap:=#1\endcsname}%
\else \edef\tmp{\csname cap:=default\endcsname}\fi
\setbox0=\hbox{{\thefontsize[\expandafter\ignorept\the\Capsize]\Capprefix#1}\kern\Capafter}%
\expandafter \CapinsertD \tmp,,%
\noindent\kern-\firstlineindent
\rlap{\kern-\protrudeCap\ptem\llap{\leftCapmaterial}%
\vbox to0pt{\kern-\Capabove\box0\vss}}%
\kern\firstlineindent
}
\def\CapinsertD #1;{\tmpnum=1 \let\firstlineindent=\undefined
\def\parshapeparams{}\def\protrudeCap{#1}\CapinsertE}
\def\CapinsertE #1,{\ifx,#1,\parshape =\tmpnum \parshapeparams 0pt \hsize
\else
\advance\tmpnum by1
\tmpdim=\wd0 \advance\tmpdim by-#1\ptem \advance\tmpdim by-\protrudeCap\ptem
\edef\parshapeparams{\parshapeparams\the\tmpdim}%
\ifx\firstlineindent\undefined \let\firstlineindent\parshapeparams \fi
\advance\tmpdim by-\hsize \tmpdim=-\tmpdim
\edef\parshapeparams{\parshapeparams\the\tmpdim}%
\expandafter \CapinsertE \fi
}
\def\hboxshift#1#2{\vbox to0pt{\vss\hbox{#2}\kern-#1}}
%% data declarations:
\newdimen\ptem \ptem=.1em
\newdimen\Capsize \Capsize=44\ptem
\newdimen\Capabove \Capabove=8\ptem
\newdimen\Capafter \Capafter=1\ptem
\def\Capprefix{\localcolor\Red}
\declCap {default} {0;0,0,0}
\declCap W {3;0,4,6}
\declCap A {1;6,2,-2}
\declCap L {0;9,0,0}
% \declCap B ... etc.
%% document:
\Capinsert {\thefontscale[\magstep3]\localcolor\Grey\hboxshift{4pt}{``}\kern.1em}
W{\caps\rm e're here,''}
Mother called out, waking me from my nap on the back seat of the car. When
you're a kid who can get carsick just being driven around the block, you
learn to sleep as much as possible on long motor trips. This one was
{\caps\rm 139} curvy miles. Our {\caps\rm 1928} black Buick sedan crunched
up the gravel driveway to the {\em cottage}. Well, that's what summer homes
were called then, even large ones like the Schuneman's. We were in {\em
Eagles~Mere,} a Victorian village in the Pocono Mountains of Pennsylvania
$\ldots$
\Capinsert Another example is here.
Mother called out, waking me from my nap on the back seat of the car. When
you're a kid who can get carsick just being driven around the block, you
learn to sleep as much as possible on long motor trips. This one was
{\caps\rm 139} curvy miles. Our {\caps\rm 1928} black Buick sedan crunched
up the gravel driveway to the {\em cottage}. Well, that's what summer homes
were called then, even large ones like the Schuneman's. We were in {\em
Eagles~Mere,} a Victorian village in the Pocono Mountains of Pennsylvania
$\ldots$
\Capinsert Lettrine package does something similar.
Mother called out, waking me from my nap on the back seat of the car. When
you're a kid who can get carsick just being driven around the block, you
learn to sleep as much as possible on long motor trips. This one was
{\caps\rm 139} curvy miles. Our {\caps\rm 1928} black Buick sedan crunched
up the gravel driveway to the {\em cottage}. Well, that's what summer homes
were called then, even large ones like the Schuneman's. We were in {\em
Eagles~Mere,} a Victorian village in the Pocono Mountains of Pennsylvania
$\ldots$
\bye
Edit: I've added global parameters \Capafter, \Capprefix and the following picture:

\parshapefor each and every letter in the alphabet(s). I think I remember seeing some talk about LuaTeX being able to figure out the shape of a letter, so I guess that could be used, too. – morbusg Jun 26 '14 at 08:59\parshapewould be needed for each letter of the alphabet. it's worse than that -- a different\parshapewould be needed for every letter times however many different depths (number of lines) are to be involved with the drop cap. i also wonder about using "L" as a "shaped" drop cap ... – barbara beeton Jun 26 '14 at 13:24