/*
* 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$ */
#include <X11/Xlib.h>
#include <DPS/dpsXclient.h>
#include <DPS/XDPSlib.h>
#include <DPS/psops.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef NeXT
#include <unistd.h>
#endif
#include <DPS/dpsXshare.h>
#include <DPS/dpsXpreview.h>
#include "XDPSpwraps.h"
#include "dpsXcommonI.h"
#include <math.h>
#include <X11/Xos.h>
#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 <xyz> // 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);
}