Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2885 lines
70 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. Module Name:
  4. output.c
  5. Abstract:
  6. This module contains common plotter output functions to the spooler and
  7. printer.
  8. Author:
  9. 15-Nov-1993 Mon 19:36:04 updatee
  10. clean up / update / re-write / debugging information
  11. 30-Nov-1993 Tue 19:47:16 updated
  12. update coordinate system during send_page
  13. 21-Dec-1993 Tue 15:49:10 updated
  14. organizied, and restructre pen cache, remove SendDefaultPalette()
  15. [Environment:]
  16. GDI Device Driver - Plotter.
  17. [Notes:]
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #define DBG_PLOTFILENAME DbgOutput
  23. #define DBG_SENDTRAILER 0x00000001
  24. #define DBG_FLUSHBUF 0x00000002
  25. #define DBG_FINDCACHEDPEN 0x00000004
  26. #define DBG_CREATEPAL 0x00000008
  27. #define DBG_FILLTYPE 0x00000010
  28. #define DBG_PENUM 0x00000020
  29. #define DBG_GETFINALCOLOR 0x00000040
  30. #define DBG_SETCLIPWINDOW 0x00000080
  31. #define DBG_OUTPUTXYPARMS 0x00000100
  32. #define DBG_PAGE_HEADER 0x00000200
  33. #define DBG_BESTPEN 0x00000400
  34. #define DBG_BESTPEN_ALL 0x00000800
  35. DEFINE_DBGVAR(0);
  36. #define MIN_POSTER_SIZE (1024L * 1024L * 12L)
  37. #if DBG
  38. static LPSTR pHSFillTypeName[] = {
  39. "HS_HORIZONTAL",
  40. "HS_VERTICAL",
  41. "HS_FDIAGONAL",
  42. "HS_BDIAGONAL",
  43. "HS_CROSS",
  44. "HS_DIAGCROSS",
  45. "HS_SOLIDCLR",
  46. "HS_FT_USER_DEFINED"
  47. };
  48. #endif
  49. //
  50. // Local #defines and data structures only used in this file
  51. //
  52. // Define, GDI fill types and the HPGL2 code used to simulate them
  53. //
  54. static const LPSTR pHSFillType[] = {
  55. "3,#d,0", // HS_HORIZONTAL 0 /* ----- */
  56. "3,#d,90", // HS_VERTICAL 1 /* ||||| */
  57. "3,#d,135", // HS_FDIAGONAL 2 /* \\\\\ */
  58. "3,#d,45", // HS_BDIAGONAL 3 /* ///// */
  59. "4,#d,0", // HS_CROSS 4 /* +++++ */
  60. "4,#d,45", // HS_DIAGCROSS 5 /* xxxxx */
  61. "" , // HS_SOLIDCLR 6
  62. "11,#d", // HS_FT_USER_DEFINED 7
  63. };
  64. //
  65. // HTPal tells the engine what formats we support for halftoning
  66. //
  67. // ulHTOutputFormat = HT_FORMAT_4BPP
  68. // ulPrimaryOrder = PRIMARY_ORDER_CBA
  69. // flHTFlags &= ~HT_FLAG_OUTPUT_CMY
  70. //
  71. PALENTRY HTPal[] = {
  72. //
  73. // B G R F
  74. //-----------------------------
  75. { 0x00, 0x00, 0x00, 0x00 }, // 0:K
  76. { 0x00, 0x00, 0xFF, 0x00 }, // 1:R
  77. { 0x00, 0xFF, 0x00, 0x00 }, // 2:G
  78. { 0x00, 0xFF, 0xFF, 0x00 }, // 3:Y
  79. { 0xFF, 0x00, 0x00, 0x00 }, // 4:B
  80. { 0xFF, 0x00, 0xFF, 0x00 }, // 5:M
  81. { 0xFF, 0xFF, 0x00, 0x00 }, // 6:C
  82. { 0xFF, 0xFF, 0xFF, 0x00 } // 7:W
  83. };
  84. //
  85. // Define the RGB colors for the pen indices. see inc\plotgpc.h for color
  86. // assignment for the each PC_IDX_XXXX
  87. //
  88. PALENTRY PlotPenPal[PC_IDX_TOTAL] = {
  89. //
  90. // B G R F
  91. //------------------------------------------
  92. { 255,255,255, 0 }, // PC_IDX_WHITE
  93. { 0, 0, 0, 0 }, // PC_IDX_BLACK
  94. { 0, 0,255, 0 }, // PC_IDX_RED
  95. { 0,255, 0, 0 }, // PC_IDX_GREEN
  96. { 0,255,255, 0 }, // PC_IDX_YELLOW
  97. { 255, 0, 0, 0 }, // PC_IDX_BLUE
  98. { 255, 0,255, 0 }, // PC_IDX_MAGENTA
  99. { 255,255, 0, 0 }, // PC_IDX_CYAN
  100. { 0,128,255, 0 }, // PC_IDX_ORANGE
  101. { 0,192,255, 0 }, // PC_IDX_BROWN
  102. { 255, 0,128, 0 } // PC_IDX_VIOLET
  103. };
  104. #define PE_BASE_BITS 6
  105. #define PE_BASE_NUM (DWORD)(1 << PE_BASE_BITS)
  106. #define PE_TERM_ADDER ((PE_BASE_NUM * 3) - 1)
  107. #define DEF_FORMATSTR_CHAR '#'
  108. #define TOTAL_LOCKED_PENS COUNT_ARRAY(HTPal)
  109. #define PEF_CACHE_LOCKED 0x01
  110. typedef struct _PENENTRY {
  111. WORD Next;
  112. WORD PenNumber;
  113. PALENTRY PalEntry;
  114. } PENENTRY, FAR *PPENENTRY;
  115. #define PCF_HAS_LOCKED_PENS 0x01
  116. typedef struct _PENCACHE {
  117. WORD Head;
  118. BYTE Flags;
  119. BYTE peFlags;
  120. WORD CurCount;
  121. WORD MaxCount;
  122. PENENTRY PenEntries[1];
  123. } PENCACHE, FAR *PPENCACHE;
  124. #define INTENSITY(r,g,b) (BYTE)(((WORD)((r) * 30) + \
  125. (WORD)((g) * 59) + \
  126. (WORD)((b) * 11)) / 100)
  127. #define SAME_PPALENTRY(p1,p2) (((p1)->R == (p2)->R) && \
  128. ((p1)->G == (p2)->G) && \
  129. ((p1)->B == (p2)->B))
  130. BYTE HPRGBGamma2p0[] = {
  131. 0, // 0
  132. 16, // 1
  133. 23, // 2
  134. 28, // 3
  135. 32, // 4
  136. 36, // 5
  137. 39, // 6
  138. 42, // 7
  139. 45, // 8
  140. 48, // 9
  141. 50, // 10
  142. 53, // 11
  143. 55, // 12
  144. 58, // 13
  145. 60, // 14
  146. 62, // 15
  147. 64, // 16
  148. 66, // 17
  149. 68, // 18
  150. 70, // 19
  151. 71, // 20
  152. 73, // 21
  153. 75, // 22
  154. 77, // 23
  155. 78, // 24
  156. 80, // 25
  157. 81, // 26
  158. 83, // 27
  159. 84, // 28
  160. 86, // 29
  161. 87, // 30
  162. 89, // 31
  163. 90, // 32
  164. 92, // 33
  165. 93, // 34
  166. 94, // 35
  167. 96, // 36
  168. 97, // 37
  169. 98, // 38
  170. 100, // 39
  171. 101, // 40
  172. 102, // 41
  173. 103, // 42
  174. 105, // 43
  175. 106, // 44
  176. 107, // 45
  177. 108, // 46
  178. 109, // 47
  179. 111, // 48
  180. 112, // 49
  181. 113, // 50
  182. 114, // 51
  183. 115, // 52
  184. 116, // 53
  185. 117, // 54
  186. 118, // 55
  187. 119, // 56
  188. 121, // 57
  189. 122, // 58
  190. 123, // 59
  191. 124, // 60
  192. 125, // 61
  193. 126, // 62
  194. 127, // 63
  195. 128, // 64
  196. 129, // 65
  197. 130, // 66
  198. 131, // 67
  199. 132, // 68
  200. 133, // 69
  201. 134, // 70
  202. 135, // 71
  203. 135, // 72
  204. 136, // 73
  205. 137, // 74
  206. 138, // 75
  207. 139, // 76
  208. 140, // 77
  209. 141, // 78
  210. 142, // 79
  211. 143, // 80
  212. 144, // 81
  213. 145, // 82
  214. 145, // 83
  215. 146, // 84
  216. 147, // 85
  217. 148, // 86
  218. 149, // 87
  219. 150, // 88
  220. 151, // 89
  221. 151, // 90
  222. 152, // 91
  223. 153, // 92
  224. 154, // 93
  225. 155, // 94
  226. 156, // 95
  227. 156, // 96
  228. 157, // 97
  229. 158, // 98
  230. 159, // 99
  231. 160, // 100
  232. 160, // 101
  233. 161, // 102
  234. 162, // 103
  235. 163, // 104
  236. 164, // 105
  237. 164, // 106
  238. 165, // 107
  239. 166, // 108
  240. 167, // 109
  241. 167, // 110
  242. 168, // 111
  243. 169, // 112
  244. 170, // 113
  245. 170, // 114
  246. 171, // 115
  247. 172, // 116
  248. 173, // 117
  249. 173, // 118
  250. 174, // 119
  251. 175, // 120
  252. 176, // 121
  253. 176, // 122
  254. 177, // 123
  255. 178, // 124
  256. 179, // 125
  257. 179, // 126
  258. 180, // 127
  259. 181, // 128
  260. 181, // 129
  261. 182, // 130
  262. 183, // 131
  263. 183, // 132
  264. 184, // 133
  265. 185, // 134
  266. 186, // 135
  267. 186, // 136
  268. 187, // 137
  269. 188, // 138
  270. 188, // 139
  271. 189, // 140
  272. 190, // 141
  273. 190, // 142
  274. 191, // 143
  275. 192, // 144
  276. 192, // 145
  277. 193, // 146
  278. 194, // 147
  279. 194, // 148
  280. 195, // 149
  281. 196, // 150
  282. 196, // 151
  283. 197, // 152
  284. 198, // 153
  285. 198, // 154
  286. 199, // 155
  287. 199, // 156
  288. 200, // 157
  289. 201, // 158
  290. 201, // 159
  291. 202, // 160
  292. 203, // 161
  293. 203, // 162
  294. 204, // 163
  295. 204, // 164
  296. 205, // 165
  297. 206, // 166
  298. 206, // 167
  299. 207, // 168
  300. 208, // 169
  301. 208, // 170
  302. 209, // 171
  303. 209, // 172
  304. 210, // 173
  305. 211, // 174
  306. 211, // 175
  307. 212, // 176
  308. 212, // 177
  309. 213, // 178
  310. 214, // 179
  311. 214, // 180
  312. 215, // 181
  313. 215, // 182
  314. 216, // 183
  315. 217, // 184
  316. 217, // 185
  317. 218, // 186
  318. 218, // 187
  319. 219, // 188
  320. 220, // 189
  321. 220, // 190
  322. 221, // 191
  323. 221, // 192
  324. 222, // 193
  325. 222, // 194
  326. 223, // 195
  327. 224, // 196
  328. 224, // 197
  329. 225, // 198
  330. 225, // 199
  331. 226, // 200
  332. 226, // 201
  333. 227, // 202
  334. 228, // 203
  335. 228, // 204
  336. 229, // 205
  337. 229, // 206
  338. 230, // 207
  339. 230, // 208
  340. 231, // 209
  341. 231, // 210
  342. 232, // 211
  343. 233, // 212
  344. 233, // 213
  345. 234, // 214
  346. 234, // 215
  347. 235, // 216
  348. 235, // 217
  349. 236, // 218
  350. 236, // 219
  351. 237, // 220
  352. 237, // 221
  353. 238, // 222
  354. 238, // 223
  355. 239, // 224
  356. 240, // 225
  357. 240, // 226
  358. 241, // 227
  359. 241, // 228
  360. 242, // 229
  361. 242, // 230
  362. 243, // 231
  363. 243, // 232
  364. 244, // 233
  365. 244, // 234
  366. 245, // 235
  367. 245, // 236
  368. 246, // 237
  369. 246, // 238
  370. 247, // 239
  371. 247, // 240
  372. 248, // 241
  373. 248, // 242
  374. 249, // 243
  375. 249, // 244
  376. 250, // 245
  377. 250, // 246
  378. 251, // 247
  379. 251, // 248
  380. 252, // 249
  381. 252, // 250
  382. 253, // 251
  383. 253, // 252
  384. 254, // 253
  385. 254, // 254
  386. 255 // 255
  387. };
  388. LONG
  389. BestMatchNonWhitePen(
  390. PPDEV pPDev,
  391. LONG R,
  392. LONG G,
  393. LONG B
  394. )
  395. /*++
  396. Routine Description:
  397. This functions locates the best match of a current pen given an RGB color.
  398. Arguments:
  399. pPDev - Pointer to our PDEV
  400. R - Red color
  401. G - Green color
  402. B - Blue color
  403. Return Value:
  404. LONG - Pen Index, this function assumes 0 is always white and 1
  405. up to the max are the rest of the pens.
  406. Author:
  407. 08-Feb-1994 Tue 00:23:36 created
  408. 23-Jun-1994 Thu 14:00:00 updated
  409. Updated for non-white pen match
  410. Revision History:
  411. --*/
  412. {
  413. PPENDATA pPenData;
  414. PALENTRY PenPalEntry;
  415. LONG LeastDiff;
  416. WORD ColorIdx;
  417. UINT Count;
  418. UINT RetIdx;
  419. UINT i;
  420. PLOTDBGBLK(PALENTRY RetPal)
  421. if (IS_RASTER(pPDev)) {
  422. PLOTASSERT(0, "BestMatchNonWhitePen: This is not PEN plotter",
  423. !IS_RASTER(pPDev), 0);
  424. return(0);
  425. }
  426. if (!(pPenData = (PPENDATA)pPDev->pPlotGPC->Pens.pData)) {
  427. PLOTWARN(("BestMatchNonWhitePen: pPlotGPC->Pens.pData=NULL"));
  428. return(0);
  429. }
  430. if (!(Count = (UINT)pPDev->pPlotGPC->Pens.Count)) {
  431. PLOTWARN(("BestMatchNonWhitePen: pPlotGPC->Pens.Count=0"));
  432. return(0);
  433. }
  434. PLOTDBGBLK(RetPal.R = 255)
  435. PLOTDBGBLK(RetPal.G = 255)
  436. PLOTDBGBLK(RetPal.B = 255)
  437. RetIdx = 0;
  438. LeastDiff = (3 * (256 * 256));
  439. for (i = 1; i < Count; i++, pPenData++) {
  440. if (((ColorIdx = pPenData->ColorIdx) < PC_IDX_TOTAL) &&
  441. (ColorIdx != PC_IDX_WHITE)) {
  442. LONG Temp;
  443. LONG Diff;
  444. PenPalEntry = PlotPenPal[ColorIdx];
  445. Temp = R - (LONG)((DWORD)PenPalEntry.R);
  446. Diff = Temp * Temp;
  447. Temp = G - (LONG)((DWORD)PenPalEntry.G);
  448. Diff += Temp * Temp;
  449. Temp = B - (LONG)((DWORD)PenPalEntry.B);
  450. Diff += Temp * Temp;
  451. PLOTDBG(DBG_BESTPEN_ALL,
  452. ("BestMatchNonWhitePen: %2ld: (%03ld:%03ld:%03ld) DIF=%ld",
  453. i, (DWORD)PenPalEntry.R, (DWORD)PenPalEntry.G,
  454. (DWORD)PenPalEntry.B, Diff));
  455. if (Diff < LeastDiff) {
  456. RetIdx = i;
  457. PLOTDBGBLK(RetPal = PenPalEntry)
  458. if (!(LeastDiff = Diff)) {
  459. //
  460. // We have exact match
  461. //
  462. break;
  463. }
  464. }
  465. }
  466. }
  467. if (!RetIdx) {
  468. PLOTWARN(("BestMatchNonWhitePen: Cannot find one make it WHITE"));
  469. }
  470. PLOTDBG(DBG_BESTPEN,
  471. ("BestMatchNonWhitePen: RGB=%02lx:%02lx:%02lx [%ld/%ld]=%02lx:%02lx:%02lx",
  472. R, G, B,
  473. (LONG)RetIdx, (LONG)pPDev->pPlotGPC->Pens.Count,
  474. (LONG)RetPal.R,
  475. (LONG)RetPal.G,
  476. (LONG)RetPal.B));
  477. return((LONG)RetIdx);
  478. }
  479. VOID
  480. GetFinalColor(
  481. PPDEV pPDev,
  482. PPALENTRY pPalEntry
  483. )
  484. /*++
  485. Routine Description:
  486. This function modifies the input RGB color based on Grayscale and GAMMA
  487. Arguments:
  488. pPDev - Our PDEV
  489. pPalEntry - Pointer to the PALENTRY of interest
  490. Return Value:
  491. VOID but pPalEntry will be modified
  492. Author:
  493. 12-Apr-1994 Tue 14:03:37 created
  494. Revision History:
  495. --*/
  496. {
  497. PALENTRY PalEntry = *pPalEntry;
  498. //
  499. // Do Gamma correction first
  500. //
  501. PalEntry.R = HPRGBGamma2p0[PalEntry.R];
  502. PalEntry.G = HPRGBGamma2p0[PalEntry.G];
  503. PalEntry.B = HPRGBGamma2p0[PalEntry.B];
  504. //
  505. // If were in GRAYSCALE mode we need to convert the color to grayscale
  506. //
  507. if (pPDev->PlotDM.dm.dmColor != DMCOLOR_COLOR) {
  508. PalEntry.R =
  509. PalEntry.G =
  510. PalEntry.B = (BYTE)INTENSITY(PalEntry.R, PalEntry.G, PalEntry.B);
  511. }
  512. PLOTDBG(DBG_GETFINALCOLOR,
  513. ("GetFinalColor: %hs RGB=%03ld:%03ld:%03ld -> Gamma=%03ld:%03ld:%03ld",
  514. (pPDev->PlotDM.dm.dmColor != DMCOLOR_COLOR) ? "MONO" : "COLOR",
  515. (DWORD)pPalEntry->R, (DWORD)pPalEntry->G, (DWORD)pPalEntry->B,
  516. (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B));
  517. //
  518. // Save it back and return
  519. //
  520. *pPalEntry = PalEntry;
  521. }
  522. LONG
  523. FindCachedPen(
  524. PPDEV pPDev,
  525. PPALENTRY pPalEntry
  526. )
  527. /*++
  528. Routine Description:
  529. This function searhes the PenCache and returns the pen number if it is
  530. found. If it is not found, it will add the new pen to the cache and
  531. delete one if needed. Finally it returns the pen back to the caller.
  532. Arguments:
  533. pPDev - Pointer to the device PDEV
  534. pPalEntry - Pointer to the PALENTRY for the specified RGB to locate.
  535. Return Value:
  536. DWORD - a Pen number, if an error occurred 0 is returned
  537. Author:
  538. 21-Dec-1993 Tue 12:42:31 updated
  539. re-write to make it as one pass search and adding. and commented
  540. 30-Nov-1993 Tue 23:19:04 created
  541. Revision History:
  542. --*/
  543. {
  544. PPENCACHE pPenCache;
  545. PPENENTRY pPenStart;
  546. PPENENTRY pCurPen;
  547. PPENENTRY pPrevPen;
  548. PPENENTRY pPrevDelPen;
  549. PALENTRY PalEntry;
  550. LONG Count;
  551. PLOTASSERT(1, "FindCahcedPen: The pPalEntry = NULL", pPalEntry, 0);
  552. if (!IS_RASTER(pPDev)) {
  553. //
  554. // Since this is the index type of palette, the PalEntry should be
  555. // also passed as index in the BGR's B component
  556. //
  557. Count = (LONG)RGB(pPalEntry->B, pPalEntry->G, pPalEntry->R);
  558. PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: PEN PLOTTER=%ld", Count));
  559. if (Count > (LONG)((DWORD)pPDev->pPlotGPC->Pens.Count)) {
  560. PLOTERR(("FindCachedPen: INVALID Pen Color Index = %ld, Set to 1",
  561. Count));
  562. Count = 1;
  563. }
  564. return(Count);
  565. }
  566. //
  567. // If we dont have a pen cache, nothing we can do but return an error.
  568. //
  569. if (!(pPenCache = (PPENCACHE)pPDev->pPenCache)) {
  570. PLOTERR(("FindCahcedPen: The pPenCache=NULL?"));
  571. return(0);
  572. }
  573. //
  574. // Make sure we set the flag correctly, the current PENENTRY flag is
  575. // located in peFlags field
  576. //
  577. PalEntry = *pPalEntry;
  578. PalEntry.Flags = pPenCache->peFlags;
  579. //
  580. // Convert to final color through gamma/gray scale
  581. //
  582. GetFinalColor(pPDev, &PalEntry);
  583. pPenStart = &(pPenCache->PenEntries[0]);
  584. pCurPen = pPenStart + pPenCache->Head;
  585. pPrevPen =
  586. pPrevDelPen = NULL;
  587. Count = (LONG)pPenCache->CurCount;
  588. while (Count--) {
  589. if (SAME_PPALENTRY(&(pCurPen->PalEntry), &PalEntry)) {
  590. PLOTDBG(DBG_FINDCACHEDPEN,
  591. ("FindCachedPen: Found Pen #%ld=%02lx:%02lx:%02lx, Linkes=%ld",
  592. (DWORD)pCurPen->PenNumber,
  593. (DWORD)PalEntry.R,
  594. (DWORD)PalEntry.G,
  595. (DWORD)PalEntry.B,
  596. (DWORD)(pPenCache->CurCount - Count)));
  597. //
  598. // Found the color for that pen, exit this loop since we are done.
  599. //
  600. break;
  601. }
  602. //
  603. // Keep track of a pen that makes sense to delete in case we need
  604. // to delete an entry in order to add the new one that is not found.
  605. // If the entry was used for something longer term, it would be locked
  606. // and thus would not be a candidate for removal.
  607. //
  608. if (!(pCurPen->PalEntry.Flags & PEF_CACHE_LOCKED)) {
  609. //
  610. // If this pen is not locked then it must ok to delete if we need to
  611. //
  612. pPrevDelPen = pPrevPen;
  613. }
  614. pPrevPen = pCurPen;
  615. pCurPen = pPenStart + pCurPen->Next;
  616. }
  617. //
  618. // If Count != -1 then we must have found a match, so we are done.
  619. //
  620. if (Count == -1) {
  621. //
  622. // We did not find the pen, so add it to the cache, remember if the
  623. // cache is full we must delete the last UNLOCKED entry
  624. //
  625. if (pPenCache->CurCount >= pPenCache->MaxCount) {
  626. //
  627. // Now delete the last un-locked entry, and add the new item to
  628. // that deleted entry
  629. //
  630. if (!(pPrevPen = pPrevDelPen)) {
  631. //
  632. // This is very strange, the last unlocked is the head?, this
  633. // is only possible if we have MaxCount = TOTAL_LOCKED_PENS + 1
  634. //
  635. PLOTDBG(DBG_FINDCACHEDPEN, ("FindCachedPen: ??? Last unlocked pen is Linked List Head"));
  636. pCurPen = pPenStart + pPenCache->Head;
  637. } else {
  638. pCurPen = pPenStart + pPrevPen->Next;
  639. }
  640. PLOTASSERT(1, "Pen #%ld is a LOCKED pen",
  641. !(pCurPen->PalEntry.Flags & PEF_CACHE_LOCKED),
  642. (DWORD)pCurPen->PenNumber);
  643. PLOTDBG(DBG_FINDCACHEDPEN,
  644. ("FindCachedPen: REPLACE Pen #%ld=%02lx:%02lx:%02lx -> %02lx:%02lx:%02lx [%ld]",
  645. (DWORD)pCurPen->PenNumber,
  646. (DWORD)pCurPen->PalEntry.R, (DWORD)pCurPen->PalEntry.G,
  647. (DWORD)pCurPen->PalEntry.B,
  648. (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B,
  649. (DWORD)(pCurPen - pPenStart)));
  650. } else {
  651. //
  652. // Increment the cached pen count
  653. //
  654. ++(pPenCache->CurCount);
  655. PLOTDBG(DBG_FINDCACHEDPEN,
  656. ("FindCachedPen: ADD New Pen #%ld=%02lx:%02lx:%02lx [%ld/%ld]",
  657. (DWORD)pCurPen->PenNumber,
  658. (DWORD)PalEntry.R, (DWORD)PalEntry.G, (DWORD)PalEntry.B,
  659. pPenCache->CurCount, pPenCache->MaxCount));
  660. }
  661. //
  662. // set the pen color in the cache and output the commands to the
  663. // plotter to add or change the current pen color setting
  664. //
  665. pCurPen->PalEntry = PalEntry;
  666. OutputFormatStr(pPDev, "PC#d,#d,#d,#d;", (LONG)pCurPen->PenNumber,
  667. (LONG)PalEntry.R, (LONG)PalEntry.G, (LONG)PalEntry.B);
  668. }
  669. //
  670. // Now move the pCurPen to the head of the linked list
  671. //
  672. if (pPrevPen) {
  673. //
  674. // Only move the current pen to the link list head if not already so
  675. //
  676. PLOTDBG(DBG_FINDCACHEDPEN,
  677. ("FindCachedPen: MOVE Pen #%ld to Linked List Head [%ld --> %ld]",
  678. (DWORD)pCurPen->PenNumber,
  679. (DWORD)pPenCache->Head,
  680. (DWORD)(pCurPen - pPenStart)));
  681. pPrevPen->Next = pCurPen->Next;
  682. pCurPen->Next = pPenCache->Head;
  683. pPenCache->Head = (WORD)(pCurPen - pPenStart);
  684. }
  685. return(pCurPen->PenNumber);
  686. }
  687. BOOL
  688. PlotCreatePalette(
  689. PPDEV pPDev
  690. )
  691. /*++
  692. Routine Description:
  693. This function creates a pen cache. It initializes the cache accordingly
  694. Arguments:
  695. pPDev - Pointer to the PDEV
  696. Return Value:
  697. BOOL to indicate operation
  698. Author:
  699. 30-Nov-1993 Tue 23:23:17 created
  700. 21-Dec-1993 Tue 12:40:30 updated
  701. Simplify version re-write
  702. 23-Dec-1993 Thu 20:16:52 updated
  703. Add NP number of pens command back to be able to use HPGL/2 palette
  704. Revision History:
  705. --*/
  706. {
  707. if (!pPDev->pPlotGPC->MaxPens) {
  708. PLOTWARN(("PlotCreatePalette: Device MaxPens = 0"));
  709. } else if (IS_RASTER(pPDev)) {
  710. PPENCACHE pPenCache;
  711. PPENENTRY pPenEntry;
  712. DWORD dw;
  713. UINT Index;
  714. //
  715. // If this is the first time around then go ahead and alloc the memory
  716. // for our pen pallete cache. If the memory is already allocated then
  717. // we don't need to worry about it.
  718. //
  719. PLOTASSERT(1, "PlotCreatePalette: device has too few pens [%ld] available",
  720. pPDev->pPlotGPC->MaxPens > TOTAL_LOCKED_PENS,
  721. (DWORD)pPDev->pPlotGPC->MaxPens);
  722. dw = (DWORD)(sizeof(PENCACHE) +
  723. sizeof(PENENTRY) * (pPDev->pPlotGPC->MaxPens - 1));
  724. if (pPDev->pPenCache == NULL) {
  725. PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: Create NEW Palette"));
  726. pPDev->pPenCache = (LPVOID)LocalAlloc(LPTR, dw);
  727. } else {
  728. PLOTDBG(DBG_CREATEPAL, ("PlotCreatePalette: Re-Initialized Palette"));
  729. }
  730. if (pPenCache = (PPENCACHE)pPDev->pPenCache) {
  731. //
  732. // 1. Clear everything to zero
  733. // 2. Set MaxCount to the amount specified in the GPC
  734. // 3. Initialize the whole linked list as a linear list with
  735. // the pen number set
  736. // 4. Make last index link to 0xffff to prevent us from using it
  737. //
  738. ZeroMemory(pPenCache, dw);
  739. pPenCache->MaxCount = (WORD)pPDev->pPlotGPC->MaxPens;
  740. for (Index = 0, pPenEntry = &(pPenCache->PenEntries[0]);
  741. Index < (UINT)pPenCache->MaxCount;
  742. Index++, pPenEntry++) {
  743. pPenEntry->Next = (WORD)(Index + 1);
  744. pPenEntry->PenNumber = (WORD)Index;
  745. }
  746. pPenCache->PenEntries[pPenCache->MaxCount-1].Next = (WORD)0xffff;
  747. //
  748. // Before we add any pen palette we will establish the size of the
  749. // HPGL/2 Pen palette, and reset every pen back to our
  750. // standard which is used by gdi and the halftone Eng. (= 0.26mm wide)
  751. //
  752. OutputFormatStr(pPDev, "NP#d", (LONG)pPenCache->MaxCount);
  753. //
  754. // Now, add the entries we know we must keep around and make sure
  755. // they get locked.
  756. //
  757. PLOTDBG(DBG_CREATEPAL,
  758. ("PlotCreatePalette: add all %ld standard locked pens",
  759. TOTAL_LOCKED_PENS));
  760. pPenCache->peFlags = PEF_CACHE_LOCKED;
  761. for (Index = 0; Index < (LONG)TOTAL_LOCKED_PENS; Index++) {
  762. FindCachedPen(pPDev, (PPALENTRY)&HTPal[Index]);
  763. }
  764. //
  765. // Now set the flag telling us the cache contains locked pens, and
  766. // unlock the cache.
  767. //
  768. pPenCache->Flags |= PCF_HAS_LOCKED_PENS;
  769. pPenCache->peFlags = 0;
  770. } else {
  771. PLOTERR(("PlotCreatePalette: LocalAlloc(PENCACHE=%ld) failed", dw));
  772. return(FALSE);
  773. }
  774. } else {
  775. pPDev->BrightestPen = BestMatchNonWhitePen(pPDev, 255, 255, 255);
  776. PLOTDBG(DBG_CREATEPAL,
  777. ("PlotCreatePalette: Pen Plotter's Closest NON-WHITE PEN Index=ld",
  778. pPDev->BrightestPen));
  779. }
  780. return(TRUE);
  781. }
  782. UINT
  783. AllocOutBuffer(
  784. PPDEV pPDev
  785. )
  786. /*++
  787. Routine Description:
  788. This function allocates a buffer to be used for caching output data
  789. specific to this job. This keeps us from making calls to EngWritePrinter
  790. with very small amounts of data.
  791. Arguments:
  792. pPDev - Pointer to our pdev
  793. Return Value:
  794. UINT count of how many bytes were allocated. If the buffer was already
  795. allocated, return the size. If an error occured (allocating memory)
  796. return 0.
  797. Author:
  798. 16-Nov-1993 Tue 07:39:46 created
  799. Revision History:
  800. --*/
  801. {
  802. if ((!(pPDev->pOutBuffer)) &&
  803. (!(pPDev->pOutBuffer = (LPBYTE)LocalAlloc(LPTR,
  804. OUTPUT_BUFFER_SIZE + 16)))) {
  805. PLOTERR(("CreateOutputBuffer: LocalAlloc(OutBuffer=%ld) failed",
  806. OUTPUT_BUFFER_SIZE));
  807. return(0);
  808. }
  809. pPDev->cbBufferBytes = 0;
  810. return(OUTPUT_BUFFER_SIZE);
  811. }
  812. VOID
  813. FreeOutBuffer(
  814. PPDEV pPDev
  815. )
  816. /*++
  817. Routine Description:
  818. This function frees the allocated output buffer
  819. Arguments:
  820. pPDev - pointer to the PDEV
  821. Return Value:
  822. VOID
  823. Author:
  824. 16-Nov-1993 Tue 07:46:16 created
  825. Revision History:
  826. --*/
  827. {
  828. if (pPDev->pOutBuffer) {
  829. LocalFree((HLOCAL)pPDev->pOutBuffer);
  830. pPDev->pOutBuffer = NULL;
  831. }
  832. pPDev->cbBufferBytes = 0;
  833. }
  834. BOOL
  835. FlushOutBuffer(
  836. PPDEV pPDev
  837. )
  838. /*++
  839. Routine Description:
  840. This function flushes the current contents of the output buffer by writing
  841. the contents to the target device via EngWritePrinter.
  842. Arguments:
  843. pPDev - Pointer to the PDEV
  844. Return Value:
  845. BOOL to indicate the result (TRUE == success)
  846. Author:
  847. 16-Nov-1993 Tue 09:56:27 created
  848. Revision History:
  849. 14-Sep-1999 Tue 17:36:08 updated
  850. Remove Checking for EngAbort(), this check in user mode will somehow
  851. return true at end of job and cause all output got cut off.
  852. --*/
  853. {
  854. if (PLOT_CANCEL_JOB(pPDev)) {
  855. return(FALSE);
  856. }
  857. if (pPDev->cbBufferBytes) {
  858. DWORD cbWritten;
  859. if (pPDev->cbBufferBytes > OUTPUT_BUFFER_SIZE) {
  860. PLOTASSERT(1, "OutputBytes: pPDev->cbBufferBytes (%ld) OVERRUN",
  861. pPDev->cbBufferBytes <= OUTPUT_BUFFER_SIZE,
  862. pPDev->cbBufferBytes);
  863. pPDev->cbBufferBytes = OUTPUT_BUFFER_SIZE;
  864. pPDev->Flags |= PDEVF_CANCEL_JOB;
  865. return(FALSE);
  866. }
  867. //
  868. // We need to be concerned with the job getting cancelled from
  869. // either the app or the spooler.
  870. // If the job is cancelled from the client app and we were printing
  871. // direct then EngCheckAbort() should return true.
  872. // If the job was cancelled from the spooler (ie printman) then
  873. // the write printer will fail.
  874. // Anywhere we do prolonged processing we need to look and verify
  875. // we break out of any loop if the job is cancelled. Currently
  876. // we do this in OutputBitmapSection, DoPolygon, DoRectFill, and
  877. // DrvTextOut when we are enuming our STROBJ glyphs
  878. //
  879. if ((!WritePrinter(pPDev->hPrinter,
  880. pPDev->pOutBuffer,
  881. pPDev->cbBufferBytes,
  882. &cbWritten)) ||
  883. (cbWritten != pPDev->cbBufferBytes)) {
  884. //
  885. // Set the cancel flag in our pdev;
  886. //
  887. PLOTDBG(DBG_FLUSHBUF, ("FlushOutBuffer: WritePrinter() failure"));
  888. pPDev->Flags |= PDEVF_CANCEL_JOB;
  889. return(FALSE);
  890. }
  891. #if 0
  892. if (EngCheckAbort(pPDev->pso)) {
  893. PLOTDBG(DBG_FLUSHBUF, ("FlushOutBuffer: EngCheckAbort return TRUE"));
  894. pPDev->Flags |= PDEVF_CANCEL_JOB;
  895. return(FALSE);
  896. }
  897. #endif
  898. //
  899. // Reset to zero for clearing the buffer
  900. //
  901. pPDev->cbBufferBytes = 0;
  902. }
  903. return(TRUE);
  904. }
  905. LONG
  906. OutputBytes(
  907. PPDEV pPDev,
  908. LPBYTE pBuf,
  909. LONG cBuf
  910. )
  911. /*++
  912. Routine Description:
  913. This function output cBuf bytes from pBuf, by copying them into the
  914. output buffer (and flushing if required).
  915. Arguments:
  916. pPDev - Pointer to the PDEV
  917. pBuf - Pointer to the buffer location
  918. cBuf - Size of the buffer in bytes
  919. Return Value:
  920. LONG size of the buffer output, if < 0 then error occurred
  921. Author:
  922. 16-Nov-1993 Tue 08:18:41 created
  923. 07-Dec-1993 Tue 17:21:53 updated
  924. re-write, so it do bulk copy rather than byte by byte
  925. Revision History:
  926. --*/
  927. {
  928. LPBYTE pOrgBuf = pBuf;
  929. LONG cSize;
  930. while (cBuf > 0) {
  931. if (PLOT_CANCEL_JOB(pPDev)) {
  932. return(-1);
  933. }
  934. if (pPDev->cbBufferBytes >= OUTPUT_BUFFER_SIZE) {
  935. if (!FlushOutBuffer(pPDev)) {
  936. return(-1);
  937. }
  938. }
  939. if ((cSize = OUTPUT_BUFFER_SIZE - pPDev->cbBufferBytes) > cBuf) {
  940. cSize = cBuf;
  941. }
  942. CopyMemory(pPDev->pOutBuffer + pPDev->cbBufferBytes, pBuf, cSize);
  943. pPDev->cbBufferBytes += cSize;
  944. pBuf += cSize;
  945. cBuf -= cSize;
  946. }
  947. return((LONG)(pBuf - pOrgBuf));
  948. }
  949. LONG
  950. OutputString(
  951. PPDEV pPDev,
  952. LPSTR pszStr
  953. )
  954. /*++
  955. Routine Description:
  956. This function outputs a null terminated string to the destination buffer
  957. Arguments:
  958. pPDev - Pointer to the PDEV
  959. pszStr - Pointer to the NULL terminated string
  960. Return Value:
  961. LONG size of the string output, if < 0 then error occurred
  962. Author:
  963. 16-Nov-1993 Tue 08:20:55 created
  964. 07-Dec-1993 Tue 17:21:37 updated
  965. re-write to call OutputBytes()
  966. Revision History:
  967. --*/
  968. {
  969. return(OutputBytes(pPDev, pszStr, strlen(pszStr)));
  970. }
  971. LONG
  972. LONGToASCII(
  973. LONG Number,
  974. LPSTR pStr16,
  975. size_t cchStr16,
  976. BYTE NumType
  977. )
  978. /*++
  979. Routine Description:
  980. This function convert a LONG number to ANSI ASCII
  981. Arguments:
  982. Number - 32-bit LONG number
  983. pStr16 - minimum 12 bytes to store the converted result
  984. Return Value:
  985. LONG - size of number string returned
  986. Author:
  987. 16-Nov-1993 Tue 08:24:07 created
  988. 16-Feb-1994 Wed 10:50:55 updated
  989. Updated so upper case character treated as polyline encoded mode
  990. Revision History:
  991. --*/
  992. {
  993. LPSTR pOrgStr = pStr16;
  994. size_t cchOrgStr = cchStr16;
  995. LPSTR pNumStr;
  996. BYTE NumStr[16]; // maximum for LONG are 1 sign + 10 digits
  997. if ((NumType >= 'A') && (NumType <= 'Z')) {
  998. //
  999. // Polyline encoded number
  1000. //
  1001. PLOTDBG(DBG_PENUM, ("LONGToASCII: Convert PE Number %ld, Base=%ld",
  1002. Number, PE_BASE_NUM));
  1003. if (Number < 0) {
  1004. Number = 1 - Number - Number;
  1005. } else {
  1006. Number += Number;
  1007. }
  1008. while (Number >= PE_BASE_NUM) {
  1009. if (cchStr16 > 0)
  1010. {
  1011. *pStr16++ = (BYTE)(63 + (Number & (PE_BASE_NUM - 1)));
  1012. cchStr16--;
  1013. }
  1014. else
  1015. {
  1016. return 0;
  1017. }
  1018. Number >>= PE_BASE_BITS;
  1019. }
  1020. if (cchStr16 > 0)
  1021. {
  1022. *pStr16++ = (BYTE)(PE_TERM_ADDER + Number);
  1023. cchStr16--;
  1024. }
  1025. else
  1026. {
  1027. return 0;
  1028. }
  1029. PLOTDBG(DBG_PENUM, ("LONGToASCII: LAST DIGIT: Number=%ld, [%02lx]",
  1030. Number, Number + PE_TERM_ADDER));
  1031. } else {
  1032. if (Number < 0) {
  1033. Number = -Number;
  1034. if (cchStr16 > 0)
  1035. {
  1036. *pStr16++ = '-';
  1037. cchStr16--;
  1038. }
  1039. else
  1040. {
  1041. return 0;
  1042. }
  1043. }
  1044. pNumStr = NumStr;
  1045. do {
  1046. *pNumStr++ = (CHAR)((Number % 10) + '0');
  1047. } while (Number /= 10);
  1048. //
  1049. // Now reverse the digits
  1050. //
  1051. while (pNumStr > NumStr && cchStr16--) {
  1052. *pStr16++ = *(--pNumStr);
  1053. }
  1054. }
  1055. if (cchStr16 == 0)
  1056. {
  1057. pStr16 = pOrgStr + cchOrgStr - 1;
  1058. }
  1059. *pStr16 = '\0'; // null teriminated
  1060. return((UINT)(pStr16 - pOrgStr));
  1061. }
  1062. LONG
  1063. OutputXYParams(
  1064. PPDEV pPDev,
  1065. PPOINTL pPtXY,
  1066. PPOINTL pPtOffset,
  1067. PPOINTL pPtCurPos,
  1068. UINT cPoints,
  1069. UINT MaxCurPosSkips,
  1070. BYTE NumType
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. This function outputs long numbers, and inserts a ',' between numbers
  1075. (other than the last number)
  1076. Arguments:
  1077. pPDev - Pointer to the PDEV
  1078. pPtXY - Pointer to the array of POINTL data structure for the XY pair
  1079. pPtOffset - Points to the POINTL Offset to be add to the pPtXY, NULL if
  1080. no offset need to be added
  1081. pPtCurPos - Points to the POINTL Current position in <<DEVICE>>
  1082. coordinates to be substracted, this is used to output XY pair as
  1083. relative model, if the pointer is NULL then absolute model is
  1084. used, if the pointer is passed and return sucessful then the
  1085. final XY position is written back to this POINTL
  1086. cPoints - count of total pPtXY pairs need to be output
  1087. MaxCurPosSkips - How many points before the current position will be
  1088. updated
  1089. NumType - one of 'l', 'L', 'F', 'f', 'p', 'P', 'D', 'd'
  1090. Return Value:
  1091. if sucessful it return the total number of bytes sent to the destination,
  1092. if negative an error occurred
  1093. Author:
  1094. 17-Feb-1994 Thu 10:13:09 created
  1095. Revision History:
  1096. --*/
  1097. {
  1098. LONG Size = 0;
  1099. POINTL ptNow;
  1100. POINTL ptTmp;
  1101. POINTL ptOffset;
  1102. POINTL ptCurPos;
  1103. UINT XCount;
  1104. UINT YCount;
  1105. UINT XIdxStart;
  1106. UINT CurPosSkips;
  1107. BOOL NeedComma;
  1108. BYTE XBuf[16];
  1109. BYTE YBuf[16];
  1110. NeedComma = (BOOL)((NumType >= 'a') && (NumType <= 'z'));
  1111. if (pPtOffset) {
  1112. ptOffset = *pPtOffset;
  1113. } else {
  1114. ptOffset.x =
  1115. ptOffset.y = 0;
  1116. }
  1117. XIdxStart = 0;
  1118. if (pPtCurPos) {
  1119. ptCurPos = *pPtCurPos;
  1120. } else if (!NeedComma) {
  1121. XBuf[0] = '=';
  1122. XIdxStart = 1;
  1123. }
  1124. CurPosSkips = MaxCurPosSkips;
  1125. while (cPoints--) {
  1126. ptNow.x = pPtXY->x + ptOffset.x;
  1127. ptNow.y = pPtXY->y + ptOffset.y;
  1128. ++pPtXY;
  1129. XCount = XIdxStart;
  1130. YCount = 0;
  1131. switch (NumType) {
  1132. case 'L':
  1133. case 'l':
  1134. ptNow.x = LTODEVL(pPDev, ptNow.x);
  1135. ptNow.y = LTODEVL(pPDev, ptNow.y);
  1136. break;
  1137. case 'F':
  1138. case 'f':
  1139. ptNow.x = FXTODEVL(pPDev, ptNow.x);
  1140. ptNow.y = FXTODEVL(pPDev, ptNow.y);
  1141. break;
  1142. case 'D':
  1143. case 'd':
  1144. break;
  1145. case 'P':
  1146. case 'p':
  1147. if (ptNow.x >= 0) {
  1148. XBuf[XCount++] = '+';
  1149. }
  1150. if (ptNow.y >= 0) {
  1151. YBuf[YCount++] = '+';
  1152. }
  1153. break;
  1154. default:
  1155. PLOTASSERT(1,"OutputXYParams: Invalid Format type '%c'",0,NumType);
  1156. return(-2);
  1157. }
  1158. if (pPtCurPos) {
  1159. ptTmp = ptNow;
  1160. ptNow.x -= ptCurPos.x;
  1161. ptNow.y -= ptCurPos.y;
  1162. if (!(--CurPosSkips)) {
  1163. ptCurPos = ptTmp;
  1164. CurPosSkips = MaxCurPosSkips;
  1165. }
  1166. if ((ptNow.x == 0) && (ptNow.y == 0) && (MaxCurPosSkips == 1)) {
  1167. //
  1168. // We do not need to move to the same position here
  1169. //
  1170. PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld), REL=(%ld, %ld) --- SKIP",
  1171. ptTmp.x, ptTmp.y, ptNow.x, ptNow.y));
  1172. continue;
  1173. } else {
  1174. PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld), REL=(%ld, %ld)",
  1175. ptTmp.x, ptTmp.y, ptNow.x, ptNow.y));
  1176. }
  1177. } else {
  1178. PLOTDBG(DBG_OUTPUTXYPARMS, ("OutputXYParms: ABS=(%ld, %ld)",
  1179. ptNow.x, ptNow.y));
  1180. }
  1181. XCount += LONGToASCII(ptNow.x, &XBuf[XCount], CCHOF(XBuf) - XCount, NumType);
  1182. YCount += LONGToASCII(ptNow.y, &YBuf[YCount], CCHOF(YBuf) - YCount, NumType);
  1183. if (NeedComma) {
  1184. XBuf[XCount++] = ',';
  1185. if (cPoints) {
  1186. YBuf[YCount++] = ',';
  1187. }
  1188. }
  1189. if ((OutputBytes(pPDev, XBuf, XCount) < 0) ||
  1190. (OutputBytes(pPDev, YBuf, YCount) < 0)) {
  1191. return(-1);
  1192. }
  1193. Size += (XCount + YCount);
  1194. }
  1195. //
  1196. // return back the new current position.
  1197. //
  1198. if (pPtCurPos) {
  1199. *pPtCurPos = ptCurPos;
  1200. }
  1201. return(Size);
  1202. }
  1203. LONG
  1204. OutputLONGParams(
  1205. PPDEV pPDev,
  1206. PLONG pNumbers,
  1207. UINT cNumber,
  1208. BYTE NumType
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This functions outputs LONG numbers and inserts a ',' between all but the
  1213. last numbers.
  1214. Arguments:
  1215. pPDev - Pointer to the PDEV
  1216. pNumbers - Point to the LONG arrary of numbers
  1217. cNumber - Total number to be output
  1218. NumType - one of 'l', 'L', 'F', 'f', 'p', 'P', 'D', 'd'
  1219. Return Value:
  1220. The return value is the total number of bytes sent to the destination.
  1221. If negative an error occurred.
  1222. Author:
  1223. 16-Nov-1993 Tue 09:37:32 created
  1224. 16-Feb-1994 Wed 10:49:16 updated
  1225. Updated to add upper case of format char as in polyline encoded mode
  1226. Revision History:
  1227. --*/
  1228. {
  1229. LONG Size = 0;
  1230. LONG Count;
  1231. LONG Num;
  1232. BOOL NeedComma;
  1233. BYTE NumBuf[16];
  1234. NeedComma = (BOOL)((NumType >= 'a') && (NumType <= 'z'));
  1235. while (cNumber--) {
  1236. Num = *pNumbers++;
  1237. Count = 0;
  1238. switch (NumType) {
  1239. case 'L':
  1240. case 'l':
  1241. Num = LTODEVL(pPDev, Num);
  1242. break;
  1243. case 'F':
  1244. case 'f':
  1245. Num = FXTODEVL(pPDev, Num);
  1246. break;
  1247. case 'D':
  1248. case 'd':
  1249. break;
  1250. case 'P':
  1251. case 'p':
  1252. if (Num >= 0) {
  1253. NumBuf[Count++] = '+';
  1254. }
  1255. break;
  1256. default:
  1257. PLOTASSERT(1,"OutputLONGParams: Invalid Format type '%c'",0,NumType);
  1258. return(-2);
  1259. }
  1260. Count += LONGToASCII(Num, &NumBuf[Count], CCHOF(NumBuf) - Count, NumType);
  1261. if ((NeedComma) && (cNumber)) {
  1262. NumBuf[Count++] = ',';
  1263. }
  1264. if (OutputBytes(pPDev, NumBuf, Count) < 0) {
  1265. return(-1);
  1266. }
  1267. Size += Count;
  1268. }
  1269. return(Size);
  1270. }
  1271. //
  1272. // The following #define code is used by the OutputFormatStrDELI() and
  1273. // OutputFormatStr() functions, it was easier to maintain this way
  1274. //
  1275. // 16-Feb-1994 Wed 10:50:24 updated
  1276. // Updated to add upper case of format char as in polyline encoded mode
  1277. //
  1278. #define DO_FORMATSTR(pPDev, NumFormatChar, pszFormat) \
  1279. { \
  1280. LPSTR pLast; \
  1281. va_list vaList; \
  1282. LONG Num; \
  1283. LONG Size; \
  1284. LONG Count; \
  1285. BYTE bCur; \
  1286. BYTE NumBuf[16]; \
  1287. \
  1288. va_start(vaList, pszFormat); \
  1289. \
  1290. Size = 0; \
  1291. pLast = pszFormat; \
  1292. \
  1293. while (bCur = *pszFormat++) { \
  1294. \
  1295. if (bCur == NumFormatChar) { \
  1296. \
  1297. if (Count = (LONG)(pszFormat - pLast - 1)) { \
  1298. \
  1299. Size += Count; \
  1300. \
  1301. if (OutputBytes(pPDev, pLast, Count) < 0) { \
  1302. \
  1303. return(-1); \
  1304. } \
  1305. } \
  1306. \
  1307. Num = va_arg(vaList, LONG); \
  1308. Count = 0; \
  1309. \
  1310. switch (bCur = *pszFormat++) { \
  1311. \
  1312. case 'L': \
  1313. case 'l': \
  1314. \
  1315. Num = LTODEVL(pPDev, Num); \
  1316. break; \
  1317. \
  1318. case 'F': \
  1319. case 'f': \
  1320. \
  1321. Num = FXTODEVL(pPDev, Num); \
  1322. break; \
  1323. \
  1324. case 'D': \
  1325. case 'd': \
  1326. \
  1327. break; \
  1328. \
  1329. case 'P': \
  1330. case 'p': \
  1331. \
  1332. if (Num >= 0) { \
  1333. \
  1334. NumBuf[Count++] = '+'; \
  1335. } \
  1336. \
  1337. break; \
  1338. \
  1339. default: \
  1340. \
  1341. PLOTASSERT(1,"Invalid Format type '%c'",0,*(pszFormat-1)); \
  1342. return(-2); \
  1343. } \
  1344. \
  1345. Count += LONGToASCII(Num, &NumBuf[Count], sizeof(NumBuf) - Count, bCur); \
  1346. Size += Count; \
  1347. pLast = pszFormat; \
  1348. \
  1349. if (OutputBytes(pPDev, NumBuf, Count) < 0) { \
  1350. \
  1351. return(-1); \
  1352. } \
  1353. } \
  1354. } \
  1355. \
  1356. if (Count = (LONG)(pszFormat - pLast - 1)) { \
  1357. \
  1358. Size += Count; \
  1359. \
  1360. if (OutputBytes(pPDev, pLast, Count) < 0) { \
  1361. \
  1362. return(-1); \
  1363. } \
  1364. } \
  1365. \
  1366. va_end(vaList); \
  1367. \
  1368. return(Size); \
  1369. }
  1370. LONG
  1371. cdecl
  1372. OutputFormatStrDELI(
  1373. PPDEV pPDev,
  1374. CHAR NumFormatChar,
  1375. LPSTR pszFormat,
  1376. ...
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This function outputs a string and optionally replaces '#' with LONG numbers
  1381. passed on the stack
  1382. Arguments:
  1383. pPDev - Pointer to the PDEV
  1384. NumFormatChar - the character in the pszFormat string will be replaced
  1385. by LONG numbers on the stack
  1386. pszFormat - a ASCII string, only 'NumFormatChar' will be replaced
  1387. with a 32-bit LONG number on the stack
  1388. Return Value:
  1389. LONG size of the string write to the output buffer, a negative number
  1390. indicates an error
  1391. Author:
  1392. 16-Nov-1993 Tue 07:56:18 created
  1393. Revision History:
  1394. --*/
  1395. {
  1396. DO_FORMATSTR(pPDev, NumFormatChar, pszFormat);
  1397. }
  1398. LONG
  1399. cdecl
  1400. OutputFormatStr(
  1401. PPDEV pPDev,
  1402. LPSTR pszFormat,
  1403. ...
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This function outputs the passed stack variables with the default format.
  1408. Arguments:
  1409. pPDev - Pointer to the PDEV
  1410. pszFormat - a ASCII string, only '#' will be replaced with a 32-bit
  1411. LONG number on the stack
  1412. Return Value:
  1413. LONG size of the string written to the output buffer, a negative number
  1414. siginals an error
  1415. Author:
  1416. 16-Nov-1993 Tue 07:56:18 created
  1417. Revision History:
  1418. --*/
  1419. {
  1420. DO_FORMATSTR(pPDev, DEF_FORMATSTR_CHAR, pszFormat);
  1421. }
  1422. BOOL
  1423. OutputCommaSep(
  1424. PPDEV pPDev
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. This funtion outputs a ',' (comma ) to the destination
  1429. Arguments:
  1430. pPDev - Pointer to the PDEV
  1431. Return Value:
  1432. BOOL
  1433. Author:
  1434. 16-Nov-1993 Tue 10:46:42 created
  1435. Revision History:
  1436. --*/
  1437. {
  1438. return(OutputString(pPDev, ",") == 1);
  1439. }
  1440. VOID
  1441. ClearClipWindow(
  1442. PPDEV pPDev
  1443. )
  1444. /*++
  1445. Routine Description:
  1446. This function clears the input window (plotter CLIP RECT) in the
  1447. target device using the correct HPGL2 command.
  1448. Arguments:
  1449. pPDev - Pointer to the PDEV data structure
  1450. Return Value:
  1451. VOID
  1452. Author:
  1453. 30-Nov-1993 Tue 19:56:09 updated
  1454. style clean up, commented
  1455. Revision History:
  1456. --*/
  1457. {
  1458. if (pPDev->Flags & PDEVF_HAS_CLIPRECT) {
  1459. pPDev->Flags &= ~PDEVF_HAS_CLIPRECT;
  1460. OutputString(pPDev, "IW;");
  1461. }
  1462. }
  1463. VOID
  1464. SetClipWindow(
  1465. PPDEV pPDev,
  1466. PRECTL pClipRectl
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This function sets the device clip rect to prevent objects drawn outside
  1471. the rect from appearing on the target surface. The target device is doing
  1472. the actual clipping in this case.
  1473. Arguments:
  1474. pPDev - Pointer to the PDEV data structure
  1475. pClipRectl - Pointer to the RECTL data structure which defines the clipping
  1476. rect to set inside the target device in engine units.
  1477. Return Value:
  1478. VOID
  1479. Author:
  1480. 30-Nov-1993 Tue 19:56:45 created
  1481. style clean up, commented
  1482. Revision History:
  1483. --*/
  1484. {
  1485. POINTL ptlPlot;
  1486. SIZEL szlRect;
  1487. RECTL rclCurClip;
  1488. ptlPlot.x = LTODEVL(pPDev, pClipRectl->left);
  1489. ptlPlot.y = LTODEVL(pPDev, pClipRectl->top );
  1490. szlRect.cx = LTODEVL(pPDev, pClipRectl->right) - ptlPlot.x;
  1491. szlRect.cy = LTODEVL(pPDev, pClipRectl->bottom ) - ptlPlot.y;
  1492. if ((szlRect.cx) && (szlRect.cy)) {
  1493. //
  1494. // Here we try to be intelligent about sending down coordinates thate
  1495. // are too small and would adversly affect the target device.
  1496. //
  1497. if (szlRect.cx < (LONG)pPDev->MinLToDevL) {
  1498. PLOTWARN(("SetClipWindow: cxRect=%ld < MIN=%ld, Make it as MIN",
  1499. szlRect.cx, (LONG)pPDev->MinLToDevL));
  1500. szlRect.cx = (LONG)pPDev->MinLToDevL ;
  1501. }
  1502. if (szlRect.cy < (LONG)pPDev->MinLToDevL) {
  1503. PLOTWARN(("SetClipWindow: cyRect=%ld < MIN=%ld, Make it as MIN",
  1504. szlRect.cy, (LONG)pPDev->MinLToDevL));
  1505. szlRect.cy = (LONG)pPDev->MinLToDevL ;
  1506. }
  1507. } else {
  1508. PLOTWARN(( "SetClipWindow: Clipping out EVERYTHING...."));
  1509. }
  1510. rclCurClip.right = (rclCurClip.left = ptlPlot.x) + szlRect.cx;
  1511. rclCurClip.bottom = (rclCurClip.top = ptlPlot.y) + szlRect.cy;
  1512. if ((pPDev->Flags & PDEVF_HAS_CLIPRECT) &&
  1513. (pPDev->rclCurClip.left == rclCurClip.left) &&
  1514. (pPDev->rclCurClip.top == rclCurClip.top) &&
  1515. (pPDev->rclCurClip.right == rclCurClip.right) &&
  1516. (pPDev->rclCurClip.bottom == rclCurClip.bottom)) {
  1517. PLOTDBG(DBG_SETCLIPWINDOW, ("SetClipWindow: PP%ld, (%ld, %ld)-(%d, %ld) *CACHED*",
  1518. pPDev->Flags & PDEVF_PP_CENTER ? 0 : 1,
  1519. rclCurClip.left, rclCurClip.top,
  1520. rclCurClip.right, rclCurClip.bottom));
  1521. } else {
  1522. PLOTDBG(DBG_SETCLIPWINDOW, ("SetClipWindow: PP%ld, (%ld, %ld)-(%d, %ld)",
  1523. pPDev->Flags & PDEVF_PP_CENTER ? 0 : 1,
  1524. rclCurClip.left, rclCurClip.top,
  1525. rclCurClip.right, rclCurClip.bottom));
  1526. pPDev->rclCurClip = rclCurClip;
  1527. pPDev->Flags |= PDEVF_HAS_CLIPRECT;
  1528. if (pPDev->Flags & PDEVF_PP_CENTER) {
  1529. --rclCurClip.right;
  1530. --rclCurClip.bottom;
  1531. }
  1532. OutputFormatStr(pPDev,
  1533. "IW#d,#d,#d,#d",
  1534. rclCurClip.left, // LL x
  1535. rclCurClip.bottom, // LL y
  1536. rclCurClip.right, // UR x
  1537. rclCurClip.top); // UR y
  1538. }
  1539. }
  1540. VOID
  1541. SetPixelPlacement(
  1542. PPDEV pPDev,
  1543. UINT SetMode
  1544. )
  1545. /*++
  1546. Routine Description:
  1547. This function sets the pixel placement to the center or edge. This
  1548. defines if a pixel is drawn at the intersection of the vertical and
  1549. horizontal coordinates, or on the edge.
  1550. Arguments:
  1551. pPDev - Pointer to the PDEV data structure
  1552. SetMode - SPP_MODE_CENTER (Intersection of pixel GRID) or
  1553. SPP_MODE_EDGE (non intersection of the pixel GRID)
  1554. SPP_FORCE_SET, force to reset regardless of the current cached mode
  1555. Return Value:
  1556. VOID
  1557. Author:
  1558. 25-Jan-1996 Thu 13:33:15 created
  1559. Revision History:
  1560. --*/
  1561. {
  1562. UINT CurMode;
  1563. CurMode = (pPDev->Flags & PDEVF_PP_CENTER) ? SPP_MODE_CENTER :
  1564. SPP_MODE_EDGE;
  1565. if ((SetMode & SPP_FORCE_SET) ||
  1566. ((SetMode & SPP_MODE_MASK) != CurMode)) {
  1567. //
  1568. // Set it now
  1569. //
  1570. if ((SetMode & SPP_MODE_MASK) == SPP_MODE_CENTER) {
  1571. pPDev->Flags |= PDEVF_PP_CENTER;
  1572. OutputString(pPDev, "PP0");
  1573. } else {
  1574. pPDev->Flags &= ~PDEVF_PP_CENTER;
  1575. OutputString(pPDev, "PP1");
  1576. }
  1577. if (pPDev->Flags & PDEVF_HAS_CLIPRECT) {
  1578. RECTL rclCurClip = pPDev->rclCurClip;
  1579. //
  1580. // Make sure we really reset the clipping rectangle
  1581. //
  1582. --(pPDev->rclCurClip.left);
  1583. SetClipWindow(pPDev, &rclCurClip);
  1584. }
  1585. }
  1586. }
  1587. BOOL
  1588. SetRopMode(
  1589. PPDEV pPDev,
  1590. DWORD Rop
  1591. )
  1592. /*++
  1593. Routine Description:
  1594. This function sends the Rop3 mode to the plotter if it is different than
  1595. the current setting.
  1596. Arguments:
  1597. pPDev - Pointer to the PDEV
  1598. Rop - a Rop3 code
  1599. Return Value:
  1600. TRUE/FALSE
  1601. Author:
  1602. 27-Jan-1994 Thu 18:55:54 created
  1603. Revision History:
  1604. --*/
  1605. {
  1606. if (pPDev->LastDevROP != (WORD)(Rop &= 0xFF)) {
  1607. pPDev->LastDevROP = (WORD)Rop;
  1608. if (Rop == 0xCC) {
  1609. return(OutputFormatStr(pPDev, "MC0;"));
  1610. } else {
  1611. return(OutputFormatStr(pPDev, "MC1,#d;", (LONG)Rop));
  1612. }
  1613. }
  1614. return(TRUE);
  1615. }
  1616. BOOL
  1617. SetHSFillType(
  1618. PPDEV pPDev,
  1619. DWORD HSFillTypeIndex,
  1620. LONG lParam
  1621. )
  1622. /*++
  1623. Routine Description:
  1624. This function set the fill type on the plotter only if not already so
  1625. Arguments:
  1626. pPDev - Pointer to our PDEV
  1627. HSFillTypeIdx - a index to pHSFillType, if invalid or out of range then
  1628. a solid color HS_SOLIDCLR is assumed
  1629. lParam - a Long parameter to be sent with FT
  1630. Return Value:
  1631. TRUE/FALSE
  1632. Author:
  1633. 27-Jan-1994 Thu 19:00:21 created
  1634. Revision History:
  1635. --*/
  1636. {
  1637. WORD Index;
  1638. PLOTASSERT(1, "SetFillType: Invalid HSFillTypeIndex=%ld passed, set to SOLID",
  1639. HSFillTypeIndex <= HS_FT_USER_DEFINED, HSFillTypeIndex);
  1640. if (HSFillTypeIndex > HS_FT_USER_DEFINED) {
  1641. HSFillTypeIndex = HS_DDI_MAX;
  1642. }
  1643. if ((Index = (WORD)HSFillTypeIndex) == (WORD)HS_FT_USER_DEFINED) {
  1644. if ((lParam < 0) || (lParam > RF_MAX_IDX)) {
  1645. PLOTASSERT(1, "SetFillType: User defined ID [%ld] invalid, make it 1",
  1646. (lParam > 0) && (lParam <= RF_MAX_IDX), lParam);
  1647. lParam = 1;
  1648. }
  1649. Index += (WORD)lParam;
  1650. }
  1651. if (Index != pPDev->LastFillTypeIndex) {
  1652. PLOTDBG(DBG_FILLTYPE, ("SetFillType: Change %hs (%ld) -> %hs (%ld)",
  1653. (pPDev->LastFillTypeIndex > HS_FT_USER_DEFINED) ?
  1654. pHSFillTypeName[HS_FT_USER_DEFINED] :
  1655. pHSFillTypeName[pPDev->LastFillTypeIndex],
  1656. (pPDev->LastFillTypeIndex > HS_FT_USER_DEFINED) ?
  1657. pPDev->LastFillTypeIndex - HS_FT_USER_DEFINED :
  1658. lParam,
  1659. (Index > HS_FT_USER_DEFINED) ?
  1660. pHSFillTypeName[HS_FT_USER_DEFINED] :
  1661. pHSFillTypeName[Index],
  1662. (Index > HS_FT_USER_DEFINED) ?
  1663. Index - HS_FT_USER_DEFINED : lParam));
  1664. pPDev->LastFillTypeIndex = Index;
  1665. if ((!OutputString(pPDev, "FT")) ||
  1666. (!OutputFormatStr(pPDev, pHSFillType[HSFillTypeIndex], lParam))) {
  1667. return(FALSE);
  1668. }
  1669. } else {
  1670. PLOTDBG(DBG_FILLTYPE, ("SetFillType: HSFillType is SAME = %hs",
  1671. (Index > HS_FT_USER_DEFINED) ?
  1672. pHSFillTypeName[HS_FT_USER_DEFINED] :
  1673. pHSFillTypeName[Index]));
  1674. }
  1675. return(TRUE);
  1676. }
  1677. BOOL
  1678. SendPageHeader(
  1679. PPDEV pPDev
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. This function sends the initialization data to the device for each new
  1684. page. Correct coordinate system and scaling is set.
  1685. Arguments:
  1686. pPDev - Pointer to the PDEV data structure for the page
  1687. Return Value:
  1688. BOOL
  1689. Author:
  1690. 30-Nov-1993 Tue 19:53:13 updated
  1691. Re-write and update to correct system for the NT
  1692. 29-Nov-1993 Mon 23:55:43 updated
  1693. Re-write
  1694. 24-Nov-1993 Wed 22:38:10 updated
  1695. Using CurForm to replace the pform and PAPER_DIM
  1696. 06-Jan-1994 Thu 00:21:17 updated
  1697. Update for SPLTOPLOTUNITS() macro
  1698. 15-Feb-1994 Tue 09:59:34 updated
  1699. Set physical position and anchor corner after command is sent
  1700. 18-Mar-1994 Fri 12:58:24 updated
  1701. add ptlRTLCAP to zero at Page Reset
  1702. 24-May-1994 Tue 00:59:17 updated
  1703. SC command should range from 0 to DEVSIZE - 1
  1704. Revision History:
  1705. --*/
  1706. {
  1707. PPLOTGPC pPlotGPC;
  1708. LONG xMin;
  1709. LONG xMax;
  1710. LONG yMin;
  1711. LONG yMax;
  1712. //
  1713. // Compute minimum required pel size in PLOTDPI from RASTER DPI
  1714. //
  1715. // pPDev->MinLToDevL = (WORD)DIVRNDUP(__PLOT_DPI, _CURR_DPI);
  1716. //
  1717. pPDev->MinLToDevL = (WORD)LTODEVL(pPDev, 1);
  1718. PLOTDBG(DBG_PAGE_HEADER,
  1719. ("SendPageHeader: MinLToDevL=LTODEVL(1)=%ld", pPDev->MinLToDevL));
  1720. //
  1721. // Speedy access
  1722. //
  1723. pPlotGPC = pPDev->pPlotGPC;
  1724. //
  1725. // First, output the Init string that the pPlotGPC has. The PCD file is
  1726. // responsible for all initialization upto and including the IN command.
  1727. //
  1728. if ((pPlotGPC->InitString.pData) &&
  1729. (pPlotGPC->InitString.SizeEach)) {
  1730. OutputBytes(pPDev,
  1731. (LPBYTE)pPlotGPC->InitString.pData,
  1732. (LONG)pPlotGPC->InitString.SizeEach);
  1733. }
  1734. //
  1735. // DMRES_DRAFT (-1)
  1736. // DMRES_LOW (-2)
  1737. // DMRES_MEDIUM (-3)
  1738. // DMRES_HIGH (-4)
  1739. //
  1740. // Assume BEST quality
  1741. //
  1742. xMax = 100;
  1743. switch (pPDev->PlotDM.dm.dmPrintQuality) {
  1744. case DMRES_DRAFT:
  1745. xMax = 0;
  1746. break;
  1747. case DMRES_HIGH:
  1748. xMax = 100;
  1749. break;
  1750. default:
  1751. switch (pPlotGPC->MaxQuality) {
  1752. case 2:
  1753. xMax = 0;
  1754. break;
  1755. case 3:
  1756. xMax = 50;
  1757. break;
  1758. default:
  1759. xMax = 34;
  1760. break;
  1761. }
  1762. if (pPDev->PlotDM.dm.dmPrintQuality == DMRES_MEDIUM) {
  1763. xMax = 100 - xMax;
  1764. }
  1765. break;
  1766. }
  1767. OutputFormatStr(pPDev, "QL#d", xMax);
  1768. //
  1769. // PS: This command tells the target device what the hard clip limits should
  1770. // be. The target device will adjust the command we send if its beyond
  1771. // the real hard clip limits. Always send CY (lenght) first then CX
  1772. // (width)
  1773. //
  1774. // RO: Only sent to rotate the target device coordinate system if the
  1775. // PlotForm.Flags is set accordinly. This is because HPGL2 always
  1776. // assumes the LONGER side sent using the PS command is X in the
  1777. // standard coordinate system. Because of this behavior we may have
  1778. // to swap X and Y in order to correct the coordinate system.
  1779. //
  1780. // IP: This command defines where the users's unit origin and extent is.
  1781. // We set this so that the origin and extend is exactly the printable
  1782. // rectangle related to the HARD CLIP LIMITS (not the paper/form size)
  1783. //
  1784. // SC: This defines the user unit scaling. Currently we are 1:1 but use
  1785. // this command to flip the X or Y origin so we have the same
  1786. // coordinate system as GDI.
  1787. //
  1788. // ALL PlotForm UNITS are in 1/1000mm or Windows 2000, Windows XP,
  1789. // Windows Server 2003 spooler forms units.
  1790. //
  1791. //
  1792. // If we support transparent mode we want to make sure its off to begin
  1793. // with, because the driver assumes its off.
  1794. //
  1795. if (IS_TRANSPARENT(pPDev)) {
  1796. OutputString( pPDev, "TR0;");
  1797. }
  1798. OutputFormatStr(pPDev, "ROPS#d,#d",
  1799. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cy),
  1800. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cx));
  1801. PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: ROPS%ld,%ld%hs",
  1802. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cy),
  1803. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.PlotSize.cx),
  1804. (pPDev->PlotForm.Flags & PFF_ROT_COORD_L90) ? "RO90" : ""));
  1805. if (pPDev->PlotForm.Flags & PFF_ROT_COORD_L90) {
  1806. OutputString(pPDev, "RO90");
  1807. }
  1808. //
  1809. // Compute the scaling amount and direction, if FLIP_X_COORD or a
  1810. // FLIP_Y_COORD flags are set then we need to flip the scale in X or Y
  1811. // direction.
  1812. //
  1813. #if 1
  1814. xMin =
  1815. xMax = pPDev->HorzRes - 1;
  1816. yMin =
  1817. yMax = pPDev->VertRes - 1;
  1818. #else
  1819. xMin =
  1820. xMax = SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogExt.cx) - 1;
  1821. yMin =
  1822. yMax = SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogExt.cy) - 1;
  1823. #endif
  1824. if (pPDev->PlotForm.Flags & PFF_FLIP_X_COORD) {
  1825. xMax = 0;
  1826. } else {
  1827. xMin = 0;
  1828. }
  1829. if (pPDev->PlotForm.Flags & PFF_FLIP_Y_COORD) {
  1830. yMax = 0;
  1831. } else {
  1832. yMin = 0;
  1833. }
  1834. //
  1835. // IP - to set the p1/p2
  1836. // SC - to scale it (only used to flip the HPGL/2 coordinate)
  1837. // AC - anchor point to default (0, 0)
  1838. //
  1839. OutputFormatStr(pPDev, "IP#d,#d,#d,#dSC#d,#d,#d,#dAC",
  1840. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.x),
  1841. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.y),
  1842. SPLTOPLOTUNITS(pPlotGPC,
  1843. (pPDev->PlotForm.LogOrg.x +
  1844. pPDev->PlotForm.LogExt.cx)) - 1,
  1845. SPLTOPLOTUNITS(pPlotGPC,
  1846. (pPDev->PlotForm.LogOrg.y +
  1847. pPDev->PlotForm.LogExt.cy)) - 1,
  1848. xMin, xMax, yMin, yMax);
  1849. PLOTDBG(DBG_PAGE_HEADER, ("SendPageHeader: IP%ld,%ld,%ld,%ldSC%ld,%ld,%ld,%ldAC",
  1850. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.x),
  1851. SPLTOPLOTUNITS(pPlotGPC, pPDev->PlotForm.LogOrg.y),
  1852. SPLTOPLOTUNITS(pPlotGPC,
  1853. (pPDev->PlotForm.LogOrg.x +
  1854. pPDev->PlotForm.LogExt.cx)) - 1,
  1855. SPLTOPLOTUNITS(pPlotGPC,
  1856. (pPDev->PlotForm.LogOrg.y +
  1857. pPDev->PlotForm.LogExt.cy)) - 1,
  1858. xMin, xMax, yMin, yMax));
  1859. //
  1860. // Set RTL CAP back to zero, this is true after a EscE is sent
  1861. //
  1862. pPDev->ptlRTLCAP.x =
  1863. pPDev->ptlRTLCAP.y =
  1864. pPDev->ptlAnchorCorner.x =
  1865. pPDev->ptlAnchorCorner.y = 0;
  1866. pPDev->PenWidth.Integer =
  1867. pPDev->PenWidth.Decimal = 0;
  1868. //
  1869. // Reset pen position to (0,0)
  1870. //
  1871. OutputString(pPDev, "PA0,0");
  1872. if ((IS_COLOR(pPDev)) && (IS_RASTER(pPDev))) {
  1873. //
  1874. // !!!Work around some color device limitations in order to make
  1875. // TR/ROP function correctly.
  1876. //
  1877. OutputString(pPDev, "PC1,255,0,0PC2,255,255,255SP1PD99,0SP2PD0,0PU");
  1878. }
  1879. //
  1880. // Create the pallete, this will send out the pens as needed
  1881. //
  1882. if (!PlotCreatePalette(pPDev)) {
  1883. PLOTERR(("DrvEnableSurface: PlotCreatePalette() failed."));
  1884. return(FALSE);
  1885. }
  1886. //
  1887. // Reset PW to 0
  1888. //
  1889. OutputString(pPDev, "WU0PW0");
  1890. if (IS_RASTER(pPDev)) {
  1891. //
  1892. // If we are in poster mode, set up for it now.
  1893. //
  1894. if (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) {
  1895. xMin = SPLTOENGUNITS(pPDev, pPDev->PlotForm.PlotSize.cx);
  1896. yMin = SPLTOENGUNITS(pPDev, pPDev->PlotForm.PlotSize.cy);
  1897. xMax = GetBmpDelta(HTBMPFORMAT(pPDev), xMin);
  1898. yMax = xMax * yMin;
  1899. PLOTDBG(DBG_PAGE_HEADER,
  1900. ("SendPageHeader: ** POSTER MODE *** Scan=%ld bytes x cy (%ld) = %ld bytes",
  1901. xMax, yMin, yMax));
  1902. if (yMax <= MIN_POSTER_SIZE) {
  1903. pPDev->PlotDM.Flags &= ~PDMF_PLOT_ON_THE_FLY;
  1904. PLOTDBG(DBG_PAGE_HEADER,
  1905. ("SendPageHeader: Size <= %ld bytes, Turn OFF Poster Mode",
  1906. MIN_POSTER_SIZE));
  1907. }
  1908. }
  1909. OutputFormatStr(pPDev,
  1910. ";\033%0A\033*t#dR\033*v1N\033&a#dN\033%0B",
  1911. pPDev->pPlotGPC->RasterXDPI,
  1912. (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) ? 1 : 0);
  1913. }
  1914. //
  1915. // Whole surface can be drawn to
  1916. //
  1917. ClearClipWindow(pPDev);
  1918. SetPixelPlacement(pPDev, SPP_FORCE_SET | SPP_MODE_EDGE);
  1919. return(TRUE);
  1920. }
  1921. BOOL
  1922. SendPageTrailer(
  1923. PPDEV pPDev
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. This function does any end of page commands, takes multiple copies into
  1928. account, and ejects the page.
  1929. Arguments:
  1930. pPDev - Pointer to PDEV data structure
  1931. Return Value:
  1932. TRUE if sucessful FALSE if failed.
  1933. Author:
  1934. 15-Feb-1994 Tue 09:56:58 updated
  1935. I move the physical position setting to the SendPageHeader
  1936. 30-Nov-1993 Tue 21:42:21 updated
  1937. clean up style, commented, Updated
  1938. Revision History:
  1939. --*/
  1940. {
  1941. //
  1942. // Store the pen back to the carousel and advance full page
  1943. //
  1944. OutputString(pPDev, "PUSPPG;");
  1945. //
  1946. // Check to see if were doing multiple copies and send them if we are
  1947. //
  1948. if (pPDev->PlotDM.dm.dmCopies > 1) {
  1949. OutputFormatStr(pPDev, "RP#d;", (LONG)pPDev->PlotDM.dm.dmCopies - 1);
  1950. }
  1951. //
  1952. // Flush the output buffer.
  1953. //
  1954. return(FlushOutBuffer(pPDev));
  1955. }