******************************************************************
*                                                                *
*                                                                *
*          Title : Font downloading to PostScript printers       *
*                                                                *
*         Author : Neil Raine                                    *
*                                                                *
*           Date : 3-Apr-90                                      *
*                                                                *
*        Version : 1.00                                          *
*                                                                *
*  Change Record : 20-Mar-90    Initial draft                    *
*                  23-Mar-90    Reorganised into three sections  *
*                   3-Apr-90    Comment about user fonts added   *
*                                                                *
*                                                                *
******************************************************************

Font downloading to PostScript printers
=======================================

The original fonts provided with RISC OS were specifically chosen to
correspond with the fonts on the Adobe LaserWriter, so that when printing to
a PostScript printer, the built-in fonts could be used directly, and no
actual font downloading was necessary.

Since then various third parties have constructed new fonts, that are not
present on the LaserWriter, and so it has become necessary to download
fonts.

By using the Adobe internal font format (recently published in the so-called
'black book'), it will be possible to download fonts more efficiently than
at present, and it may also be possible to preserve hinting information.

There are two main ways of downloading font information to a PostScript
printer - one is to download a copy of the font with each print job that
uses it, and another is to download a single copy of each font, so that it
remains resident in the printer for all subsequent print jobs.

Both methods have their drawbacks - the first involves a lot of data
transfer, as each job must download the fonts it needs, while the second
consumes large amounts of memory in the printer, especially if there is a
large variety of fonts to be downloaded.

I believe that we should support both methods, as they are each suitable for
certain scenarios (the first when there are a lot of print jobs using
'special' fonts, and the second where a manual is being printed in separate
sections, all of which use the same font which is not resident by default.

This will involve certain changes to the application printing interface,
since it is necessary (due to the Adobe print job Structuring Conventions)
to declare all fonts to be used before any pages are printed.

In addition, if the printer driver is to automatically download fonts within
print jobs, it must be made aware of which fonts have already been
permanently downloaded into the printer, so it can ignore them.  This could
be done by user intervention on the client machine, but is better done by
interrogating the printer server.

I propose that the work in this area be executed in three stages, where the
output of each stage could be used as a stepping-off point, but where each
stage constitutes a significant advance over the previous one:


Stage 1
-------

!PrinterPS includes an option to allow the user to download a font to the
printer (which can then be used by all subsequent print jobs).  If the
printer has a non-zero 'exitserver' password, the user would have to enter
it.  This prevents unauthorised users from clogging-up shared printers with
fonts.

Note that the user is responsible for explicitly downloading any fonts that
will be required by a subsequent print job - no automatic checking is done.


Stage 2
-------

As well as the explicit permanent downloading of fonts, applications can be
improved to declare the fonts they are going to use to the printer driver
module.  If any fonts in the current print job are not already loaded in the
printer, the printer driver dynamically converts the relevant fonts to
PostScript, and downloads them within the job.  The fonts cannot be used by
subsequent print jobs, and the memory they occupy in the printer will be
freed as soon as the job finishes.

The printer driver needs to know:

    a) Which fonts have already been permanently downloaded
    b) Which fonts to download if the application does not declare any

Because not all applications will immediately be upgraded to declare the
fonts they will use, it is necessary to allow the user to specify this
explicitly in some cases.  Normally the list of fonts to download will be
limited to those fonts that can simply be mapped directly onto existing
PostScript fonts (eg. Trinity.Medium maps onto Times-Roman).

The list of permanently downloaded fonts can be automatically updated if a
new font is permanently downloaded, but unfortunately this does not cope
with the printer being reset, or someone else downloading a font to the
printer from somewhere else on the network.


Stage 3
-------

In order to hide the issues of which fonts are already downloaded from the
naïve user, the printer driver will have to be able to find out which fonts
are already downloaded automatically.

The established method of finding this out is to send a 'query job' to the
printer, which is a PostScript job that causes no pages to be printed, but
send some output back to the sender (in this case a list of the permanently
downloaded fonts).

This can only happen if the printer is able to talk back to the client,
which is not always possible (eg. if the printer is off-site, and the job is
being printed to a file), so it will still be necessary for a user-supplied
default to be used.

When talking to a printer that is controlled by a spooler, another problem
arises - the printer might be busy printing another job.  To get round this,
the query job contains some 'structured comments', which allow the spooler
software to recognise it itself, and send back an appropriate reply if the
printer is busy.  The spooler can know which fonts are already downloaded
by recognising the structured comments that occur in font download jobs.


Work involved
-------------

The above is a relatively brief summary of the mechanisms that could be used
to achieve automatic font downloading to PostScript printers.

The following sections go through the mechanisms at a lower level of detail,
in an attempt to assess the amount of work involved.


Stage 1 in more detail
----------------------

We need a utility that can convert from the Risc OS file format to the Adobe
type 1 internal font format, and a front-end that allows the user to specify
the font(s) to download.

The front end would probably reside within !PrinterPS, since the destination
printer must be specified, which is already done within that program.

Most of the work for this stage is to write a convertor that takes a Risc OS
outline font and converts it to PostScript.  Adobe have recently published
their 'type 1' internal format, which includes hint information, so it may
be possible to convert our hint information too.  Further elaboration is
impossible without seeing the contents of the Adobe 'black book', detailing
the type 1 format.

Since some 'PostScript' printers may not understand the Adobe type 1 format,
we should also allow conversion to 'user' PostScript fonts, using only legal
PostScript constructs.  These fonts will be bigger, slower and will probably
lack hints, however.

Note that the output from the downloader would have to include the
exitserver password, entered by the user, and some structured comments as
defined by the Adobe Structuring Conventions.

This converter would initially be written in C.


Stage 2 in more detail
----------------------

The PDriverPS module provides a new SWI PDriver_DeclareFont that is capable
of converting from outline fonts to the equivalent Adobe type 1 format
PostScript.  This can be called by applications to declare the fonts that
are to be used within a job, and also by the permanent font downloader,
which passes in the exitserver password.

        SWI PDriver_DeclareFont
        In      R0 = print job handle (or handle of destination file)
                R1 -> font name (0 => no fonts in print job)
                R2 = exitserver password
                     or -1 => download within job
        Out     Adobe type 1 version of font sent to handle in R0

        If the R2 on entry is not -1, the SWI should be called outside the
        context of a print job, to permanently download the font.  The
        "exitserver password" is an integer that is required in order to
        execute the exitserver command in PostScript, which in turn allows
        the font to be retained for subsequent print jobs.

        If R2 = -1 on entry, the SWI should be called after
        PDriver_SelectJob and before the first PDriver_DrawPage, once for
        each font that will be used in the job.

        The printer driver looks in "PDriverPS:FontNames" to find out how to
        download a font.  The file would look something like this:

                Corpus.Medium           Courier                 Latin1
                Corpus.Medium.Oblique   Courier-Oblique         Latin1
                Corpus.Bold             Courier-Bold            Latin1
                Corpus.Bold.Oblique     Courier-BoldOblique     Latin1
                Selwyn                  ZapfDingbats            Selwyn
                Sidney                  Symbol                  Sidney
                Trinity.Medium          Times-Roman             Latin1
                Trinity.Medium.Italic   Times-Italic            Latin1
                Trinity.Bold            Times-Bold              Latin1
                Trinity.Bold.Italic     Times-BoldItalic        Latin1
                etc.

        All fonts that have a known PostScript equivalent that is resident
        in the default LaserWriter should be in here - when a font is to be
        downloaded within a job, PDriverPS looks in here to see if the
        mapping can be done by mapping onto an existing font.

        If the font name is found, then the file
        "PDriverPS:Encodings.<encoding>" is downloaded (unless it has
        already been done for this print job), and a small section of
        PostScript that creates (eg) a font called "Acorn-Trinity.Medium"
        that is like "Times-Roman" but with a new encoding.

        If the font name is not found, then the downloading must be done the
        hard way, by converting from the outlines to the Adobe type 1
        format.

        If R2 <> -1 on entry, then the whole lot is surrounded by an
        "exitserver" command, so that the results are made permanent.

A file of which fonts have been downloaded already should be associated with
each printer known to the system.  Each printer on the network has a name
that can be determined by sending a message to it.  NetPrint needs to be
extended to allow the printer name for a given file handle to be determined
(with a default name if this is not a NetPrint file).

PDriverPS then reads from "PDriverPS:Downloaded.<printername>", which
contains a list of fonts that should be treated as being already present in
the LaserWriter (so should be ignored if passed to PDriver_DeclareFont).

If no fonts are declared at the start of the print job, the printer driver
will look in the file "PDriverPS:Default" to see which fonts to download. 
Note that if a new-style application realises that there are no fonts in the
job to be printed, it should make a single call to PDriver_DeclareFont to
stop the printer driver module from downloading the default set.

The printer driver front end allows the user to select the set of fonts that
will be 'downloaded' if the application doesn't declare any fonts.  This is
written to the file "<PDriverPS$Dir>.Default", and read as
"PDriverPS:Default" by the printer driver module.

When a font is permanently downloaded, the file
"<PDriverPS$Dir>.Downloaded.<printername>" is updated so that the printer
driver knows not to download that font again when sending print jobs to that
printer.


Stage 3 in more detail
----------------------

In order for the PDriverPS module to interrogate the printer, it will have
to be able to find out where the current print job destination is, and send
a query job to it.  This causes several problems:

    *   The printer stream will have been opened for output only by the
        application, so it is not possible to simply use this stream to send
        the query job.

    *   The file handle given to the application will have been returned
        from opening "Printer:" for output, which is a filing system that
        sends its output to the printer via SWI OS_PrintChar.  This in turn
        sends it to the relevant file handle, if the printer type (*FX 5) is
        4 or more, or direct to the relevant buffer for types 1 and 2.  This
        means that the process of determining which is the correct input
        stream appropriate to the given output stream is rather grubby.

    *   NetPrint supports a "lazy connection" system via the "*SetPS"
        command, whereby a the printer name supplied is only searched for
        when the next print job is opened.  This means that if "NetPrint:"
        is opened again, a different printer may well be found (if there are
        several with the same name).

In fact these problems can be solved if we assume that the user can only set
the print destination using !PrinterPS, and that, for all types of output
except file printing, the file handle will have been obtained by opening
"Printer:" for output.

Given these assumptions all the printer driver has to do is spot the
following special cases:
                                          query job
        print job output        output stream   input stream
        ----------------        -------------   ------------

        parallel                "parallel:"     "serial:"
        serial                  "serial:"       "serial:"
        network                 "netprint:"     "netprint:"
        file                    <none>          <none>

Note that if the parallel port is being used for output, the serial port can
still be used to receive data from the PostScript printer.

In all cases where a query job might be sent, it is possible that the
printer might not be able to return any data (eg. if the serial port is not
connected), so the printer driver must be able to recognise this and revert
to the "default" set of fonts to be considered as already downloaded (held
in the file "PDriverPS:Downloaded.<printername>").

This means that NetPrint must be improved so that "NetPrint:" can be opened
for input, to receive data back from the printer.

Theoretically it would also be better if multiple input and output streams
were possible, and also a 'broadcast' input stream, that picked up data from
a printer that was not associated with another open stream.  This would
allow a logging program to display the normal output of the PostScript
printer (such as "Out of paper" error messages) in a window.

Another improvement to NetPrint, which is not strictly essential to font
downloading, would be to make it double-buffer its data, so it could receive
data into one buffer while attempting to send the previous buffer in the
background.  This allows the printer driver to do conversion work while
NetPrint is waiting for the network to become free.

Two further problems occur when the printer is to be accessed via a spooler:

    1)  The spooler needs to be able to send output from the printer back to
        the client.

    2)  The printer might be busy printing another job, and you don't want
        to have to queue the query job and wait till it executes.

The first problem can be solved as follows:

        The spooler should send all output from the printer back to the
        client that sent the original job.  This is desirable for other
        reasons too, as things like error reports from the printer should be
        sent back to the job anyway.

        The data coming back must be tagged with a reference handle that
        is passed in with the original print job, so that the client knows
        which print job each piece of data is associated with.  This is
        important since when sending a query job, other print jobs may still
        be executing and sending back data, which must not be confused with
        the query job results.

        PostScript printers send back a ctrl-D when the job has finished,
        which should be returned to the client, so it knows when it is OK to
        close the input stream.

        If a client is not listening (NB retries should be done in the
        background), the data should be thrown away (ie. no error generated
        in the spooler).

The second problem can be solved as follows:

        A query job contains a piece of PostScript that finds out the names
        of all the fonts in the machine, and writes them out to the client.

        The job also contains some "structured comments", which can be
        recognised by the spooler software as a query job which is trying to
        send back the names of all the fonts in the machine.  Font
        downloading jobs also contain (different) structuring information,
        which tells the spooler that it should recache the list of
        downloaded fonts (by sending a query job to the printer).

        Then, if the PostScript printer is stand-alone, the PostScript job
        will execute normally and return the desired information.

        If the spooler is controlling the printer, it will pick up the query
        job and deal with it itself, by sending back its cached list of the
        fonts in the printer.  This means that it doesn't matter if the
        printer is currently busy.

Note that Acorn's current printer spooler software has never been released
to the outside world, so the first spooler that the punters are likely to
see is the one in the Acorn Level 4 Fileserver.


Summary
-------

Work in stage 1:
        Front end in !PrinterPS:        1 man week
        Font to PostScript Convertor:   6 man weeks

Work in stage 2:
        PDriver_DeclareFont:            2 man weeks
        Front end in !PrinterPS:        2 man weeks

Work in stage 3:
        PDriver code:                   3 man weeks
        Improvements to NetPrint:       3 man weeks
        Improvements to spooler:        3 man weeks

