This document is intended to tell application authors how to write their applications so as to make use of the standard RISC OS printer driver interface. It starts with a general explanation of how the printer drivers are supposed to be used. Then the SWI interface is described and an example BASIC procedure is given that shows an application might do its printing. The final section of the document specifies exactly what VDU sequences and other plotting operations the application may use while printing. PRINTER DRIVER PHILOSOPHY ========================= What the application user sees ------------------------------ RISC OS comes with two printer driver applications, !PSPrinter for PostScript printers and !DMPrinter for a range of dot matrix printers. If I possess a PostScript printer and I wish to print, I should do the following: Double-click on !PSPrinter. An icon will appear. Menu on this and check that the settings are right for where the printer is connected, e.g. net/parallel/serial etc. This setting will be retained in CMOS RAM, so it need only be done once. If I wish to print Text files, drag them onto the printer icon. They will get printed. If I wish to print from ArcDraw, click Print on the Print dialogue box after running !PSPrinter. The diagram will be printed. Or, drag the icon from the Save dialogue box onto the printer icon. If I wish to print from ArcPaint, it's exactly the same. If I with to print from any other editor program, it's exactly the same. If I have a dot matrix printer, run !DMPrinter. Click on the printer icon to produce a dialogue box of the correct type of printer. Click on the printer-type field to cycle through the various dot matrix printers supported, until it reflects mine. If I can't find mine, seek help. Drivers for other printers will appear, from Acorn and from others, in an analogous form. New printer drivers will work with all existing applications, subject to the limitations of any particular printing device. How and Why ----------- I use the term "editor" to mean any sort of interactive program that prepares, changes and processes data files. This includes word processors, DTP packages, spreadsheets, draw programs, etc. I use the term "Foo" to refer to any editor program, which operates on "Foo data files": so, substitute ArcDraw, ArcPaint, or whatever as you read. I use the term "Poo" to refer to any printer capable of generating graphics, e.g. FX80, Apple LaserWriter, etc. In the general case, editors save data in files of their own format, with an appropriate file type. Only Foo understands Foo data files. Also, different printers are entirely different from each other, and a pain to drive. If each editor is to understand each printer, and there are X editors and Y printers in the world, then: (a) There is X*Y work to do (b) If a new printer type comes along, all applications need updating. Because of this, RISC OS separates printer drivers from editors so that they are separate programs. This means: (a) There is X+Y work to do (b) If a new printer type comes along, once a printer driver has been written for it, it will work with all applications. This is clearly a better situation, and is one of the main reasons why applications working together is important. How do we achieve this? The main step is to define an interface that all editors should use when talking to printers, a sort of "virtual printer interface". All editors then output to this virtual interface, knowing little of the characteristics of the physical printer itself. The "virtual printer interface" chosen in RISC OS is to say that the printer supports a specified subset of the screen graphics primitives. This is because a WYSIWYG editor (where what you see on the screen is what you get on paper) will already contain code to render the data file using screen primitives; provided the application restricts itself to the specified subset, printing is unlikely to require very much extra code. There are several reasons why not all the screen primitives are supported by the virtual printer interface. The main ones are: (a) Some screen primitives are screen hardware specific (e.g. flashing colours, hardware palette changes, etc.). (b) Some screen primitives are very hard or impossible to implement on common types of printer (e.g. PostScript printers cannot handle non-overwriting GCOL actions). (c) Some screen primitives - e.g. flood fill - cannot be split across multiple boxes and so do not work with the window system. The printer drivers use a similar interface to the window system and have the same problems with these calls as it does. Each printer driver is implemented as a RISC OS relocatable module, which provides extra SWIs (system calls) concerned with starting, stopping and controlling a print job. The interface allows the printer driver to ask the application to render specific rectangles of the picture in any order, to give the printer driver maximum freedom in manipulating buffer space, etc. The interface to printer drivers means that an editor is not able to supply an acceptable user interface for setting printer-specific options such as quality/draft mode. For this reason, a separate application exists for each possible printer driver, to allow any printer-specific options to be set. The printing of plain text is such a basic facility that it is considered unacceptable to require the loading of ArcEdit. Furthermore, printers tend to provide a much simpler method for the printing of simple text than the facilities provided for arbitrary graphics. For this reason, every printer interface program provides simple facilities for the printing of plain text files. THE SWI INTERFACE ================= To send output to the printer, an application must engage in a dialogue with the printer driver. Parts of this dialogue is similar to the dialogue with the window manager when a window requires redrawing. The dialogue can be summarised as follows: The application starts by opening a file to receive the printer driver's output. Typically this file is "printer:", but any file may be used. It passes this file's handle to SWI PDriver_SelectJob in order to start a print job. To output a page, the application then uses SWI PDriver_GiveRectangle to give the printer driver a list of the rectangles it wants to appear on the page and where it wants them to appear. When it has specified all the rectangles it wants printed, it uses SWI PDriver_DrawPage to ask the printer driver for the first rectangle to be printed. It then prints this rectangle and uses SWI PDriver_GetRectangle to get another rectangle to print, until there are no further rectangles to print. This is very similar to the way an application uses SWI Wimp_RedrawWindow and SWI Wimp_GetRectangle when redrawing its window. When all the desired pages have been output in this manner, the application first uses SWI PDriver_EndJob to end the print job, then closes the output file. The full set of printer driver SWIs is as follows: SWI PDriver_Info (&80140) ------------------------- Entry: - Exit: R0 (top 16 bits) identifies general type of printer driven. Current assignments: 0 = PostScript printers. 1 = FX80 and similar dot matrix printers. R0 (bottom 16 bits) = 100 * version number of printer driver. R1 = X pixel resolution of printer driven (pixels/inch). R2 = Y pixel resolution of printer driven (pixels/inch). R3 = features word: Bit 0 set => colour If bit 0 set, bit 1 set => full colour range not available. Bit 2 set => only a discrete set of colours supported. Bit 8 set => cannot handle filled shapes well. Bit 9 set => cannot handle thick lines well. Bit 10 set => cannot handle overwriting well. Bit 24 set => supports the PDriver_ScreenDump call. Bit 25 set => supports arbitrary transformations (else only axis-preserving ones). R4 -> adjectival description of printers supported (a maximum of 20 characters, excluding the zero-termination). R5 = X halftone resolution (repeats/inch). If no halftoning is done, this is equal to the value returned in R1. R6 = Y halftone resolution (repeats/inch). If no halftoning is done, this is equal to the value returned in R2. R7 identifies a specific configured printer. Assignments of these numbers are specific to each printer driver. Some of these values can be changed by the configuration application associated with the printer driver (using SWI PDriver_SetInfo). If SWI PDriver_Info is called while a print job is selected, the values returned are those that were in effect when that print job was started (i.e. when it was first selected using PDriver_SelectJob). If SWI PDriver_Info is called when no print job is active, the values returned are those that would be used for a new print job. The printer/driver features word returned in R3 describes the various ways in which the printers supported differ from a "standard" printer. Most applications need not look at this word, but sophisticated ones may want to in order to ensure that the printer can handle their output, or to adjust their output to the printer being used. In more detail than above, the bits in R3 have the following meanings: Bits 0-7 relate to the printer/driver's colour capabilities: Bit 0 = 0: It can only print grey colours. (I.e. it produces monochrome output.) Bit 0 = 1: It supports at least some non-grey colours. Bit 1 is irrelevant if bit 0 = 0. Otherwise: Bit 1 = 0: It supports the full colour range - i.e. it can manage each of the eight primary colours (white, yellow, cyan, green, magenta, red, blue, black). Bit 1 = 1: It supports only a limited set of colours (this would typically be set e.g. for an XY-plotter which only had black, red, blue and green pens loaded). Bit 2 = 0: It supports a semi-continuous range of colours at the software level (e.g. if bit 0 = 0 and bit 2 = 0, the application can expect to be able to plot a reasonable approximation to any grey). Bit 2 = 1: It only supports a discrete set of colours at the software level - for example, an XY-plotter would probably set this bit, not having many pen colours, nor being able to mix its pen colours sensibly by halftoning, dithering or any similar technique. Bits 3-7 are reserved - current printer drivers will set them to zero. Bits 8-15 relate to the printer/driver's plotting capabilities: Bit 8 = 0: It can handle filled shapes. Bit 8 = 1: It cannot handle filled shapes other than by outlining them (e.g. an unsophisticated XY-plotter driver would have this bit set). Bit 9 = 0: It can handle thick lines. Bit 9 = 1: It cannot handle thick lines other than by plotting a thin line. (Unsophisticated XY-plotter drivers might again come into this category. It differs from the filled shape criterion in bit 8 in that it can be solved, at least partially, if the plotter has a range of pens of differing thicknesses available.) Bit 10 = 0: It handles overwriting of one colour by another on the paper properly (this is generally true of any printer/driver that buffers its output, either in the printer or in the driver). Bit 10 = 1: It does not handle overwriting of one colour by another properly - only overwriting of the background colour by another. (Again, this is a standard property of XY-plotters.) Bits 11-15 are reserved - current printer drivers will set them to zero. Bits 16-23 are reserved - current printer drivers will set them to zero. Bits 24-31 relate to optional features of the printer driver: Bit 24 = 0: This printer driver does not support screen dumps. Bit 24 = 1: This printer driver does support screen dumps. Bit 25 = 0: This printer driver does not support transformations (supplied to PDriver_DrawPage) other than scalings, translations, rotations by multiples of 90 degrees and combinations thereof. Bit 25 = 1: This printer driver supports arbitrary transformations supplied to PDriver_DrawPage. Bits 25-31 are reserved - current printer drivers will set them to zero. SWI PDriver_SetInfo (&80141) ---------------------------- Entry: R1 = X pixel resolution of printer driven (pixels/inch). R2 = Y pixel resolution of printer driven (pixels/inch). R3 (bit 0) is zero to set monochrome, 1 to set colour. The other bits of R3 are ignored. R5 = X halftone resolution (repeats/inch). If no halftoning is to be done, this should be equal to the value in R1. R6 = Y halftone resolution (repeats/inch). If no halftoning is to be done, this should be equal to the value in R2. R7 identifies a specific configured printer. Exit: - The configuration application associated with a particular printer driver uses this SWI to change the information values associated with subsequent print jobs. In general, no other application should use this SWI. SWI PDriver_CheckFeatures (&80142) ---------------------------------- Entry: R0 = features word mask. R1 = features word value. Exit: If the features word that PDriver_Info would return in R3 satisfies ((features word) AND R0) = (R1 AND R0), return is normal with all registers preserved. Otherwise a suitable error is generated, if appropriate - e.g. no error will be generated if the printer driver has the ability to support arbitrary rotations and your features word value merely requests axis-preserving ones. This call may be used by an application to check that the current printer driver has the features it requires, and to generate a suitable descriptive error if it doesn't. SWI PDriver_PageSize (&80143) ----------------------------- Entry: - Exit: R1 = X size of paper, including margins. (Units 1/72000 inch) R2 = Y size of paper, including margins. (Units 1/72000 inch) R3 = left edge of printable area of paper, relative to the left edge of the paper. (Units 1/72000 inch) R4 = bottom edge of printable area of paper, relative to the bottom edge of the paper. (Units 1/72000 inch) R5 = right edge of printable area of paper, relative to the left edge of the paper. (Units 1/72000 inch) R6 = top edge of printable area of paper, relative to the bottom edge of the paper. (Units 1/72000 inch) An application can use this call to find out how big the paper in use is and how large the printable area on the paper is. This information can then be used to decide how to place the data to be printed on the page. These values can be changed by the configuration application associated with the printer driver (using SWI PDriver_SetPageSize). If SWI PDriver_PageSize is called while a print job is selected, the values returned are those that were in effect when that print job was started (i.e. when it was first selected using PDriver_SelectJob). If SWI PDriver_PageSize is called when no print job is active, the values returned are those that would be used for a new print job. SWI PDriver_SetPageSize (&80144) -------------------------------- Entry: R1 = X size of paper, including margins. (Units 1/72000 inch) R2 = Y size of paper, including margins. (Units 1/72000 inch) R3 = left edge of printable area of paper, relative to the left edge of the paper. (Units 1/72000 inch) R4 = bottom edge of printable area of paper, relative to the bottom edge of the paper. (Units 1/72000 inch) R5 = right edge of printable area of paper, relative to the left edge of the paper. (Units 1/72000 inch) R6 = top edge of printable area of paper, relative to the bottom edge of the paper. (Units 1/72000 inch) Exit: - The configuration application associated with a particular printer driver uses this SWI to change the page size values associated with subsequent print jobs. In general, no other application should use this SWI. SWI PDriver_SelectJob (&80145) ------------------------------ Entry: R0 = file handle for print job to be selected, or zero to cease having any print job selected. R1 is zero or points to a title string for the job. This title string is terminated by any character outside the range ASCII 32-126. Exit: R0 = file handle for print job that was previously active, or zero if no print job was active. A print job is identified by a file handle, which must be that of a file that is open for output. The printer output for the job concerned is sent to this file. Calling SWI PDriver_SelectJob with R0=0 will cause the current print job (if any) to be suspended, and the printer driver will cease intercepting plotting calls. Calling SWI PDriver_SelectJob with R0 containing a file handle will cause the current print job (if any) to be suspended, and a print job with the given file handle to be selected. If a print job with this file handle already exists, it is resumed; otherwise a new print job is started. The printer driver will start to intercept plotting calls if it is not already doing so. Note that this call never ends a print job - to do so, use one of SWI PDriver_EndJob and SWI PDriver_AbortJob. The title string pointed to by R1 is treated by different printer drivers in different ways. It is only ever used if a new print job is being started, not when an old one is being resumed. Typical uses are: (a) A simple printer driver might ignore it. (b) The PostScript printer driver adds a line "%%Title: " followed by the given title string to the PostScript header it generates. (c) Printer drivers whose output is destined for an expensive central printer in a large organisation might use it when generating a cover sheet for the document. An application is always entitled not to supply a title (by setting R1=0), and a printer driver is entitled to ignore any title supplied. Printer drivers may also use the following OS variables when creating cover sheets, etc.: PDriver$For - indicates who the output is intended to go to. PDriver$Address - indicates where to send the output. These variables should not contain characters outside the range ASCII 32-126. If an error occurs during PDriver_SelectJob, the previous job will still be selected afterwards (though it may have been de-selected and re-selected during the call). No new job will exist (one may have been created during the call, but the error will cause it to be destroyed again). SWI PDriver_CurrentJob (&80146) ------------------------------- Entry: - Exit: R0 = file handle for print job that is currently active, or zero if no print job is active. SWI PDriver_FontSWI (&80147) ---------------------------- This SWI is part of the internal interface between the font system and printer drivers. Applications should not call it. SWI PDriver_EndJob (&80148) --------------------------- Entry: R0 = file handle for print job to be ended. Exit: - This SWI should be used to end a print job normally. This may result in further printer output - e.g. the PostScript printer driver will produce the standard trailer comments. If the print job being ended is the currently active one, there will be no current print job after this call (so plotting calls will no longer be intercepted). If the print job being ended is not currently active, it will be ended without altering which print job is currently active or whether plotting calls are being intercepted. SWI PDriver_AbortJob (&80149) ----------------------------- Entry: R0 = file handle for print job to be aborted. Exit: - This SWI should be used to end a print job abnormally - it should generally be called after errors while printing. It will not try to produce any further printer output - this is important if an error occurs while sending output to the print job's output file. If the print job being aborted is the currently active one, there will be no current print job after this call (so plotting calls will no longer be intercepted). If the print job being aborted is not currently active, it will be aborted without altering which print job is currently active or whether plotting calls are being intercepted. Application authors should note (a) that many error messages reported by the printer driver are buffered within a print job's workspace; (b) that aborting the print job with this call (or with PDriver_Reset) releases the print job's workspace back to the heap. So if (as is likely) the application wants to report the error after issuing SWI PDriver_AbortJob, it should take a copy of the error number and message first. (This is even more important if the application is going to close the output file before reporting the error, as filing systems are quite liable to claim some workspace from the heap temporarily while closing the file.) SWI PDriver_Reset (&8014A) -------------------------- Entry: - Exit: - This SWI aborts all print jobs known to the printer driver, leaving the printer driver with no active or suspended print jobs and ensuring that plotting calls are not being intercepted. Normal applications shouldn't use this SWI, but it can be useful as an emergency recovery measure when developing an application. A call to this SWI is generated automatically if the machine is reset or the printer driver module is killed or RMTIDYed. SWI PDriver_GiveRectangle (&8014B) ---------------------------------- Entry: R0 = rectangle identification word. This word is reported back to the application when it is requested to plot all or part of this rectangle. R1 -> 4 word block, containing rectangle to be plotted. Units are OS units. R2 -> 4 word block, containing dimensionless transformation to be applied to the specified rectangle before printing it. The entries are given as fixed point numbers with 16 binary places, so the transformation is: x' = (x * R2!0 + y * R2!8)/2^16 y' = (x * R2!4 + y * R2!12)/2^16 R3 -> 2 word block, containing the position where the bottom left corner of the rectangle is to be plotted on the printed page. Units are 1/72000 inch. R4 = background colour for this rectangle, in the form &BBGGRRXX. Exit: - This SWI allows an application to specify a rectangle from its workspace to be printed, how it is to be transformed and where it is to appear on the printed page. An application should make one or more calls to SWI PDriver_GiveRectangle before a call to SWI PDriver_DrawPage and the subsequent calls to SWI PDriver_GetRectangle. (Multiple calls allow the application to print multiple rectangles from its workspace to one printed page - e.g. for "two up" printing). The printer driver may subsequently ask the application to plot the specified rectangles or parts thereof in any order it chooses. An application should not make any assumptions about this order or whether the rectangles it specifies will be split. (A common reason why a printer driver might split a rectangle is that it prints the page in strips to avoid using excessively large page buffers.) Assuming that a non-zero number of copies is requested and that none of the requested rectangles go outside the area available for printing, it is certain to ask the application to plot everything requested at least once. It may ask for some areas to be plotted more than once, even if only one copy is being printed, and it may ask for areas marginally outside the requested rectangles to be plotted (this can typically happen if the boundaries of the requested rectangles are not on exact device pixel boundaries). If SWI PDriver_GiveRectangle is used to specify a set of rectangles that overlap on the output page, the rectangles will be printed in the order of the SWI PDriver_GiveRectangle calls. For appropriate printers (i.e. most printers, but not e.g. XY plotters), this means that rectangles supplied via later PDriver_GiveRectangle calls will overwrite rectangles supplied via earlier calls. SWI PDriver_DrawPage (&8014C) ----------------------------- Entry: R0 = number of copies to print. R1 -> 4 word block, to receive the rectangle to print. R2 is zero or contains the page's sequence number within the document being printed (i.e. 1-n for an n-page document). R3 is zero or points to a string, terminated by a character in the ASCII range 33-126 (note spaces are not allowed), which gives the 'real' page number. (Examples: "23", "viii", "A-1") Exit: R0 = number of copies still requiring printing. This is zero if and only if no more plotting is required. If R0 is non-zero, the area pointed to by R1 has been filled in with the rectangle that needs to be plotted, and R2 contains the rectangle identification word for the user-specified rectangle that this is a part of. If R0 is zero, the contents of R2 and the area pointed to by R1 are undefined. This SWI should be called after all rectangles to be plotted on the current page have been specified (using SWI PDriver_GiveRectangle). It returns the first rectangle that the printer driver wants plotted in the area pointed to by R1. If nothing requires plotting - i.e. if there is no such rectangle - it returns R0=0. So the application should stop trying to plot the current page if R0=0, and continue otherwise. If R0<>0, the fact that R0 is the number of copies still to be printed is only intended to be used for information purposes (e.g. putting a "Printing page m of n" message on the screen); as long as it is non-zero, R0's value does not affect what the application should try to plot. The information passed in R2 and R3 is not particularly important, though it helps to make output produced by the PostScript printer driver conform better to Adobe's structuring conventions. If non-zero values are supplied, they should be correct. Note that R2 is NOT the sequence number of the page in the print job, but in the document. An example: if a document consists of 11 pages, numbered "" (the title page), "i"-"iii" and "1"-"7", and the application is requested to print the entire preface part, it should use R2 = 2, 3, 4 and R3 -> "i", "ii", "iii" for the three pages. When plotting starts in a rectangle supplied by a printer driver, the printer driver behaves as though the VDU system is in the following state: * VDU drivers enabled. * VDU 5 state has been set up. * all graphics cursor positions and the graphics origin have been set to (0,0). * the current dot pattern for dotted lines plotted via VDU calls is &AA,&AA,&AA,&AA,&AA,&AA,&AA,&AA, with a repeat length of 8. * a VDU 5 character size and spacing of 16 OS units by 32 OS units. * the graphics clipping region has been set to bound the actual area that is to be plotted. (But note that an application cannot read what this area is: the printer drivers do not - and cannot - intercept OS_ReadVduVariables or OS_ReadModeVariable.) * the area in which plotting will actually take place has been cleared to the background colour supplied in the corresponding PDriver_GiveRectangle call, as though a CLG had occurred. * the cursor movement control bits (i.e. the ones that would be set by VDU 23,16,...) are set to &40 - i.e. cursor movement is normal, except that movements beyond the edge of the graphics window in VDU 5 mode do not generate special actions. * one OS unit on the paper is 1/180 inch. This is designed to be as similar as possible to the state set up by the window manager when redrawing. SWI PDriver_GetRectangle (&8014D) --------------------------------- Entry: R1 -> 4 word block, to receive the rectangle to print. Exit: R0 = number of copies still requiring printing. This is zero if and only if no more plotting is required. If R0 is non-zero, the area pointed to by R1 has been filled in with the rectangle that needs to be plotted, and R2 contains the rectangle identification word for the user-specified rectangle that this is a part of. If R0 is zero, the contents of R2 and the area pointed to by R1 are undefined. This SWI should be used after plotting a rectangle returned by a previous call to SWI PDriver_DrawPage or SWI PDriver_GetRectangle, to get the next rectangle the printer driver wants plotted. It returns precisely the same information as PDriver_DrawPage. SWI PDriver_CancelJob (&8014E) ------------------------------ Entry: R0 = file handle for job to be cancelled. Exit: - This SWI causes subsequent attempts to output to the print job associated with the given file handle to do nothing other than generate the error "Print cancelled". An application is expected to respond to this error by aborting the print job. SWI PDriver_ScreenDump (&8014F) ------------------------------- Entry: R0 = file handle of file to receive the dump. Exit: - If this SWI is supported (i.e. if bit 24 is set in the value SWI PDriver_Info returns in R3), this SWI causes the printer driver to output a screen dump to the file handle supplied in R0. The file concerned should be open for output. If the SWI is not supported, an error is returned. SWI PDriver_EnumerateJobs (&80150) ---------------------------------- Entry: R0 = 0 to get file handle of first print job, or file handle of a print job to get the file handle of the next print job. Exit: R0 = file handle of print job requested, or 0 if there are no more print jobs. This allows the print jobs that exist to be enumerated. The order in which they appear is undefined. SWI PDriver_SetPrinter (&80151) ------------------------------- Entry: Printer-driver specific. Exit: Printer-driver specific. This allows the setting of options specific to a particular printer driver. See the individual printer driver documentation for details. In general, this SWI is used by the configuration application associated with the printer driver module and no other application should use it. EXAMPLE BASIC PROCEDURE ======================= An example BASIC procedure that does a standard "two up" printing job: DEFPROCprintout(firstpage%, lastpage%, title$, filename$) : REM Get SWI numbers used in this procedure. LOCAL select%, abort%, pagesize%, giverect%, drawpage%, getrect%, end% SYS "OS_SWINumberFromString",,"PDriver_SelectJob" TO select% SYS "OS_SWINumberFromString",,"PDriver_AbortJob" TO abort% SYS "OS_SWINumberFromString",,"PDriver_PageSize" TO pagesize% SYS "OS_SWINumberFromString",,"PDriver_GiveRectangle" TO giverect% SYS "OS_SWINumberFromString",,"PDriver_DrawPage" TO drawpage% SYS "OS_SWINumberFromString",,"PDriver_GetRectangle" TO getrect% SYS "OS_SWINumberFromString",,"PDriver_EndJob" TO end% : REM Open destination file and set up a local error handler that will REM close it again on an error. Note that our local error handlers REM take copies of error messages and numbers: this avoids the danger REM that they will be lost when a print job is aborted or a subsequent REM file operation occurs. LOCAL H%, O% H% = OPENOUT(filename$) LOCAL e%, e$ LOCAL ERROR ON ERROR LOCAL:RESTORE ERROR:PROCrderr:CLOSE#H%:PROCerr : REM Start up a print job associated with this file, remembering the REM handle associated with the previous print job (if any), then set up a REM a local error handler for it. SYS select%,H%,title$ TO O% LOCAL ERROR ON ERROR LOCAL:RESTORE ERROR:PROCrderr:SYSabort%,H%:SYSselect%,O%:PROCerr : REM Now we decide how two pages are to fit on a piece of paper. LOCAL left%, bottom%, right%, top% PROCgetdocumentsize(box%) SYS pagesize% TO ,,,left%,bottom%,right%,top% PROCfittwopages(left%,bottom%,right%,top%,box%,matrix%,origin1%,origin2%) : REM Start the double page loop LOCAL page%, copiesleft%, pagetoprint%, white% white%=&FFFFFF00 FOR page%=firstpage% TO lastpage% STEP 2 : REM Set up to print two pages, or possibly just one if an odd number of REM pages are being printed and this is the last time around. SYS giverect%, page%, box%, matrix%, origin1%, white% IF page%0 PROCprintpage(pagetoprint%, box2%) SYS getrect%,,box% TO copiesleft%,,pagetoprint% ENDWHILE : REM End of page loop NEXT : REM All pages have now been printed. Terminate this print job. SYS end%,H% : REM Go back to the first of our local error handlers. RESTORE ERROR : REM And go back to whatever print job was active on entry to this REM procedure (or to no print job in no print job was active). SYS select%,O% : REM Go back to the caller's error handler. RESTORE ERROR : REM Close the destination file. CLOSE#H% ENDPROC : REM Procedure to take a copy of the current error report DEFPROCrderr e%=ERR: e$=REPORT$ ENDPROC : REM Procedure to re-report the error last registered with PROCrderr, with REM a backtrace error line attached to it. DEFPROCerr ERROR e%,e$+" (from line "+STR$(ERL)+")" ENDPROC This uses the following global areas of store: box%: 4 words box2%: 4 words matrix%: 4 words origin1%: 2 words origin2%: 2 words And the following external procedures: DEFPROCgetdocumentsize(box%) - fills the area pointed to by 'box%' with the size of a document page in OS units. DEFPROCfittwopages(l%, b%, r%, t%, box%, transform%, org1%, org2%) - given left, bottom, right and top bounds of a piece of paper in units of 1/72000 inch, and a bounding box of a document page in OS units, sets up a transformation and two origins in the areas pointed to by 'tr%','org1%' and 'org2%' to print two of those pages on a piece of paper. DEFPROCdrawpage(page%, box%) - draw the parts of document page number 'page%' that lie with the box held in the 4 word area pointed to by 'box%'. If printing is likely to take a long time and the application does not want to hold other applications up while it prints, it should regularly use a sequence like the following during printing: SYS select%,O% SYS "Wimp_Poll",mask%,area% TO reason% SYS select%,H% TO O% THE VIRTUAL PRINTER INTERFACE ============================= When a print job is active, the printer driver intercepts the following vectors: (a) WrchV (= WriteCV): all character output is received and interpreted by the printer driver. Many VDU sequences are converted into printer output to do similar things on the printed page. Some VDU sequences produce errors. A few are passed through to the real VDU drivers. Only these last go through the usual output stream selection controlled by OS_Byte 3. See the section entitled 'VDU SEQUENCES' below for more details. (b) SpriteV: most sprite operations are passed on unchanged to the SpriteExtend module and/or the operating system. Those that do sprite plotting are intercepted and generate printer output to do similar sprite plotting on the printed page. Note that, because of the way vector interception is done, the SpriteExtend module must be initialised before the printer driver. See the section entitled 'SPRITE OPERATIONS' below for more details. (c) DrawV: Draw calls that would not normally plot to the screen are passed on unchanged to the Draw module. Others are intercepted and, where possible, used to generate printer output to do similar things on the printed page. However, some of the intercepted calls cannot be so treated and instead produce errors. Note that, because of the way vector interception is done, the Draw module must be initialised before the printer driver. See the section entitled 'DRAW MODULE CALLS' below for more details. (d) ColourV: some ColourTrans calls are intercepted and processed by the printer driver, others are left to be dealt with by the ColourTrans module itself. Note that, because of the way vector interception is done, the ColourTrans module must be initialised before the printer driver. See the section entitled 'COLOURTRANS MODULE CALLS' below for more details. (e) ByteV: The OS_Byte calls dealing with dot-dash repeat lengths (OS_Byte 163,242,0-64) are intercepted and processed by the printer driver. The same applies to OS_Byte 218 (read/write bytes in VDU queue). See the section entitled 'MISCELLANEOUS CALLS' below for more details. In addition, the font manager and the printer driver interact to cause many of the font manager calls to be processed by the printer driver. See the section entitled 'FONT MANAGER CALLS' below for more details. VDU SEQUENCES ============= General rules ------------- Whenever a print job is active, the printer driver will intercept all characters sent through WrchV. It will then queue them in the same way as the VDU drivers do and process complete VDU sequences as they appear. Because the printer driver will not pick up any data currently in the VDU queue, and may send sequences of its own to the VDU drivers, a print job should not be selected with an incomplete sequence in the VDU queue. Also, because the printer driver may send sequences of its own to the VDU drivers, the output stream specification set by OS_Byte 3 should be in its standard state (i.e. as though set by OS_Byte 3,0). The printer driver will pass the following VDU sequences through to the normal VDU drivers, either because they control the screen hardware or because they affect global resources such as the character and ECF definitions: VDU 7 - Produce bell sound VDU 19,l,p,r,g,b - Change hardware palette VDU 20 - Set default hardware palette VDU 23,0,n,m| - "Program 6845 registers" VDU 23,1,n| - Change cursor appearance VDU 23,2-5,a,b,c,d,e,f,g,h - Set ECF pattern VDU 23,9-10,n| - Set flash durations VDU 23,11| - Set default ECF patterns VDU 23,12-15,a,b,c,d,e,f,g,h - Simple setting of ECF pattern VDU 23,17,4,m| - Set ECF type VDU 23,17,6,x;y;| - Set ECF origin VDU 23,32-255,a,b,c,d,e,f,g,h - Define character The printer driver will interpret or fault all other VDU sequences. If the printer driver currently wants a rectangle printed (i.e. if there has been a call to SWI PDriver_DrawPage or SWI PDriver_GetRectangle and the last such call returned R0 <> 0), these will result in it producing appropriate output or errors. Otherwise, the printer driver will keep track of some state information (e.g. what the current foreground and background colours are), but will not produce any printer output. The printer driver will always behave as though it is in VDU 5 state. No text co-ordinate system is defined, and no scrolling is possible. For these reasons, the following VDU sequences are faulted: VDU 4 - exit VDU 5 state VDU 23,7,m,d,z| - scroll display VDU 23,8,t1,t2,x1,y1,x2,y2| - clear text block It is generally meaningless to try to send or echo characters directly to the printer while printing. Furthermore, attempts to do so are likely to disrupt the operation of printer drivers. For these reasons, the following VDU sequences are faulted: VDU 1,c - send character to printer VDU 2 - start echoing characters to printer It is not possible to change the "mode" of a printed page, so the following VDU sequence is faulted: VDU 22,m - change display mode A printer driver cannot be written to deal with undefined or reserved calls, so the following VDU sequences are faulted: VDU 23,18-24,... - reserved for Acorn expansion VDU 23,28-31,... - reserved for use by applications VDU 25,216-231,... - reserved for Acorn expansion VDU 25,240-255,... - reserved for use by applications The following VDU sequences are ignored, either because they normally do nothing (at least when stuck in VDU 5 mode and not echoing characters to the printer) or because they have no sensible interpretation when applied to printed output rather than a screen. VDU 0 - do nothing VDU 3 - stop echoing characters to printer VDU 5 - enter VDU 5 state VDU 14 - start "paged" display VDU 15 - end "paged" display VDU 17,c - define text colour VDU 23,17,5| - exchange text foreground and background VDU 27 - do nothing VDU 28,l,b,r,t - define text window Colours ------- Colours are a rather complicated matter. It is strongly recommended that applications should use SWI ColourTrans_SetGCOL, SWI ColourTrans_SelectTable and SWI ColourTrans_SetFontColours to set colours, as these will allow the printer to produce as accurate an approximation as it can to the desired colour, independently of the screen palette. The GCOL sequence (VDU 18,k,c) should only be used if absolutely necessary, and the application writer should be aware of the fact that the printer driver has a simplified interpretation of the parameters, as follows: * The fact that the background colour is affected if c >= 128 and the foreground colour if c < 128 is unchanged. * If k MOD 8 <> 0, subsequent plots and sprite plots will not do anything. * If k=0, subsequent plots will cause the colour c MOD 128 (possibly modified by the current tint) is looked up in the screen palette (at the time of plotting, not the time the VDU 18,k,c command was issued). Plotting is done by overwriting with the closest approximation the printer can produce to the RGB combination found. Subsequent sprite plotting will be done without use of the sprite's mask. * If k=8, subsequent plots will be treated the same as k=0 above, except that sprite plots will be done using the sprite's mask (if any). * If k > 8, an unspecified solid colour will be used. The major problems with the use of VDU 18,k,c to set colours are (a) that it makes the printer driver output dependent on the current screen mode and palette; (b) that it artificially limits the printer driver to the number of colours displayed on the screen (which can be very limiting in a two colour mode!). Other techniques that depend on GCOLs (e.g. SWI Font_SetFontColours, colour-changing sequences in strings passed to Font_Paint, plotting sprites without a translation table, etc.) have the same problems and are similarly not recommended. No operations other than overwriting are permitted, mainly because they cannot be implemented on many common printers (e.g. PostScript printers). Note that the printer driver maintains its own foreground and background colour information. The screen foreground and background colours are not affected by VDU 18,k,c sequences encountered while a print job is active. Similarly, VDU 23,17,2-3,t| sequences encountered while a print job is active do not affect the screen tints, just the printer driver's own tints. VDU 23,17,0-1,t| sequences would only affect the colours of the text tints, so the printer driver ignores them. Other graphics state operations ------------------------------- The VDU 6 and VDU 21 sequences have their normal effects of enabling and disabling execution (but not parsing) of subsequent VDU sequences. As usual, the printer driver keeps track of this independently of the VDU drivers. The cursor movement VDU sequences (i.e. VDU 8-11, VDU 13, VDU 30 and VDU 31,x,y) all update the current graphics position (without updating the previous graphics positions used in e.g. triangle plotting), precisely as they do in VDU 5 mode on the screen. VDU 24,l;b;r;t; will set the printer driver's graphics clipping box. The rectangle specified should lie completely within the box that was reported on return from the last call to SWI PDriver_DrawPage or SWI PDriver_GetRectangle. If this is not the case, it is not defined what will happen, and different printer drivers may treat it in different ways. This is analogous to the situation with the window manager: attempts to set a graphics clipping box outside the rectangle currently being redrawn may be ignored completely (if they go outside the screen) or may get obeyed (with consequences that are almost certainly wrong!). VDU 29,x;y; sets the printer driver's graphics origin. VDU 26 will reset the printer driver's graphics clipping box to its maximum size (this is essentially the box reported on return from the last call to SWI PDriver_DrawPage or SWI PDriver_GetRectangle, but may be slightly different due to rounding problems when converting from a box expressed in printer pixels to one expressed in OS units). It also resets its versions of the graphics origin, the current graphics position and all the previous graphics positions to (0,0). VDU 23,6,a,b,c,d,e,f,g,h will set the printer driver's current dot pattern (for use with lines plotted via VDU 25,16-31,x;y; and VDU 25,48-63,x;y;). The exact lengths of the dashes and gaps produced may differ between various printer drivers, and also between the screen and printer drivers, so an application should not rely on them. However, an application can reasonably expect each set bit in the pattern to correspond to approximately 2 to 3 OS units on the printed page. VDU 23,16,x,y| changes the printer driver's version of the cursor control flags, and thus how the cursor movement control sequences and BBC-style character plotting affect the current graphics position. As usual, this is completely independent of the corresponding flags in the VDU drivers. However, printer drivers pay no attention to the setting of bit 6 (which controls whether movements beyond the edge of the graphics window cause carriage return/line feeds and other cursor movements to be generated automatically) - they always behave as though it is set. Note that the Wimp normally sets this bit, and that it is not sensible to have it clear at any time during a Wimp redraw. VDU 23,17,7,flags,x;y;| changes the printer driver's version of the size that BBC-style characters are to be plotted and the spacing that is required between them. Setting the VDU 4 character size cannot possibly affect the printer driver's output and so will be ignored completely. As noted below under 'Plotting operations', a "pixel" is regarded as the size of a screen pixel for the screen mode that was in effect when the print job was started. Plotting operations ------------------- The printer driver regards a "pixel" as having size 2 OS units square (1/90 inch square). The main effect of this is that all PLOT line, PLOT point and PLOT outline calls will produce lines that are approximately 2 OS units wide. However, when translating the character size and spacing information provided by VDU 23,17,7,... (see above) from pixels to OS units, the screen pixel size for the screen mode that was in effect when the print job was started is used. This is done in the expectation that the application is basing its requested sizes on that screen mode. The following VDU sequences perform straightforward plotting operations; printer drivers will produce the corresponding printed output: VDU 12 - clear graphics window (in VDU 5 state) VDU 16 - clear graphics window VDU 25,0-63,x;y; - draw line; however, the lines are always plotted solid, so only VDU 25,0-15,... and VDU 25,32-47,... will look the same as in VDU output. Use Draw_Stroke to generate dashed lines that will come out well in printed output. VDU 25,64-71,x;y; - draw point VDU 25,80-87,x;y; - fill triangle VDU 25,96-103,x;y; - fill axis-aligned rectangle VDU 25,112-119,x;y; - fill parallelogram VDU 25,144-151,x;y; - draw circle VDU 25,152-159,x;y; - fill circle VDU 25,160-167,x;y; - draw circular arc VDU 25,168-175,x;y; - fill circular segment VDU 25,176-183,x;y; - fill circular sector VDU 25,192-199,x;y; - draw ellipse VDU 25,200-207,x;y; - fill ellipse VDU 32-126 - print characters in BBC-style font VDU 127 - backspace & delete VDU 128-255 - print characters in BBC-style font One difference to note is that most printer drivers will either not do the rounding to pixel centres normally done by the VDU drivers, or will round to different pixel centres (probably the centres of their device pixels). The following VDU sequences are faulted because they cannot be split up easily across rectangles, and also because they depend on the current picture contents and so cannot be implemented e.g. on PostScript printers: VDU 25,72-79,x;y; - horizontal line fill (flood fill primitive) VDU 25,88-95,x;y; - horizontal line fill (flood fill primitive) VDU 25,104-111,x;y; - horizontal line fill (flood fill primitive) VDU 25,120-127,x;y; - horizontal line fill (flood fill primitive) VDU 25,128-143,x;y; - flood fills VDU 25,184-191,x;y; - copy/move rectangle Exception: VDU 25,184,x;y; and VDU 25,188,x;y; are now correctly interpreted by printer drivers (as being equivalent to VDU 25,0,x;y; and VDU 25,4,x;y; respectively). The sprite plotting VDU sequences (VDU 23,27,m,n| and VDU 25,232-239,x;y;) and the font manager VDU sequences (VDU 23,25,a,b,c,d,e,f,g,h, VDU 23,26,a,b,c,d,e,f,g,h,text and VDU 25,208-215,x;y;text) cannot be handled by the printer drivers and generate errors. Application authors should use SWI OS_SpriteOp and the font manager SWIs instead. SPRITE OPERATIONS ================= Printer drivers intercept OS_SpriteOp via the SpriteV vector. Most calls are simply passed through to the operating system or the SpriteExtend module. The ones that normally plot to the screen are generally intercepted and used to generate printer output by the printer driver. The following reason codes normally involve reading or writing the screen contents and are not straightforward sprite plotting operations. Because some printer drivers redirect output to a sprite internally, it is unknown what the "screen" is during these operations. They are therefore faulted. 2 - screen save 3 - screen load 14 - get sprite from current point on screen 16 - get sprite from specified point on screen Reason codes that are passed through to the operating system or the SpriteExtend module are: 8 - read sprite area control block 9 - initialise sprite area 10 - load sprite file 11 - merge sprite file 12 - save sprite file 13 - return name of numbered sprite 15 - create sprite 25 - delete sprite 26 - rename sprite 27 - copy sprite 29 - create mask 30 - remove mask 31 - insert row 32 - delete row 33 - flip about X axis 35 - append sprite 36 - set pointer shape 40 - read sprite size 41 - read pixel colour 42 - write pixel colour 43 - read pixel mask 44 - write pixel mask 45 - insert column 46 - delete column 47 - flip about Y axis 62 - read save area size The following reason code is passed through to the operating system when it is called for a user sprite (i.e. with &100 or &200 added to it), as this call is simply asking the operating system for the address of the sprite concerned. If the system version is called (i.e. without anything added to it), it is asking for a sprite to be selected for use with the VDU sprite plotting sequences. As these sequences are not handled by the printer driver, this version of the call generates an error. 24 - select sprite The following reason codes plot a sprite or its mask, and are converted into appropriate printer output: 28 - plot sprite at current point on screen 34 - plot sprite at specified point on screen 48 - plot mask at current point on screen 49 - plot mask at specified point on screen 50 - plot mask at specified point on screen, scaled 52 - plot sprite at specified point on screen, scaled 53 - plot sprite at specified point on screen, grey scaled The following reason code is mainly used by the VDU drivers to implement sizes other than 8x8 and 8x16 for VDU 5 characters. It is not handled by the printer drivers (which deal with scaled VDU 5 text by another mechanism) and causes an error if encountered during a print job. 51 - plot character, scaled As usual for a printer driver, only some GCOL actions are understood. If the GCOL action is not divisible by 8, nothing is plotted. If it is divisible by 8, the "overwrite" action is used. If it is divisible by 16, the sprite is plotted without using its mask; otherwise the mask is used. The colours used to plot sprite pixels are determined as follows: * If the call does not allow a pixel translation table, or if no translation table is supplied, the current screen palette is consulted to find out what RGB combination the sprite pixel's value corresponds to. The printer driver then does its best to produce that RGB combination. Use of this option is not really recommended. * If a translation table is supplied with the call, the printer driver assumes that the table contains code values allocated by one of: SWI ColourTrans_SelectTable with R2 = -1 SWI ColourTrans_ReturnColourNumber SWI ColourTrans_ReturnColourNumberForMode with R1 = -1 SWI ColourTrans_ReturnOppColourNumber SWI ColourTrans_ReturnOppColourNumberForMode with R1 = -1 It can therefore look up precisely which RGB combination is supposed to correspond to each sprite pixel value. Because of the variety of ways in which printer drivers can allocate these values, the translation table should always have been set up in the current print job and using these calls. If a sprite is printed unscaled, its size on the printed output is the same as its size would be if it were plotted to the screen in the screen mode that was in effect at the time that the print job concerned was started. If it is printed scaled, the scaling factors are applied to this size. This is one of the few ways in which the printed output does depend on this screen mode (the main other ones are in interpreting GCOL and TINT values, and in interpreting VDU 5 character sizes). It is done this way in the expectation that the application is scaling the sprite for what it believes is the current screen mode. Finally, the following two reason codes are intercepted to keep track of whether plotting output is currently supposed to go to a sprite or to the screen. If it is supposed to go to a sprite, it really will go to that sprite - this allows applications to create sprites normally while printing. If it is supposed to go to the screen, it will be processed by the printer driver. (Note that printer drivers that redirect output to a sprite internally will treat this case specially, regarding output as still being destined for the screen!) 60 - switch output to sprite 61 - switch output to mask DRAW MODULE CALLS ================= Printer drivers intercept the DrawV vector and re-interpret those calls whose purpose is to plot something on the screen, producing appropriate printer output instead. There are a number of restrictions on the calls that can be dealt with, mainly due to the limitations of PostScript. Most of the operations that are disallowed are not particularly useful, fortunately. Note that the Draw module calls normally use the graphics foreground colour to plot with and the graphics origin. The printer driver uses its versions of these values. In particular, this means that the fill colour is subject to all the restrictions noted elsewhere in this document. The floating point Draw module calls are not intercepted at present. If and when the Draw module is upgraded to deal with them, printer drivers will be similarly upgraded. SWI Draw_Fill ------------- Printer drivers can deal with most common calls to this SWI. The restrictions are: (a) They cannot deal with fill styles that invoke the positive or negative winding number rules - i.e. those with bit 0 set. (b) They cannot deal with a fill style which asks for non-boundary exterior pixels to be plotted (i.e. which have bit 2 set). Exception: they can deal with the trivial case in which all of bits 2-5 are set - i.e. if all pixels in the plane are to be plotted! (c) They cannot deal with the following values for bits 5-2: 0010 - plot exterior boundary pixels only. 0100 - plot interior boundary pixels only. 1010 - plot exterior boundary and interior non-boundary pixels only. (d) An application should not rely on there being any difference between what is printed for the following three values of bits 5-2: 1000 - plot interior non-boundary pixels only. 1100 - plot all interior pixels. 1110 - plot all interior pixels and exterior boundary pixels. (A printer driver will generally try its best to distinguish these, but it may not be possible.) SWI Draw_Stroke --------------- Again, most common calls to this SWI can be dealt with. The restrictions on the parameters depend on whether the specified thickness is zero or not: If the specified thickness is zero, the restrictions are: (a) Printer drivers cannot deal with a fill style with bits 3-2 equal to 01 - i.e. one that asks for pixels lying on the stroke to be plotted and those that lie off the stroke not to be. (b) Most printer drivers will not pay any attention to bit 31 of the fill style - the one that distinguishes plotting the stroke subpath by subpath from plotting it all at once. If the specified thickness is non-zero, the restrictions are: (a) All the restrictions mentioned under SWI Draw_Fill above. (b) They cannot deal with bits 5-2 being 0110 - i.e. asking for just the boundary pixels of the resulting filled path to be plotted. (c) Most printer drivers will not pay any attention to bit 31 of the fill style - the one that distinguishes plotting the stroke subpath by subpath from plotting it all at once. SWI Draw_StrokePath, SWI Draw_FlattenPath and SWI Draw_TransformPath -------------------------------------------------------------------- None of these do any plotting; they are all dealt with in the normal way by the Draw module. SWI Draw_ProcessPath -------------------- This SWI is faulted if R7=1 (fill path normally) or R7=2 (fill path subpath by subpath) on entry. Use the appropriate one of Draw_Fill or Draw_Stroke if you want to produce printed output. If the operation you're trying to do is too complicated for them, it almost certainly cannot be handled by e.g. the PostScript printer driver. All other values of R7 correspond to calls that don't do any plotting and are dealt with in the normal way by the Draw module. If you're trying to do something complicated and you've got enough workspace and RMA, a possible useful trick is to use SWI Draw_ProcessPath with R7 pointing to an output buffer, followed by SWI Draw_Fill on the result. COLOURTRANS MODULE CALLS ======================== The printer driver intercepts calls to the ColourTrans module, via the ColourV vector. Most of them are passed straight on to the ColourTrans module - the exceptions are: SWI ColourTrans_SelectTable with R2 = -1 ---------------------------------------- Each RGB combination in the source palette (or implied by it in the case of 256 colour modes) is converted into a colour number as though by SWI ColourTrans_ReturnColourNumber (see below). The resulting values are placed in the table. SWI ColourTrans_SetGCOL ----------------------- The printer driver's version of the foreground or background colour (as appropriate) is set. The GCOL actions are interpreted precisely as for the VDU 18,k,c call (see above). However, rather than looking up a GCOL in the screen palette at plot time, the exact RGB combination specified in this call is remembered and used (as accurately as the printer will render it) at plot time. After this has been done, the call is effectively converted into SWI ColourTrans_ReturnGCOL and passed down to the ColourTrans module in order to set the information returned correctly. Note that this implies that subsequently using the GCOL returned in a VDU 18,k,c sequence will not produce the same effect on the colour as this call: it will merely produce the best approximation the printer can manage to the best approximation the current screen palette can manage to the specified RGB combination. It is therefore probably a bad idea to use the values returned. This call therefore allows the application to make full use of a printer's colour resolution without having to switch to another screen mode or mess around with the screen's palette, and without worrying about the effects of a change in the screen's palette. It is therefore the recommended way to set the foreground and background colours. SWI ColourTrans_ReturnColourNumber ---------------------------------- This will return a code value (in the range 0-255) that identifies the specified RGB combination as accurately as possible to the printer driver. How this code value is determined may vary from printer driver to printer driver, and indeed even from print job to print job for the same printer driver. An application should therefore not make any assumptions about what these code values mean. (Most printer drivers implement this by pre-allocating some range of code values to evenly spaced RGB combinations, then adopting the following approach: (a) If the RGB combination is already known about, return the corresponding code value. (b) If the RGB combination is not already known about and some code values are still free, allocate one of the unused code values to the new RGB combination and return that code value. (c) If the RGB combination is not already known about and all code values have been allocated, return the code number whose RGB combination is as close as possible to the desired RGB combination. The pre-allocation of evenly spaced RGB combinations will ensure that even case (c) does not have really terrible results.) SWI ColourTrans_ReturnColourNumberForMode with R1 = -1 ------------------------------------------------------ This is treated exactly the same as SWI ColourTrans_ReturnColourNumber above. SWI ColourTrans_SetOppGCOL -------------------------- This behaves like ColourTrans_SetGCOL above, except that the RGB combination it remembers is the furthest possible RGB combination from the one actually specified in R0, and it ends by being converted into a call to ColourTrans_ReturnOppGCOL. Note that there is no guarantee that the GCOL returned is anywhere near the RGB combination remembered! SWI ColourTrans_ReturnOppColourNumber ------------------------------------- This behaves exactly as though ColourTrans_ReturnColourNumber (see above) had been called with R0 containing the furthest possible RGB combination from the one actually specified. SWI ColourTrans_ReturnOppColourNumberForMode with R1 = -1 --------------------------------------------------------- This behaves exactly as though ColourTrans_ReturnColourNumberForMode (see above) had been called with R1 = -1 and R0 containing the furthest possible RGB combination from the one actually specified. SWI ColourTrans_SetFontColours ------------------------------ The printer driver's version of the font colours is set, to as accurate a representation of the desired RGB combinations as the printer can manage. After this has been done, the call is effectively converted into SWI ColourTrans_ReturnFontColours and passed down to the ColourTrans module in order to set the information returned correctly. Note that this implies that subsequently using the values returned in a SWI Font_SetFontColours call will not produce the same effect on the font colours as this call: it will merely produce the best approximations the printer can manage to the best approximations the current screen palette can manage to the specified RGB combinations. It is therefore probably a bad idea to use the values returned. This call therefore allows the application to make full use of a printer's colour resolution without having to switch to another screen mode or mess around with the screen's palette, and without worrying about the effects of a change in the screen's palette. It is the recommended way to set the font colours. FONT MANAGER CALLS ================== The printer driver interacts with the font manager (via a service call and SWI PDriver_FontSWI) in such a way that when it is active, calls to the following SWIs are processed by the printer driver: SWI Font_Paint SWI Font_LoseFont SWI Font_SetFontColours SWI Font_SetPalette This enables the printer driver to make SWI Font_Paint produce printer output rather than affecting the screen. The use of SWI Font_SetFontColours is not recommended, as it results in the setting of colours that depend on the current screen palette. Instead, use SWI ColourTrans_SetFontColours to set font colours to absolute RGB values. Similarly, the use of colour-changing control sequences in strings passed to SWI Font_Paint is not recommended. In addition to the control sequences allowed by current font managers, printer drivers will be able to handle the following control sequence if the font manager they are working with can: 19,background red,green,blue,foreground red,green,blue,maximum offset This gives a way of changing colour in the middle of a string without sacrificing colour resolution. (How exactly it does this varies quite markedly between printer drivers: for instance, most dot matrix printer drivers will probably use the font manager to write into the sprite they are using to hold the current strip of printed output, while the PostScript printer driver uses the PostScript prologue to define a translation from font manager font names to printer fonts.) MISCELLANEOUS CALLS =================== OS_Byte 163,242,0-64 are intercepted to set the printer driver version of the dot pattern repeat length instead of the VDU drivers' version. OS_Byte 218 is intercepted to act on the printer driver's VDU queue instead of the VDU drivers' version. It should be noted that most of the informational calls associated with the VDU drivers (and OS_ReadVduVariables in particular) will produce undefined results when a printer driver is active. These results are likely to differ between printer drivers (in particular, they will vary according to whether the printer driver plots to a sprite internally and if so, how large the sprite concerned is). The only informational calls that the application may rely upon are: OS_Word 10 - used to read character and ECF definitions. OS_Word 11 - used to read palette definitions. OS_ReadPalette - used to read palette definitions. OS_Byte 218 - when used to read the number of bytes in the VDU queue. ERROR HANDLING ============== There are a couple of somewhat unusual features about the printer drivers' error handling that an application author should be aware of: First, ESCAPE condition generation and side effects are turned on within various calls to the printer driver and restored to their original state afterwards. If the application has ESCAPE generation turned off, it is guaranteed that any ESCAPE generated within the print job will be acknowledged and turned into an 'Escape' error. If the application has ESCAPE generation turned on, most ESCAPEs generated within the print job will be acknowledged and turned into 'Escape' errors, but there is a small window at the end of the call during which an ESCAPE will not be acknowledged. If the application makes a subsequent call of one of the relevant types to the printer driver, that subsequent call will catch the ESCAPE. If no such subsequent call is made, the application will need to trap the ESCAPE itself. The SWIs during which ESCAPE generation is turned on are: PDriver_SelectJob for a new job PDriver_EndJob OS_WriteC All ColourTrans SWIs Draw_Fill Draw_Stroke Font_SetFontColours Font_SetPalette Font_Paint OS_SpriteOp with reason codes: PutSprite PutSpriteUserCoords PutSpriteScaled PutSpriteGreyScaled PlotMask PlotMaskUserCoords PlotMaskScaled All but the first two only apply at times when the printer driver is intercepting plotting calls - i.e. at times when all of the following conditions hold: (a) There is an active print job. (b) Plotting output is directed either to the screen or to a sprite internal to the printer driver. (c) The Wimp is not reporting an error (as defined by the service call with reason WimpReportError). Secondly, inside a number of calls, any error that occurs is converted into a "persistent error". The net effect of this is that: (a) The error number is left unchanged. (b) The error message has the string " (print cancelled)" appended to it. If it is so long that this would cause it to exceed 255 characters, it is truncated to a suitable length and "... (print cancelled)" is appended to it. (c) Any subsequent call to any of the routines concerned will immediately return the same error. The reason for this behaviour is to prevent errors the application is not expecting from being ignored. (E.g. quite a lot of code assumes incorrectly that OS_WriteC cannot produce an error. This ensures that an error during OS_WriteC cannot reasonably get ignored forever.) The SWIs during which persistent errors are created are: PDriver_EndJob PDriver_GiveRectangle PDriver_DrawPage PDriver_GetRectangle OS_WriteC All ColourTrans SWIs Draw_Fill Draw_Stroke Draw_ProcessPath with R7=1 Font_SetFontColours Font_SetPalette Font_Paint OS_SpriteOp with reason codes: PutSprite PutSpriteUserCoords PutSpriteScaled PutSpriteGreyScaled PlotMask PlotMaskUserCoords PlotMaskScaled ScreenSave ScreenLoad GetSprite GetSpriteUserCoords PaintCharScaled SelectSprite (system version only) Reason codes unknown to the printer driver All but the first four only apply at times that the printer driver is intercepting plotting calls - see above for details of this. SWI PDriver_CancelJob puts a print job into a similar state, with the error message being simply "Print cancelled". However, this error is only returned by subsequent calls from the list above - not by PDriver_CancelJob itself. Note that an application must respond to any error during a print job that could have come from one of the above sources by calling PDriver_AbortJob. In particular, take care to respond to errors from PDriver_EndJob by calling PDriver_AbortJob, not PDriver_EndJob - otherwise an infinite succession of errors will occur or an unfinished print job will be left around.