/* * XDPSpreview.c * * (c) Copyright 1990-1994 Adobe Systems Incorporated. * All rights reserved. * * Permission to use, copy, modify, distribute, and sublicense this software * and its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notices appear in all copies and that * both those copyright notices and this permission notice appear in * supporting documentation and that the name of Adobe Systems Incorporated * not be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. No trademark license * to use the Adobe trademarks is hereby granted. If the Adobe trademark * "Display PostScript"(tm) is used to describe this software, its * functionality or for any other purpose, such use shall be limited to a * statement that this software works in conjunction with the Display * PostScript system. Proper trademark attribution to reflect Adobe's * ownership of the trademark shall be given whenever any such reference to * the Display PostScript system is made. * * ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. * ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON- INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE * TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT * PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE. * * Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems * Incorporated which may be registered in certain jurisdictions * * Author: Adobe Systems Incorporated */ /* $XFree86: xc/lib/dpstk/XDPSpreview.c,v 1.2 2000/06/07 22:03:01 tsi Exp $ */ #include #include #include #include #include #include #ifndef NeXT #include #endif #include #include #include "XDPSpwraps.h" #include "dpsXcommonI.h" #include #include #if defined(hpux) || defined(AIXV3) #define SELECT_TYPE int * #else #define SELECT_TYPE fd_set * #endif #define BEGINDOCUMENTLEN 15 /* Length of "%%BeginDocument" */ #define BEGINBINARYLEN 14 /* Length of "%%BeginBinary:" */ static int ParseFileForBBox(FILE *file, XRectangle *bb); static void FillPixmapWithGray( Screen *screen, Drawable dest, XRectangle *bbox, int xOffset, int yOffset, double pixelsPerPoint, Bool createMask); static XDPSRewindFunction rewindFunction = XDPSFileRewindFunc; static DPSPointer rewindClientData = NULL; static XDPSGetsFunction getsFunction = XDPSFileGetsFunc; static DPSPointer getsClientData = NULL; int XDPSSetFileFunctions( XDPSRewindFunction rewindFunc, DPSPointer rewindData, XDPSGetsFunction getsFunc, DPSPointer getsData) { if (rewindFunc != NULL) { rewindFunction = rewindFunc; rewindClientData = rewindData; } if (getsFunc != NULL) { getsFunction = getsFunc; getsClientData = getsData; } return 0; } /* ARGSUSED */ void XDPSFileRewindFunc(FILE *f, DPSPointer data) { rewind(f); } /* ARGSUSED */ char *XDPSFileGetsFunc(char *buf, int n, FILE *f, DPSPointer data) { return fgets(buf, n, f); } void XDPSEmbeddedEPSFRewindFunc(FILE *f, DPSPointer data) { XDPSPosition *p = (XDPSPosition *) data; p->nestingLevel = 0; p->continuedLine = False; p->binaryCount = 0; if (fseek(f, p->startPos, SEEK_SET) != 0) { (void) fseek(f, 0L, SEEK_END); /* Go to the end */ } } static Bool imaging = False; char *XDPSEmbeddedGetsFunc(char *buf, int n, FILE *f, DPSPointer data) { XDPSPosition *p = (XDPSPosition *) data; int count; unsigned len; if (fgets(buf, n, f) == NULL) { if (imaging) p->startPos = -1; return NULL; } /* If previous call didn't get a whole line, we're somewhere in the middle, so don't check for comments. Also, if we're in the middle of binary data, don't look for comments either. */ len = strlen(buf); if (p->binaryCount != 0) { if (len > p->binaryCount) p->binaryCount = 0; else p->binaryCount -= len; } else if (!p->continuedLine) { if (strncmp(buf, "%%BeginDocument", BEGINDOCUMENTLEN) == 0) { p->nestingLevel++; } else if (strncmp(buf, "%%BeginBinary:", BEGINBINARYLEN) == 0) { count = sscanf(buf, "%%%%BeginBinary: %lu", &p->binaryCount); if (count != 1) p->binaryCount = 0; /* Malformed comment */ } else if (strcmp(buf, "%%EndDocument\n") == 0) { if (p->nestingLevel == 0) { if (imaging) p->startPos = ftell(f); return NULL; } else p->nestingLevel--; } } if ((int)len == n-1 && buf[n-1] != '\n') p->continuedLine = True; else p->continuedLine = False; return buf; } int XDPSCreatePixmapForEPSF( DPSContext context, Screen *screen, FILE *epsf, int depth, double pixelsPerPoint, Pixmap *pixmap, XRectangle *pixelSize, XRectangle *bbox) { Pixmap p; int width, height; XRectangle bb; if (screen == NULL || depth <= 0 || pixelsPerPoint <= 0) { return dps_status_illegal_value; } if (context == NULL) { context = XDPSGetSharedContext(DisplayOfScreen(screen)); } (*rewindFunction)(epsf, rewindClientData); if (ParseFileForBBox(epsf, &bb) == dps_status_failure) { return dps_status_failure; } width = ceil(bb.width * pixelsPerPoint); height = ceil(bb.height * pixelsPerPoint); if (width <= 0 || height <= 0) return dps_status_failure; p = XCreatePixmap(DisplayOfScreen(screen), RootWindowOfScreen(screen), width, height, depth); if (pixmap != NULL) *pixmap = p; if (pixelSize != NULL) { pixelSize->x = pixelSize->y = 0; pixelSize->width = width; pixelSize->height = height; } if (bbox != NULL) *bbox = bb; if (context != NULL) return dps_status_success; else return dps_status_no_extension; } static int ParseFileForBBox(FILE *file, XRectangle *bb) { #define BBOXLEN 14 /* Length of "%%BoundingBox:" */ #define BUFLEN 256 #define ATENDLEN 8 /* Length of "(atend)" plus one byte for \0 */ char buf[BUFLEN]; char buf2[ATENDLEN]; Bool atend = False; /* Found a %%BoundingBox: (atend) */ float x, y, r, t; int n; int nestingLevel = 0; unsigned long binaryCount = 0; Bool continuedLine = False; unsigned len; while (1) { if ((*getsFunction)(buf, BUFLEN, file, getsClientData) == NULL) { return dps_status_failure; } len = strlen(buf); /* If in binary data or continued line, ignore everything */ if (binaryCount != 0) { if (len > binaryCount) binaryCount = 0; else binaryCount -= len; } else if (!continuedLine) { if (strncmp(buf, "%%BeginBinary:", BEGINBINARYLEN) == 0) { n = sscanf(buf, "%%%%BeginBinary: %lu", &binaryCount); if (n != 1) binaryCount = 0; /* Malformed comment */ } else if (strncmp(buf, "%%BeginDocument", BEGINDOCUMENTLEN) == 0) { nestingLevel++; } else if (strcmp(buf, "%%EndDocument\n") == 0) { nestingLevel--; /* Only check for bounding box comments at nesting level 0 */ } else if (nestingLevel == 0) { /* If we haven't already hit an (atend), the end of the comments is a good place to stop looking for the bbox */ if (!atend && (strcmp(buf, "%%EndComments\n") == 0 || strcmp(buf, "%%EndProlog\n") == 0)) { return dps_status_failure; } if (strncmp(buf, "%%BoundingBox:", BBOXLEN) == 0) { n = sscanf(buf, "%%%%BoundingBox: %f %f %f %f", &x, &y, &r, &t); if (n != 4) { n = sscanf(buf, "%%%%BoundingBox: %7s", buf2); if (n == 1 && strcmp(buf2, "(atend)") == 0) { atend = True; } else return dps_status_failure; } else { bb->x = (int) x; bb->y = (int) y; bb->width = r - bb->x; if ((float)((int) r) != r) bb->width++; bb->height = t - bb->y; if ((float)((int) t) != t) bb->height++; return dps_status_success; } } } } /* See if this line fills the buffer */ if (len == BUFLEN-1 && buf[BUFLEN-1] != '\n') continuedLine = True; } #undef ATENDLEN #undef BUFLEN #undef BBOXLEN } #define mmPerPoint (25.4/72.0) double XDPSPixelsPerPoint(Screen *screen) { return (float) WidthOfScreen(screen) * mmPerPoint / (float) WidthMMOfScreen(screen); } static int timeStart = 200, maxDoubles = 3; void XDPSSetImagingTimeout(int timeout, int max) { timeStart = timeout; maxDoubles = max; } typedef struct _StatusInfo { DPSContext ctxt; DPSPointer cookie; Bool *doneFlag; unsigned long startReqNum, endReqNum; XDPSStatusProc oldProc; struct _StatusInfo *next, *prev; } StatusInfo; static StatusInfo *StatusList; static void SetUpStatusVariables( DPSContext context, DPSPointer cookie, Bool *doneFlag, unsigned long startReq, XDPSStatusProc oldProc) { StatusInfo *info = (StatusInfo *) malloc(sizeof(StatusInfo)); info->ctxt = context; info->cookie = cookie; info->doneFlag = doneFlag; info->startReqNum = startReq; info->endReqNum = 0xFFFFFFFF; info->oldProc = oldProc; if (StatusList != NULL) StatusList->prev = info; info->next = StatusList; info->prev = NULL; StatusList = info; } static void SetEndReqNum( DPSContext context, unsigned long endReq) { StatusInfo *info = StatusList; while (info != NULL && info->ctxt != context) info = info->next; if (info != NULL) info->endReqNum = endReq; } static void HandlePreviewStatus( DPSContext context, int status) { unsigned long serial; Display *dpy; StatusInfo *info = StatusList; while (info != NULL && info->ctxt != context) info = info->next; if (info == NULL) return; (void) XDPSXIDFromContext(&dpy, context); serial = LastKnownRequestProcessed(dpy); /* This event is from before our imaging; send to old status proc. */ if (serial < info->startReqNum) { (*info->oldProc) (context, status); return; } /* This event is from during our imaging; ignore it */ if (serial < info->endReqNum) return; /* This event is juuuuust right. */ if (status == PSFROZEN) *info->doneFlag = True; } static int FinishUp( DPSContext context, DPSPointer cookie) { static char restorebuf[] = "\n$Adobe$DPS$Lib$Dict /EPSFsave get restore grestore\n"; StatusInfo *info = StatusList; int err; /* Check the results of the imaging: Get the error status and restore the context */ _DPSPCheckForError(context, &err); /* Can't do this is a wrap because of restore semantics */ DPSWritePostScript(context, restorebuf, strlen(restorebuf)); (void) XDPSPopContextParameters(cookie); /* See if we have an info record and delete it if so */ while (info != NULL && info->ctxt != context) info = info->next; if (info != NULL) { if (info == StatusList) StatusList = info->next; else info->prev->next = info->next; if (info->next != NULL) info->next->prev = info->prev; XDPSRegisterStatusProc(context, info->oldProc); free(info); } if (err) return dps_status_postscript_error; else return dps_status_success; } int XDPSCheckImagingResults( DPSContext context, Screen *screen) { StatusInfo *info = StatusList; int status; if (context == NULL) { context = XDPSGetSharedContext(DisplayOfScreen(screen)); if (context == NULL) return dps_status_no_extension; } while (info != NULL && info->ctxt != context) info = info->next; if (info == NULL) return dps_status_illegal_value; status = XDPSGetContextStatus(context); if (status != PSFROZEN) return dps_status_imaging_incomplete; XDPSUnfreezeContext(context); return FinishUp(context, info->cookie); } static void msleep(int ms) { struct timeval incr; incr.tv_sec = ms / 1000; incr.tv_usec = (ms % 1000) * 1000; (void) select (0, (SELECT_TYPE) NULL, (SELECT_TYPE) NULL, (SELECT_TYPE) NULL, &incr); } int XDPSImageFileIntoDrawable( DPSContext context, Screen *screen, Drawable dest, FILE *file, int drawableHeight, int drawableDepth, XRectangle *bbox, int xOffset, int yOffset, double pixelsPerPoint, Bool clear, Bool createMask, Bool waitForCompletion, Bool *doneFlag) { #define BUFSIZE 256 #define EXECLEN 6 char buf[BUFSIZE]; static char eobuf[] = "\n$Adobe$DPS$Lib$Dict /execSuccess true put\n\ stop\n\ Magic end of data line )))))))))) 99#2 2#99 // 7gsad,32h4ghNmndFgj2\n"; XDPSStandardColormap maskMap; XDPSStandardColormap rgbMap; unsigned int flags = 0; int status; Bool inited; DPSPointer cookie; int doublings; int ms; XDPSStatusProc oldProc; unsigned long startReqNum = 0, endReqNum; if (screen == NULL || dest == None || drawableHeight <= 0 || drawableDepth <= 0 || pixelsPerPoint <= 0) { return dps_status_illegal_value; } if (context == NULL) { context = XDPSGetSharedContext(DisplayOfScreen(screen)); if (context == NULL) { FillPixmapWithGray(screen, dest, bbox, xOffset, yOffset, pixelsPerPoint, createMask); return dps_status_no_extension; } } (*rewindFunction)(file, rewindClientData); if (!waitForCompletion) { DPSWaitContext(context); /* Any status events before this point go to old handler */ startReqNum = NextRequest(DisplayOfScreen(screen)); } status = _XDPSTestComponentInitialized(context, dps_init_bit_preview, &inited); if (status != dps_status_success) return status; if (!inited) { (void) _XDPSSetComponentInitialized(context, dps_init_bit_preview); _DPSPDefineExecFunction(context); } if (createMask) { if (drawableDepth != 1) return dps_status_illegal_value; maskMap.colormap = None; maskMap.red_max = 1; maskMap.red_mult = -1; maskMap.base_pixel = 1; rgbMap.colormap = None; rgbMap.red_max = rgbMap.green_max = rgbMap.blue_max = rgbMap.red_mult = rgbMap.green_mult = rgbMap.blue_mult = rgbMap.base_pixel = 0; flags = XDPSContextGrayMap | XDPSContextRGBMap; } status = XDPSPushContextParameters(context, screen, drawableDepth, dest, drawableHeight, &rgbMap, &maskMap, flags | XDPSContextScreenDepth | XDPSContextDrawable, &cookie); if (status != dps_status_success) return status; _DPSPSetMatrix(context, xOffset, yOffset, pixelsPerPoint); if (clear) _DPSPClearArea(context, (int) bbox->x, (int) bbox->y, (int) bbox->width, (int) bbox->height); if (createMask) _DPSPSetMaskTransfer(context); /* Prepare to read PostScript code */ _DPSPSaveBeforeExec(context, !waitForCompletion); DPSWritePostScript(context, "\nexec\n", EXECLEN); imaging = True; while ((*getsFunction)(buf, BUFSIZE, file, getsClientData) != NULL) { DPSWritePostScript(context, buf, strlen(buf)); } imaging = False; /* This marks the end of the data stream */ DPSWritePostScript(context, eobuf, strlen(eobuf)); if (!waitForCompletion) { *doneFlag = False; oldProc = XDPSRegisterStatusProc(context, HandlePreviewStatus); SetUpStatusVariables(context, cookie, doneFlag, startReqNum, oldProc); XDPSSetStatusMask(context, 0, 0, PSFROZENMASK); ms = timeStart; /* Check for done until we run out of time */ doublings = 0; while (1) { if (XDPSGetContextStatus(context) == PSFROZEN) { waitForCompletion = True; XDPSUnfreezeContext(context); break; } if (doublings >= maxDoubles) break; /* Wait a while */ msleep(ms); ms *= 2; doublings++; } } /* If previous decided imaging is done, it changed waitForCompletion */ if (waitForCompletion) return FinishUp(context, cookie); else { endReqNum = NextRequest(DisplayOfScreen(screen)) - 1; SetEndReqNum(context, endReqNum); return dps_status_imaging_incomplete; } #undef EXECLEN #undef BUFSIZE } static void FillPixmapWithGray( Screen *screen, Drawable dest, XRectangle *bbox, int xOffset, int yOffset, double pixelsPerPoint, Bool createMask) { int width, height, x, y; GC gc; XGCValues v; static char grayBits[] = {0x01, 0x02}; Pixmap grayStipple; Display *dpy = DisplayOfScreen(screen); width = ceil(bbox->width * pixelsPerPoint); height = ceil(bbox->height * pixelsPerPoint); x = (bbox->x + xOffset) * pixelsPerPoint; y = (bbox->y + yOffset) * pixelsPerPoint; if (createMask) { v.foreground = 1; v.function = GXcopy; gc = XCreateGC(dpy, dest, GCForeground | GCFunction, &v); XFillRectangle(dpy, dest, gc, x, y, width, height); XFreeGC(dpy, gc); return; } grayStipple = XCreateBitmapFromData(dpy, dest, grayBits, 2, 2); v.foreground = BlackPixelOfScreen(screen); v.background = WhitePixelOfScreen(screen); v.function = GXcopy; v.stipple = grayStipple; v.fill_style = FillOpaqueStippled; gc = XCreateGC(dpy, dest, GCForeground | GCBackground | GCFunction | GCStipple | GCFillStyle, &v); XFillRectangle(dpy, dest, gc, x, y, width, height); XFreeGC(dpy, gc); XFreePixmap(dpy, grayStipple); }