diff options
Diffstat (limited to 'xorg-server/hw/xprint/raster/Raster.c')
-rw-r--r-- | xorg-server/hw/xprint/raster/Raster.c | 1563 |
1 files changed, 1563 insertions, 0 deletions
diff --git a/xorg-server/hw/xprint/raster/Raster.c b/xorg-server/hw/xprint/raster/Raster.c new file mode 100644 index 000000000..dccef613c --- /dev/null +++ b/xorg-server/hw/xprint/raster/Raster.c @@ -0,0 +1,1563 @@ +/* +(c) Copyright 1996 Hewlett-Packard Company +(c) Copyright 1996 International Business Machines Corp. +(c) Copyright 1996 Sun Microsystems, Inc. +(c) Copyright 1996 Novell, Inc. +(c) Copyright 1996 Digital Equipment Corp. +(c) Copyright 1996 Fujitsu Limited +(c) Copyright 1996 Hitachi, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the copyright holders shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from said +copyright holders. +*/ + + +/******************************************************************* +** +** ********************************************************* +** * +** * File: printer/Raster.c +** * +** * Contents: +** * Raster driver for the print server. +** * +** * Copyright: Copyright 1993, 1995 Hewlett-Packard Company +** * +** ********************************************************* +** +********************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <X11/X.h> +#include <X11/Xos.h> /* for SIGCLD on pre-POSIX systems */ +#define NEED_EVENTS +#include <X11/Xproto.h> +#undef NEED_EVENTS +#include <X11/Xatom.h> +#include "misc.h" +#include "dixstruct.h" +#include "scrnintstr.h" +#include "screenint.h" +#include "colormapst.h" +#include "windowstr.h" +#include "propertyst.h" +#include "servermd.h" /* needed for IMAGE_BUFSIZE */ +#include "fb.h" +#include "mi.h" + +#include <X11/extensions/Print.h> +#include "Raster.h" + +#include "attributes.h" +#include "AttrValid.h" +#include "DiPrint.h" + +static void AllocateRasterPrivates( + ScreenPtr pScreen); +static Bool RasterChangeWindowAttributes( + WindowPtr pWin, + unsigned long mask); +static int StartJob( + XpContextPtr pCon, + Bool sendClientData, + ClientPtr client); +static int StartPage( + XpContextPtr pCon, + WindowPtr pWin); +static int StartDoc( + XpContextPtr pCon, + XPDocumentType type); +static int EndDoc( + XpContextPtr pCon, + Bool cancel); +static int EndJob( + XpContextPtr pCon, + Bool cancel); +static int EndPage( + XpContextPtr pCon, + WindowPtr pWin); +static int DocumentData( + XpContextPtr pCon, + DrawablePtr pDraw, + char *pData, + int len_data, + char *pDoc_fmt, + int len_fmt, + char *pOptions, + int len_options, + ClientPtr client); +static int GetDocumentData( + XpContextPtr pContext, + ClientPtr client, + int maxBufferSize); +static void FreePageFiles( + RasterContextPrivPtr pWinPriv); +static int SystemCmd( + char *pCommand); +static Bool RasterCloseScreen( + int index, + ScreenPtr pScreen); +static int RasterInitContext(XpContextPtr pCon); +static Bool RasterDestroyContext(XpContextPtr pCon); +static char *RasterGetAttributes( + XpContextPtr pContext, + XPAttributes class); +static char *RasterGetOneAttribute(XpContextPtr pCon, + XPAttributes class, + char *attribute); +static int RasterSetAttributes(XpContextPtr pCon, + XPAttributes class, + char *attributes); +static int RasterAugmentAttributes(XpContextPtr pCon, + XPAttributes class, + char *attributes); +static int RasterMediumDimensions(XpContextPtr pCon, + CARD16 *width, + CARD16 *height); +static int RasterReproducibleArea(XpContextPtr pCon, + xRectangle *pRect); + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define DOC_PCL 1 +#define DOC_RASTER 2 + +static DevPrivateKey RasterScreenPrivateKey = &RasterScreenPrivateKey; +static DevPrivateKey RasterContextPrivateKey = &RasterContextPrivateKey; +static char RASTER_DRIV_NAME[] = "XP-RASTER"; +static int doc_type = DOC_RASTER; + +#define ABSOLUTE_PCLCOMP_PATH1 "/usr/openwin/bin/pclcomp" +#define ABSOLUTE_PCLCOMP_PATH2 "/usr/X11/bin/pclcomp" + +static char *pcl3_output_cmds[] = { + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -0 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -01 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -02 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -03 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -012 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -013 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -023 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% | pclcomp -0123 > %(OutFile)%", + "xpr -device ljet -rv -landscape < %(InFile)% > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -0 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -01 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -02 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -03 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -012 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -013 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -023 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% | pclcomp -0123 > %(OutFile)%", + "xpr -device ljet -rv < %(InFile)% > %(OutFile)%"}; + +Bool +InitializeRasterDriver( + int ndx, + ScreenPtr pScreen, + int argc, + char **argv) +{ + int xRes, yRes; + int maxRes, maxDim, numBytes; + RasterScreenPrivPtr pPriv; + + /* + * Register this driver's InitContext function with the print extension. + * This is a bit + * sleazy, as the extension hasn't yet been initialized, but the + * extension needs to know this, and this seems the best time to + * provide the information. + */ + XpRegisterInitFunc( pScreen, RASTER_DRIV_NAME, RasterInitContext ); + + /* + * Create and load the devPrivate for the printer layer. + */ + AllocateRasterPrivates(pScreen); + + pPriv = (RasterScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, RasterScreenPrivateKey); + + maxDim = MAX( pScreen->height, pScreen->width ); + numBytes = maxDim + BITMAP_SCANLINE_PAD - 1; /* pixels per row */ + numBytes *= maxDim; + numBytes /= 8; /* bytes per row */ + xRes = pScreen->width / (pScreen->mmWidth / 25.4); + yRes = pScreen->height / (pScreen->mmHeight / 25.4); + maxRes = MAX( xRes, yRes ); + + pPriv->pBits = (char *)xalloc(numBytes); + + /* + * Have to allocate maxDim X maxDim to allow for landscape mode. + */ + fbScreenInit(pScreen, pPriv->pBits, maxDim, maxDim, maxRes, + maxRes, maxDim, 1); + miInitializeBackingStore(pScreen); + pScreen->blackPixel = 1; + pScreen->whitePixel = 0; + if(fbCreateDefColormap(pScreen) == FALSE) + ; /* XXX what do I do if it fails? */ + + pScreen->SaveScreen = (SaveScreenProcPtr)_XpBoolNoop; + pPriv->ChangeWindowAttributes = pScreen->ChangeWindowAttributes; + pScreen->ChangeWindowAttributes = RasterChangeWindowAttributes; + pPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = RasterCloseScreen; + + return TRUE; +} + +/* + * GetPropString searches the context's config database for a property + * by the name of propName. If found, it returns the property's + * value, otherwise it returns NULL unless the requested attribute + * is RASTER_PRINT_PAGE_COMMAND, in which case it returns a hard-coded + * default string to invoke xpr to produce a PostScript(tm) formatted + * raster. + */ + +static char * +GetPropString( + XpContextPtr pCon, + char *propName) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + char *type; + XrmValue val; + struct stat status; + int pclcomp_exists = 0; + + if( XrmGetResource(pConPriv->config, propName, propName, &type, &val) == + True ) + return (char *)val.addr; + + if( !strcmp( propName, RASTER_PRINT_PAGE_COMMAND ) ) + if( doc_type == DOC_RASTER ) + return "xpr -device ps %(InFile)% > %(OutFile)%"; + else + { + XpOid orientation; + XpOid compression; + int pcl3_output_index = 0; + + orientation = XpGetContentOrientation(pCon); + compression = XpGetAvailableCompression(pCon); + + switch(orientation) { + case xpoid_val_content_orientation_landscape: + pcl3_output_index = 0; + break; + default: + pcl3_output_index += 9; + break; + } + + if(stat(ABSOLUTE_PCLCOMP_PATH1, &status) != -1) + pclcomp_exists = 1; + else if(stat(ABSOLUTE_PCLCOMP_PATH2, &status) != -1) + pclcomp_exists = 1; + + if(pclcomp_exists) + switch(compression) { + case xpoid_val_available_compressions_0: + pcl3_output_index += 0; + break; + case xpoid_val_available_compressions_01: + pcl3_output_index += 1; + break; + case xpoid_val_available_compressions_02: + pcl3_output_index += 2; + break; + case xpoid_val_available_compressions_03: + pcl3_output_index += 3; + break; + case xpoid_val_available_compressions_012: + pcl3_output_index += 4; + break; + case xpoid_val_available_compressions_013: + pcl3_output_index += 5; + break; + case xpoid_val_available_compressions_023: + pcl3_output_index += 6; + break; + default: + pcl3_output_index += 7; + break; + } + else + pcl3_output_index += 8; + + return pcl3_output_cmds[pcl3_output_index]; + } + else + return NULL; +} + +static void +SetDocumentType( + XpContextPtr pCon) +{ + XpOidList* attrs_supported; + + /* + * only validate attributes found in document-attributes-supported + */ + attrs_supported = + XpGetListAttr(pCon, XPPrinterAttr, + xpoid_att_document_attributes_supported, + (const XpOidList*)NULL); + + if(XpOidListHasOid(attrs_supported, xpoid_att_document_format)) + { + const char* value_in; + XpOidDocFmt *f; + + value_in = XpGetStringAttr(pCon, XPDocAttr, xpoid_att_document_format); + + f = XpOidDocFmtNew( value_in ); + + if( f != NULL ) + { + if( !strcmp( f->format, "PCL" ) ) + doc_type = DOC_PCL; + else + doc_type = DOC_RASTER; + + XpOidDocFmtDelete( f ); + } + } + + /* + * clean up + */ + XpOidListDelete(attrs_supported); +} + +static int +StartJob( + XpContextPtr pCon, + Bool sendClientData, + ClientPtr client) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + SetDocumentType( pCon ); + + /* + * Check for existing page file, and delete it if it exists. + */ + if(pConPriv->pageFileName != (char *)NULL) + { + if(pConPriv->pPageFile != (FILE *)NULL) + { + fclose(pConPriv->pPageFile); + pConPriv->pPageFile = (FILE *)NULL; + } + unlink(pConPriv->pageFileName); + Xfree(pConPriv->pageFileName); + pConPriv->pageFileName = (char *)NULL; + } + + /* + * Create a temporary file to store the printer output. + */ + if(!sendClientData) + { + /* + * Create a temporary file to store the printer output. + */ + if (!XpOpenTmpFile("w", &pConPriv->jobFileName, &pConPriv->pJobFile)) + return BadAlloc; + } + + return Success; +} + +/* + * StartDoc and EndDoc are just no-ops in this implementation, since + * our view of the spooler really doesn't recognize documents. + */ + +static int +StartDoc( + XpContextPtr pCon, + XPDocumentType type) +{ + return Success; +} + +static int EndDoc( + XpContextPtr pCon, + Bool cancel) +{ + return Success; +} + +#if 0 + +/* XXX Not used. */ + +/* + * BuidArgVector takes a pointer to a comma-separated list of command + * options and splits it out into an array of argument pointers. The + * caller must not free the optionList after calling this function until + * the returned arg vector is no longer needed, at which time the arg + * vector should also be freed. + */ + +#define SEPARATOR_CHAR (char)',' + +static char ** +BuildArgVector( + char *optionList, + char **argVector, + int argCount) +{ + char *curArg, *lastChar, *endArg; + + curArg = optionList; + lastChar = optionList + strlen(optionList); /* includes final NULL */ + + while(curArg != (char *)NULL && curArg < lastChar) + { + /* strip leading white space */ + while(curArg < lastChar && isascii((int)*curArg) && + isspace((int)*curArg)) + curArg++; + + if(curArg < lastChar) + { + argVector = (char **)Xrealloc(argVector, + sizeof(char *) * (argCount + 2)); + argVector[argCount] = curArg; + argVector[++argCount] = (char *)NULL; + + endArg = strchr(curArg, SEPARATOR_CHAR); + + /* Should I strip trailing white space ??? */ + + if(endArg != (char *)NULL) + { + *endArg = (char)'\0'; + curArg = endArg + 1; + } + else + curArg = (char *)NULL; + } + } + + return argVector; +} +#endif + +static int +EndJob( + XpContextPtr pCon, + Bool cancel) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + if( cancel == True ) + { + if(pConPriv->getDocClient != (ClientPtr)NULL) { + XpFinishDocData(pConPriv->getDocClient); + + pConPriv->getDocClient = (ClientPtr)NULL; + pConPriv->getDocBufSize = 0; + } + + if(pConPriv->jobFileName != (char *)NULL) + { + unlink(pConPriv->jobFileName); + Xfree(pConPriv->jobFileName); + pConPriv->jobFileName = (char *)NULL; + } + + return Success; + } + + if(pConPriv->getDocClient != (ClientPtr)NULL&&pConPriv->getDocBufSize > 0) + { + XpFinishDocData(pConPriv->getDocClient); + + pConPriv->getDocClient = (ClientPtr)NULL; + pConPriv->getDocBufSize = 0; + + return Success; + } + + if(pConPriv->pJobFile != (FILE *)NULL) + { + fclose(pConPriv->pJobFile); + pConPriv->pJobFile = (FILE *)NULL; + + if(pConPriv->jobFileName != (char *)NULL) + { + XpSubmitJob( pConPriv->jobFileName, pCon ); + unlink(pConPriv->jobFileName); + Xfree(pConPriv->jobFileName); + pConPriv->jobFileName = (char *)NULL; + } + } + + return Success; +} + +/* StartPage + * + * If page file exists + * close page file + * set page file pointer = NULL + * unlink page file + */ +static int +StartPage( + XpContextPtr pCon, + WindowPtr pWin) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + if(pConPriv->pPageFile != (FILE *)NULL) + { + fclose(pConPriv->pPageFile); + pConPriv->pPageFile = (FILE *)NULL; + } + if(pConPriv->pageFileName != (char *)NULL) + { + unlink(pConPriv->pageFileName); + pConPriv->pageFileName = (char *)NULL; + } + + return Success; +} + +#include "X11/XWDFile.h" + + +#define lowbit(x) ((x) & (~(x) + 1)) + +/* + * Get the XWDColors of all pixels in colormap - returns # of colors + */ +static XWDColor * +Get_XWDColors( + ColormapPtr pCmap) +{ + int i, ncolors; + xrgb *prgbList; + Pixel *pPixels; + XWDColor *colors; + + ncolors = pCmap->pVisual->ColormapEntries; + if (!(colors = (XWDColor *) malloc (sizeof(XWDColor) * ncolors))) + return (XWDColor *) NULL; + if (!(prgbList = (xrgb*) malloc(sizeof(xrgb) * ncolors))) + { + Xfree(colors); + return (XWDColor *) NULL; + } + if (!(pPixels = (Pixel*) malloc(sizeof(Pixel) * ncolors))) + { + Xfree(colors); + Xfree(prgbList); + return (XWDColor *) NULL; + } + + if (pCmap->pVisual->class == DirectColor || + pCmap->pVisual->class == TrueColor) { + Pixel red, green, blue, red1, green1, blue1; + + red = green = blue = 0; + red1 = lowbit(pCmap->pVisual->redMask); + green1 = lowbit(pCmap->pVisual->greenMask); + blue1 = lowbit(pCmap->pVisual->blueMask); + for (i=0; i<ncolors; i++) { + colors[i].pixel = red|green|blue; + colors[i].pad = 0; + red += red1; + if (red > pCmap->pVisual->redMask) + red = 0; + green += green1; + if (green > pCmap->pVisual->greenMask) + green = 0; + blue += blue1; + if (blue > pCmap->pVisual->blueMask) + blue = 0; + } + } else { + for (i=0; i<ncolors; i++) { + colors[i].pixel = i; + colors[i].pad = 0; + } + } + + for(i = 0; i < ncolors; i++) + pPixels[i] = colors[i].pixel; + + QueryColors(pCmap, ncolors, pPixels, prgbList); + Xfree(pPixels); + + for(i = 0; i < ncolors; i++) + { + colors[i].red = prgbList[i].red; + colors[i].green = prgbList[i].green; + colors[i].blue = prgbList[i].blue; + } + Xfree(prgbList); + + return(colors); +} + +static void +_swapshort ( + register char *bp, + register unsigned n) +{ + register char c; + register char *ep = bp + n; + + while (bp < ep) { + c = *bp; + *bp = *(bp + 1); + bp++; + *bp++ = c; + } +} + +static void +_swaplong ( + register char *bp, + register unsigned n) +{ + register char c; + register char *ep = bp + n; + register char *sp; + + while (bp < ep) { + sp = bp + 3; + c = *sp; + *sp = *bp; + *bp++ = c; + sp = bp + 1; + c = *sp; + *sp = *bp; + *bp++ = c; + bp += 2; + } +} +static int +WriteWindowRaster( + WindowPtr pWin, + FILE *pRasterFile) +{ + long widthBytesLine, length; + int nlines, linesPerBuf, height, linesDone; + char *pBuf; + DrawablePtr pDraw = &pWin->drawable; + XWDFileHeader header; + int win_name_size; + int header_size; + int ncolors, i; + char *win_name; + VisualPtr pVisual; + ColormapPtr pCmap; + XWDColor *pColors; + unsigned long swaptest = 1; + + widthBytesLine = PixmapBytePad(pWin->drawable.width, pWin->drawable.depth); + length = widthBytesLine * pWin->drawable.height; + height = pWin->drawable.height; + + if(length <= 0) + return Success; + + if (widthBytesLine >= IMAGE_BUFSIZE) + linesPerBuf = 1; + else + { + linesPerBuf = IMAGE_BUFSIZE / widthBytesLine; + if (linesPerBuf > height) + linesPerBuf = height; + } + length = linesPerBuf * widthBytesLine; + if (linesPerBuf < height) + { + /* we have to make sure intermediate buffers don't need padding */ + while ((linesPerBuf > 1) && (length & 3)) + { + linesPerBuf--; + length -= widthBytesLine; + } + while (length & 3) + { + linesPerBuf++; + length += widthBytesLine; + } + } + if(!(pBuf = (char *) Xalloc(length))) + return (BadAlloc); + + /* + * Start of Xwd header code. + */ + + /* + * XXX - Should we use the real window name??? + */ + win_name = "xwdump"; + /* sizeof(char) is included for the null string terminator. */ + win_name_size = strlen(win_name) + sizeof(char); + + pCmap = (ColormapPtr)LookupIDByType(wColormap (pWin), RT_COLORMAP); + pVisual = pCmap->pVisual; + if((pColors = Get_XWDColors(pCmap)) == (XWDColor *)NULL) + { + Xfree(pBuf); + return (BadAlloc); + } + + /* + * Write out header information. + */ + header_size = sizeof(header) + win_name_size; + header.header_size = (CARD32) header_size; + header.file_version = (CARD32) XWD_FILE_VERSION; + header.pixmap_format = (CARD32) ZPixmap; /* Must match GetImage below */ + header.pixmap_depth = (CARD32) pDraw->depth; + header.pixmap_width = (CARD32) pDraw->width; + header.pixmap_height = (CARD32) pDraw->height; + header.xoffset = (CARD32) 0; + header.byte_order = (CARD32) screenInfo.imageByteOrder; + header.bitmap_unit = (CARD32) screenInfo.bitmapScanlineUnit; + header.bitmap_bit_order = (CARD32) screenInfo.bitmapBitOrder; + header.bitmap_pad = (CARD32) screenInfo.bitmapScanlinePad; + header.bits_per_pixel = (CARD32) pDraw->bitsPerPixel; + header.bytes_per_line = (CARD32) widthBytesLine; + header.visual_class = (CARD32) pVisual->class; + header.red_mask = (CARD32) pVisual->redMask; + header.green_mask = (CARD32) pVisual->greenMask; + header.blue_mask = (CARD32) pVisual->blueMask; + header.bits_per_rgb = (CARD32) pVisual->bitsPerRGBValue; + header.colormap_entries = (CARD32) pVisual->ColormapEntries; + header.ncolors = ncolors = (CARD32) pVisual->ColormapEntries; + header.window_width = (CARD32) pDraw->width; + header.window_height = (CARD32) pDraw->height; + header.window_x = 0; + header.window_y = 0; + header.window_bdrwidth = (CARD32) 0; + + if (*(char *) &swaptest) { + _swaplong((char *) &header, sizeof(header)); + for (i = 0; i < ncolors; i++) { + _swaplong((char *) &pColors[i].pixel, sizeof(long)); + _swapshort((char *) &pColors[i].red, 3 * sizeof(short)); + } + } + + (void) fwrite((char *)&header, sizeof(header), 1, pRasterFile); + (void) fwrite(win_name, win_name_size, 1, pRasterFile); + (void) fwrite((char *) pColors, sizeof(XWDColor), ncolors, pRasterFile); + + Xfree(pColors); + + /* + * End of Xwd header code. + */ + + linesDone = 0; + while(height - linesDone > 0) + { + nlines = min(linesPerBuf, height - linesDone); + (*pDraw->pScreen->GetImage) (pDraw, + 0, + linesDone, + pWin->drawable.width, + nlines, + ZPixmap, + ~0, + pBuf); + + if(fwrite(pBuf, sizeof(char), (size_t)(nlines * widthBytesLine), + pRasterFile) != + (size_t)(nlines * widthBytesLine)) + { + Xfree(pBuf); + return BadAlloc; + } + linesDone += nlines; + } + Xfree(pBuf); + return Success; +} + + +static int +SendPage( XpContextPtr pCon ) +{ + struct stat statBuf; + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + if(stat(pConPriv->pageFileName, &statBuf) < 0) + return BadAlloc; + + return XpSendDocumentData(pConPriv->getDocClient, + pConPriv->pPageFile, (int)statBuf.st_size, + pConPriv->getDocBufSize); +} + +/* + * EndPage: + * + * If page file doesn't exist: + * { + * Create page file + * Open page file + * Write page header to page file + * if(preRasterFile exists) + * copy preRasterFile contents to page file + * if(noRasterFile exists) + * write noRasterFile contents to page file + * else + * Create raster image file + * Open raster image file + * GetImage data + * Write Image data to raster image file + * invoke page_command on raster image file + * Write raster image file contents to page file + * Unlink tempPage file + * if(postRasterFile exists) + * write postRasterFile contents to page file + * Write page trailer to page file + * } + * Write page file to job file + */ +static int +EndPage( + XpContextPtr pCon, + WindowPtr pWin) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + struct stat statBuf; + char *rasterFileName = (char *)NULL, *pCommand = (char *)NULL; + FILE *pRasterFile = (FILE *)NULL; + + if(pConPriv->pageFileName == (char *)NULL) + { + /* + * Open the page file. + */ + if (!XpOpenTmpFile("w+", &pConPriv->pageFileName, + &pConPriv->pPageFile)) + goto BAD_PAGE_ALLOC; + + /* + * Copy any pre-raster document data to the page file. + */ + if(pConPriv->pPreRasterFile != (FILE *)NULL) + { + if(CopyContentsAndDelete(&pConPriv->pPreRasterFile, + &pConPriv->preRasterFileName, + pConPriv->pPageFile) == FALSE) + goto BAD_PAGE_ALLOC; + } + + /* + * Copy either the no-raster document data, or the raster + * data itself to the page file. + * If the no-raster file exists, then we don't process the + * actual window raster bits. + */ + if(pConPriv->pNoRasterFile != (FILE *)NULL) + { + if(CopyContentsAndDelete(&pConPriv->pNoRasterFile, + &pConPriv->noRasterFileName, + pConPriv->pPageFile) == FALSE) + goto BAD_PAGE_ALLOC; + } + else + { + /* + * Open the raster image file. + */ + if (!XpOpenTmpFile("w", &rasterFileName, &pRasterFile)) + goto BAD_PAGE_ALLOC; + + /* + * Write the page image data to the raster image file. + */ + if(WriteWindowRaster(pWin, pRasterFile) != Success) + goto BAD_PAGE_ALLOC; + + /* + * Invoke the page_command on the raster image file. + */ + if((pCommand = GetPropString(pCon, RASTER_PRINT_PAGE_COMMAND)) != + (char *)NULL) + { + char *outFileName; + FILE *pOutFile; + + if (!XpOpenTmpFile("w", &outFileName, &pOutFile)) + goto BAD_PAGE_ALLOC; + fclose(pOutFile); + + pCommand = ReplaceFileString(strdup(pCommand), rasterFileName, + outFileName); + fclose(pRasterFile); + SystemCmd(pCommand); + free(pCommand); + /* + * Delete the unprocessed raster file. + */ + unlink(rasterFileName); + Xfree(rasterFileName); + rasterFileName = outFileName; + if((pRasterFile = fopen(rasterFileName, "r")) == (FILE *)NULL) + goto BAD_PAGE_ALLOC; + } + else + { + fclose(pRasterFile); + if((pRasterFile = fopen(rasterFileName, "r")) == (FILE *)NULL) + goto BAD_PAGE_ALLOC; + } + + /* + * Copy the raster image file contents to the page file. + * Note that pRasterFile must be set to the start of the + * raster file. + */ + if(CopyContentsAndDelete(&pRasterFile, + &rasterFileName, + pConPriv->pPageFile) == FALSE) + goto BAD_PAGE_ALLOC; + } + + /* + * Copy any post-raster document data to the page file. + */ + if(pConPriv->pPostRasterFile != (FILE *)NULL) + { + if(CopyContentsAndDelete(&pConPriv->pPostRasterFile, + &pConPriv->postRasterFileName, + pConPriv->pPageFile) == FALSE) + goto BAD_PAGE_ALLOC; + } + + } + + /* + * Write the page file contents to the job file or to the client + * performing GetDocumentData. + * pConPriv->pPageFile must first be set to the start of the page file. + */ + rewind(pConPriv->pPageFile); + if(stat(pConPriv->pageFileName, &statBuf) < 0) + goto BAD_PAGE_ALLOC; + + /* + * Send the page data to whatever client has called GetDocumentData. + */ + if(pConPriv->getDocClient != (ClientPtr)NULL&&pConPriv->getDocBufSize > 0) + { + int retval; + /* + * We should do something like the following: suspend the + * caller until we can gracefully write all the data in small + * chunks to the receiver, but for now we'll just call WriteToClient + * on the huge chunk + */ + retval = SendPage(pCon); + fclose(pConPriv->pPageFile); + pConPriv->pPageFile = (FILE *)NULL; + unlink(pConPriv->pageFileName); + free(pConPriv->pageFileName); + pConPriv->pageFileName = (char *)NULL; + return retval; + } + + if(pConPriv->pJobFile == (FILE *)NULL) + { + /* + * This shouldn't be necessary. I believe we only get here if + * someone calls "EndPage" prior to "StartJob". This error + * condition should probably be trapped at a higher level. + */ + + if(pConPriv->jobFileName != (char *)NULL) + Xfree(pConPriv->jobFileName); + /* + * Create a temporary file to store the printer output. + */ + if (!XpOpenTmpFile("w", &pConPriv->jobFileName, &pConPriv->pJobFile)) + goto BAD_PAGE_ALLOC; + } + + if(TransferBytes(pConPriv->pPageFile, pConPriv->pJobFile, + (int)statBuf.st_size) != (int)statBuf.st_size) + goto BAD_PAGE_ALLOC; + + fclose(pConPriv->pPageFile); + pConPriv->pPageFile = (FILE *)NULL; + unlink(pConPriv->pageFileName); + free(pConPriv->pageFileName); + pConPriv->pageFileName = (char *)NULL; + + return Success; + + BAD_PAGE_ALLOC: + + FreePageFiles(pConPriv); + + if(pRasterFile != (FILE *)NULL) + fclose(pRasterFile); + if(rasterFileName != (char *)NULL) + { + unlink(rasterFileName); + Xfree(rasterFileName); + } + return BadAlloc; +} + +static int +DocumentData( + XpContextPtr pCon, + DrawablePtr pDraw, + char *pData, + int len_data, + char *pDoc_fmt, + int len_fmt, + char *pOptions, + int len_options, + ClientPtr client) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + char *preRasterStr = PRE_RASTER, *postRasterStr = POST_RASTER, + *noRasterStr = NO_RASTER; + + /* + * Check that options equals either PRE_RASTER or POST_RASTER. + */ + if(len_options == strlen(preRasterStr) && + strncmp(pOptions, preRasterStr, strlen(preRasterStr)) == 0) + { + if(pConPriv->pPreRasterFile == (FILE *)NULL) + { + if (!XpOpenTmpFile("w+", &pConPriv->preRasterFileName, + &pConPriv->pPreRasterFile)) + return BadAlloc; + } + if(fwrite(pData, sizeof(char), (size_t)len_data, + pConPriv->pPreRasterFile) != (size_t)len_data) + return BadAlloc; + fflush(pConPriv->pPreRasterFile); + } + else if(len_options == strlen(postRasterStr) && + strncmp(pOptions, postRasterStr, strlen(postRasterStr)) == 0) + { + if(pConPriv->pPostRasterFile == (FILE *)NULL) + { + if (!XpOpenTmpFile("w+", &pConPriv->postRasterFileName, + &pConPriv->pPostRasterFile)) + return BadAlloc; + } + if(fwrite(pData, sizeof(char), (size_t)len_data, + pConPriv->pPostRasterFile) != (size_t)len_data) + return BadAlloc; + fflush(pConPriv->pPostRasterFile); + } + else if(len_options == strlen(noRasterStr) && + strncmp(pOptions, noRasterStr, strlen(noRasterStr)) == 0) + { + if(pConPriv->pNoRasterFile == (FILE *)NULL) + { + if (!XpOpenTmpFile("w+", &pConPriv->noRasterFileName, + &pConPriv->pNoRasterFile)) + return BadAlloc; + } + if(fwrite(pData, sizeof(char), (size_t)len_data, + pConPriv->pNoRasterFile) != (size_t)len_data) + return BadAlloc; + fflush(pConPriv->pNoRasterFile); + } + else + return BadValue; + + return Success; +} + +/* + * GetDocumentData notes which client is requesting the document data for + * a particular context. The Raster driver's EndPage function causes the + * data to be written to the proper client. + */ +static int +GetDocumentData( + XpContextPtr pContext, + ClientPtr client, + int maxBufferSize) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pContext->devPrivates, RasterContextPrivateKey); + + pConPriv->getDocClient = client; + pConPriv->getDocBufSize = maxBufferSize; + return Success; +} + +static void +AllocateRasterPrivates( + ScreenPtr pScreen) +{ + dixRequestPrivate(RasterContextPrivateKey, sizeof( RasterContextPrivRec ) ); + dixSetPrivate(&pScreen->devPrivates, RasterScreenPrivateKey, + Xalloc(sizeof(RasterScreenPrivRec))); +} + +/* + * RasterChangeWindowAttributes - Make sure that the window's backing + * store is turned on. + */ +static Bool +RasterChangeWindowAttributes( + WindowPtr pWin, + unsigned long mask) +{ + Bool status = Success; + ScreenPtr pScreen = pWin->drawable.pScreen; + RasterScreenPrivPtr pScreenPriv = (RasterScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, RasterScreenPrivateKey); + + if(pWin->backingStore == NotUseful) + { + pWin->backingStore = WhenMapped; + mask |= CWBackingStore; + } + + if(pScreenPriv->ChangeWindowAttributes != NULL) + { + pScreen->ChangeWindowAttributes = pScreenPriv->ChangeWindowAttributes; + status = pScreen->ChangeWindowAttributes(pWin, mask); + pScreen->ChangeWindowAttributes = RasterChangeWindowAttributes; + } + return status; +} + +/* + * RasterValidateDocFormats - Inspects the files available in the + * ddx-config/XP-RASTER directory to find the names of PDLs for which + * we have processing commands. These names are then intersected with + * the contents of the printer's document-formats-supported attribute, + * and the result is stored back into document-formats-supported. + * We have hard-coded knowledge of how to produce PS, so we always + * leave that in, if it's listed in document-formats-supported, + * even if we don't have a configuration file. If there is a + * configuration file for PS, then its contents will override our default. + */ +static void +RasterValidateDocFormats( + XpContextPtr pCon) +{ +} + +/* + * RasterValidateAttrs - Inspects and Corrects the attribute values + * in the specified context. + */ +static void +RasterValidateAttrs( + XpContextPtr pCon) +{ + RasterValidateDocFormats(pCon); + XpValidatePrinterPool(pCon, &RasterValidatePoolsRec); + XpValidateJobPool(pCon, &RasterValidatePoolsRec); + XpValidateDocumentPool(pCon, &RasterValidatePoolsRec); +} + +/* + * RasterInitContext - Establish the appropriate values for a + * PrintContext used with the Raster Driver. + */ +static char DOC_ATT_SUPP[]="document-attributes-supported:\tdefault-medium document-format"; +static char JOB_ATT_SUPP[]="job-attributes-supported:\t"; +static char DDX_DIR[]="ddx-config"; + +static int +RasterInitContext( + XpContextPtr pCon) +{ + char *configFileName, *val, *attrStr; + RasterContextPrivPtr pConPriv; + XpDriverFuncsPtr pFuncs; + + /* + * Initialize the attribute store for this printer. + */ + XpInitAttributes( pCon ); + + /* + * Validate the attributes + */ + RasterValidateAttrs( pCon ); + + + /* + * Initialize the function pointers + */ + pFuncs = &( pCon->funcs ); + pFuncs->StartJob = StartJob; + pFuncs->EndJob = EndJob; + pFuncs->StartDoc = StartDoc; + pFuncs->EndDoc = EndDoc; + pFuncs->StartPage = StartPage; + pFuncs->EndPage = EndPage; + pFuncs->PutDocumentData = DocumentData; + pFuncs->GetDocumentData = GetDocumentData; + pFuncs->DestroyContext = RasterDestroyContext; + pFuncs->GetAttributes = RasterGetAttributes; + pFuncs->GetOneAttribute = RasterGetOneAttribute; + pFuncs->SetAttributes = RasterSetAttributes; + pFuncs->AugmentAttributes = RasterAugmentAttributes; + pFuncs->GetMediumDimensions = RasterMediumDimensions; + pFuncs->GetReproducibleArea = RasterReproducibleArea; + + /* + * Set up the context privates + */ + pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + pConPriv->jobFileName = (char *)NULL; + pConPriv->pageFileName = (char *)NULL; + pConPriv->preRasterFileName = (char *)NULL; + pConPriv->postRasterFileName = (char *)NULL; + pConPriv->noRasterFileName = (char *)NULL; + pConPriv->pJobFile = (FILE *)NULL; + pConPriv->pPageFile = (FILE *)NULL; + pConPriv->pPreRasterFile = (FILE *)NULL; + pConPriv->pPostRasterFile = (FILE *)NULL; + pConPriv->pNoRasterFile = (FILE *)NULL; + + pConPriv->getDocClient = (ClientPtr)NULL; + pConPriv->getDocBufSize = 0; + + /* + * Get the configuration information for the context's printer + */ + configFileName = XpGetOneAttribute( pCon, XPPrinterAttr, + "xp-ddx-config-file-name" ); + if(configFileName && strlen(configFileName)) + { + if( configFileName[0] == '/' ) + pConPriv->config = XrmGetFileDatabase( configFileName ); + else + { + char *configDir, *configFilePath; + + configDir = XpGetConfigDir(FALSE); + configFilePath = (char *)malloc((strlen(configDir) + + strlen(DDX_DIR) + + strlen(RASTER_DRIV_NAME) + + strlen(configFileName) + + 4)* sizeof(char)); + sprintf(configFilePath, "%s/%s/%s/%s", configDir, DDX_DIR, + RASTER_DRIV_NAME, configFileName); + pConPriv->config = XrmGetFileDatabase(configFilePath); + free(configDir); + free(configFilePath); + } + } + else + pConPriv->config = (XrmDatabase)NULL; + + /* + * Add our own attribute initialization + */ + /* + * document-attributes-supported + */ + val = XpGetOneAttribute(pCon, XPServerAttr, "document-attributes-supported"); + if((attrStr = (char *)xalloc(strlen(val) + strlen(DOC_ATT_SUPP) + 4)) == + (char *)NULL) + return BadAlloc; + sprintf(attrStr, "*%s %s", DOC_ATT_SUPP, val); + XpAugmentAttributes(pCon, XPPrinterAttr, attrStr); + xfree(attrStr); + + /* + * job-attributes-supported + */ + val = XpGetOneAttribute(pCon, XPServerAttr, "job-attributes-supported"); + if((attrStr = (char *)xalloc(strlen(val) + strlen(JOB_ATT_SUPP) + 4)) == + (char *)NULL) + return BadAlloc; + sprintf(attrStr, "*%s %s", JOB_ATT_SUPP, val); + XpAugmentAttributes(pCon, XPPrinterAttr, attrStr); + xfree(attrStr); + + /* + * PageAttributesSupported + */ + XpAugmentAttributes(pCon, XPPrinterAttr, "*xp-page-attributes-supported:"); + + return Success; +} + + + +static Bool +RasterDestroyContext( + XpContextPtr pCon) +{ + RasterContextPrivPtr pConPriv = (RasterContextPrivPtr) + dixLookupPrivate(&pCon->devPrivates, RasterContextPrivateKey); + + /* + * Clean up the temporary files + */ + FreePageFiles( pConPriv ); + + if( pConPriv->pJobFile != (FILE *)NULL ) + { + fclose( pConPriv->pJobFile ); + pConPriv->pJobFile = (FILE *)NULL; + } + if( pConPriv->jobFileName != (char *)NULL ) + { + unlink( pConPriv->jobFileName ); + Xfree( pConPriv->jobFileName ); + } + if(pConPriv->config) + { + XrmDestroyDatabase(pConPriv->config); + pConPriv->config = (XrmDatabase)NULL; + } + + XpDestroyAttributes( pCon ); + return Success; +} + +static char * +RasterGetAttributes( + XpContextPtr pContext, + XPAttributes class) +{ + return XpGetAttributes( pContext, class ); +} + +static char * +RasterGetOneAttribute( + XpContextPtr pContext, + XPAttributes class, + char *attr) +{ + return XpGetOneAttribute( pContext, class, attr ); +} + +static int +RasterSetAttributes(XpContextPtr pCon, + XPAttributes class, + char *attributes) +{ + return XpSetAttributes( pCon, class, attributes ); +} + +static int +RasterAugmentAttributes( + XpContextPtr pCon, + XPAttributes class, + char *attributes) +{ + return XpAugmentAttributes( pCon, class, attributes ); +} + +static void +FreePageFiles( + RasterContextPrivPtr pConPriv) +{ + if(pConPriv->pPageFile != (FILE *)NULL) + { + fclose(pConPriv->pPageFile); + pConPriv->pPageFile = (FILE *)NULL; + } + if(pConPriv->pageFileName != (char *)NULL) + { + unlink(pConPriv->pageFileName); + Xfree(pConPriv->pageFileName); + pConPriv->pageFileName = (char *)NULL; + } + if(pConPriv->pPreRasterFile != (FILE *)NULL) + { + fclose(pConPriv->pPreRasterFile); + pConPriv->pPreRasterFile = (FILE *)NULL; + } + if(pConPriv->preRasterFileName != (char *)NULL) + { + unlink(pConPriv->preRasterFileName); + Xfree(pConPriv->preRasterFileName); + pConPriv->preRasterFileName = (char *)NULL; + } + if(pConPriv->pPostRasterFile != (FILE *)NULL) + { + fclose(pConPriv->pPostRasterFile); + pConPriv->pPostRasterFile = (FILE *)NULL; + } + if(pConPriv->postRasterFileName != (char *)NULL) + { + unlink(pConPriv->postRasterFileName); + Xfree(pConPriv->postRasterFileName); + pConPriv->postRasterFileName = (char *)NULL; + } + if(pConPriv->pNoRasterFile != (FILE *)NULL) + { + fclose(pConPriv->pNoRasterFile); + pConPriv->pNoRasterFile = (FILE *)NULL; + } + if(pConPriv->noRasterFileName != (char *)NULL) + { + unlink(pConPriv->noRasterFileName); + Xfree(pConPriv->noRasterFileName); + pConPriv->noRasterFileName = (char *)NULL; + } +} + +/* + * RasterCloseScreen - Call any wrapped CloseScreen function, + * and free the screen memory. + */ +static Bool +RasterCloseScreen( + int index, + ScreenPtr pScreen) +{ + Bool status = Success; + RasterScreenPrivPtr pScreenPriv = (RasterScreenPrivPtr) + dixLookupPrivate(&pScreen->devPrivates, RasterScreenPrivateKey); + + /* + * Call any wrapped CloseScreen proc. + */ + if(pScreenPriv->CloseScreen != NULL) + { + pScreen->CloseScreen = pScreenPriv->CloseScreen; + status = pScreen->CloseScreen(index, pScreen); + pScreen->CloseScreen = RasterCloseScreen; + } + + Xfree(pScreenPriv->pBits); + Xfree(pScreenPriv); + + return status; +} + +#include <signal.h> + +/* ARGSUSED */ +static void SigchldHndlr (int dummy) +{ + int status; + int olderrno = errno; + struct sigaction act; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = SigchldHndlr; + + (void) wait (&status); + + /* + * Is this really necessary? + */ + sigaction(SIGCHLD, &act, (struct sigaction *)NULL); + errno = olderrno; +} + +/* + * SystemCmd provides a wrapper for the 'system' library call. The call + * appears to be sensitive to the handling of SIGCHLD, so this wrapper + * sets the status to SIG_DFL, and then resets the established handler + * after system returns. + */ +static int +SystemCmd(char *cmdStr) +{ + int status; + struct sigaction newAct, oldAct; + sigfillset(&newAct.sa_mask); + newAct.sa_flags = 0; + newAct.sa_handler = SIG_DFL; + sigfillset(&oldAct.sa_mask); + oldAct.sa_flags = 0; + oldAct.sa_handler = SigchldHndlr; + + /* + * get the old handler, and set the action to IGN + */ + sigaction(SIGCHLD, &newAct, &oldAct); + + status = system (cmdStr); + + sigaction(SIGCHLD, &oldAct, (struct sigaction *)NULL); + return status; +} + +/* + * RasterMediumDimensions is installed in the GetMediumDimensions field + * of each raster-initialized context. + */ +static int +RasterMediumDimensions(XpContextPtr pCon, + CARD16 *width, + CARD16 *height) +{ + XpGetMediumDimensions(pCon, width, height); + return Success; +} + +/* + * RasterReproducibleArea is installed in the GetReproducibleArea field + * of each raster-initialized context. + */ +static int +RasterReproducibleArea(XpContextPtr pCon, + xRectangle *pRect) +{ + XpGetReproductionArea(pCon, pRect); + return Success; +} |