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.

3036 lines
102 KiB

  1. /***************************** Module Header ********************************
  2. * render.c
  3. * High level functions associated with rendering a bitmap to a
  4. * printer. Basic operation depends upon whether we are going to
  5. * rotate the bitmap - either because the printer cannot, or it
  6. * is faster if we do it.
  7. * With rotation, allocate a chunk of memory and transpose the
  8. * output bitmap into it. Call the normal processing code, but
  9. * with this allocated memory and new fake bitmap info. After
  10. * processing this chunk, transpose the next and process. Repeat
  11. * until the entire bitmap has been rendered. Free the memory, return.
  12. * Without rotation, simply pass the bitmap onto the rendering
  13. * code, to process in one hit.
  14. *
  15. *
  16. * Copyright (C) 1991 - 1999, Microsoft Corporation
  17. *
  18. ***************************************************************************/
  19. #include "raster.h"
  20. #include "compress.h"
  21. #include "rmrender.h"
  22. #include "fontif.h"
  23. #include "rmdebug.h"
  24. #include "xlraster.h"
  25. /*
  26. * Constants used to calculate the amount of memory to request if we
  27. * need to transpose the engine's bitmap before sending to the printer.
  28. * If at least one head pass will fit within the the TRANSPOSE_SIZE
  29. * buffer, then request this amount of storage. If not, calculate how
  30. * much is needed and request that much.
  31. */
  32. #define TRANSPOSE_SIZE 0x20000 /* 128k */
  33. //used when we can grow the block height
  34. #define DEF_BLOCK_SIZE 0x08000 /* 32k */
  35. #define MAX_BLOCK_SIZE 0x40000 /* 256k */
  36. /*
  37. * Set a limit to the number of interlaced lines that we can print.
  38. * Interlacing is used to increase the resolution of dot matrix printers,
  39. * by printing lines in between lines. Typically the maximum interlace
  40. * will be 2, but we allow more just in case. This size determines the
  41. * size of an array allocated on the stack. The array is of ints, so
  42. * there is not much storage consumed by setting this high a value.
  43. */
  44. #define MAX_INTERLACE 10 /* Dot matrix style interlace factor */
  45. /*
  46. * Local function prototypes.
  47. */
  48. BOOL bRealRender( PDEV *, DWORD *, RENDER * );
  49. BOOL bOnePassOut( PDEV *, BYTE *, RENDER * );
  50. BOOL bOneColourPass( PDEV *, BYTE *, RENDER * );
  51. INT iLineOut( PDEV *, RENDER *, BYTE *, INT, INT );
  52. void vInvertBits( DWORD *, INT );
  53. //void vFindWhiteInvertBits ( RASTERPDEV *, RENDER *, DWORD *);
  54. BOOL bLookAheadOut( PDEV *, INT, RENDER *, INT );
  55. #ifdef TIMING
  56. #include <stdio.h>
  57. void DrvDbgPrint(
  58. char * pch,
  59. ...)
  60. {
  61. va_list ap;
  62. char buffer[256];
  63. va_start(ap, pch);
  64. EngDebugPrint("",pch,ap);
  65. va_end(ap);
  66. }
  67. #endif
  68. /************************ Function Header ***********************************
  69. * bRenderInit
  70. * Called during DrvEnableSurface time - we initialise a RENDER_DATA
  71. * structure which will be used for the duration of this surface.
  72. *
  73. * RETURNS:
  74. * TRUE/FALSE, FALSE means a minidriver problem or no memory.
  75. *
  76. * HISTORY:
  77. * Monday November 29 1993 -by- Norman Hendley [normanh]
  78. * Implement multiple scanline printing; fixed & variable block height.
  79. *
  80. * 10:58 on Tue 10 Nov 1992 -by- Lindsay Harris [lindsayh]
  81. * Moved from start of bRender() - second incarnation.
  82. *
  83. ****************************************************************************/
  84. BOOL
  85. bRenderInit( pPDev, sizl, iFormat )
  86. PDEV *pPDev; /* Our key to the universe */
  87. SIZEL sizl; /* Size of processing band, <= sizlPage */
  88. INT iFormat; /* GDI bitmap format */
  89. {
  90. INT cbOutBand; /* Bytes per output band: based on # pins */
  91. INT cbOneBlock; /* Bytes per minimum sized block if block variable */
  92. INT iBPP; /* Bits per pel - expect 1 or 4 */
  93. INT iIndex; /* Loop paramter */
  94. INT iBytesPCol; /* Bytes per column - only for colour */
  95. RASTERPDEV *pRPDev; /* The unidrive PDEV - printer details */
  96. RENDER *pRD; /* Miscellaneous rendering data */
  97. #ifdef TIMING
  98. ENG_TIME_FIELDS TimeTab;
  99. pRPDev = pPDev->pRasterPDEV;
  100. EngQueryLocalTime(&TimeTab);
  101. pRPDev->dwTiming = (((TimeTab.usMinute*60)+TimeTab.usSecond)*1000)+
  102. TimeTab.usMilliseconds;
  103. #endif
  104. ASSERTMSG(!(sizl.cx == 0 || sizl.cy == 0),("unidrv!bRenderInit - null shadow bitmap\n"));
  105. /*
  106. * Allocate storage for our RENDER structure, then set it all to
  107. * zero, so that it is in a known safe state.
  108. */
  109. pRPDev = pPDev->pRasterPDEV;
  110. if( !(pRD = (RENDER *) MemAllocZ(
  111. ( pPDev->bBanding) ? sizeof(RENDER) * 2 : sizeof( RENDER ))))
  112. return FALSE;
  113. pRPDev->pvRenderData = pRD;
  114. pRPDev->pvRenderDataTmp = ( pPDev->bBanding ) ? pRD+1 : NULL;
  115. /*
  116. * Various operations depend upon what format bitmap we have. So
  117. * now is the time to set this all up.
  118. */
  119. pRD->dwDevWhiteIndex = 0;
  120. switch( iFormat )
  121. {
  122. case BMF_1BPP:
  123. iBPP = 1;
  124. pRD->bWhiteLine = bIsLineWhite;
  125. pRD->bWhiteBand = bIsBandWhite;
  126. pRD->ubFillWhite = 0;
  127. pRD->vLtoPTransFn = vTrans8N;
  128. break;
  129. case BMF_4BPP:
  130. iBPP = 4;
  131. if ((pRPDev->fColorFormat & DC_OEM_BLACK) &&
  132. !(pRPDev->fColorFormat & DC_PRIMARY_RGB))
  133. {
  134. pRD->bWhiteLine = bIsLineWhite;
  135. pRD->bWhiteBand = bIsBandWhite;
  136. pRD->ubFillWhite = 0;
  137. }
  138. else
  139. {
  140. if (pRPDev->fColorFormat & DC_PRIMARY_RGB)
  141. pRD->dwDevWhiteIndex = 0x77777777;
  142. pRD->bWhiteLine = bIsRGBLineWhite;
  143. pRD->bWhiteBand = bIsRGBBandWhite;
  144. pRD->ubFillWhite = 0x77;
  145. }
  146. pRD->vLtoPTransFn = vTrans8N4BPP;
  147. break;
  148. case BMF_8BPP:
  149. iBPP = 8;
  150. pRD->bWhiteLine = bIs8BPPLineWhite;
  151. pRD->bWhiteBand = bIs8BPPBandWhite;
  152. pRD->dwDevWhiteIndex = pRD->ubFillWhite = (BYTE)pRPDev->pPalData->iWhiteIndex;
  153. pRD->dwDevWhiteIndex |= pRD->dwDevWhiteIndex << 8;
  154. pRD->dwDevWhiteIndex |= pRD->dwDevWhiteIndex << 16;
  155. pRD->vLtoPTransFn = vTrans8BPP;
  156. break;
  157. case BMF_24BPP:
  158. iBPP = 24;
  159. pRD->bWhiteLine = bIs24BPPLineWhite;
  160. pRD->bWhiteBand = bIs24BPPBandWhite;
  161. pRD->ubFillWhite = 0xff;
  162. pRD->dwDevWhiteIndex = ~(DWORD)0;
  163. pRD->vLtoPTransFn = vTrans24BPP;
  164. break;
  165. default:
  166. #if DBG
  167. DbgPrint( "Unidrv!bRender: not 1, 4, 8 or 24 bits per pel bitmap\n" );
  168. #endif
  169. SetLastError( ERROR_INVALID_PARAMETER );
  170. return FALSE;
  171. }
  172. pRD->iBPP = iBPP;
  173. // If there is no Y movement commands we need to send every scan
  174. // so we don't want to find white lines
  175. // PCLXL GPD files don't have YMOVE commands. But it needs to find white
  176. // lines.
  177. if (pPDev->arCmdTable[CMD_YMOVERELDOWN] == NULL &&
  178. pPDev->arCmdTable[CMD_YMOVEABSOLUTE] == NULL &&
  179. pPDev->arCmdTable[CMD_SETLINESPACING] == NULL &&
  180. pPDev->ePersonality != kPCLXL_RASTER)
  181. {
  182. pRD->bWhiteLine = pRD->bWhiteBand = bIsNeverWhite;
  183. pRPDev->fBlockOut |= RES_BO_NO_YMOVE_CMD;
  184. }
  185. // initialize bTTY for TTY device
  186. pRD->PrinterType = pPDev->pGlobals->printertype;
  187. if( pRPDev->sMinBlankSkip == 0 || iBPP == 24)
  188. {
  189. /* Presume this means skip should not be performed. */
  190. pRPDev->fBlockOut &= ~RES_BO_ENCLOSED_BLNKS;
  191. }
  192. pRD->iCursor = pRPDev->fCursor;
  193. pRD->iFlags = 0; /* Nothing set, yet */
  194. pRD->fDump = pRPDev->fDump;
  195. pRD->Trans.pdwTransTab = pRPDev->pdwTrans;
  196. pRD->pdwBitMask = pRPDev->pdwBitMask;
  197. pRD->pdwColrSep = pRPDev->pdwColrSep; /* Colour translation */
  198. pRD->ix = sizl.cx;
  199. pRD->iy = sizl.cy;
  200. pRD->iSendCmd = CMD_SENDBLOCKDATA; //CMD_RES_SENDBLOCK;
  201. pRD->cBLine = pRD->ix * iBPP; /* Bits in scanline */
  202. pRD->cDWLine = (pRD->cBLine + DWBITS - 1) / DWBITS;
  203. pRD->cBYLine = pRD->cDWLine * DWBYTES;
  204. pRD->iPassHigh = pRPDev->sNPins;
  205. // Derryd : Minidriver Callback
  206. if (pRPDev->fRMode & PFR_BLOCK_IS_BAND ) //means callback wants entire band as one block
  207. {
  208. //don't want any stripping, because would mean creating new buffers
  209. pRPDev->fBlockOut &= ~(RES_BO_LEADING_BLNKS |
  210. RES_BO_TRAILING_BLNKS | RES_BO_ENCLOSED_BLNKS);
  211. pRD->fDump &= ~RES_DM_LEFT_BOUND;
  212. pRD->iPassHigh = pRD->iy ;
  213. }
  214. // end
  215. if (pPDev->ePersonality == kPCLXL_RASTER)
  216. {
  217. pRPDev->fBlockOut |= RES_BO_LEADING_BLNKS | RES_BO_TRAILING_BLNKS;
  218. pRPDev->fBlockOut &= ~RES_BO_ENCLOSED_BLNKS;
  219. }
  220. //Set the key fields which enable us print multiple scanlines
  221. if (pRD->fDump & RES_DM_GDI) //GDI style graphics
  222. {
  223. // No interlacing on these devices
  224. pRD->iInterlace = 1;
  225. // iHeight is fixed & the minimum size block we can print
  226. pRD->iHeight= pRD->iPassHigh;
  227. //iNumScans can grow if device allows it.
  228. pRD->iNumScans= pRD->iHeight;
  229. //in case minidriver developer sets otherwise
  230. //Existing code relies on this being one for GDI style graphics
  231. pRD->iBitsPCol = 1;
  232. }
  233. else //Old dot matrix column style graphics
  234. {
  235. pRD->iBitsPCol = pRPDev->sPinsPerPass;
  236. pRD->iInterlace = pRD->iPassHigh / pRD->iBitsPCol;
  237. // questionable choice, but enables easier checking later
  238. pRD->iNumScans= 1;
  239. //our one constant between graphics modes
  240. pRD->iHeight= pRD->iBitsPCol;
  241. }
  242. pRD->iPosnAdv = pRD->iHeight; // can be negative
  243. if( pRD->iInterlace > MAX_INTERLACE )
  244. {
  245. #if DBG
  246. DbgPrint( "unidrv!bRenderInit: Printer Interlace too big to handle\n" );
  247. #endif
  248. SetLastError( ERROR_INVALID_PARAMETER );
  249. return FALSE;
  250. }
  251. // We'll need to scan the bitmap in blocks rather than single lines
  252. //
  253. if (pRD->iNumScans > 1)
  254. pRD->bWhiteLine = pRD->bWhiteBand;
  255. /*
  256. * Calculate the size needed for the output transpose buffer. This
  257. * is the buffer used to convert the data into the pin order needed
  258. * for dot matrix printers.
  259. */
  260. if( pPDev->fMode & PF_ROTATE )
  261. {
  262. /* We do the rotation, so the Y dimension is the one to use. */
  263. cbOutBand = pRD->iy;
  264. }
  265. else
  266. cbOutBand = pRD->ix; /* Format as it comes in */
  267. //used for dangling scanline scenario
  268. cbOneBlock = ((cbOutBand * iBPP + DWBITS - 1) / DWBITS) *
  269. DWBYTES * pRD->iHeight;
  270. // In this case we don't know how large our final blocks will be.
  271. // Set a reasonable limit of 32k & use that for compression & white
  272. // space stripping buffers.
  273. // Calculate what the corresponding max number of scanlines should be.
  274. if (pRPDev->fBlockOut & RES_BO_MULTIPLE_ROWS)
  275. {
  276. INT tmp = ((cbOutBand * iBPP + DWBITS - 1) / DWBITS) * DWBYTES;
  277. cbOutBand = pPDev->pGlobals->dwMaxMultipleRowBytes;
  278. if (cbOutBand < tmp)
  279. cbOutBand = DEF_BLOCK_SIZE;
  280. else if (cbOutBand > MAX_BLOCK_SIZE)
  281. cbOutBand = MAX_BLOCK_SIZE;
  282. pRD->iMaxNumScans = cbOutBand / tmp;
  283. }
  284. else
  285. {
  286. pRD->iMaxNumScans = pRD->iHeight;
  287. cbOutBand = cbOneBlock;
  288. }
  289. //
  290. // If each data byte needs to be mirrored before output
  291. // we will generate the table here
  292. //
  293. if (pRPDev->fBlockOut & RES_BO_MIRROR)
  294. {
  295. INT i;
  296. if ((pRD->pbMirrorBuf = MemAlloc(256)) == NULL)
  297. return FALSE;
  298. for (i = 0;i < 256;i++)
  299. {
  300. BYTE bOut = 0;
  301. if (i & 0x01) bOut |= 0x80;
  302. if (i & 0x02) bOut |= 0x40;
  303. if (i & 0x04) bOut |= 0x20;
  304. if (i & 0x08) bOut |= 0x10;
  305. if (i & 0x10) bOut |= 0x08;
  306. if (i & 0x20) bOut |= 0x04;
  307. if (i & 0x40) bOut |= 0x02;
  308. if (i & 0x80) bOut |= 0x01;
  309. pRD->pbMirrorBuf[i] = bOut;
  310. }
  311. }
  312. //
  313. // time to do more color depth specific calculations
  314. //
  315. switch( iBPP )
  316. {
  317. case 4: /* 4 bits per pel - printer is planar */
  318. /* Colour, so select the colour rendering function */
  319. pRD->bPassProc = bOneColourPass;
  320. pRD->Trans.pdwTransTab = pRPDev->pdwColrSep;
  321. //
  322. // map the color order to the required data offset for planar data
  323. // rgbOrder valid values are emum {none,r,g,b,c,m,y,k}
  324. //
  325. iBytesPCol = (pRD->iBitsPCol + BBITS - 1) / BBITS;
  326. {
  327. INT offset = (pRPDev->fColorFormat & DC_PRIMARY_RGB) ? 1 : 4 ;
  328. for( iIndex = 0; iIndex < COLOUR_MAX; ++iIndex )
  329. {
  330. INT tmp = pRPDev->rgbOrder[iIndex] - offset;
  331. pRD->iColOff[ iIndex ] = iBytesPCol * (COLOUR_MAX - 1 - tmp);
  332. }
  333. }
  334. pRD->pbColSplit = MemAlloc( cbOutBand / 4 );
  335. if( pRD->pbColSplit == 0 )
  336. return FALSE;
  337. //
  338. // If we need to send every color plane we must disable LEADING and ENCLOSED
  339. // white space removal for 4bpp. However, as long as we're not sending RGB data
  340. // we can still enable TRAILING white space removal.
  341. //
  342. if (pRPDev->fColorFormat & DC_SEND_ALL_PLANES)
  343. {
  344. pRD->iFlags |= RD_ALL_COLOUR;
  345. pRD->fDump &= ~RES_DM_LEFT_BOUND;
  346. if (pRPDev->fColorFormat & DC_PRIMARY_RGB)
  347. pRPDev->fBlockOut &= ~(RES_BO_LEADING_BLNKS | RES_BO_ENCLOSED_BLNKS | RES_BO_TRAILING_BLNKS);
  348. else
  349. pRPDev->fBlockOut &= ~(RES_BO_LEADING_BLNKS | RES_BO_ENCLOSED_BLNKS);
  350. }
  351. break;
  352. case 1: /* 1 bit per pel - monochrome */
  353. case 8: /* Seiko special - 8 bits per pel */
  354. pRD->bPassProc = bOnePassOut;
  355. pRD->Trans.pdwTransTab = pRPDev->pdwTrans;
  356. pRD->pbColSplit = 0; /* No storage allocated either! */
  357. break;
  358. case 24:
  359. pRD->bPassProc = bOnePassOut;
  360. pRD->Trans.pdwTransTab = NULL;
  361. pRD->pbColSplit = 0; /* No storage allocated either! */
  362. break;
  363. }
  364. /*
  365. * There are potentially 2 transpose operations. For printers
  366. * which print more than one line per pass, AND which require the
  367. * data in column order across the page (this defines dot matrix
  368. * printers), we need to transpose per output head pass. This is
  369. * not required for devices like laser printers, which require
  370. * the data one scan line at a time.
  371. * Note also that this operation is unrelated to the larger
  372. * question of rotating the PAGE image before rendering - for sending
  373. * a landscape image to a printer that can only print portrait mode.
  374. */
  375. if (pRD->fDump & RES_DM_GDI) // GDI style graphics
  376. {
  377. if( iBPP == 4 )
  378. {
  379. /* Paintjet style printer - need to colour separate */
  380. pRD->vTransFn = vTransColSep;
  381. }
  382. else
  383. {
  384. /* LaserJet style printer - one pin per head pass */
  385. pRD->vTransFn = 0; /* Nothing to call */
  386. }
  387. //This allows us use iIsBandWhite with multi scanline printing
  388. pRD->iTransHigh = pRD->iHeight;
  389. }
  390. else
  391. {
  392. /*
  393. * General dot matrix case. Apart from selecting an active
  394. * transpose function, we must allocate a transpose buffer;
  395. * this is required for fiddling with the bit order in the lines
  396. * of data to be sent to the printer.
  397. */
  398. pRD->iTransWide = pRD->ix * iBPP;
  399. pRD->iTransHigh = pRD->iBitsPCol;
  400. pRD->iTransSkip = (pRD->iTransHigh + BBITS - 1) / BBITS;
  401. /* How to change the address pointer during transpose operations */
  402. pRD->cbTLine = pRD->cDWLine * DWBYTES * pRD->iInterlace;
  403. if( pRD->iBitsPCol == BBITS )
  404. {
  405. /*
  406. * When the printer has 8 pins, we have a special transpose
  407. * function which is faster than the more general case.
  408. * So, use that one!
  409. */
  410. pRD->vTransFn = vTrans8x8;
  411. }
  412. else if (pRD->PrinterType != PT_TTY)
  413. pRD->vTransFn = vTrans8N; /* The general case */
  414. else
  415. pRD->vTransFn = NULL; /* Txtonly no need to transpose */
  416. }
  417. if( pRD->vTransFn )
  418. {
  419. /*
  420. * Determine the amount of memory needed for the transpose buffer.
  421. * The scan lines are DWORD aligned, but there may be any number of
  422. * scan lines involved. The presumption is that the output of
  423. * the transpose function will be packed on byte boundaries, so
  424. * storage size only needs to be rounded up to the nearest byte size.
  425. */
  426. if( !(pRD->pvTransBuf = MemAlloc( cbOutBand )) )
  427. return FALSE;
  428. }
  429. else
  430. pRD->pvTransBuf = 0; /* No store, nothing to free */
  431. pRD->iyBase = 0; /* When multiple passes are required */
  432. pRD->ixOrg = 0; /* Graphics origin - laserjet style */
  433. //We need a buffer so we can strip leading and/or trailing white space
  434. //on multiple scan line devices.
  435. //We also need to set up a buffer to mask non-interesting data at end
  436. //of page if ScanLines_Left < iNumScans
  437. //This is not a concern for old dot matrix style graphics as the
  438. //transpose code takes care of it.
  439. if ( ((pRD->iNumScans > 1) || (pRPDev->fBlockOut & RES_BO_MULTIPLE_ROWS))
  440. && (!(pRPDev->fRMode & PFR_BLOCK_IS_BAND ) ))
  441. {
  442. if ( !(pRD->pStripBlanks = MemAlloc(cbOutBand)))
  443. return FALSE;
  444. if (pRD->iNumScans > 1)
  445. if ( !(pRD->pdwTrailingScans = MemAlloc( cbOneBlock)) )
  446. return FALSE;
  447. }
  448. //
  449. // We need to determine which compression modes are enabled
  450. //
  451. if (pRPDev->fRMode & PFR_COMP_TIFF)
  452. {
  453. pRD->pdwCompCmds[pRD->dwNumCompCmds++] = CMD_ENABLETIFF4;
  454. }
  455. if (pRPDev->fRMode & PFR_COMP_FERLE)
  456. {
  457. pRD->pdwCompCmds[pRD->dwNumCompCmds++] = CMD_ENABLEFERLE;
  458. }
  459. if (pRPDev->fRMode & PFR_COMP_DRC)
  460. {
  461. pRD->pdwCompCmds[pRD->dwNumCompCmds++] = CMD_ENABLEDRC;
  462. }
  463. if (pRPDev->fRMode & PFR_COMP_OEM)
  464. {
  465. pRD->pdwCompCmds[pRD->dwNumCompCmds++] = CMD_ENABLEOEMCOMP;
  466. }
  467. //
  468. // if compression is available we need to allocate a buffer for
  469. // each active compression type
  470. //
  471. if (pRD->dwNumCompCmds)
  472. {
  473. INT i = pRD->dwNumCompCmds;
  474. //
  475. // calculate the size for the buffers
  476. //
  477. pRD->dwCompSize = cbOutBand + (cbOutBand >> 5) + COMP_FUDGE_FACTOR;
  478. //
  479. // if there is FERLE or OEM compression we can enable
  480. // no compression as a valid compression type
  481. //
  482. if (pRPDev->fRMode & (PFR_COMP_FERLE | PFR_COMP_OEM))
  483. {
  484. if (COMMANDPTR(pPDev->pDriverInfo,CMD_DISABLECOMPRESSION))
  485. {
  486. pRD->pdwCompCmds[pRD->dwNumCompCmds++] = CMD_DISABLECOMPRESSION;
  487. }
  488. //
  489. // need to allocate a larger buffer for RLE or OEM compression if
  490. // no compression is not an option since it must have enough space
  491. //
  492. else
  493. pRD->dwCompSize = cbOutBand + (cbOutBand >> 1) + COMP_FUDGE_FACTOR;
  494. }
  495. //
  496. // loop once per compression type to allocate buffers
  497. //
  498. while (--i >= 0)
  499. {
  500. // allocate compression buffer
  501. //
  502. pRD->pCompBufs[i] = MemAlloc (pRD->dwCompSize);
  503. if (!pRD->pCompBufs[i])
  504. return FALSE;
  505. //
  506. // if delta row, allocate buffer for previous row
  507. // and initialize it to zero assuming blank row
  508. //
  509. if (pRD->pdwCompCmds[i] == CMD_ENABLEDRC)
  510. {
  511. pRD->pDeltaRowBuffer = MemAlloc(cbOutBand);
  512. if (!pRD->pDeltaRowBuffer)
  513. return FALSE;
  514. }
  515. }
  516. }
  517. pRD->dwLastCompCmd = CMD_DISABLECOMPRESSION;
  518. /*
  519. * Adjustments to whether we rotate the bitmap, and if so, which way.
  520. */
  521. if( pPDev->fMode & PF_ROTATE )
  522. {
  523. /* Rotation is our responsibility */
  524. if( pPDev->fMode & PF_CCW_ROTATE90 )
  525. {
  526. /* Counter clockwise rotation - LaserJet style */
  527. pRD->iyPrtLine = pPDev->sf.szImageAreaG.cx - 1;
  528. pRD->iPosnAdv = -pRD->iPosnAdv;
  529. pRD->iXMoveFn = YMoveTo;
  530. pRD->iYMoveFn = XMoveTo;
  531. }
  532. else
  533. {
  534. /* Clockwise rotation - dot matrix style */
  535. pRD->iyPrtLine = 0;
  536. pRD->iXMoveFn = XMoveTo;
  537. pRD->iYMoveFn = YMoveTo;
  538. }
  539. }
  540. else
  541. {
  542. /* No rotation: either portrait, or printer does it */
  543. pRD->iyPrtLine = 0;
  544. pRD->iXMoveFn = XMoveTo;
  545. pRD->iYMoveFn = YMoveTo;
  546. }
  547. pRD->iyLookAhead = pRD->iyPrtLine; /* For DeskJet lookahead */
  548. /*
  549. * When we hit the lower level functions, we want to know how many
  550. * bytes are in the buffer of stuff to be sent to the printer. This
  551. * depends upon the number of bits per pel, number of pels and the
  552. * the number of scan lines processed at the same time.
  553. * The only oddity is that when we have a 4 BPP device, the
  554. * planes are split before we get to the lowest level, and so we
  555. * we need to reduce the size by 4 to obtain the real length.
  556. */
  557. // Note when printing a block of scanlines iMaxBytesSend will be the max byte
  558. // count for each scanline, not of the block , which is dword aligned.
  559. pRD->iMaxBytesSend = (pRD->cBLine * pRD->iBitsPCol + BBITS - 1) / BBITS;
  560. if( iBPP == 4 )
  561. pRD->iMaxBytesSend = (pRD->iMaxBytesSend + 3) / 4;
  562. return TRUE; /* Must be OK if we made it this far */
  563. }
  564. /************************ Function Header *********************************
  565. * bRenderStartPage
  566. * Called at the start of a new page. This is mostly to assist in
  567. * banding, where much of the per page initialisation would be
  568. * done more than once.
  569. *
  570. * RETURNS:
  571. * TRUE/FALSE, FALSE largely being failure to allocate memory.
  572. *
  573. * HISTORY:
  574. * 09:42 on Fri 19 Feb 1993 -by- Lindsay Harris [lindsayh]
  575. * First incarnation, to solve some banding problems.
  576. *
  577. ***************************************************************************/
  578. BOOL
  579. bRenderStartPage( pPDev )
  580. PDEV *pPDev; /* Access to everything */
  581. {
  582. #ifndef DISABLE_RULES
  583. RASTERPDEV *pRPDev;
  584. pRPDev = pPDev->pRasterPDEV;
  585. /*
  586. * If the printer can handle rules, now is the time to initialise
  587. * the rule finding code.
  588. */
  589. if( pRPDev->fRMode & PFR_RECT_FILL )
  590. vRuleInit( pPDev, pRPDev->pvRenderData );
  591. #endif
  592. return TRUE;
  593. }
  594. /************************ Function Header *********************************
  595. * bRenderPageEnd
  596. * Called at the end of rendering a page. Basically frees up the
  597. * per page memory, cleans up any dangling bits and pieces, and
  598. * otherwise undoes vRenderPageStart.
  599. *
  600. * RETURNS:
  601. * TRUE/FALSE, FALSE being a failure of memory freeing operations.
  602. *
  603. * HISTORY:
  604. * 15:16 on Fri 09 Apr 1993 -by- Lindsay Harris [lindsayh]
  605. * White text support.
  606. *
  607. * 09:44 on Fri 19 Feb 1993 -by- Lindsay Harris [lindsayh]
  608. * First incarnation.
  609. *
  610. **************************************************************************/
  611. BOOL
  612. bRenderPageEnd( pPDev )
  613. PDEV *pPDev;
  614. {
  615. #ifndef DISABLE_RULES
  616. RASTERPDEV *pRPDev = pPDev->pRasterPDEV;
  617. /* Finish up with the rules code - includes freeing memory */
  618. if( pRPDev->fRMode & PFR_RECT_FILL )
  619. vRuleEndPage( pPDev );
  620. #endif
  621. return TRUE;
  622. }
  623. /************************ Function Header ***********************************
  624. * vRenderFree
  625. * Free up any and all memory used by rendering. Basically this is
  626. * the complementary function to bRenderInit().
  627. *
  628. * RETURNS:
  629. * Nothing.
  630. *
  631. * HISTORY:
  632. * 12:46 on Tue 10 Nov 1992 -by- Lindsay Harris [lindsayh]
  633. * Removed from bRender() when initialisation code was moved out.
  634. *
  635. *****************************************************************************/
  636. void
  637. vRenderFree( pPDev )
  638. PDEV *pPDev; /* All that we need */
  639. {
  640. /*
  641. * First verify that we have a RENDER structure to free!
  642. */
  643. RENDER *pRD; /* For our convenience */
  644. PRASTERPDEV pRPDev = pPDev->pRasterPDEV;
  645. if( pRD = pRPDev->pvRenderData )
  646. {
  647. if( pRD->pvTransBuf )
  648. {
  649. /*
  650. * Dot matrix printers require a transpose for each print head
  651. * pass, so we now free the memory used for that.
  652. */
  653. MemFree ( pRD->pvTransBuf );
  654. }
  655. if( pRD->pbColSplit )
  656. MemFree ( pRD->pbColSplit );
  657. if( pRD->pStripBlanks )
  658. MemFree ( pRD->pStripBlanks );
  659. if( pRD->pdwTrailingScans)
  660. MemFree ( pRD->pdwTrailingScans );
  661. if (pRD->pbMirrorBuf)
  662. MemFree (pRD->pbMirrorBuf);
  663. if( pRD->plrWhite)
  664. {
  665. // WARNING(("Freeing plrWhite in vRenderFree\n"));
  666. MemFree ( pRD->plrWhite );
  667. }
  668. // free compression buffers
  669. //
  670. if (pRD->dwNumCompCmds)
  671. {
  672. DWORD i;
  673. for (i = 0;i < pRD->dwNumCompCmds;i++)
  674. {
  675. if (pRD->pCompBufs[i])
  676. MemFree (pRD->pCompBufs[i]);
  677. }
  678. if (pRD->pDeltaRowBuffer)
  679. MemFree(pRD->pDeltaRowBuffer);
  680. }
  681. MemFree ( (LPSTR)pRD );
  682. pRPDev->pvRenderData = NULL; /* Won't do it again! */
  683. }
  684. #ifndef DISABLE_RULES
  685. if( pRPDev->fRMode & PFR_RECT_FILL )
  686. vRuleFree( pPDev ); /* Could do this in DisableSurface */
  687. #endif
  688. return;
  689. }
  690. /************************ Function Header ***********************************
  691. * bRender
  692. * Function to take a bitmap and render it to the printer. This is the
  693. * high level function that basically hides the requirement of
  694. * bitmap transposing from the real rendering code.
  695. *
  696. * Auguments
  697. * SURFOBJ *pso; Surface object
  698. * PDEV *pPDev; Our PDEV: key to everything
  699. * RENDER *pRD; The RENDER structure of our dreams
  700. * SIZEL sizl; Bitmap size
  701. * DWORD *pBits; Actual data to process
  702. *
  703. * This code still has a lot of room for optimization. The current
  704. * implementation makes multiple passes over the entire bitmap. This
  705. * guarantees that there will rarely be an internal (8K or 16K) or
  706. * external (64K to 256K) cache hit slowing things down significantly.
  707. * Any possiblity to make all passes a count of scans totaling
  708. * 8K (minus code) or less will have significant performance advantages.
  709. * Also attempting to avoid writes will have significant advantages.
  710. *
  711. * As a first pass at attempting this, the HP laserjet code has been
  712. * optimized to merge the invertion pass in with the rule processing
  713. * pass along with the detection of blank scans. It also eliminates
  714. * the inversion of inverting (writing) the left and right edges of
  715. * scans that are white. It processes the scans in 34 scan bands which
  716. * will have great cache effects if the area between the left and
  717. * right edges of non white data total less than 4K to 6K and reasonable
  718. * cache effects in all cases since it at least stay in the external
  719. * cache. In the future, this code should also be modified to ouput
  720. * the scans as soon as it is done processing the rules for each band.
  721. * Currently it processes all scans on the page for rules and then
  722. * calls the routine to output the scans. This would trully make it
  723. * a one pass alogrithm.
  724. *
  725. * As of 12/30/93, only the HP laserjets have been optimized in this way.
  726. * All raster printers could probably be optimized particularly when
  727. * any transposing is necessary, detecting the left and right edges
  728. * of scans that are white. Transposing is expensive. It is probably
  729. * less important for dot matrix printers that take so long to output
  730. * but it is still burning up CPU time that might be better served
  731. * giving a USER bet responsiveness from apps while printing in the
  732. * back ground.
  733. *
  734. * The optimizations to the HP LaserJet had the following results. All
  735. * numbers are in terms of number of instructions and were pretty closely
  736. * matched with total times to render an entire 8.5 X 11 300dpi page.
  737. *
  738. * OLD OPTIMIZED
  739. * Blank page 8,500,000 950,000
  740. * full text page 15,500,000 8,000,000
  741. *
  742. *
  743. * RETURNS:
  744. * TRUE for successful completion, else FALSE.
  745. *
  746. * HISTORY:
  747. * 30-Dec-1993 -by- Eric Kutter [erick]
  748. * optimized for HP laserjet
  749. *
  750. * 14:23 on Tue 10 Nov 1992 -by- Lindsay Harris [lindsayh]
  751. * Split up for journalling - initialisation moved up above.
  752. *
  753. * 16:11 on Fri 11 Jan 1991 -by- Lindsay Harris [lindsayh]
  754. * Created it, before DDI spec'd on how we are called.
  755. *
  756. ****************************************************************************/
  757. BOOL
  758. bRender(
  759. SURFOBJ *pso,
  760. PDEV *pPDev,
  761. RENDER * pRD,
  762. SIZEL sizl,
  763. DWORD *pBits )
  764. {
  765. BOOL bRet; /* Return value */
  766. INT iBPP; /* Bits per pel - expect 1 or 4 */
  767. RASTERPDEV *pRPDev; /* The unidrive PDEV - printer details */
  768. #ifdef TIMING
  769. ENG_TIME_FIELDS TimeTab;
  770. DWORD sTime,eTime;
  771. pRPDev = pPDev->pRasterPDEV;
  772. EngQueryLocalTime(&TimeTab);
  773. sTime = (((TimeTab.usMinute*60)+TimeTab.usSecond)*1000)+
  774. TimeTab.usMilliseconds;
  775. {
  776. char buf[80];
  777. sprintf (buf,"Unidrv!bRender: GDI=%d, %dx%dx%d\n",
  778. sTime-pRPDev->dwTiming,sizl.cx,sizl.cy,pRD->iBPP);
  779. DrvDbgPrint(buf);
  780. }
  781. #else
  782. pRPDev = pPDev->pRasterPDEV;
  783. #endif
  784. // if all scan lines need to be output then we need to
  785. // make sure we don't send the extra scan lines at the
  786. // end of the last band
  787. //
  788. if (pRPDev->fBlockOut & RES_BO_NO_YMOVE_CMD)
  789. {
  790. if (!(pPDev->fMode & PF_ROTATE))
  791. {
  792. if ((pRD->iyPrtLine + sizl.cy) > pPDev->rcClipRgn.bottom)
  793. sizl.cy = pPDev->rcClipRgn.bottom - pRD->iyPrtLine;
  794. }
  795. }
  796. //
  797. // if this band is blank we will update our position
  798. // and then just return
  799. //
  800. else if (!(pPDev->fMode & PF_SURFACE_USED) &&
  801. (pRD->PrinterType == PT_PAGE || !pPDev->iFonts))
  802. {
  803. if (pPDev->fMode & PF_ROTATE)
  804. {
  805. if (pPDev->fMode & PF_CCW_ROTATE90)
  806. pRD->iyPrtLine -= sizl.cx;
  807. else
  808. pRD->iyPrtLine += sizl.cx;
  809. }
  810. else
  811. pRD->iyPrtLine += sizl.cy;
  812. #ifdef TIMING
  813. DrvDbgPrint ("Unidrv!bRender: Skipping blank band\n");
  814. #endif
  815. return TRUE;
  816. }
  817. iBPP = pRD->iBPP; /* Speedier access as local variable */
  818. // this code filters the raster data so that any set pixel
  819. // will have at least one adjacent horizontal pixel set and
  820. // at least one adjacent vertical pixel set
  821. //
  822. if (iBPP == 1 && (pPDev->fMode & PF_SINGLEDOT_FILTER))
  823. {
  824. INT cy,i;
  825. cy = sizl.cy;
  826. while (--cy >= 0)
  827. {
  828. DWORD *pdwC,*pdwB,*pdwA;
  829. // Calculate pointers
  830. //
  831. pdwC = &pBits[pRD->cDWLine*cy];
  832. //
  833. // We will do horizontal filter first
  834. //
  835. if (pPDev->pbRasterScanBuf[cy / LINESPERBLOCK])
  836. {
  837. BYTE bA,bL,*pC;
  838. // skip leading white space
  839. for (i = 0;i < pRD->cDWLine;i++)
  840. if (pdwC[i] != ~0) break;
  841. pC = (BYTE *)pdwC;
  842. bL = (BYTE)~0;
  843. i *= DWBYTES;
  844. while (i < pRD->cBYLine)
  845. {
  846. bA = pC[i];
  847. pC[i] &= (((bA >> 1) | (bL << 7)) | ~((bA >> 2) | (bL << 6)));
  848. bL = bA;
  849. i++;
  850. }
  851. }
  852. // Test if adjacent scan line is blank
  853. //
  854. if (cy && pPDev->pbRasterScanBuf[(cy-1) / LINESPERBLOCK])
  855. {
  856. // test if scan line is blank
  857. pdwB = &pdwC[-pRD->cDWLine];
  858. pdwA = &pdwB[-pRD->cDWLine];
  859. if (pPDev->pbRasterScanBuf[cy / LINESPERBLOCK] == 0)
  860. {
  861. RECTL rcTmp;
  862. // test if anything needs to be set here
  863. //
  864. i = pRD->cDWLine;
  865. while (--i >= 0)
  866. if ((~pdwA[i] | pdwB[i]) != ~0) break;
  867. //
  868. // if line is blank we can skip it
  869. if (i < 0) continue;
  870. // we need to clear this block
  871. //
  872. rcTmp.top = cy;
  873. rcTmp.bottom = cy;
  874. rcTmp.left = rcTmp.right = 0;
  875. CheckBitmapSurface(pso,&rcTmp);
  876. }
  877. // this is the normal case
  878. //
  879. if (cy > 1 && pPDev->pbRasterScanBuf[(cy-2) / LINESPERBLOCK])
  880. {
  881. for (i = 0;i < pRD->cDWLine;i++)
  882. {
  883. pdwC[i] &= ~pdwA[i] | pdwB[i];
  884. }
  885. }
  886. // in this case line A is blank
  887. //
  888. else
  889. {
  890. for (i = 0;i < pRD->cDWLine;i++)
  891. {
  892. pdwC[i] &= pdwB[i];
  893. }
  894. }
  895. }
  896. }
  897. }
  898. // test whether we need to erase the rest of the bitmap
  899. //
  900. if (pPDev->bTTY) // bug fix 194505
  901. {
  902. pPDev->fMode &= ~PF_SURFACE_USED;
  903. }
  904. else if ((pRPDev->fBlockOut & RES_BO_NO_YMOVE_CMD) ||
  905. (pPDev->fMode & PF_SURFACE_USED &&
  906. ((pPDev->fMode & PF_ROTATE) ||
  907. pRPDev->sPinsPerPass != 1 ||
  908. pRPDev->sNPins != 1)))
  909. {
  910. CheckBitmapSurface(pso,NULL);
  911. }
  912. #ifdef TIMING
  913. if (!(pPDev->fMode & PF_SURFACE_ERASED) && pPDev->pbRasterScanBuf)
  914. {
  915. INT i,j,k;
  916. char buf[80];
  917. k = (pPDev->szBand.cy + LINESPERBLOCK - 1) / LINESPERBLOCK;
  918. for (i = 0, j = 0;i < k;i++)
  919. if (pPDev->pbRasterScanBuf[i] == 0) j++;
  920. sprintf (buf,"Unidrv!bRender: Skipped %d of %d blocks\n",j,k);
  921. DrvDbgPrint(buf);
  922. }
  923. #endif
  924. /*
  925. * Initialize the fields for optimizing the rendering of the bitmap.
  926. * The main purpose is to have a single pass over the bits. This
  927. * can significantly speed up rendering due to cache effects. In
  928. * the old days, we took at least 3 passes over the entire bitmap for
  929. * laserjets. One to invert the bits, one+ to find rules, and then
  930. * a third to output the data. We now delay the invertion of the
  931. * bits until after rules are found. We also keep left/right information
  932. * of non white space for each row. This way, any white on the edges
  933. * or completely white rows are only touch once and from then on, only
  934. * DWORDS with black need be touched. Also, the invertion is expensive
  935. * since it causes writing every DWORD.
  936. */
  937. pRD->plrWhite = NULL;
  938. pRD->plrCurrent = NULL;
  939. pRD->clr = 0;
  940. //
  941. // Set flag to clear delta row buffer
  942. //
  943. pRD->iFlags |= RD_RESET_DRC;
  944. /*
  945. * Various operations depend upon what format bitmap we have. So
  946. * now is the time to set this all up.
  947. */
  948. //
  949. // If 1 bit per pixel mode we need to explicitly invert the
  950. // data, but we may do it later in rules.
  951. // The only other data this is allowed to be inverted is
  952. // 4BPP and it is done in the transform functions
  953. //
  954. if (pRD->iBPP == 1 && (pPDev->fMode & PF_SURFACE_USED))
  955. pRD->bInverted = FALSE;
  956. else
  957. pRD->bInverted = TRUE;
  958. /*
  959. * Check if rotation is required. If so, allocate storage,
  960. * start transposing, etc.
  961. */
  962. if( pPDev->fMode & PF_ROTATE )
  963. {
  964. /*
  965. * Rotation is the order of the day. First chew up some memory
  966. * for the transpose function.
  967. */
  968. INT iTHigh; /* Height after transpose */
  969. INT cTDWLine; /* DWORDS per line after transpose */
  970. INT iAddrInc; /* Address increment AFTER transpose */
  971. INT iDelta; /* Transpose book keeping */
  972. INT cbTransBuf; /* Bytes needed for L -> P transpose */
  973. INT ixTemp; /* Maintain pRD->ix around this op */
  974. TRANSPOSE tpBig; /* For the landscape transpose */
  975. TRANSPOSE tpSmall; /* For the per print head pass */
  976. TRANSPOSE tp; /* Banding: restore after we clobber */
  977. /*
  978. * First step is to determine how large to make the area
  979. * wherein the data will be transposed for later rendering.
  980. * Take the number of scan lines, and round this up to a
  981. * multiple of DWORDS. Then find out how many of these will
  982. * fit into a reasonable size chunk of memory. The number
  983. * should be a multiple of the number of pins per pass -
  984. * this to make sure we don't have partial head passes, if
  985. * that is possible.
  986. */
  987. /*
  988. * OPTIMIZATION POTENTIAL - deterimine left/right edges of non
  989. * white area and only transpose that portion (at least for
  990. * laser printers). There are often areas of white at the
  991. * top and or bottom. In the case of the HP laser printers,
  992. * only the older printers (I believe series II) go through
  993. * this code. LaserJet III and beyond can do graphics in
  994. * landscape so don't need this. (erick 12/20/93)
  995. */
  996. tp = pRD->Trans; /* Keep a safe copy for later use */
  997. ixTemp = pRD->ix;
  998. cTDWLine = (sizl.cy * iBPP + DWBITS - 1) / DWBITS;
  999. cbTransBuf = DWBYTES * cTDWLine * pRD->iPassHigh;
  1000. if( cbTransBuf < TRANSPOSE_SIZE )
  1001. cbTransBuf = TRANSPOSE_SIZE;
  1002. iTHigh = cbTransBuf / (cTDWLine * DWBYTES);
  1003. if( iTHigh > sizl.cx )
  1004. {
  1005. /* Bigger than we need, so shrink to actual size */
  1006. iTHigh = sizl.cx; /* Scan lines we have to process */
  1007. /* Make multiple of pins per pass - round up */
  1008. if( pRD->iPassHigh == 1 )
  1009. {
  1010. /*
  1011. * LaserJet/PaintJet style, so round to byte alignment.
  1012. */
  1013. if (iBPP < BBITS)
  1014. iTHigh = (iTHigh + BBITS / iBPP - 1) & ~(BBITS / iBPP - 1);
  1015. }
  1016. else
  1017. iTHigh += (pRD->iPassHigh - (iTHigh % pRD->iPassHigh)) %
  1018. pRD->iPassHigh;
  1019. }
  1020. else
  1021. {
  1022. /* Make multiple of pins per pass - round down */
  1023. if( pRD->iPassHigh == 1 )
  1024. {
  1025. if (iBPP < BBITS)
  1026. iTHigh &= ~(BBITS / iBPP - 1); /* Byte alignment for LJs */
  1027. }
  1028. else
  1029. iTHigh -= iTHigh % pRD->iPassHigh;
  1030. }
  1031. cbTransBuf = iTHigh * cTDWLine * DWBYTES;
  1032. pRD->iy = iTHigh;
  1033. /* Set up data for the transpose function */
  1034. tpBig.iHigh = sizl.cy;
  1035. tpBig.iSkip = cTDWLine * DWBYTES; /* Bytes per transpose output */
  1036. tpBig.iWide = iTHigh * iBPP; /* Scanlines we will process */
  1037. tpBig.cBL = pRD->ix * iBPP;
  1038. pRD->ix = sizl.cy;
  1039. tpBig.cDWL = (tpBig.cBL + DWBITS - 1) / DWBITS;
  1040. tpBig.iIntlace = 1; /* Landscape -> portrait: no interlace */
  1041. tpBig.cBYL = tpBig.cDWL * DWBYTES;
  1042. tpBig.icbL = tpBig.cDWL * DWBYTES;
  1043. tpBig.pdwTransTab = pRPDev->pdwTrans; /* For L -> P rotation */
  1044. if( !(tpBig.pvBuf = MemAlloc( cbTransBuf )) )
  1045. {
  1046. bRet = FALSE;
  1047. }
  1048. else
  1049. {
  1050. /* Have the memory, start pounding away */
  1051. INT iAdj; /* Alignment adjustment, first band */
  1052. bRet = TRUE; /* Until proven guilty */
  1053. /*
  1054. * Recompute some of the transpose data for the smaller
  1055. * bitmap produced from our call to transpose.
  1056. */
  1057. pRD->iTransWide = sizl.cy * iBPP; /* Smaller size */
  1058. pRD->cBLine = pRD->ix * iBPP;
  1059. pRD->iMaxBytesSend = (pRD->cBLine * pRD->iBitsPCol + BBITS - 1) /
  1060. BBITS;
  1061. if( iBPP == 4 )
  1062. pRD->iMaxBytesSend = (pRD->iMaxBytesSend+3) / 4;
  1063. pRD->cDWLine = (pRD->cBLine + DWBITS - 1) / DWBITS;
  1064. pRD->cBYLine = pRD->cDWLine * DWBYTES;
  1065. pRD->cbTLine = pRD->cDWLine * DWBYTES * pRD->iInterlace;
  1066. tpSmall = pRD->Trans; /* Keep it for later reuse */
  1067. /*
  1068. * Set up the move commands required when rendering. In this
  1069. * instance, the X and Y operations are interchanged.
  1070. */
  1071. iAddrInc = (pRD->iy * iBPP) / BBITS; /* Bytes per scanline */
  1072. if( pPDev->fMode & PF_CCW_ROTATE90 )
  1073. {
  1074. /*
  1075. * This is typified by the LaserJet Series II case.
  1076. * The output bitmap should be rendered from the end
  1077. * to the beginning, the scan line number decreases from
  1078. * one line to the next (moving down the output page),
  1079. * and the X and Y move functions are interchanged.
  1080. */
  1081. tpSmall.icbL = -tpSmall.icbL; /* Scan direction */
  1082. /*
  1083. * Need to process bitmap in reverse order. This means
  1084. * shifting the address to the right hand end of the
  1085. * first scan line, then coming back one transpose pass
  1086. * width. Also set the address increment to be negative,
  1087. * so that we work our way towards the beginning.
  1088. */
  1089. /*
  1090. * To simplify the transpose loop following, we start
  1091. * rendering the bitmap from the RHS. The following
  1092. * statement does just that: the sizl.cx / BBITS is
  1093. * the number of used bytes in the scan line, iAddrInc
  1094. * is the number per transpose pass, so subtracting it
  1095. * will put us at the beginning of the last full band
  1096. * on this transpose.
  1097. */
  1098. /* !!!LindsayH - should sizl.cx be sizl.cx * iBPP ????? */
  1099. iAdj = (BBITS - (sizl.cx & (BBITS - 1))) % BBITS;
  1100. sizl.cx += iAdj; /* Byte multiple */
  1101. (BYTE *)pBits += (sizl.cx * iBPP) / BBITS - iAddrInc;
  1102. iAddrInc = -iAddrInc;
  1103. }
  1104. else
  1105. {
  1106. /*
  1107. * Typified by HP PaintJet printers - those that have no
  1108. * landscape mode, and where the output is rendered from
  1109. * the start of the bitmap towards the end, where the
  1110. * scan line number INCREASES by one from one line to the
  1111. * the next (moving down the output page), and the X and Y
  1112. * move functions are as expected.
  1113. */
  1114. pBits += tpBig.cDWL * (sizl.cy - 1); /* Start of last row */
  1115. tpBig.icbL = -tpBig.icbL; /* Backwards through memory */
  1116. iAdj = 0;
  1117. }
  1118. while( bRet && (iDelta = (int)sizl.cx) > 0 )
  1119. {
  1120. pRD->Trans = tpBig; /* For the chunk transpose */
  1121. if( (iDelta * iBPP) < pRD->iTransWide )
  1122. {
  1123. /* Last band - reduce the number of rows */
  1124. pRD->iTransWide = iDelta * iBPP; /* The remainder */
  1125. pRD->iy = iDelta; /* For bRealRender */
  1126. if( iAddrInc < 0 )
  1127. {
  1128. iDelta = -iDelta; /* The OTHER dirn */
  1129. (BYTE *)pBits += -iAddrInc + (iDelta * iBPP) / BBITS;
  1130. }
  1131. }
  1132. /* Transpose this chunk of data unless it is empty */
  1133. if (pPDev->fMode & PF_SURFACE_USED)
  1134. pRD->vLtoPTransFn( (BYTE *)pBits, pRD );
  1135. pRD->Trans = tpSmall;
  1136. pRD->iy -= iAdj;
  1137. bRet = bRealRender( pPDev, tpBig.pvBuf, pRD );
  1138. pRD->iy += iAdj;
  1139. iAdj = 0;
  1140. /* Skip to the next chunk of input data */
  1141. (BYTE *)pBits += iAddrInc; /* May go backwards */
  1142. pRD->iyBase += pRD->iy;
  1143. sizl.cx -= pRD->iy;
  1144. }
  1145. MemFree ( tpBig.pvBuf );
  1146. }
  1147. pRD->Trans = tp;
  1148. pRD->ix = ixTemp;
  1149. }
  1150. else
  1151. {
  1152. /*
  1153. * Simple case - no rotation, so process the bitmap as is.
  1154. * This means starting at the FIRST scan line which we have
  1155. * set to the top of the image.
  1156. * Set up the move commands required when rendering. In this
  1157. * instance, the X and Y operations are their normal way.
  1158. */
  1159. INT iyTemp;
  1160. iyTemp = pRD->iy;
  1161. pRD->iy = sizl.cy;
  1162. bRet = bRealRender( pPDev, pBits, pRD );
  1163. pRD->iy = iyTemp;
  1164. }
  1165. /*
  1166. * Turn unidirection off
  1167. */
  1168. if (pRD->iFlags & RD_UNIDIR)
  1169. {
  1170. pRD->iFlags &= ~RD_UNIDIR;
  1171. WriteChannel (pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_UNIDIRECTIONOFF));
  1172. }
  1173. /*
  1174. * Return from graphics mode, to be civilised.
  1175. */
  1176. if( pRD->iFlags & RD_GRAPHICS)
  1177. {
  1178. if (pRD->dwLastCompCmd != CMD_DISABLECOMPRESSION)
  1179. {
  1180. pRD->dwLastCompCmd = CMD_DISABLECOMPRESSION;
  1181. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_DISABLECOMPRESSION));
  1182. }
  1183. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_ENDRASTER));
  1184. pRD->iFlags &= ~RD_GRAPHICS;
  1185. }
  1186. #ifdef TIMING
  1187. EngQueryLocalTime(&TimeTab);
  1188. eTime = (((TimeTab.usMinute*60)+TimeTab.usSecond)*1000)+
  1189. TimeTab.usMilliseconds;
  1190. eTime -= sTime;
  1191. {
  1192. char buf[80];
  1193. sprintf (buf,"Unidrv!bRender: %ld\n",eTime);
  1194. DrvDbgPrint(buf);
  1195. }
  1196. #endif
  1197. return bRet;
  1198. }
  1199. /************************ Function Header ***********************************
  1200. * bRealRender
  1201. * The REAL rendering function. By the time we reach here, the bitmap
  1202. * is in the correct orientation, and so we need to be serious
  1203. * about rendering it.
  1204. *
  1205. * RETURNS:
  1206. * TRUE for successful rendering, else FALSE.
  1207. *
  1208. * HISTORY:
  1209. * Friday 26 November -by- Norman Hendley [normanh]
  1210. * Added multiple scanline per send block support
  1211. *
  1212. * 16:22 on Fri 11 Jan 1991 -by- Lindsay Harris [lindsayh]
  1213. * Started on it.
  1214. *
  1215. ****************************************************************************/
  1216. BOOL
  1217. bRealRender( pPDev, pBits, pRData )
  1218. PDEV *pPDev; /* Our PDEV: key to everything */
  1219. DWORD *pBits; /* Actual data to process */
  1220. RENDER *pRData; /* Details of rendering process */
  1221. {
  1222. /*
  1223. * Process the bitmap in groups of scan lines. The number in the
  1224. * the group is determined by the printer. Laser printers are
  1225. * processed one scan line at a time, while dot matrix are processed
  1226. * according to the number of pins they can fire at once. This
  1227. * information is generated by our caller from the printer
  1228. * characterisation data, or otherwise!
  1229. */
  1230. INT iLine; /* Current scan line */
  1231. INT cDWPass; /* DWORDS per head pass */
  1232. INT iDWLine; /* DWORDS processed per interlace scan */
  1233. INT iILAdv; /* Line advance per interlace operation */
  1234. INT iHeadLine; /* Decide when graphics pass required */
  1235. INT iTHKeep; /* Local copy of iTransHigh: we change it */
  1236. INT iHeight;
  1237. INT iNumScans; /* local copy*/
  1238. BOOL bCheckBlocks;
  1239. RASTERPDEV * pRPDev;
  1240. PAL_DATA *pPD;
  1241. INT iWhiteIndex;
  1242. INT iILDone[ MAX_INTERLACE ]; /* For head pass reduction */
  1243. PLEFTRIGHT plr = NULL; /* left/right of non white area */
  1244. pRPDev = pPDev->pRasterPDEV;
  1245. pPD = pRPDev->pPalData;
  1246. iWhiteIndex = pPD->iWhiteIndex;
  1247. iHeight = pRData->iHeight;
  1248. cDWPass = pRData->cDWLine * iHeight;
  1249. if( pRData->iPosnAdv < 0 )
  1250. {
  1251. /* Data needs to be sent in reverse order, so adjust now */
  1252. pBits += cDWPass * (pRData->iy / pRData->iPassHigh - 1);
  1253. cDWPass = -cDWPass;
  1254. iDWLine = -pRData->cDWLine;
  1255. iILAdv = -1;
  1256. }
  1257. else
  1258. {
  1259. /* Usual case, but some special local variables */
  1260. iDWLine = pRData->cDWLine;
  1261. iILAdv = 1;
  1262. }
  1263. /* if the bits have already been inverted, don't bother with the rule proc.
  1264. * The bits will be inverted for the multi scan line devices inside
  1265. * bRuleProc because multi scan line implementation assumes
  1266. * that bits are inverted. The function bRuleProc is changed to take
  1267. * take care of multi scan line support (erick)
  1268. */
  1269. if(!pRData->bInverted)
  1270. {
  1271. if (pRPDev->fRMode & PFR_RECT_FILL)
  1272. {
  1273. if (!bRuleProc( pPDev, pRData, pBits ))
  1274. vInvertBits(pBits, pRData->iy * pRData->cDWLine);
  1275. }
  1276. else if (pRData->iNumScans != 1 || pRData->iPassHigh != 1 ||
  1277. (pRPDev->fBlockOut & RES_BO_NO_YMOVE_CMD))
  1278. vInvertBits(pBits, pRData->iy * pRData->cDWLine);
  1279. else {
  1280. pRData->bWhiteLine = bIsNegatedLineWhite;
  1281. pRData->bWhiteBand = bIsNegatedLineWhite;
  1282. }
  1283. }
  1284. iHeadLine = 0;
  1285. for( iLine = 0; iLine < pRData->iInterlace; ++iLine )
  1286. iILDone[ iLine ] = 0;
  1287. iTHKeep = pRData->iTransHigh;
  1288. plr = (pRData->iMaxNumScans > 1) ? NULL : pRData->plrWhite;
  1289. if (!(pPDev->fMode & PF_SURFACE_ERASED) && pPDev->pbRasterScanBuf)
  1290. bCheckBlocks = TRUE;
  1291. else
  1292. bCheckBlocks = FALSE;
  1293. //normanh This code could be made tighter. My concern in adding multiple
  1294. //scanline support was not to risk breaking existing code.
  1295. //For improved performance, having separate code paths for GDI style &
  1296. //old dot matrix style graphics could be considered
  1297. for( iLine = 0; iLine < pRData->iy; iLine += iNumScans )
  1298. {
  1299. /*
  1300. * Check to see if there is graphics data in the current
  1301. * print pass. This only happens once at the start of each
  1302. * print pass.
  1303. */
  1304. BOOL bIsWhite = FALSE; /* Set if no graphics in this pass*/
  1305. BYTE *pbData; /* pointer to data we will send */
  1306. /*
  1307. * Have we been aborted? If so, return failure NOW.
  1308. */
  1309. if(pPDev->fMode & PF_ABORTED )
  1310. return FALSE;
  1311. iNumScans = pRData->iNumScans;
  1312. if (!(pPDev->fMode & PF_SURFACE_USED))
  1313. {
  1314. bIsWhite = TRUE;
  1315. }
  1316. else if (plr != NULL)
  1317. {
  1318. if (plr[iLine].left > plr[iLine].right)
  1319. bIsWhite = TRUE;
  1320. pRData->plrCurrent = plr + iLine;
  1321. }
  1322. else if (bCheckBlocks && pPDev->pbRasterScanBuf[iLine / LINESPERBLOCK] == 0)
  1323. {
  1324. //
  1325. // Since this whole block is white we will try to skip to the first line
  1326. // of the next block rather than loop for each scan line. However we need
  1327. // to make sure we don't skip past the end of the band.
  1328. //
  1329. if (((pRData->PrinterType == PT_PAGE) || !(pPDev->iFonts)) &&
  1330. (pRData->iInterlace == 1))
  1331. {
  1332. if ((iNumScans = pRData->iy - iLine) > LINESPERBLOCK)
  1333. iNumScans = LINESPERBLOCK;
  1334. }
  1335. bIsWhite = TRUE;
  1336. }
  1337. if( iILDone[ iHeadLine ] == 0 )
  1338. {
  1339. if( (pRData->iy - iLine) < pRData->iPassHigh )
  1340. {
  1341. /*
  1342. * MESSY: the end of the page, and there are some
  1343. * dangling scan lines. Since this IS the end of the
  1344. * page, we can fiddle with RENDER information, since
  1345. * this will no longer be used after this time. iTransHigh
  1346. * is used for rendering operations. They will be
  1347. * adjusted now so that we do not flow off the end of
  1348. * the engine's bitmap.
  1349. */
  1350. pRData->iTransHigh = (pRData->iy - iLine +
  1351. pRData->iInterlace - 1) / pRData->iInterlace;
  1352. if (plr == NULL && !bIsWhite)
  1353. bIsWhite = pRData->bWhiteBand( pBits, pRData, iWhiteIndex );
  1354. /*
  1355. * If this band is all white, we can set the iLDone
  1356. * entry, since we now know that this remaining part
  1357. * of the page/band is white, and so we do not wish to
  1358. * consider it further. Note that interlaced output
  1359. * allows the possibility that some other lines in this
  1360. * area will be output.
  1361. * Note that the value (iBitsPCol - 1) may be larger than
  1362. * the number of lines remaining in this band. However
  1363. * this is safe to do, since we drop out of this function
  1364. * before reaching the excess lines, and the array data
  1365. * is initialised on every call to this function.
  1366. */
  1367. if( bIsWhite )
  1368. iILDone[ iHeadLine ] = pRData->iBitsPCol - 1;
  1369. else
  1370. {
  1371. /*
  1372. * Need to consider a special case in here. If the
  1373. * printer has > 8 pins, and there are 8 or more
  1374. * scan lines to be dropped off the bottom, then the
  1375. * transpose function will not clear the remaining
  1376. * part of the buffer, since it only zeroes up
  1377. * to 7 scan lines at the bottom of the transpose area.
  1378. * Hence, if we meet these conditions, we zero the
  1379. * area before calling the transpose operation.
  1380. *
  1381. * It can be argued that this should happen in the
  1382. * transpose code, but it is really a special case that
  1383. * can only happen at this location.
  1384. */
  1385. if( pRData->vTransFn &&
  1386. (iHeight - pRData->iTransHigh) >= BBITS )
  1387. {
  1388. /* Set the memory to zero. */
  1389. ZeroMemory( pRData->pvTransBuf,
  1390. DWBYTES * pRData->cDWLine * pRData->iHeight );
  1391. }
  1392. // Another special case; block of scanlines
  1393. // Copy the data we're interesed in , into a white buffer of
  1394. // block size
  1395. if (iNumScans > 1)
  1396. {
  1397. DWORD iDataLeft = DWBYTES * pRData->cDWLine * (pRData->iy - iLine);
  1398. FillMemory((PBYTE)pRData->pdwTrailingScans+iDataLeft,
  1399. (pRData->cDWLine * iHeight * DWBYTES) - iDataLeft,
  1400. pRData->ubFillWhite);
  1401. CopyMemory(pRData->pdwTrailingScans,pBits,iDataLeft);
  1402. pBits = pRData->pdwTrailingScans;
  1403. }
  1404. }
  1405. }
  1406. else
  1407. {
  1408. if (plr == NULL && !bIsWhite)
  1409. {
  1410. bIsWhite = pRData->bWhiteLine( pBits, pRData, iWhiteIndex );
  1411. }
  1412. }
  1413. /* Data to go, so go send it to the printer */
  1414. if( !bIsWhite )
  1415. {
  1416. pbData = (BYTE *)pBits; /* What we are given */
  1417. // This is not elegant. This code is not structured to what we need to
  1418. // do here when printing multiple scanlines.
  1419. // What we do is basically take control from the outer loop, increase the
  1420. // block size to what we want to print, print it & then increase outer
  1421. // loop counters appropriately
  1422. // Found First non-white scanline
  1423. // Grow the block height until we hit a white scanline,
  1424. // reach the max block height, or end of page
  1425. // Note the following loop will execute only if the device is
  1426. // capable of increasing the block height: iHeight < iMaxNumScans
  1427. while (((pRData->iNumScans + iHeight) < pRData->iMaxNumScans) &&
  1428. ((iLine + iHeight + iHeight) <= pRData->iy) &&
  1429. (!bCheckBlocks || pPDev->pbRasterScanBuf[(iLine+iHeight) / LINESPERBLOCK]) &&
  1430. !(pRData->bWhiteBand((DWORD *)(pBits + cDWPass),pRData,iWhiteIndex)))
  1431. {
  1432. pRData->iNumScans += iHeight;
  1433. pBits += cDWPass;
  1434. iLine += iHeight;
  1435. }
  1436. /*
  1437. * Time to transpose the data into the order required to be
  1438. * sent to the printer. For single pin printers (Laserjets),
  1439. * nothing happens at this stage, but for dot matrix printers,
  1440. * typically n scan lines are sent in bit column order, so now
  1441. * the bits are transposed into that order.
  1442. */
  1443. if( pRData->vTransFn )
  1444. {
  1445. /*
  1446. * this will not work with lazy invertion used with rule
  1447. * detection for HP laserjet's. (erick 12/20/93)
  1448. */
  1449. ASSERTMSG(plr == NULL,("unidrv!bRealRender - vTrans with rules\n"));
  1450. /* Transpose activity - do some transposing now */
  1451. pRData->vTransFn( pbData, pRData );
  1452. pbData = pRData->pvTransBuf; /* Data to process */
  1453. }
  1454. if( !pRData->bPassProc( pPDev, pbData, pRData ) )
  1455. return FALSE;
  1456. // Have we grown the block height
  1457. if (pRData->iNumScans > iHeight)
  1458. {
  1459. // Update our Y cursor position remembering iTLAdv can be negative
  1460. pRData->iyPrtLine += iILAdv * (pRData->iNumScans - iHeight);
  1461. // Reset to minimum block height
  1462. pRData->iNumScans = iHeight;
  1463. }
  1464. iILDone[ iHeadLine ] = pRData->iBitsPCol -1;
  1465. }
  1466. //
  1467. // Set flag to clear delta row buffer since we are
  1468. // skipping white lines
  1469. //
  1470. else
  1471. pRData->iFlags |= RD_RESET_DRC;
  1472. }
  1473. else
  1474. --iILDone[ iHeadLine ];
  1475. /*
  1476. * Output some text. The complication here is that we have just
  1477. * printed a bunch of scan lines, so we need to print text that
  1478. * is positioned within any of those. This means we need to
  1479. * scan through all those lines now, and print any fonts that
  1480. * are positioned within them.
  1481. */
  1482. if ((pRData->PrinterType != PT_PAGE) && (pPDev->iFonts) )
  1483. {
  1484. /* Possible text, so go to it */
  1485. BOOL bRetn;
  1486. if( pPDev->dwLookAhead > 0 )
  1487. {
  1488. /* DeskJet style lookahead region to handle */
  1489. bRetn = bLookAheadOut( pPDev, pRData->iyPrtLine, pRData,
  1490. iILAdv );
  1491. }
  1492. else
  1493. {
  1494. /* Plain vanilla dot matrix */
  1495. bRetn = BDelayGlyphOut( pPDev, pRData->iyPrtLine );
  1496. }
  1497. if( !bRetn )
  1498. return FALSE; /* Bad news no matter how you see it */
  1499. }
  1500. pRData->iyPrtLine += iILAdv * iNumScans; /* Next line to print */
  1501. pBits += iDWLine * iNumScans; /* May step backward */
  1502. /*
  1503. * Keep track of the location of the head relative to the
  1504. * graphics band. For multiple pin printers, we only print
  1505. * graphics data on the first few scan lines, the exact number
  1506. * depending upon the interlace factor. For example, an 8 pin printer
  1507. * with interlace set to 1, then graphics data is output only
  1508. * on scan lines 0, 8, 16, 24,..... We proces all of the scan
  1509. * lines for text, since the text may appear on any line.
  1510. */
  1511. iHeadLine = (iHeadLine + 1) % pRData->iInterlace;
  1512. }
  1513. pRData->iTransHigh = iTHKeep;
  1514. return TRUE;
  1515. }
  1516. /************************** Function Header *******************************
  1517. * bOneColourPass
  1518. * Transforms an output pass consisting of colour data (split into
  1519. * sequences of bytes per colour) into a single, contiguous array
  1520. * of data that is then passed to bOnePassOut. We also check that
  1521. * some data is to be set, and set the colour as required.
  1522. *
  1523. * RETURNS:
  1524. * TRUE/FALSE, as returned from bOnePassOut
  1525. *
  1526. * HISTORY:
  1527. * Friday December 3rd 1993 -by- Norman Hendley [norman]
  1528. * Trivial change to allow multiple scanlines
  1529. *
  1530. * 14:11 on Tue 25 Jun 1991 -by- Lindsay Harris [lindsayh]
  1531. * Created it to complete (untested) colour support.
  1532. *
  1533. *************************************************************************/
  1534. BOOL
  1535. bOneColourPass( pPDev, pbData, pRData )
  1536. PDEV *pPDev; /* The key to everything */
  1537. BYTE *pbData; /* Actual bitmap data */
  1538. RENDER *pRData; /* Information about rendering operations */
  1539. {
  1540. register BYTE *pbIn, *pbOut; /* Copying data */
  1541. register INT iBPC;
  1542. INT iColour; /* Colour we are handling */
  1543. INT iColourMax; /* Number of colour iterations */
  1544. INT iByte; /* Byte number of output */
  1545. INT iBytesPCol; /* Bytes per column */
  1546. INT iTemp;
  1547. BYTE bSum; /* Check for empty line */
  1548. RASTERPDEV *pRPDev; /* For convenience */
  1549. pRPDev = pPDev->pRasterPDEV;
  1550. iBytesPCol = (pRData->iBitsPCol + BBITS - 1) / BBITS;
  1551. iColourMax = pRPDev->sDevPlanes;
  1552. iTemp = pRData->cBYLine;
  1553. /*
  1554. * The RENDERDATA structure value for the count of DWORDS per
  1555. * scanline should now be reduced to the number of bits per plane.
  1556. * The reason is that colour separation takes place in here, so
  1557. * bOnePassOut() only sees the data for a single plane. This means
  1558. * that bOnePassOut() is then independent of colour/monochrome.
  1559. */
  1560. pRData->cBYLine = iTemp / COLOUR_MAX;
  1561. /*
  1562. * Disable the automatic cursor adjustment at the end of the line.
  1563. * This only happens on the last colour pass, so we delay accounting
  1564. * for the printing until then.
  1565. */
  1566. pRData->iCursor = pRPDev->fCursor & ~RES_CUR_Y_POS_AUTO;
  1567. for( iColour = 0; iColour < iColourMax; ++iColour )
  1568. {
  1569. /*
  1570. * Separate out the data for this particular colour. Basically,
  1571. * it means copy n bytes, skip COLOUR_MAX * n bytes, copy n bytes
  1572. * etc, up to the end of the line. Then call bOnePassOut with
  1573. * this data.
  1574. */
  1575. if( iColour == (iColourMax - 1) )
  1576. {
  1577. /* Reinstate the automatic cursor position adjustment */
  1578. pRData->iCursor |= pRPDev->fCursor & RES_CUR_Y_POS_AUTO;
  1579. }
  1580. pbIn = pbData + pRData->iColOff[ iColour ];
  1581. pbOut = pRData->pbColSplit; /* Colour splitting data */
  1582. bSum = 0;
  1583. // now we need to repack the color data
  1584. //
  1585. iByte = pRData->iMaxBytesSend * pRData->iNumScans;
  1586. if (iBytesPCol == 1)
  1587. {
  1588. // This repacks a specific color plane
  1589. // into concurrent planar data
  1590. // It does multiple bytes per loop
  1591. // for performance.
  1592. DWORD dwSum = 0;
  1593. while (iByte >= 4)
  1594. {
  1595. pbOut[0] = pbIn[0];
  1596. pbOut[1] = pbIn[4];
  1597. pbOut[2] = pbIn[8];
  1598. pbOut[3] = pbIn[12];
  1599. dwSum |= *((DWORD *)pbOut)++;
  1600. pbIn += COLOUR_MAX*4;
  1601. iByte -= 4;
  1602. }
  1603. bSum = dwSum ? 1 : 0;
  1604. while (--iByte >= 0)
  1605. {
  1606. bSum |= *pbOut++ = *pbIn;
  1607. pbIn += 4;
  1608. }
  1609. }
  1610. else if (iBytesPCol == 3)
  1611. {
  1612. // special case 24 pin printers
  1613. do {
  1614. bSum |= *pbOut = *pbIn;
  1615. bSum |= pbOut[1] = pbIn[1];
  1616. bSum |= pbOut[2] = pbIn[2];
  1617. pbIn += 3 * COLOUR_MAX;
  1618. pbOut += 3;
  1619. } while ((iByte -= 3) > 0);
  1620. }
  1621. else {
  1622. // generic data repacking for V_BYTE devices
  1623. //
  1624. do {
  1625. iBPC = iBytesPCol;
  1626. do {
  1627. bSum |= *pbOut++ = *pbIn++;
  1628. } while (--iBPC);
  1629. pbIn += (COLOUR_MAX-1) * iBytesPCol;
  1630. } while ((iByte -= iBytesPCol) > 0);
  1631. }
  1632. /*
  1633. * Check to see if any of this colour is to be printed. We are
  1634. * called here if there is any non-white on the line. However,
  1635. * it could, for instance, be red only, and so it is wasteful
  1636. * of printer time to send a null green pass!
  1637. */
  1638. if( (pRData->iFlags & RD_ALL_COLOUR) || bSum )
  1639. {
  1640. //
  1641. // Send a separate color command from the data to select
  1642. // the color plane
  1643. //
  1644. if( pRPDev->fColorFormat & DC_EXPLICIT_COLOR )
  1645. SelectColor (pPDev, iColour);
  1646. //
  1647. // The color command is sent with the data so we determine
  1648. // which command should be used.
  1649. //
  1650. else
  1651. pRData->iSendCmd = pRPDev->rgbCmdOrder[iColour];
  1652. //
  1653. // OK, lets output 1 color plane of data
  1654. //
  1655. if( !bOnePassOut( pPDev, pRData->pbColSplit, pRData ) )
  1656. {
  1657. pRData->cBYLine = iTemp;
  1658. return FALSE;
  1659. }
  1660. }
  1661. }
  1662. pRData->cBYLine = iTemp; /* Correct value for other parts */
  1663. return TRUE;
  1664. }
  1665. /************************* Function Header ***********************************
  1666. * SelectColor
  1667. * Selects color, 0 must be the last color to be selected.
  1668. * Assumes that color info contains parameters for selecting
  1669. * black cyan magenta yellow
  1670. * Keep track of the current color selection, to reduce the amount
  1671. * of data sent to the printer
  1672. *
  1673. * RETURNS:
  1674. * Nothing.
  1675. *
  1676. * HISTORY:
  1677. *
  1678. *****************************************************************************/
  1679. void
  1680. SelectColor(
  1681. PDEV *pPDev,
  1682. INT color
  1683. )
  1684. {
  1685. PRASTERPDEV pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV;
  1686. if( color >= 0 && color != pPDev->ctl.sColor )
  1687. {
  1688. // check to see if to send CR or not.
  1689. if( pRPDev->fColorFormat & DC_CF_SEND_CR )
  1690. XMoveTo( pPDev, 0, MV_PHYSICAL );
  1691. WriteChannel(pPDev,COMMANDPTR(pPDev->pDriverInfo,
  1692. pRPDev->rgbCmdOrder[color]));
  1693. pPDev->ctl.sColor = (short)color;
  1694. }
  1695. }
  1696. /************************** Function Header ********************************
  1697. * bOnePassOut
  1698. * Function to process a group of scan lines and turn the data into
  1699. * commands for the printer.
  1700. *
  1701. * RETURNS:
  1702. * TRUE for success, else FALSE.
  1703. *
  1704. * HISTORY:
  1705. * 30-Dec-1993 -by- Eric Kutter [erick]
  1706. * optimized for HP laserjet
  1707. * 14:26 on Thu 17 Jan 1991 -by- Lindsay Harris [lindsayh]
  1708. * Started on it, VERY loosely based on Windows 16 UNIDRV.
  1709. *
  1710. * Thu 25 Nov 1993 -by- Norman Hendley [normanh]
  1711. * Enabled multple scanlines & multiple parameters
  1712. *
  1713. ***************************************************************************/
  1714. BOOL
  1715. bOnePassOut( pPDev, pbData, pRData )
  1716. PDEV *pPDev; /* The key to everything */
  1717. BYTE *pbData; /* Actual bitmap data */
  1718. register RENDER *pRData; /* Information about rendering operations */
  1719. {
  1720. INT iLeft; /* Left bound of output buffer, as a byte index */
  1721. INT iRight; /* Right bound, as array index of output buffer */
  1722. INT iBytesPCol; /* Bytes per column of print data */
  1723. INT iMinSkip; /* Minimum null byte count before skipping */
  1724. INT iNumScans; /* Number Of Scanlines in Block */
  1725. INT iWidth; /* Width of one scanline in multiscanline printing
  1726. * before stripping */
  1727. INT iSzBlock; /* size of Block */
  1728. WORD fCursor; /* Temporary copy of cursor modes in Resolution */
  1729. WORD fDump; /* Device capabilities */
  1730. WORD fBlockOut; /* Output minimising details */
  1731. RASTERPDEV *pRPDev; /* Unidrv's pdev */
  1732. DWORD dwWhiteIndex;
  1733. PLEFTRIGHT plr = pRData->plrCurrent;
  1734. pRPDev = pPDev->pRasterPDEV;
  1735. fDump = pRData->fDump;
  1736. fCursor = pRPDev->fCursor;
  1737. fBlockOut = pRPDev->fBlockOut;
  1738. if (pRData->iBPP == 24)
  1739. iBytesPCol = 3;
  1740. else
  1741. iBytesPCol = (pRData->iBitsPCol + BBITS - 1) / BBITS;
  1742. iMinSkip = (int)pRPDev->sMinBlankSkip;
  1743. iNumScans= pRData->iNumScans;
  1744. iWidth = pRData->cBYLine; // bytes per line
  1745. iSzBlock= iWidth * iNumScans;
  1746. iRight = pRData->iMaxBytesSend;
  1747. dwWhiteIndex = pRData->dwDevWhiteIndex;
  1748. /*
  1749. * IF we can skip any leading null data, then do so now. This
  1750. * reduces the amount of data sent to the printer, and so can
  1751. * be beneficial to speed up data transmission time.
  1752. */
  1753. if ((fBlockOut & RES_BO_LEADING_BLNKS) || ( fDump & RES_DM_LEFT_BOUND ))
  1754. {
  1755. if (iNumScans == 1) //Don't slow the single scanline code
  1756. {
  1757. /* Look for the first non zero column */
  1758. iLeft = 0;
  1759. if (plr != NULL)
  1760. {
  1761. ASSERTMSG ((WORD)iRight >= (plr->right * sizeof(DWORD)),("unidrv!bOnePassOut - invalid right\n"));
  1762. ASSERTMSG (fBlockOut & RES_BO_TRAILING_BLNKS,("unidrv!bOnePassOut - invalid fBlockOut\n"));
  1763. iLeft = plr->left * sizeof(DWORD);
  1764. iRight = (plr->right+1) * sizeof(DWORD);
  1765. }
  1766. // since the left margin is zero this buffer will be DWORD aligned
  1767. // this allows for faster white space detection
  1768. // NOTE: we don't currently support 8 bit indexed mode
  1769. else
  1770. {
  1771. while ((iLeft+4) <= iRight && *(DWORD *)&pbData[iLeft] == dwWhiteIndex)
  1772. iLeft += 4;
  1773. }
  1774. while (iLeft < iRight && pbData[iLeft] == (BYTE)dwWhiteIndex)
  1775. iLeft++;
  1776. /* Round it to the nearest column */
  1777. iLeft -= iLeft % iBytesPCol;
  1778. /*
  1779. * If less than the minimum skip amount, ignore it.
  1780. */
  1781. if((plr == NULL) && (iLeft < iMinSkip))
  1782. iLeft = 0;
  1783. }
  1784. else
  1785. {
  1786. INT pos;
  1787. pos = iSzBlock +1;
  1788. for (iLeft=0; iRight > iLeft && pos >= iSzBlock ;iLeft++)
  1789. for (pos =iLeft; pos < iSzBlock && pbData[ pos] == (BYTE)dwWhiteIndex ;pos += iWidth)
  1790. ;
  1791. iLeft--;
  1792. /* Round it to the nearest column */
  1793. iLeft -= iLeft % iBytesPCol;
  1794. /*
  1795. * If less than the minimum skip amount, ignore it.
  1796. */
  1797. if( iLeft < iMinSkip )
  1798. iLeft = 0;
  1799. }
  1800. }
  1801. else
  1802. {
  1803. iLeft = 0;
  1804. }
  1805. /*
  1806. * Check for eliminating trailing blanks. If possible, now
  1807. * is the time to find the right end of the data.
  1808. */
  1809. if( fBlockOut & RES_BO_TRAILING_BLNKS )
  1810. {
  1811. /* Scan from the RHS to the first non-zero byte */
  1812. if (iNumScans == 1)
  1813. {
  1814. if (plr != NULL)
  1815. iRight = (plr->right+1) * sizeof(DWORD);
  1816. // if the number of bytes to check is large
  1817. // we will optimize to check it using DWORDS
  1818. else if ((iRight - iLeft) >= 8)
  1819. {
  1820. // first we need to DWORD align the right position
  1821. // we will be aligned when the 2 LSB's of iRight are 0
  1822. //
  1823. while (iRight & 3)
  1824. if (pbData[--iRight] != (BYTE)dwWhiteIndex)
  1825. goto DoneTestingBlanks;
  1826. // OK now that we are DWORD aligned we can check
  1827. // for white space a DWORD at a time
  1828. //
  1829. while ((iRight -= 4) >= iLeft && *(DWORD *)&pbData[iRight] == dwWhiteIndex);
  1830. iRight += 4;
  1831. }
  1832. // now we can quickly test any remaining bytes
  1833. //
  1834. while (--iRight >= iLeft && pbData[iRight] == (BYTE)dwWhiteIndex);
  1835. }
  1836. else
  1837. {
  1838. INT pos;
  1839. pos = iSzBlock +1;
  1840. while(iRight > iLeft && pos > iSzBlock)
  1841. for (pos = --iRight; pos < iSzBlock && pbData[ pos] == (BYTE)dwWhiteIndex ;pos += iWidth)
  1842. ;
  1843. }
  1844. DoneTestingBlanks:
  1845. iRight += iBytesPCol - (iRight % iBytesPCol);
  1846. }
  1847. /*
  1848. * If possible, switch to unidirectional printing for graphics.
  1849. * The reason is to improve output quality, since head position
  1850. * is not as reproducible in bidirectional mode.
  1851. */
  1852. if( (fBlockOut & RES_BO_UNIDIR) && !(pRData->iFlags & RD_UNIDIR) )
  1853. {
  1854. pRData->iFlags |= RD_UNIDIR;
  1855. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_UNIDIRECTIONON) );
  1856. }
  1857. if( fBlockOut & RES_BO_ENCLOSED_BLNKS )
  1858. {
  1859. /*
  1860. * We can skip blank patches in the middle of the scan line.
  1861. * This is only worthwhile when the number of blank columns
  1862. * is > iMinSkip, because there is also overhead in not
  1863. * sending blanks, especially the need to reposition the cursor.
  1864. */
  1865. INT iIndex; /* Scan between iLeft and iRight */
  1866. INT iBlank; /* Start of blank area */
  1867. INT iMax;
  1868. INT iIncrement;
  1869. iBlank = 0; /* None to start with */
  1870. if (iNumScans ==1)
  1871. {
  1872. iMax = iBytesPCol;
  1873. iIncrement =1;
  1874. }
  1875. else
  1876. {
  1877. iMax = iSzBlock;
  1878. iIncrement = iWidth;
  1879. }
  1880. for( iIndex = iLeft; iIndex < iRight; iIndex += iBytesPCol )
  1881. {
  1882. INT iI;
  1883. for( iI = 0; iI < iMax; iI +=iIncrement )
  1884. {
  1885. if( pbData[iIndex + iI] )
  1886. break;
  1887. }
  1888. if( iI < iMax )
  1889. {
  1890. /*
  1891. * If this is the end of a blank stretch, then consider
  1892. * the possibility of not sending the blank part.
  1893. */
  1894. if( iBlank && (iIndex - iBlank) >= iMinSkip )
  1895. {
  1896. /* Skip it! */
  1897. iLineOut( pPDev, pRData, pbData, iLeft, iBlank );
  1898. iLeft = iIndex;
  1899. }
  1900. iBlank = 0; /* Back in the printed zone */
  1901. }
  1902. else
  1903. {
  1904. /*
  1905. * A blank column - remember it if this is the first.
  1906. */
  1907. if( iBlank == 0 )
  1908. iBlank = iIndex; /* Record start of blank */
  1909. }
  1910. }
  1911. /* What's left over needs to go too! */
  1912. if( iLeft != iIndex )
  1913. iLineOut( pPDev, pRData, pbData, iLeft, iIndex );
  1914. }
  1915. else
  1916. {
  1917. //
  1918. // PCLXL raster mode
  1919. //
  1920. if (pPDev->ePersonality == kPCLXL_RASTER)
  1921. {
  1922. DWORD dwcbOut;
  1923. if (S_OK != PCLXLSetCursor((PDEVOBJ)pPDev,
  1924. pRData->ixOrg,
  1925. pRData->iyPrtLine) ||
  1926. S_OK != PCLXLSendBitmap((PDEVOBJ)pPDev,
  1927. pRData->iBPP,
  1928. pRData->iNumScans,
  1929. pRData->cBYLine,
  1930. iLeft,
  1931. iRight,
  1932. pbData,
  1933. &dwcbOut))
  1934. {
  1935. return FALSE;
  1936. }
  1937. }
  1938. else
  1939. {
  1940. /* Write the whole of the (remaining) scan line out */
  1941. /* For multiple scanlines, iRight is right side of top scanline */
  1942. iLineOut( pPDev, pRData, pbData, iLeft, iRight );
  1943. }
  1944. }
  1945. return TRUE;
  1946. }
  1947. /************************** Function Header *********************************
  1948. * iLineOut
  1949. * Sends the passed in line of graphics data to the printer, after
  1950. * setting the X position, etc.
  1951. *
  1952. * RETURNS:
  1953. * Value from WriteSpoolBuf: number of bytes written.
  1954. *
  1955. * HISTORY:
  1956. * 30-Dec-1993 -by- Eric Kutter [erick]
  1957. * optimized for HP laserjet
  1958. * Mon 29th November 1993 -by- Norman Hendley [normanh]
  1959. * Added multiple scanline support
  1960. *
  1961. * 10:38 on Wed 15 May 1991 -by- Lindsay Harris [lindsayh]
  1962. * Created it during render speed ups
  1963. *
  1964. ****************************************************************************/
  1965. int
  1966. iLineOut( pPDev, pRData, pbOut, ixPos, ixEnd )
  1967. PDEV *pPDev; /* The key to everything */
  1968. RENDER *pRData; /* Critical rendering information */
  1969. BYTE *pbOut; /* Area containing data to send */
  1970. INT ixPos; /* X location to start the output */
  1971. INT ixEnd; /* Byte address of first byte to NOT send */
  1972. {
  1973. INT iBytesPCol; /* Bytes per output col; dot matrix */
  1974. INT ixErr; /* Error in setting X location */
  1975. INT ixLeft; /* Left position in dots */
  1976. INT cbOut; /* Number of bytes to send */
  1977. INT iRet; /* Return value from output function */
  1978. INT iNumScans; /* local copy */
  1979. INT iScanWidth; /* Width of scanline, used for multi-scanline printing*/
  1980. INT iCursor; /* Cursor behavior flag */
  1981. DWORD fRMode; // local copy
  1982. BYTE *pbSend; /* Address of data to send out */
  1983. RASTERPDEV *pRPDev;
  1984. if (ixPos < 0)
  1985. {
  1986. ERR (("Unidrv!iLineOut: ixPos < 0\n"));
  1987. ixPos = 0;
  1988. }
  1989. pRPDev = pPDev->pRasterPDEV;
  1990. fRMode = pRPDev->fRMode;
  1991. iNumScans = pRData->iNumScans;
  1992. iCursor = pRData->iCursor;
  1993. /*
  1994. * Set the Y position - safe to do so at anytime.
  1995. */
  1996. pRData->iYMoveFn( pPDev, pRData->iyPrtLine, MV_GRAPHICS );
  1997. if ((iBytesPCol = pRData->iBitsPCol) != 1)
  1998. iBytesPCol /= BBITS;
  1999. #if DBG
  2000. if( (ixEnd - ixPos) % iBytesPCol )
  2001. {
  2002. DbgPrint( "unidrv!iLineOut: cbOut = %ld, NOT multiple of iBytesPCol = %ld\n",
  2003. ixEnd - ixPos, iBytesPCol );
  2004. return 0;
  2005. }
  2006. #endif
  2007. /*
  2008. * Set the preferred left limit and number of columns to send.
  2009. * Note that the left limit may be adjusted to the left if the
  2010. * command to set the X position cannot set it exactly.
  2011. * Note also that some printers are unable to set the x position
  2012. * while in graphics mode, so for these, we ignore what may be
  2013. * able to be skipped.
  2014. */
  2015. if( pRData->fDump & RES_DM_LEFT_BOUND)
  2016. {
  2017. INT iMinSkip = pRPDev->sMinBlankSkip;
  2018. if (!(pRData->iFlags & RD_GRAPHICS))
  2019. iMinSkip >>= 2;
  2020. if (ixPos < pRData->ixOrg || (pRData->ixOrg + iMinSkip) < ixPos)
  2021. {
  2022. /*
  2023. * Need to move left boundary. This may mean
  2024. * exiting graphics mode if we are already there, since
  2025. * that is the only way to change the origin!
  2026. */
  2027. if( pRData->iFlags & RD_GRAPHICS )
  2028. {
  2029. pRData->iFlags &= ~RD_GRAPHICS;
  2030. if (pRData->dwLastCompCmd != CMD_DISABLECOMPRESSION)
  2031. {
  2032. pRData->dwLastCompCmd = CMD_DISABLECOMPRESSION;
  2033. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_DISABLECOMPRESSION));
  2034. }
  2035. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_ENDRASTER));
  2036. }
  2037. //
  2038. // Save the new graphics origin
  2039. //
  2040. pRData->ixOrg = ixPos;
  2041. }
  2042. else
  2043. {
  2044. // we can't optimize the left edge, better make it white
  2045. if (pRData->plrCurrent != NULL)
  2046. ZeroMemory(&pbOut[pRData->ixOrg], ixPos - pRData->ixOrg);
  2047. ixPos = pRData->ixOrg;
  2048. }
  2049. }
  2050. /*
  2051. * Adjust the right side position to dot column version.
  2052. */
  2053. if( pRData->iBitsPCol == 1 )
  2054. {
  2055. /* Laserjet style - work in byte units */
  2056. if (pRData->iBPP == 8)
  2057. ixLeft = ixPos; /* In dot/column units */
  2058. else if (pRData->iBPP == 24)
  2059. ixLeft = (ixPos * BBITS) / 24;
  2060. else
  2061. ixLeft = ixPos * BBITS;
  2062. }
  2063. else
  2064. {
  2065. /* Dot matrix printers */
  2066. ixLeft = ixPos / iBytesPCol;
  2067. }
  2068. /*
  2069. * Move as close as possible to the position along this scanline.
  2070. * This is true regardless of orientation - this move is ALONG the
  2071. * direction of the scan line.
  2072. */
  2073. if( ixErr = pRData->iXMoveFn( pPDev, ixLeft, MV_GRAPHICS ) )
  2074. {
  2075. /*
  2076. * Fiddle factor - the head location could not
  2077. * be exactly set, so send extra graphics data to
  2078. * compensate.
  2079. * NOTE: Presumption is that this will NEVER try to move
  2080. * the head past the left most position. If it does, then
  2081. * we will be referencing memory lower than the scan line
  2082. * buffer!
  2083. */
  2084. if( pRData->iBitsPCol == 1 )
  2085. {
  2086. /*
  2087. * We should not come in here - there are some difficulties
  2088. * in adjusting the position because there is also a byte
  2089. * alignment requirement.
  2090. */
  2091. #if DBG
  2092. DbgPrint( "+++BAD NEWS: ixErr != 0 for 1 pin printer\n" );
  2093. #endif
  2094. }
  2095. else
  2096. {
  2097. /*
  2098. * Should adjust our position by the number of additional cols
  2099. * we wish to send. Also recalculate the array index position
  2100. * corresponding to the new graphical position,
  2101. */
  2102. if (ixLeft <= ixErr)
  2103. ixPos = 0;
  2104. else
  2105. ixPos = (ixLeft - ixErr) * iBytesPCol;
  2106. }
  2107. }
  2108. // For a multiple scanline block the printable data will not be contiguous.
  2109. // We have already identified where to strip white space
  2110. // Only now can we actually remove the white data
  2111. if(( iNumScans > 1 ) && !( fRMode & PFR_BLOCK_IS_BAND ))
  2112. {
  2113. cbOut = iStripBlanks( pRData->pStripBlanks, pbOut, ixPos,
  2114. ixEnd, iNumScans, pRData->cBYLine);
  2115. ixEnd = ixEnd - ixPos;
  2116. ixPos = 0;
  2117. pbOut = pRData->pStripBlanks;
  2118. }
  2119. // Calculate the width of the source data in bytes and check
  2120. // whether we need to output this to the device. If so, we
  2121. // evidently need to exit raster mode first
  2122. iScanWidth = ixEnd - ixPos;
  2123. if ((DWORD)iScanWidth != pPDev->dwWidthInBytes)
  2124. {
  2125. pPDev->dwWidthInBytes = iScanWidth;
  2126. if (fRMode & PFR_SENDSRCWIDTH)
  2127. {
  2128. if( pRData->iFlags & RD_GRAPHICS )
  2129. {
  2130. pRData->iFlags &= ~RD_GRAPHICS;
  2131. if (pRData->dwLastCompCmd != CMD_DISABLECOMPRESSION)
  2132. {
  2133. pRData->dwLastCompCmd = CMD_DISABLECOMPRESSION;
  2134. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_DISABLECOMPRESSION) );
  2135. }
  2136. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_ENDRASTER) );
  2137. }
  2138. WriteChannel (pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETSRCBMPWIDTH));
  2139. }
  2140. }
  2141. //
  2142. // Check whether we should send the source height to the device
  2143. //
  2144. if ((DWORD)iNumScans != pPDev->dwHeightInPixels)
  2145. {
  2146. pPDev->dwHeightInPixels = iNumScans;
  2147. if (fRMode & PFR_SENDSRCHEIGHT)
  2148. WriteChannel (pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETSRCBMPHEIGHT));
  2149. }
  2150. //
  2151. // Make sure we are in raster mode at this point
  2152. //
  2153. if( !(pRData->iFlags & RD_GRAPHICS))
  2154. {
  2155. pRData->iFlags |= RD_GRAPHICS;
  2156. if (fRMode & PFR_SENDBEGINRASTER)
  2157. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_BEGINRASTER));
  2158. }
  2159. //
  2160. // Calculate the number of bytes to send.
  2161. // If compression is available, use it first.
  2162. //
  2163. cbOut = iScanWidth * iNumScans ;
  2164. pbSend = &pbOut[ ixPos ];
  2165. //
  2166. // Mirror each data byte if required
  2167. //
  2168. if (pRData->pbMirrorBuf)
  2169. {
  2170. INT i = cbOut;
  2171. PBYTE pMirror = pRData->pbMirrorBuf;
  2172. while (--i >= 0)
  2173. pbSend[i] = pMirror[pbSend[i]];
  2174. }
  2175. //
  2176. // If there are compression modes we want to determine the
  2177. // most efficient algorithm of those that are enabled.
  2178. //
  2179. if (pRData->dwNumCompCmds)
  2180. {
  2181. DWORD i;
  2182. INT iBestCompSize;
  2183. DWORD dwBestCompCmd;
  2184. INT iCompLimit;
  2185. INT iLastCompLimit;
  2186. PBYTE pBestCompPtr;
  2187. //
  2188. // test whether to initialize dwDeltaRowBuffer
  2189. //
  2190. if (pRData->pDeltaRowBuffer && pRData->iFlags & RD_RESET_DRC)
  2191. {
  2192. pRData->iFlags &= ~RD_RESET_DRC;
  2193. ZeroMemory(pRData->pDeltaRowBuffer,pRData->iMaxBytesSend);
  2194. }
  2195. // initialize to size of buffer
  2196. //
  2197. iCompLimit = iLastCompLimit = pRData->dwCompSize;
  2198. dwBestCompCmd = 0;
  2199. // loop until we've compressed using all active compression modes
  2200. // and have found the most efficient
  2201. //
  2202. for (i = 0;i < pRData->dwNumCompCmds;i++)
  2203. {
  2204. INT iTmpCompSize;
  2205. PBYTE pTmpCompBuffer = pRData->pCompBufs[i];
  2206. DWORD dwTmpCompCmd = pRData->pdwCompCmds[i];
  2207. //
  2208. // do the appropriate compression
  2209. //
  2210. iTmpCompSize = -1;
  2211. switch (dwTmpCompCmd)
  2212. {
  2213. case CMD_ENABLETIFF4:
  2214. iTmpCompSize = iCompTIFF(pTmpCompBuffer,pbSend,cbOut);
  2215. break;
  2216. case CMD_ENABLEFERLE:
  2217. iTmpCompSize = iCompFERLE(pTmpCompBuffer,pbSend,cbOut,iLastCompLimit);
  2218. break;
  2219. case CMD_ENABLEOEMCOMP:
  2220. FIX_DEVOBJ(pPDev,EP_OEMCompression);
  2221. // also add these members to the struct _PDEV (unidrv2\inc\pdev.h)
  2222. // POEM_PLUGINS pOemEntry;
  2223. // note add macro FIX_DEVOBJ in unidrv2\inc\oemkm.h so it also does this:
  2224. // (pPDev)->pOemEntry = ((pPDev)->pOemHookInfo[ep].pOemEntry)
  2225. // (pOemEntry is defined as type POEM_PLUGIN_ENTRY in printer5\inc\oemutil.h)
  2226. //
  2227. if(pPDev->pOemEntry)
  2228. {
  2229. if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented.
  2230. {
  2231. HRESULT hr ;
  2232. hr = HComCompression((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
  2233. (PDEVOBJ)pPDev,pbSend,pTmpCompBuffer,cbOut,iLastCompLimit, &iTmpCompSize);
  2234. if(SUCCEEDED(hr))
  2235. ; // cool !
  2236. }
  2237. else
  2238. {
  2239. iTmpCompSize = pRPDev->pfnOEMCompression((PDEVOBJ)pPDev,pbSend,pTmpCompBuffer,cbOut,iLastCompLimit);
  2240. }
  2241. }
  2242. break;
  2243. case CMD_ENABLEDRC:
  2244. iTmpCompSize = iCompDeltaRow(pTmpCompBuffer,pbSend,
  2245. pRData->pDeltaRowBuffer,pRData->iMaxBytesSend,iLastCompLimit);
  2246. break;
  2247. case CMD_DISABLECOMPRESSION:
  2248. iTmpCompSize = cbOut;
  2249. pTmpCompBuffer = pbSend;
  2250. break;
  2251. }
  2252. //
  2253. // decide if new compression is smaller than last
  2254. //
  2255. if (iTmpCompSize >= 0)
  2256. {
  2257. if (dwTmpCompCmd == pRData->dwLastCompCmd)
  2258. {
  2259. if (iTmpCompSize >= iLastCompLimit)
  2260. continue;
  2261. iLastCompLimit = iCompLimit = iTmpCompSize - COMP_FUDGE_FACTOR;
  2262. }
  2263. else if (iTmpCompSize < iCompLimit)
  2264. {
  2265. iCompLimit = iTmpCompSize;
  2266. if (iLastCompLimit > (iTmpCompSize + COMP_FUDGE_FACTOR))
  2267. iLastCompLimit = iTmpCompSize + COMP_FUDGE_FACTOR;
  2268. }
  2269. else
  2270. continue;
  2271. iBestCompSize = iTmpCompSize;
  2272. pBestCompPtr = pTmpCompBuffer;
  2273. dwBestCompCmd = dwTmpCompCmd;
  2274. if (iCompLimit <= 1)
  2275. break;
  2276. }
  2277. }
  2278. // if DRC is enabled we need to save the scan line
  2279. //
  2280. if (pRData->pDeltaRowBuffer)
  2281. CopyMemory (pRData->pDeltaRowBuffer,pbSend,pRData->iMaxBytesSend);
  2282. //
  2283. // verify we found a valid compression technique
  2284. // otherwise use no compression mode
  2285. //
  2286. if (dwBestCompCmd == 0)
  2287. {
  2288. dwBestCompCmd = CMD_DISABLECOMPRESSION;
  2289. if (!(COMMANDPTR(pPDev->pDriverInfo,CMD_DISABLECOMPRESSION)))
  2290. {
  2291. ERR (("Unidrv: No valid compression found\n"));
  2292. pPDev->fMode |= PF_ABORTED;
  2293. }
  2294. }
  2295. else
  2296. {
  2297. // update the output pointer and size with the best
  2298. // compression method.
  2299. //
  2300. pbSend = pBestCompPtr;
  2301. cbOut = iBestCompSize;
  2302. }
  2303. // if we've changed compression modes we need to
  2304. // output the new mode to the printer
  2305. //
  2306. if (dwBestCompCmd != pRData->dwLastCompCmd)
  2307. {
  2308. // DbgPrint ("New Comp: %ld,y=%ld,size=%ld\n",dwBestCompCmd,
  2309. // pRData->iyPrtLine,cbOut);
  2310. pRData->dwLastCompCmd = dwBestCompCmd;
  2311. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,dwBestCompCmd));
  2312. }
  2313. }
  2314. // update data block size
  2315. // output the raster command and
  2316. // output the actual raster data
  2317. //
  2318. pPDev->dwNumOfDataBytes = cbOut;
  2319. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,pRData->iSendCmd));
  2320. //
  2321. // if callback, adjust the pdev and make the OEM callback
  2322. //
  2323. if (pRPDev->pfnOEMFilterGraphics)
  2324. {
  2325. FIX_DEVOBJ(pPDev,EP_OEMFilterGraphics);
  2326. if(pPDev->pOemEntry)
  2327. {
  2328. if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented.
  2329. {
  2330. HRESULT hr ;
  2331. hr = HComFilterGraphics((POEM_PLUGIN_ENTRY)pPDev->pOemEntry,
  2332. (PDEVOBJ)pPDev, pbSend, cbOut);
  2333. if(SUCCEEDED(hr))
  2334. iRet = cbOut; // cool !
  2335. else
  2336. iRet = 0 ; // hackey, the OEM function should return # bytes written to spooler
  2337. // but too late to change the interface now.
  2338. }
  2339. else
  2340. {
  2341. iRet = pRPDev->pfnOEMFilterGraphics((PDEVOBJ)pPDev, pbSend, cbOut);
  2342. }
  2343. }
  2344. }
  2345. //
  2346. // otherwise we just write out the data ourselves
  2347. //
  2348. else
  2349. iRet = WriteSpoolBuf(pPDev, pbSend, cbOut );
  2350. // Test whether to send end of block command
  2351. //
  2352. if (fRMode & PFR_ENDBLOCK)
  2353. WriteChannel (pPDev,COMMANDPTR(pPDev->pDriverInfo,CMD_ENDBLOCKDATA));
  2354. //
  2355. // Test whether to reset fonts after sending raster data
  2356. //
  2357. if (pPDev->fMode & PF_RESELECTFONT_AFTER_GRXDATA)
  2358. {
  2359. VResetFont(pPDev);
  2360. }
  2361. /*
  2362. * Adjust our idea of the printer's cursor position. IF the printer
  2363. * does not change the cursor's X position after printing, then we leave
  2364. * it where it now is, otherwise we set to what the printer has.
  2365. */
  2366. if( !(iCursor & RES_CUR_X_POS_ORG) )
  2367. {
  2368. if( iCursor & RES_CUR_X_POS_AT_0 )
  2369. {
  2370. /*
  2371. * This type of printer sets the cursor to the left hand
  2372. * side after printing, so set that as our current position.
  2373. */
  2374. pRData->iXMoveFn( pPDev, 0, MV_PHYSICAL | MV_UPDATE );
  2375. }
  2376. else
  2377. {
  2378. /*
  2379. * Cursor remains at end of output. So, set that as our
  2380. * position too. But first, calculate the RHS dot position.
  2381. */
  2382. INT ixRight;
  2383. if( pRData->iBitsPCol == 1 )
  2384. ixRight = ixEnd * BBITS; /* Laserjet style */
  2385. else
  2386. ixRight = ixEnd / iBytesPCol; /* Dot matrix printers */
  2387. pRData->iXMoveFn( pPDev, ixRight, MV_UPDATE | MV_GRAPHICS );
  2388. }
  2389. }
  2390. /*
  2391. * If the printer moves the Y position after printing, then now
  2392. * is the time to adjust our Y position.
  2393. */
  2394. if( iCursor & RES_CUR_Y_POS_AUTO )
  2395. {
  2396. pRData->iYMoveFn( pPDev, pRData->iPosnAdv,
  2397. MV_UPDATE | MV_RELATIVE | MV_GRAPHICS );
  2398. }
  2399. return iRet;
  2400. }
  2401. //*******************************************************
  2402. void
  2403. vInvertBits (
  2404. DWORD *pBits,
  2405. INT cDW
  2406. )
  2407. /*++
  2408. Routine Description:
  2409. This function inverts a group of bits. This is used to convert
  2410. 1 bit data from 0 = black and 1 = white to the opposite.
  2411. Arguments:
  2412. pRD Pointer to RENDER structure
  2413. pBits Pointer to data buffer to invert
  2414. Return Value:
  2415. none
  2416. --*/
  2417. {
  2418. #ifndef _X86_
  2419. INT cDWT = cDW >> 2;
  2420. while( --cDWT >= 0 )
  2421. {
  2422. pBits[0] ^= ~((DWORD)0);
  2423. pBits[1] ^= ~((DWORD)0);
  2424. pBits[2] ^= ~((DWORD)0);
  2425. pBits[3] ^= ~((DWORD)0);
  2426. pBits += 4;
  2427. }
  2428. cDWT = cDW & 3;
  2429. while (--cDWT >= 0)
  2430. *pBits++ ^= ~((DWORD)0);
  2431. #else
  2432. //
  2433. // if intel processor, do it in assembly, for some reason
  2434. // the compiler always does the NOT in three vs one instruction
  2435. //
  2436. __asm
  2437. {
  2438. mov ecx,cDW
  2439. mov eax,pBits
  2440. sar ecx,2
  2441. jz SHORT IB2
  2442. IB1:
  2443. not DWORD PTR [eax]
  2444. not DWORD PTR [eax+4]
  2445. not DWORD PTR [eax+8]
  2446. not DWORD PTR [eax+12]
  2447. add eax,16
  2448. dec ecx
  2449. jnz IB1
  2450. IB2:
  2451. mov ecx,cDW
  2452. and ecx,3
  2453. jz SHORT IB4
  2454. IB3:
  2455. not DWORD PTR [eax]
  2456. add eax,4
  2457. dec ecx
  2458. jnz IB3
  2459. IB4:
  2460. }
  2461. #endif
  2462. }
  2463. #if 0
  2464. //*******************************************************
  2465. void
  2466. vFindWhiteInvertBits (
  2467. RASTERPDEV *pRPDev,
  2468. RENDER *pRD,
  2469. DWORD *pBits
  2470. )
  2471. /*++
  2472. Routine Description:
  2473. This function determines the leading and trailing white
  2474. space for this buffer and inverts all the necessary bits
  2475. such that 0's are white and 1's are black.
  2476. Arguments:
  2477. pRPDev Pointer to RASTERPDEV structure
  2478. pRD Pointer to RENDER structure
  2479. pBits Pointer to data buffer to invert
  2480. Return Value:
  2481. none
  2482. --*/
  2483. {
  2484. DWORD cDW = pRD->cDWLine;
  2485. DWORD cLine = pRD->iy;
  2486. //
  2487. // if the MaxNumScans is 1 then it is useful to determine
  2488. // the first and last non-white dword and store them as left
  2489. // and right in the plrWhite structure. Only the non-white
  2490. // data needs to be inverted in this case
  2491. //
  2492. if (pRD->iMaxNumScans == 1 &&
  2493. ((pRPDev->fBlockOut & RES_BO_LEADING_BLNKS) ||
  2494. (pRD->fDump & RES_DM_LEFT_BOUND)) &&
  2495. (pRPDev->fBlockOut & RES_BO_TRAILING_BLNKS))
  2496. {
  2497. PLEFTRIGHT plr;
  2498. DWORD dwMask = pRD->pdwBitMask[pRD->cBLine % DWBITS];
  2499. if (dwMask != 0)
  2500. dwMask = ~dwMask;
  2501. // allocate blank space structure
  2502. //
  2503. if (pRD->plrWhite == NULL || (pRD->clr < cLine))
  2504. {
  2505. if (pRD->plrWhite != NULL)
  2506. MemFree (pRD->plrWhite);
  2507. pRD->plrWhite = MemAlloc(sizeof(LEFTRIGHT) * cLine);
  2508. pRD->clr = cLine;
  2509. // can't allocate structure so invert everything
  2510. //
  2511. if (pRD->plrWhite == NULL)
  2512. {
  2513. vInvertBits( pBits, cDW * cLine );
  2514. return;
  2515. }
  2516. }
  2517. plr = pRD->plrWhite;
  2518. while (cLine-- > 0)
  2519. {
  2520. DWORD *pdwIn = pBits;
  2521. DWORD *pdwLast = &pBits[cDW-1];
  2522. DWORD dwLast = *pdwLast | dwMask;
  2523. // find leading blanks, set last dword to zero
  2524. // for faster checking
  2525. //
  2526. *pdwLast = 0;
  2527. while (*pdwIn == -1)
  2528. pdwIn++;
  2529. *pdwLast = dwLast;
  2530. // find trailing blanks
  2531. //
  2532. if (dwLast == (DWORD)-1)
  2533. {
  2534. pdwLast--;
  2535. if (pdwIn < pdwLast)
  2536. {
  2537. while (*pdwLast == (DWORD)-1)
  2538. pdwLast--;
  2539. }
  2540. }
  2541. plr->left = pdwIn - pBits;
  2542. plr->right = pdwLast - pBits;
  2543. // invert remaining dwords
  2544. //
  2545. while (pdwIn <= pdwLast)
  2546. *pdwIn++ ^= ~((DWORD)0);
  2547. // increment to next line
  2548. pBits += cDW;
  2549. plr++;
  2550. }
  2551. }
  2552. // MaxNumScans > 1 so invert everything
  2553. //
  2554. else
  2555. vInvertBits( pBits, cDW * cLine );
  2556. }
  2557. #endif
  2558. /************************** Function Header *********************************
  2559. * bLookAheadOut
  2560. * Process text for printers requiring a lookahead region. These are
  2561. * typified by the HP DeskJet family, where the output needs to be
  2562. * sent before the printer reaches that point in the raster scan.
  2563. * The algorithm is explained in the DeskJet manual.
  2564. *
  2565. * RETURNS:
  2566. * TRUE/FALSE, FALSE being some substantial failure.
  2567. *
  2568. * HISTORY:
  2569. * 10:43 on Mon 11 Jan 1993 -by- Lindsay Harris [lindsayh]
  2570. * Created it to support the DeskJet.
  2571. *
  2572. ****************************************************************************/
  2573. BOOL
  2574. bLookAheadOut( pPDev, iyVal, pRD, iILAdv )
  2575. PDEV *pPDev; /* Our PDEV, gives us access to all our data */
  2576. INT iyVal; /* Scan line being processed. */
  2577. RENDER *pRD; /* The myriad of data about what we do */
  2578. INT iILAdv; /* Add to scan line number to get next one */
  2579. {
  2580. /*
  2581. * First step is to find the largest font in the lookahead region.
  2582. * The position sorting code does this for us.
  2583. */
  2584. INT iTextBox; /* Scan lines to look for text to send */
  2585. INT iIndex; /* Loop parameter */
  2586. RASTERPDEV *pRPDev; /* The active stuff */
  2587. pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV;
  2588. iTextBox = ILookAheadMax( pPDev, iyVal, pPDev->dwLookAhead );
  2589. iIndex = pRD->iyLookAhead - iyVal;
  2590. iyVal = pRD->iyLookAhead; /* Base address of scan */
  2591. while( iIndex < iTextBox )
  2592. {
  2593. if( !BDelayGlyphOut( pPDev, iyVal ) )
  2594. return FALSE; /* Doomsday is here */
  2595. ++iIndex;
  2596. ++iyVal;
  2597. }
  2598. pRD->iyLookAhead = iyVal;
  2599. return TRUE;
  2600. }