|
|
1.1 root 1: //--------------------------------------------------------------------------
2: //
3: // Module Name: ESCAPE.C
4: //
5: // Brief Description: This module contains the PSCRIPT driver's Escape
6: // functions and related routines.
7: //
8: // Author: Kent Settle (kentse)
9: // Created: 08-Feb-1991
10: //
11: // Copyright (c) 1991 - 1992 Microsoft Corporation
12: //
13: // This routine contains routines to handle the various Escape functions.
14: //--------------------------------------------------------------------------
15:
16: #include "pscript.h"
17: #include "enable.h"
18:
19: // DrawEscape to output encapsulated PostScript data.
20:
21: typedef struct tagEPSDATA
22: {
23: DWORD cbData; // Size of the structure and EPS data in bytes.
24: DWORD nVersion; // Language level, e.g. 1 for level 1 PostScript.
25: POINTL aptl[3]; // Output parallelogram in 28.4 FIX device coords.
26: // This is followed by the EPS data.
27: } EPSDATA, *PEPSDATA;
28:
29: FLOAT FixToFloat(FIX);
30: BOOL bDoEpsXform(PDEVDATA, PEPSDATA);
31: extern BOOL bDoClipObj(PDEVDATA, CLIPOBJ *, RECTL *, RECTL *, BOOL *, BOOL *, DWORD);
32:
33: #define ESC_NOT_SUPPORTED 0xFFFFFFFF
34: #define ESC_IS_SUPPORTED 0x00000001
35:
36: //--------------------------------------------------------------------------
37: // ULONG DrvEscape (pso, iEsc, cjIn, pvIn, cjOut, pvOut)
38: // SURFOBJ *pso;
39: // ULONG iEsc;
40: // ULONG cjIn;
41: // PVOID pvIn;
42: // ULONG cjOut;
43: // PVOID pvOut;
44: //
45: // This entry point serves more than one function call. The particular
46: // function depends on the value of the iEsc parameter.
47: //
48: // In general, the DrvEscape functions will be device specific functions
49: // that don't belong in a device independent DDI. This entry point is
50: // optional for all devices.
51: //
52: // Parameters:
53: // pso
54: // Identifies the surface that the call is directed to.
55: //
56: // iEsc
57: // Specifies the particular function to be performed. The meaning of
58: // the remaining arguments depends on this parameter. Allowed values
59: // are as follows.
60: //
61: // ESC_QUERYESCSUPPORT
62: // Asks if the driver supports a particular escape function. The
63: // escape function number is a ULONG pointed to by pvIn. A non-zero
64: // value should be returned if the function is supported. cjIn has a
65: // value of 4. The arguments cjOut and pvOut are ignored.
66: //
67: // ESC_PASSTHROUGH
68: // Passes raw device data to the device driver. The number of BYTEs of
69: // raw data is indicated by cjIn. The data is pointed to by pvIn. The
70: // arguments cjOut and pvOut are ignored. Returns the number of BYTEs
71: // written if the function is successful. Otherwise, it returns zero
72: // and logs an error code.
73: // cjIn
74: // The size, in BYTEs, of the data buffer pointed to by pvIn.
75: //
76: // pvIn
77: // The input data for the call. The format of the input data depends
78: // on the function specified by iEsc.
79: //
80: // cjOut
81: // The size, in BYTEs, of the output data buffer pointed to by pvOut.
82: // The driver must never write more than this many BYTEs to the output
83: // buffer.
84: //
85: // pvOut
86: // The output buffer for the call. The format of the output data depends
87: // on the function specified by iEsc.
88: //
89: // Returns:
90: // Depends on the function specified by iEsc. In general, the driver should
91: // return 0xFFFFFFFF if an unsupported function is called.
92: //
93: // History:
94: // 02-Feb-1991 -by- Kent Settle (kentse)
95: // Wrote it.
96: //--------------------------------------------------------------------------
97:
98: ULONG DrvEscape (pso, iEsc, cjIn, pvIn, cjOut, pvOut)
99: SURFOBJ *pso;
100: ULONG iEsc;
101: ULONG cjIn;
102: PVOID pvIn;
103: ULONG cjOut;
104: PVOID pvOut;
105: {
106: PDEVDATA pdev;
107: DWORD cWritten;
108: FLOAT *pfloat;
109: LONG ytmp;
110: ULONG ulRet = ESC_NOT_SUPPORTED;
111:
112: // handle each case depending on which escape function is being asked for.
113:
114: switch (iEsc)
115: {
116: case QUERYESCSUPPORT:
117: // when querying escape support, the function in question is
118: // passed in the ULONG passed in pvIn.
119:
120: switch (*(PULONG)pvIn)
121: {
122: case QUERYESCSUPPORT:
123: case PASSTHROUGH:
124: case POSTSCRIPT_PASSTHROUGH:
125: case GETDEVICEUNITS:
126: return(ESC_IS_SUPPORTED);
127:
128: case SETCOPYCOUNT:
129: return(MAX_COPIES);
130:
131: default:
132: // return 0 if the escape in question is not supported.
133:
134: return(0);
135: }
136:
137: case POSTSCRIPT_PASSTHROUGH:
138: case PASSTHROUGH:
139: // get the pointer to our DEVDATA structure and make sure it is ours.
140:
141: pdev = (PDEVDATA) pso->dhpdev;
142:
143: if (bValidatePDEV(pdev) == FALSE)
144: {
145: RIP("PSCRIPT!DrvEscape: invalid pdev.\n");
146: SetLastError(ERROR_INVALID_PARAMETER);
147: ulRet = 0;
148: break;
149: }
150:
151: // do nothing if the document has been cancelled.
152:
153: if (pdev->dwFlags & PDEV_CANCELDOC)
154: return(*(LPWORD)pvIn);
155:
156: if (iEsc == POSTSCRIPT_PASSTHROUGH)
157: {
158: // initialize the current graphics state.
159:
160: init_cgs(pdev);
161:
162: if (pdev->dwFlags & PDEV_WITHINPAGE)
163: {
164: ps_restore(pdev, FALSE);
165: pdev->dwFlags &= ~PDEV_WITHINPAGE;
166: }
167:
168: if (pdev->dwFlags & PDEV_PROCSET)
169: {
170: PrintString(pdev, "end\n");
171: pdev->dwFlags &= ~PDEV_PROCSET;
172: }
173: }
174:
175: pdev->dwFlags |= PDEV_RAWDATASENT;
176:
177: // just write out what is in the buffer. do NOT add a
178: // header to the output. that would be wrong.
179:
180: bPSFlush(pdev);
181:
182: cjIn = (*(LPWORD)pvIn);
183: pvIn = (LPVOID)(((LPWORD)pvIn) + 1);
184:
185: if (!WritePrinter(pdev->hPrinter, pvIn, cjIn, &cWritten))
186: {
187: DbgPrint("PSCRIPT!DrvEscape PASSTHROUGH: WritePrinter failed.\n");
188: ulRet = 0;
189: break;
190: }
191: else
192: ulRet = cWritten;
193:
194: break;
195:
196: case GETDEVICEUNITS:
197: // get the pointer to our DEVDATA structure and make sure it is ours.
198:
199: pdev = (PDEVDATA) pso->dhpdev;
200:
201: if ((bValidatePDEV(pdev) == FALSE) || (cjOut < (sizeof(LONG) * 4)))
202: {
203: RIP("PSCRIPT!DrvEscape GETDEVICEUNITS: invalid pdev or cjOut.\n");
204: SetLastError(ERROR_INVALID_PARAMETER);
205: ulRet = 0;
206: break;
207: }
208:
209: pfloat = (FLOAT *)pvOut;
210:
211: // fill in the first two bytes with the resolution we actually
212: // send to the printer.
213:
214: *pfloat++ =(FLOAT)(pdev->CurForm.imagearea.right -
215: pdev->CurForm.imagearea.left);
216:
217: // handle landscape vs portrait.
218:
219: ytmp = pdev->CurForm.imagearea.bottom -
220: pdev->CurForm.imagearea.top;
221:
222: #ifndef LANDSCAPE_270_ROTATE // 90 degree case.
223: if ((pdev->psdm.dm.dmFields & DM_ORIENTATION) &&
224: (pdev->psdm.dm.dmOrientation == DMORIENT_LANDSCAPE))
225: ytmp = -ytmp;
226: #endif
227:
228: *pfloat++ = (FLOAT)ytmp;
229:
230: // now fill in the offset of our origin from the upper left
231: // corner of the piece of paper.
232:
233: *pfloat++ = (FLOAT)pdev->CurForm.imagearea.left;
234:
235: ytmp = pdev->CurForm.imagearea.top;
236:
237: *pfloat = (FLOAT)ytmp;
238:
239: ulRet = TRUE;
240: break;
241:
242: case SETCOPYCOUNT:
243: // the copy count is a DWORD count sitting at pvIn.
244:
245: if (!pvIn)
246: {
247: ulRet = 0;
248: break;
249: }
250:
251: // get the pointer to our DEVDATA structure and make sure it is ours.
252:
253: pdev = (PDEVDATA) pso->dhpdev;
254:
255: if (bValidatePDEV(pdev) == FALSE)
256: {
257: RIP("PSCRIPT!DrvEscape: invalid pdev.\n");
258: SetLastError(ERROR_INVALID_PARAMETER);
259: ulRet = 0;
260: break;
261: }
262:
263: // if user specified zero or one copy, do nothing. one
264: // copy will be printed by default.
265:
266: if (*(DWORD *)pvIn <= MIN_COPIES)
267: {
268: // let the caller know how many copies we will do.
269:
270: pdev->cCopies = 1;
271:
272: if (pvOut)
273: *(DWORD *)pvOut = pdev->cCopies;
274:
275: ulRet = TRUE;
276: break;
277: }
278:
279: // we have a positive number of copies. let's set a limit.
280:
281: pdev->cCopies = min(*(DWORD *)pvIn, MAX_COPIES);
282:
283: // let the caller know how many copies we will do.
284:
285: if (pvOut)
286: *(DWORD *)pvOut = pdev->cCopies;
287:
288: ulRet = TRUE;
289: break;
290:
291: default:
292: // if we get to the default case, we have been passed an
293: // unsupported escape function number.
294:
295: DbgPrint("PSCRIPT!DrvEscape %x ESC_NOT_SUPPORTED.\n", iEsc);
296: ulRet = ESC_NOT_SUPPORTED;
297: break;
298:
299: }
300:
301: return(ulRet);
302: }
303:
304: //--------------------------------------------------------------------------
305: // ULONG DrvDrawEscape(
306: // SURFOBJ *pso,
307: // ULONG iEsc,
308: // CLIPOBJ *pco,
309: // RECTL *prcl,
310: // ULONG cjIn,
311: // PVOID pvIn);
312: //
313: // Supports the ESCAPSULATED_POSTSCRIPT escape.
314: //
315: // History:
316: // Sat May 08 13:27:52 1993 -by- Hock San Lee [hockl]
317: // Wrote it.
318: //--------------------------------------------------------------------------
319:
320: ULONG DrvDrawEscape(
321: SURFOBJ *pso,
322: ULONG iEsc,
323: CLIPOBJ *pco,
324: RECTL *prcl,
325: ULONG cjIn,
326: PVOID pvIn)
327: {
328: PDEVDATA pdev;
329: DWORD cWritten;
330: PEPSDATA pEpsData;
331: BOOL bRet;
332: BOOL bFirstClipPass; // TRUE 1st call to bDoClipObj.
333: BOOL bMoreClipping; // TRUE if more clipping to enumerate.
334: BOOL bClipping; // TRUE if clipping being done.
335:
336: // handle each case depending on which escape function is being asked for.
337:
338: switch (iEsc)
339: {
340: case QUERYESCSUPPORT:
341: // when querying escape support, the function in question is
342: // passed in the ULONG passed in pvIn.
343:
344: switch (*(PULONG)pvIn)
345: {
346: case QUERYESCSUPPORT:
347: case ENCAPSULATED_POSTSCRIPT:
348: return(ESC_IS_SUPPORTED);
349:
350: default:
351: // return 0 if the escape in question is not supported.
352: return(0);
353: }
354:
355: case ENCAPSULATED_POSTSCRIPT:
356:
357: // get the pointer to our DEVDATA structure and make sure it is ours.
358:
359: pdev = (PDEVDATA) pso->dhpdev;
360:
361: if (bValidatePDEV(pdev) == FALSE)
362: {
363: RIP("PSCRIPT!DrvDrawEscape: invalid pdev.\n");
364: SetLastError(ERROR_INVALID_PARAMETER);
365: return(0);
366: }
367:
368: // get the encapsulated PostScript data.
369:
370: pEpsData = (PEPSDATA) pvIn;
371:
372: // make sure that the driver can handle the eps language level.
373:
374: if ((pdev->pntpd->LangLevel < pEpsData->nVersion)
375: && !(pdev->pntpd->LangLevel == 0 && pEpsData->nVersion <= 1))
376: {
377: SetLastError(ERROR_NOT_SUPPORTED);
378: return(0);
379: }
380:
381: // set up the clip path.
382:
383: bFirstClipPass = TRUE;
384: bMoreClipping = TRUE;
385:
386: while (bMoreClipping)
387: {
388: if (bClipping = bDoClipObj(pdev, pco, NULL, NULL,
389: &bMoreClipping, &bFirstClipPass,
390: 25))
391: ps_clip(pdev, TRUE);
392:
393: // prepare for the included EPS data.
394:
395: ps_begin_eps(pdev);
396:
397: // set up the transform needed to map the EPS to the device
398: // parallelogram.
399: // We ignore prcl here and assume that it is at (0,0).
400:
401: if (!bDoEpsXform(pdev, pEpsData))
402: {
403: RIP("PSCRIPT!DrvDrawEscape: invalid xform.\n");
404: SetLastError(ERROR_INVALID_PARAMETER);
405: ps_end_eps(pdev);
406: return(0);
407: }
408:
409: // write out the EPS data. The EPS data is assumed to begin
410: // with %%BeginDocument as recommanded in the DSC version 3.0
411: // by Adobe.
412:
413: bPSFlush(pdev);
414: bRet = WritePrinter(pdev->hPrinter,
415: (PBYTE) pEpsData + sizeof(EPSDATA),
416: pEpsData->cbData - sizeof(EPSDATA),
417: &cWritten);
418: if (!bRet)
419: DbgPrint("PSCRIPT!DrvDrawEscape ENCAPSULATED_POSTSCRIPT: WritePrinter failed.\n");
420:
421: // restore state and cleanup stacks.
422:
423: ps_end_eps(pdev);
424:
425: if (bClipping)
426: ps_restore(pdev, TRUE);
427:
428: }
429:
430: return(bRet ? 1 : 0);
431:
432: default:
433: // if we get to the default case, we have been passed an
434: // unsupported escape function number.
435:
436: DbgPrint("PSCRIPT!DrvDrawEscape %x ESC_NOT_SUPPORTED.\n", iEsc);
437:
438: return(ESC_NOT_SUPPORTED);
439: }
440: }
441:
442: BOOL bDoEpsXform(pdev, pEpsData)
443: PDEVDATA pdev;
444: PEPSDATA pEpsData;
445: {
446: PBYTE pbEps, pbEpsEnd, pbBoundingBox;
447: FLOAT aeBoundingBox[4]; // bl.x, bl.y, tr.x, tr.y
448: XFORM xform;
449: PS_FIX psfxM11, psfxM12, psfxM21, psfxM22, psfxdx, psfxdy;
450: int i;
451: BOOL bIsNegative;
452: POINTE apteDst[3], apteSrc[3];
453:
454: // look for the string %%BoundingBox:
455:
456: pbEps = (PBYTE) pEpsData + sizeof(EPSDATA);
457: pbEpsEnd = (PBYTE) pEpsData + pEpsData->cbData - 1;
458:
459: pbBoundingBox = pbEps;
460: while (pbBoundingBox <= pbEpsEnd)
461: {
462: if (!memcmp(pbBoundingBox, "%%BoundingBox:", 14))
463: {
464: pbBoundingBox += 14;
465:
466: // store the bounding box coordinates in aeBoundingBox[].
467:
468: for (i = 0; i < 4; i++)
469: {
470: // initialize bounding box.
471:
472: aeBoundingBox[i] = 0.0f;
473:
474: // skip white space.
475:
476: while (*pbBoundingBox == ' ' || *pbBoundingBox == '\t')
477: pbBoundingBox++;
478:
479: // get sign.
480:
481: if (*pbBoundingBox == '-')
482: {
483: pbBoundingBox++;
484: bIsNegative = TRUE;
485: }
486: else
487: bIsNegative = FALSE;
488:
489: // if this is not an integer, it may be an (atend) and
490: // the bounding box is at the end of the EPS data.
491:
492: if (!(*pbBoundingBox >= '0' && *pbBoundingBox <= '9' || *pbBoundingBox == '.'))
493: goto find_bounding_box;
494:
495: // get integer.
496:
497: while (*pbBoundingBox >= '0' && *pbBoundingBox <= '9')
498: {
499: aeBoundingBox[i] = aeBoundingBox[i] * 10.0f
500: + (FLOAT) (int) (*pbBoundingBox - '0');
501: pbBoundingBox++;
502: }
503:
504: // get fraction if any.
505:
506: if (*pbBoundingBox == '.')
507: {
508: FLOAT eDiv;
509:
510: pbBoundingBox++; // skip '.'
511:
512: eDiv = 10.0f;
513: while (*pbBoundingBox >= '0' && *pbBoundingBox <= '9')
514: {
515: aeBoundingBox[i] += (FLOAT) (int) (*pbBoundingBox - '0')
516: / eDiv;
517: eDiv *= 10.0f;
518: pbBoundingBox++;
519: }
520: }
521:
522: if (bIsNegative)
523: aeBoundingBox[i] = aeBoundingBox[i] * -1.0f;
524: }
525: break; // got it!
526: }
527: else
528: pbBoundingBox++;
529:
530: // look for the '%' character.
531:
532: find_bounding_box:
533:
534: while (*pbBoundingBox != '%' && pbBoundingBox <= pbEpsEnd)
535: pbBoundingBox++;
536: }
537:
538: if (pbBoundingBox > pbEpsEnd)
539: {
540: RIP("PSCRIPT!bDoEpsXform: invalid EPS bounding box.\n");
541: SetLastError(ERROR_INVALID_PARAMETER);
542: return(FALSE);
543: }
544:
545: // convert the parallelogram to PostScript coordinates (FLOAT, 72dpi).
546:
547: apteDst[0].x = XE72DPI(FixToFloat(pEpsData->aptl[0].x)); // left u0
548: apteDst[0].y = YE72DPI(FixToFloat(pEpsData->aptl[0].y)); // top v0
549: apteDst[1].x = XE72DPI(FixToFloat(pEpsData->aptl[1].x)); // right u1
550: apteDst[1].y = YE72DPI(FixToFloat(pEpsData->aptl[1].y)); // top v1
551: apteDst[2].x = XE72DPI(FixToFloat(pEpsData->aptl[2].x)); // left u2
552: apteDst[2].y = YE72DPI(FixToFloat(pEpsData->aptl[2].y)); // bottom v2
553:
554: apteSrc[0].x = aeBoundingBox[0]; // left x0
555: apteSrc[0].y = aeBoundingBox[3]; // top y0
556: apteSrc[1].x = aeBoundingBox[2]; // right x1
557: apteSrc[1].y = aeBoundingBox[3]; // top y1
558: apteSrc[2].x = aeBoundingBox[0]; // left x2
559: apteSrc[2].y = aeBoundingBox[1]; // bottom y2
560:
561: // Here is the transform equation from source EPS parallelogram
562: // [(x0,y0) (x1,y1) (x2,y2)] to the device parallelogram
563: // [(u0,v0) (u1,v1) (u2,v2)]:
564: //
565: // (u) (u0) [(x) (x0)]
566: // ( ) = ( ) + M * [( ) - ( )]
567: // (v) (v0) [(y) (y0)]
568: //
569: // where
570: //
571: // [(u1-u0)/(x1-x0) (u2-u0)/(y2-y0)]
572: // M = [ ]
573: // [(v1-v0)/(x1-x0) (v2-v0)/(y2-y0)]
574:
575: xform.eM11 = (apteDst[1].x - apteDst[0].x) / (apteSrc[1].x - apteSrc[0].x);
576: xform.eM12 = (apteDst[1].y - apteDst[0].y) / (apteSrc[1].x - apteSrc[0].x);
577: xform.eM21 = (apteDst[2].x - apteDst[0].x) / (apteSrc[2].y - apteSrc[0].y);
578: xform.eM22 = (apteDst[2].y - apteDst[0].y) / (apteSrc[2].y - apteSrc[0].y);
579: xform.eDx = apteDst[0].x - xform.eM11 * apteSrc[0].x - xform.eM21 * apteSrc[0].y;
580: xform.eDy = apteDst[0].y - xform.eM12 * apteSrc[0].x - xform.eM22 * apteSrc[0].y;
581:
582: // output the transform.
583:
584: psfxM11 = ETOPSFX(xform.eM11);
585: psfxM12 = ETOPSFX(xform.eM12);
586: psfxM21 = ETOPSFX(xform.eM21);
587: psfxM22 = ETOPSFX(xform.eM22);
588: psfxdx = ETOPSFX(xform.eDx);
589: psfxdy = ETOPSFX(xform.eDy);
590:
591: PrintString(pdev, "[");
592: PrintPSFIX(pdev, 6, psfxM11, psfxM12, psfxM21, psfxM22,
593: psfxdx, psfxdy);
594: PrintString(pdev, "] concat\n");
595:
596: return(TRUE);
597: }
598:
599: FLOAT ae16[16] = { 0.0f / 16.0f, 1.0f / 16.0f, 2.0f / 16.0f, 3.0f / 16.0f,
600: 4.0f / 16.0f, 5.0f / 16.0f, 6.0f / 16.0f, 7.0f / 16.0f,
601: 8.0f / 16.0f, 9.0f / 16.0f, 10.0f / 16.0f, 11.0f / 16.0f,
602: 12.0f / 16.0f, 13.0f / 16.0f, 14.0f / 16.0f, 15.0f / 16.0f};
603:
604: // Convert 28.4 FIX to FLOAT.
605:
606: FLOAT FixToFloat(FIX fx)
607: {
608: FLOAT e;
609:
610: e = (FLOAT) ((LONG) fx >> 4);
611: e += ae16[fx & 0xF];
612:
613: return(e);
614: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.