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.

1516 lines
51 KiB

  1. /************************* Module Header ************************************
  2. * rules.c
  3. * Functions to rummage over the final bitmap and replace black
  4. * rectangular areas with rules. The major benefit of this is
  5. * to reduce the volume of data sent to the printer. This speeds
  6. * up printing by reducing the I/O bottleneck.
  7. *
  8. * Strategy is based on Ron Murray's work for the PM PCL driver.
  9. *
  10. * CREATED:
  11. * 11:39 on Thu 16 May 1991 -by- Lindsay Harris [lindsayh]
  12. *
  13. * Copyright (C) 1991 - 1999, Microsoft Corporation.
  14. *
  15. *****************************************************************************/
  16. //#define _LH_DBG 1
  17. #include "raster.h"
  18. #include "rastproc.h"
  19. #include "rmrender.h"
  20. /*
  21. * The structure that maps BYTES into DWORDS.
  22. */
  23. typedef union
  24. {
  25. DWORD dw; /* Data as a DWORD */
  26. BYTE b[ DWBYTES ]; /* Data as bytes */
  27. } UBDW;
  28. /*
  29. * The RULE structure stores details of the horizontal rules we have
  30. * so far found. Each rule contains the start address (top left corner)
  31. * and end address (bottom right corner) of the area.
  32. */
  33. typedef struct
  34. {
  35. WORD wxOrg; /* X origin of this rule */
  36. WORD wyOrg; /* Y origin */
  37. WORD wxEnd; /* X end of rule */
  38. WORD wyEnd; /* Y end of rule */
  39. } RULE;
  40. #define HRULE_MAX_OLD 15 /* Maximum horizontal rules per stripe */
  41. #define HRULE_MAX_NEW 32 /* Maximum horizontal rules per stripe */
  42. #define HRULE_MIN 2 /* Minimum DWORDs for a horizontal rule */
  43. #define HRULE_MIN_HCNT 2 /* Minimum number of horizontal rules */
  44. #define LJII_MAXHEIGHT 34 /* maximum height of laserjet II rules */
  45. /*
  46. * Other RonM determined data is:-
  47. * 34 scan lines per stripe
  48. * 14 null bytes between raster column operations
  49. * 112 raster rows maximum in raster column searching.
  50. * The latter reduces the probability of error 21.
  51. */
  52. /*
  53. * Define the structure to hold the various pointers, tables, etc used
  54. * during the rule scanning operations. The PDEV structure holds a pointer
  55. * to this, to simplify access and freeing of the memory.
  56. */
  57. typedef struct
  58. {
  59. int iLines; /* Scan lines processed per pass */
  60. int cdwLine; /* Dwords per scan line */
  61. int iyPrtLine; /* Actual line number as printer sees it */
  62. int ixScale; /* Scale factor for X variables */
  63. int iyScale; /* Scale factor for Y */
  64. int ixOffset; /* X Offset for landscape shift */
  65. int iMaxRules; /* Maximum number of rules to allow per stripe */
  66. RENDER *pRData; /* Rendering info - useful everywhere */
  67. /* Entries for finding vertical rules. */
  68. DWORD *pdwAccum; /* Bit accumulation this stripe */
  69. /* Horizontal rule parameters. */
  70. RULE HRule[ HRULE_MAX_NEW ]; /* Horizontal rule details */
  71. short *pRTVert; /* Vertical run table */
  72. short *pRTLast; /* Run table for the last line */
  73. short *pRTCur; /* Current line run table */
  74. RULE **ppRLast; /* Rule descriptor for the last scan line */
  75. RULE **ppRCur; /* Current scan line rule details */
  76. } RULE_DATA;
  77. #if _LH_DBG
  78. /* Useful for debugging purposes */
  79. #define NO_RULES 0x0001 /* Do not look for rules */
  80. #define NO_SEND_RULES 0x0002 /* Do not transmit rules, but erase */
  81. #define NO_SEND_HORZ 0x0004 /* Do not send horizontal rules */
  82. #define NO_SEND_VERT 0x0008 /* Do not send vertical rules */
  83. #define NO_CLEAR_HORZ 0x0010 /* Do not erase horizontal rules */
  84. #define NO_CLEAR_VERT 0x0020 /* Do not erase vertical rules */
  85. #define RULE_VERBOSE 0x0040 /* Print rule dimensions */
  86. #define RULE_STRIPE 0x0080 /* Draw a rule at the end of stripe */
  87. #define RULE_BREAK 0x0100 /* Enter debugger at init time */
  88. static int _lh_flags = 0;
  89. #endif
  90. /* Private function headers */
  91. static void vSendRule( PDEV *, int, int, int, int );
  92. /*************************** Module Header ********************************
  93. * vRuleInit
  94. * Called at the beginning of rendering a bitmap. Function allocates
  95. * storage and initialises it for later. Storage is only allocated
  96. * as needed. Second and later calls will only initialise the
  97. * previously allocated storage.
  98. *
  99. * RETURNS:
  100. * Nothing
  101. *
  102. * HISTORY:
  103. * 13:20 on Thu 16 May 1991 -by- Lindsay Harris [lindsayh]
  104. * Created it, based on Ron Murray's ideas.
  105. *
  106. **************************************************************************/
  107. void
  108. vRuleInit( pPDev, pRData )
  109. PDEV *pPDev; /* Record the info we want */
  110. RENDER *pRData; /* Useful rendering info */
  111. {
  112. int cbLine; /* Byte count per scan line */
  113. int cdwLine; /* DWORDs per scan line - often used */
  114. int iI; /* Loop parameter */
  115. RULE_DATA *pRD;
  116. RASTERPDEV *pRPDev; /* For access to scaling information */
  117. if( pRData->iBPP != 1 )
  118. return; /* Can't handle colour */
  119. pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV;
  120. /*
  121. * Calculate the size of the input scan lines. We do this because
  122. * we need to consider whether we rotate or not; the information in
  123. * the RENDER structure passed in does not consider this until later.
  124. */
  125. // cdwLine = pPDev->fMode & PF_ROTATE ? pRPDev->szlPage.cy :
  126. // pRPDev->szlPage.cx;
  127. cdwLine = pPDev->fMode & PF_ROTATE ? pPDev->sf.szImageAreaG.cy :
  128. pPDev->sf.szImageAreaG.cx;
  129. cdwLine = (cdwLine + DWBITS - 1) / DWBITS;
  130. cbLine = cdwLine * DWBYTES;
  131. if( pRD = pRPDev->pRuleData )
  132. {
  133. /*
  134. * This can happen if the document switches from landscape
  135. * to portrait, for example. The code in vRuleFree will
  136. * throw away all out memory and then set the pointer to NULL,
  137. * so that we allocate anew later on.
  138. */
  139. if( (int)pRD->cdwLine != cdwLine )
  140. vRuleFree( pPDev ); /* Free it all up! */
  141. }
  142. /*
  143. * First step is to allocate a RULE_DATA structure from our heap.
  144. * Then we can allocate the other data areas in it.
  145. */
  146. if( (pRD = pRPDev->pRuleData) == NULL )
  147. {
  148. /*
  149. * Nothing exists, so first step is to allocate it all.
  150. */
  151. if( !(pRD = (RULE_DATA *)MemAllocZ(sizeof( RULE_DATA ) )) )
  152. return;
  153. pRPDev->pRuleData = pRD;
  154. /*
  155. * Allocate storage for the vertical rule finding code.
  156. */
  157. if( !(pRD->pdwAccum = (DWORD *)MemAllocZ( cbLine )) )
  158. {
  159. vRuleFree( pPDev );
  160. return;
  161. }
  162. #ifndef DISABLE_HRULES
  163. /*
  164. * Allocate storage for the horizontal rule finding code.
  165. */
  166. if (pRPDev->fRMode & PFR_RECT_HORIZFILL)
  167. {
  168. iI = cdwLine * sizeof( short );
  169. if( !(pRD->pRTVert = (short *)MemAlloc( iI )) ||
  170. !(pRD->pRTLast = (short *)MemAlloc( iI )) ||
  171. !(pRD->pRTCur = (short *)MemAlloc( iI )) )
  172. {
  173. vRuleFree( pPDev );
  174. return;
  175. }
  176. /*
  177. * Storage for the horizontal rule descriptors. These are pointers
  178. * to the array stored in the RULE_DATA structure.
  179. */
  180. iI = cdwLine * sizeof( RULE * );
  181. if( !(pRD->ppRLast = (RULE **)MemAlloc( iI )) ||
  182. !(pRD->ppRCur = (RULE **)MemAlloc( iI )) )
  183. {
  184. vRuleFree( pPDev );
  185. return;
  186. }
  187. }
  188. #endif
  189. }
  190. // determine maximum number of rules to allow, we allow more for
  191. // FE_RLE since we know these devices can handle the additional rules
  192. //
  193. if (pRPDev->fRMode & PFR_COMP_FERLE)
  194. pRD->iMaxRules = HRULE_MAX_NEW;
  195. else
  196. {
  197. pRD->iMaxRules = HRULE_MAX_OLD;
  198. if (pRPDev->fRMode & PFR_RECT_HORIZFILL)
  199. pRD->iMaxRules -= HRULE_MIN_HCNT;
  200. }
  201. /*
  202. * Storage now available, so initialise the bit vectors, etc.
  203. */
  204. if (pPDev->ptGrxRes.y >= 1200)
  205. pRD->iLines = 128;
  206. else if (pPDev->ptGrxRes.y >= 600)
  207. pRD->iLines = 64;
  208. else
  209. pRD->iLines = LJII_MAXHEIGHT; // optimized for laserjet series II
  210. pRD->cdwLine = cdwLine;
  211. pRD->pRData = pRData; /* For convenience */
  212. pRD->ixScale = pPDev->ptGrxScale.x;
  213. pRD->iyScale = pPDev->ptGrxScale.y;
  214. if ((pPDev->fMode & PF_CCW_ROTATE90) &&
  215. pPDev->ptDeviceFac.x < pPDev->ptGrxScale.x &&
  216. pPDev->ptDeviceFac.x > 0)
  217. {
  218. pRD->ixOffset = pPDev->ptGrxScale.x - 1;
  219. }
  220. else
  221. pRD->ixOffset = 0;
  222. return;
  223. }
  224. /************************** Module Header **********************************
  225. * vRuleFree
  226. * Frees the storage allocated in vRuleInit.
  227. *
  228. * RETURNS:
  229. * Nothing.
  230. *
  231. * HISTORY:
  232. * 13:24 on Thu 16 May 1991 -by- Lindsay Harris [lindsayh]
  233. * Created.
  234. *
  235. ***************************************************************************/
  236. void
  237. vRuleFree( pPDev )
  238. PDEV *pPDev; /* Points to our storage areas */
  239. {
  240. RULE_DATA *pRD;
  241. RASTERPDEV *pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV;
  242. if( pRD = pRPDev->pRuleData )
  243. {
  244. /* Storage allocated, so free it */
  245. if( pRD->pdwAccum )
  246. MemFree( (LPSTR)pRD->pdwAccum );
  247. if( pRD->pRTVert )
  248. MemFree( (LPSTR)pRD->pRTVert );
  249. if( pRD->pRTLast )
  250. MemFree( (LPSTR)pRD->pRTLast );
  251. if( pRD->pRTCur )
  252. MemFree( (LPSTR)pRD->pRTCur );
  253. if( pRD->ppRLast )
  254. MemFree( (LPSTR)pRD->ppRLast );
  255. if( pRD->ppRCur )
  256. MemFree( (LPSTR)pRD->ppRCur );
  257. MemFree (pRD);
  258. pRPDev->pRuleData = 0; /* Not there now that it's gone! */
  259. }
  260. return;
  261. }
  262. /**************************** Module Header ********************************
  263. * vRuleProc
  264. * Function to find the rules in a bitmap stripe, then to send them
  265. * to the printer and erase them from the bitmap.
  266. *
  267. * This function has been optimized to combine invertion and whitespace
  268. * edge detection into a single pass. Refer to the comments in bRender
  269. * for a description.
  270. *
  271. * Future optimizations include:
  272. * call the output routines for each 34 scan band as the
  273. * band is done with rule detection. (while it's still in the cache).
  274. *
  275. * For various reasons, mainly due to the limitations of the ,
  276. * HP LaserJet Series II, the maximum number of rules is limited to
  277. * 15 per 34 scan band and no coalescing is performed. This should
  278. * be made to be a per printer parameter so that the newer laserjets
  279. * don't need to deal with this limitation.
  280. *
  281. * The rules should be coalesced between bands. I believe this can
  282. * cause problems, however, for the LaserJet Series II.
  283. *
  284. * If the printer supports compression (HP LaserJet III and on I believe)
  285. * no hrules should be detected (according to info from LindsayH).
  286. *
  287. * RETURNS:
  288. * Nothing. Failure is benign.
  289. *
  290. * HISTORY:
  291. * 30-Dec-1993 -by- Eric Kutter [erick]
  292. * optimized for HP laserjet
  293. *
  294. * 13:29 on Thu 16 May 1991 -by- Lindsay Harris [lindsayh]
  295. * Created it, from Ron Murray's PM PCL driver ideas.
  296. *
  297. ****************************************************************************/
  298. // given a bit index 0 - 31, this table gives a mask to see if the bit is on
  299. // in a DWORD.
  300. DWORD gdwBitOn[DWBITS] =
  301. {
  302. 0x00000080,
  303. 0x00000040,
  304. 0x00000020,
  305. 0x00000010,
  306. 0x00000008,
  307. 0x00000004,
  308. 0x00000002,
  309. 0x00000001,
  310. 0x00008000,
  311. 0x00004000,
  312. 0x00002000,
  313. 0x00001000,
  314. 0x00000800,
  315. 0x00000400,
  316. 0x00000200,
  317. 0x00000100,
  318. 0x00800000,
  319. 0x00400000,
  320. 0x00200000,
  321. 0x00100000,
  322. 0x00080000,
  323. 0x00040000,
  324. 0x00020000,
  325. 0x00010000,
  326. 0x80000000,
  327. 0x40000000,
  328. 0x20000000,
  329. 0x10000000,
  330. 0x08000000,
  331. 0x04000000,
  332. 0x02000000,
  333. 0x01000000
  334. };
  335. // given a bit index from 1 - 31, this table gives all bits right of that index
  336. // in a DWORD.
  337. DWORD gdwBitMask[DWBITS] =
  338. {
  339. 0xffffff7f,
  340. 0xffffff3f,
  341. 0xffffff1f,
  342. 0xffffff0f,
  343. 0xffffff07,
  344. 0xffffff03,
  345. 0xffffff01,
  346. 0xffffff00,
  347. 0xffff7f00,
  348. 0xffff3f00,
  349. 0xffff1f00,
  350. 0xffff0f00,
  351. 0xffff0700,
  352. 0xffff0300,
  353. 0xffff0100,
  354. 0xffff0000,
  355. 0xff7f0000,
  356. 0xff3f0000,
  357. 0xff1f0000,
  358. 0xff0f0000,
  359. 0xff070000,
  360. 0xff030000,
  361. 0xff010000,
  362. 0xff000000,
  363. 0x7f000000,
  364. 0x3f000000,
  365. 0x1f000000,
  366. 0x0f000000,
  367. 0x07000000,
  368. 0x03000000,
  369. 0x01000000,
  370. 0x00000000,
  371. };
  372. #if DBG
  373. BOOL gbDoRules = 1;
  374. #endif
  375. BOOL
  376. bRuleProc( pPDev, pRData, pdwBits )
  377. PDEV *pPDev; /* All we wanted to know */
  378. RENDER *pRData; /* All critical rendering information */
  379. DWORD *pdwBits; /* The base of the data area. */
  380. {
  381. register DWORD *pdwOr; /* Steps through the accumulation array */
  382. register DWORD *pdwIn; /* Passing over input vector */
  383. register int iIReg; /* Inner loop parameter */
  384. int i;
  385. int iI; /* Loop parameter */
  386. int iLim; /* Loop limit */
  387. int iLine; /* The outer loop */
  388. int iLast; /* Remember the previous horizontal segment */
  389. int cdwLine; /* DWORDS per scan line */
  390. int idwLine; /* SIGNED dwords per line - for address fiddling */
  391. int iILAdv; /* Line number increment, scan line to scan line */
  392. int ixOrg; /* X origin of this rule */
  393. int iyPrtLine; /* Line number, as printer sees it. */
  394. int iyEnd; /* Last scan line this stripe */
  395. int iy1Short; /* Number of scan lines minus 1 - LJ bug?? */
  396. int iLen; /* Length of horizontal run */
  397. int cHRules; /* Count of horizontal rules in this stripe */
  398. int cRuleLim; /* Max rules allowed per stripe */
  399. DWORD dwMask; /* Chop off trailing bits on bitmap */
  400. RULE_DATA *pRD; /* The important data */
  401. RASTERPDEV *pRPDev; // pointer to raster pdev
  402. BYTE *pbRasterScanBuf; // pointer to surface block status
  403. PLEFTRIGHT plrCur; /* left/right structure for current row */
  404. PLEFTRIGHT plr = pRData->plrWhite; /* always points to the top of the segment */
  405. #if _LH_DBG
  406. if( _lh_flags & NO_RULES )
  407. return(FALSE); /* Nothing wanted here */
  408. #endif
  409. pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV;
  410. if( !(pRD = pRPDev->pRuleData) )
  411. return(FALSE); /* Initialisation failed */
  412. if( pRD->cdwLine != pRData->cDWLine )
  413. {
  414. /*
  415. * This code detects the case where vRuleInit() was called with
  416. * the printer set for landscape mode, and then we are called here
  417. * after the transpose and so are (effectively) in portrait mode.
  418. * If the old parameters are used, heap corruption will occur!
  419. * This should not be necessary, as we ought to call vRuleInit()
  420. * at the correct time, but that means hacking into the rendering
  421. * code.
  422. */
  423. #if DBG
  424. DbgPrint( "unidrv!bRuleProc: cdwLine differs: old = %ld, new = %ld\n",
  425. pRD->cdwLine, pRData->cDWLine );
  426. #endif
  427. vRuleFree( pPDev );
  428. vRuleInit( pPDev, pRData );
  429. if( !(pRD = pRPDev->pRuleData) )
  430. {
  431. return(FALSE);
  432. }
  433. }
  434. idwLine = cdwLine = pRData->cDWLine;
  435. iILAdv = 1;
  436. if( pRData->iPosnAdv < 0 )
  437. {
  438. idwLine = -idwLine;
  439. iILAdv = -1;
  440. }
  441. iyPrtLine = pRD->iyPrtLine = pRData->iyPrtLine;
  442. dwMask = *(pRPDev->pdwBitMask + pRData->ix % DWBITS);
  443. if( dwMask == 0 )
  444. dwMask = ~((DWORD)0); /* All bits are in use */
  445. /*
  446. * setup the left/right structure. If we can not allocate enough memory
  447. * free the rule structure and return failure.
  448. */
  449. if ((plr == NULL) || ((int)pRData->clr < pRData->iy))
  450. {
  451. if (plr != NULL)
  452. MemFree(plr);
  453. pRData->plrWhite = (PLEFTRIGHT)MemAlloc(sizeof(LEFTRIGHT)*pRData->iy);
  454. if (pRData->plrWhite == NULL)
  455. {
  456. vRuleFree( pPDev );
  457. return(FALSE);
  458. }
  459. plr = pRData->plrWhite;
  460. pRData->clr = pRData->iy;
  461. }
  462. //
  463. // Determine if block erasing of the bitmap is enabled
  464. //
  465. if (!(pPDev->fMode & PF_SURFACE_ERASED))
  466. pbRasterScanBuf = pPDev->pbRasterScanBuf;
  467. else
  468. pbRasterScanBuf = NULL;
  469. /*
  470. * Outer loop processes through the bitmap in chunks of iLine,
  471. * the number of lines we like to process in one pass. iLine is
  472. * the basic vertical granularity for vertical rule finding.
  473. * Any line less than iLines high will NOT be detected by this
  474. * mechanism.
  475. */
  476. /*
  477. * NOTE: iy1Short is used to bypass what appears to be a bug in
  478. * the LaserJet Series II microcode. It does not print a rule on
  479. * the last scan line of a portrait page. SO, we stop scanning
  480. * on the second last line, and so will send any data here. It
  481. * will be transmitted as normal scan line data.
  482. *
  483. * We also need to setup the left/right table for the last scan
  484. * and invert it.
  485. */
  486. if (pRD->iLines == LJII_MAXHEIGHT)
  487. {
  488. iy1Short = pRData->iy - 1; /* Bottom line not printed! */
  489. plr[iy1Short].left = 1; /* assume last row blank */
  490. plr[iy1Short].right = 0;
  491. if (!pbRasterScanBuf || pbRasterScanBuf[iy1Short / LINESPERBLOCK])
  492. {
  493. pdwIn = pdwBits + idwLine * iy1Short;
  494. pdwIn[cdwLine-1] |= ~dwMask; // make unused bits white
  495. for (i = 0; i < cdwLine; ++i, pdwIn++)
  496. {
  497. *pdwIn = ~*pdwIn;
  498. if(*pdwIn && plr[iy1Short].left)
  499. {
  500. plr[iy1Short].left = 0; /* last row not blank*/
  501. plr[iy1Short].right = cdwLine - 1;
  502. }
  503. }
  504. }
  505. }
  506. else
  507. iy1Short = pRData->iy;
  508. //
  509. // This is the main loop for rules. It processes iLim scan lines per
  510. // pass looking for vertical rules of that height. Hozizontal rules
  511. // are created where no vertical rules have occurred.
  512. //
  513. // NOTE: iLim is initialised inside the loop!
  514. for( iLine = 0; iLine < iy1Short; iLine += iLim )
  515. {
  516. BOOL bAllWhite = TRUE;
  517. DWORD *pdw;
  518. int left,right; /* bounds for verticle rules */
  519. iLim = iy1Short - iLine;
  520. if( iLim >= 2 * pRD->iLines )
  521. iLim = pRD->iLines; /* Limit to nominal band size */
  522. //
  523. // Fill in the left/right structure with the values of the first
  524. // nonwhite dword for each scan line. The bits have still not
  525. // been inverted at this point. So 0's are black and 1's are
  526. // white.
  527. //
  528. pdw = pdwBits;
  529. left = 0;
  530. right = cdwLine-1;
  531. for (iI = 0, plrCur = plr; iI < iLim; plrCur++, ++iI)
  532. {
  533. // if surface block erasing is enabled check for blank block
  534. //
  535. if (pbRasterScanBuf && !pbRasterScanBuf[(iLine+iI) / LINESPERBLOCK])
  536. {
  537. plrCur->left = 1; /* assume last row blank */
  538. plrCur->right = 0;
  539. }
  540. // this scan line was erased so need to check if still white
  541. //
  542. else
  543. {
  544. DWORD *pdwLast = &pdw[cdwLine-1]; // pointer to last dword
  545. DWORD dwOld = *pdwLast | ~dwMask; // make unused bits white
  546. // find the first non white DWORD in this scan line
  547. // we set the last DWORD to black so we don't have
  548. // to test for the end of line
  549. *pdwLast = 0; // set last dword temporarily to black
  550. pdwIn = pdw;
  551. while (*pdwIn == (DWORD)-1)
  552. ++pdwIn;
  553. *pdwLast = dwOld; // restore original value
  554. /*
  555. * find the last non white DWORD. If the last dword is white,
  556. * see if pdwIn reached the end of the scan. If not, work
  557. * backwards with pdwLast.
  558. */
  559. if (dwOld == (DWORD)-1)
  560. {
  561. if (pdwIn < pdwLast)
  562. {
  563. do {
  564. pdwLast--;
  565. } while (*pdwLast == (DWORD)-1);
  566. }
  567. else
  568. pdwLast--;
  569. }
  570. // update the per row and per segment left and right dword indexes
  571. plrCur->left = (WORD)(pdwIn - pdw);
  572. plrCur->right = (WORD)(pdwLast - pdw);
  573. }
  574. // Adjust the overall left and right margin for blank space
  575. // If any dword is zero within this pass no vertical rules
  576. // can be found, so we want to avoid looking
  577. //
  578. if (plrCur->left > left)
  579. left = plrCur->left;
  580. if (plrCur->right < right)
  581. right = plrCur->right;
  582. // turn off bAllWhite if any black was found
  583. //
  584. bAllWhite &= (plrCur->left > plrCur->right);
  585. pdw += idwLine;
  586. }
  587. // non-white pass so lets look for rules
  588. //
  589. if (!bAllWhite)
  590. {
  591. // Initialize the accumulation array to all 1's (white)
  592. // to begin searching for vertical rules.
  593. RtlFillMemory(pRD->pdwAccum, cdwLine * DWBYTES,-1);
  594. #if DBG
  595. if (gbDoRules)
  596. {
  597. #endif
  598. cRuleLim = pRD->iMaxRules; /* Rule limit for this stripe */
  599. // if any scan line in this pass was all white there won't
  600. // be any vertical rules to find.
  601. //
  602. if (left <= right)
  603. {
  604. int cdw;
  605. int iBit;
  606. int iWhite;
  607. // vertical rules are found by or'ing together all the
  608. // scan lines in this pass. Wherever a 0 bit still exists
  609. // designates a vertical black line the height of the pass
  610. // This is where we or the scan lines together
  611. /* Set the accumulation array to the first scan */
  612. pdw = pdwBits + left;
  613. cdw = right - left + 1;
  614. memcpy(pRD->pdwAccum + left , pdw, cdw * DWBYTES);
  615. /*
  616. * Scan across the bitmap - fewer page faults in mmu.
  617. */
  618. for( iI = 1; iI < iLim; ++iI )
  619. {
  620. pdw += idwLine;
  621. pdwIn = pdw;
  622. pdwOr = pRD->pdwAccum + left;
  623. //
  624. // or 4 dwords at a time for speed
  625. //
  626. iIReg = cdw >> 2;
  627. while(--iIReg >= 0)
  628. {
  629. pdwOr[0] |= pdwIn[0];
  630. pdwOr[1] |= pdwIn[1];
  631. pdwOr[2] |= pdwIn[2];
  632. pdwOr[3] |= pdwIn[3];
  633. pdwOr += 4;
  634. pdwIn += 4;
  635. }
  636. //
  637. // or remaining dwords
  638. //
  639. iIReg = cdw & 3;
  640. while (--iIReg >= 0)
  641. *pdwOr++ |= *pdwIn++;
  642. }
  643. /*
  644. * Can now determine what happened in this band. First step is
  645. * to figure out which rules started in this band. Any 0 bit
  646. * in the output array corresponds to a rule extending the whole
  647. * band. If the corresponding bit in the pdwAccum array
  648. * is NOT set, then we record the rule as starting in the
  649. * first row of this stripe.
  650. */
  651. iyEnd = iyPrtLine + (iLim - 1) * iILAdv; /* Last line */
  652. iWhite = DWBITS;
  653. for( iI = left, iBit = 0; iI <= right;)
  654. {
  655. DWORD dwTemp;
  656. int ixEnd;
  657. // we can skip any dword that is all 1's (white)
  658. //
  659. if((iBit == 0) && ((dwTemp = pRD->pdwAccum[ iI ]) == (DWORD)-1) )
  660. {
  661. iWhite += DWBITS;
  662. ++iI;
  663. continue;
  664. }
  665. /* find the first black bit */
  666. iWhite -= iBit;
  667. while (dwTemp & gdwBitOn[iBit])
  668. ++iBit;
  669. iWhite += iBit;
  670. /* set the origin */
  671. ixOrg = iI * DWBITS + iBit;
  672. // find the length by looking for first white bit
  673. //
  674. do
  675. {
  676. if (++iBit == DWBITS)
  677. {
  678. iBit = 0;
  679. if (++iI > right)
  680. {
  681. dwTemp = (DWORD)-1;
  682. break;
  683. }
  684. dwTemp = pRD->pdwAccum[ iI ];
  685. }
  686. } while (!(dwTemp & gdwBitOn[iBit]));
  687. #ifndef OLDSTUFF
  688. //
  689. // Now that we have found a rule we need to determine
  690. // whether it is worthwhile to actually use it. If the rule won't
  691. // result in at least 4 white bytes and we just had another rule
  692. // we will skip it. If we are in rapidly changing data with data runs
  693. // of less than 4 bytes then this isn't of any benefit
  694. //
  695. ixEnd = iI * DWBITS + iBit;
  696. if ((iWhite < 16) && (((ixEnd & ~7) - ixOrg) < 32))
  697. {
  698. int iCnt;
  699. for (iCnt = ixOrg;iCnt < ixEnd;iCnt++)
  700. pRD->pdwAccum[iCnt / DWBITS] |= gdwBitOn[iCnt & 31];
  701. }
  702. // save this rule if there is enough space
  703. //
  704. else if (cRuleLim)
  705. {
  706. cRuleLim--;
  707. pRD->HRule[cRuleLim].wxOrg = (WORD)ixOrg;
  708. pRD->HRule[cRuleLim].wxEnd = (WORD)ixEnd;
  709. }
  710. // too many rules so look for a smaller one
  711. //
  712. else
  713. {
  714. WORD wDx1,wDx2;
  715. int iCnt,iIndex;
  716. wDx1 = MAX_WORD;
  717. iCnt = pRD->iMaxRules;
  718. iIndex = 0;
  719. while (iCnt)
  720. {
  721. iCnt--;
  722. wDx2 = pRD->HRule[iCnt].wxEnd - pRD->HRule[iCnt].wxOrg;
  723. if (wDx2 < wDx1)
  724. {
  725. wDx1 = wDx2;
  726. iIndex = iCnt;
  727. }
  728. }
  729. wDx2 = ixEnd - ixOrg;
  730. // if this is a bigger rule, substitute
  731. // for the smallest earlier rule
  732. if (wDx2 > wDx1)
  733. {
  734. // clear original rule
  735. for (iCnt = pRD->HRule[iIndex].wxOrg;iCnt < pRD->HRule[iIndex].wxEnd;iCnt++)
  736. pRD->pdwAccum[iCnt / DWBITS] |= gdwBitOn[iCnt & 31];
  737. // update to new values
  738. pRD->HRule[iIndex].wxEnd = (WORD)ixEnd;
  739. pRD->HRule[iIndex].wxOrg = (WORD)ixOrg;
  740. }
  741. // new rule is too small so flush it
  742. //
  743. else
  744. {
  745. for (iCnt = ixOrg;iCnt < ixEnd;iCnt++)
  746. pRD->pdwAccum[iCnt / DWBITS] |= gdwBitOn[iCnt & 31];
  747. }
  748. }
  749. /* check if there are any remaining black bits in this DWORD */
  750. if (!(gdwBitMask[iBit] & ~dwTemp))
  751. {
  752. iWhite = DWBITS - iBit;
  753. ++iI;
  754. iBit = 0;
  755. }
  756. else
  757. iWhite = 0;
  758. }
  759. //
  760. // OK, time to output the rules
  761. iI = pRD->iMaxRules;
  762. while ( iI > cRuleLim)
  763. {
  764. iI--;
  765. vSendRule( pPDev, pRD->HRule[iI].wxOrg,iyPrtLine,pRD->HRule[iI].wxEnd-1,iyEnd);
  766. pRD->HRule[iI].wxOrg = pRD->HRule[iI].wxEnd = 0;
  767. }
  768. #else
  769. #if _LH_DBG
  770. if( !(_lh_flags & NO_SEND_VERT) )
  771. #endif
  772. //
  773. vSendRule( pPDev, ixOrg, iyPrtLine, iI * DWBITS + iBit - 1, iyEnd );
  774. /* check if there are any remaining black bits in this DWORD */
  775. if (!(gdwBitMask[iBit] & ~dwTemp))
  776. {
  777. ++iI;
  778. iBit = 0;
  779. }
  780. // quit looking if we've created the maximum number of rules
  781. if (--cRuleLim == 0)
  782. break;
  783. }
  784. /*
  785. * if we ended due to too many rules, zap any remaining bits.
  786. */
  787. if ((cRuleLim == 0) && (iI <= right))
  788. {
  789. /* make accum bits white */
  790. if (iBit > 0)
  791. {
  792. pRD->pdwAccum[iI] |= gdwBitMask[iBit];
  793. ++iI;
  794. }
  795. RtlFillMemory((PVOID)&pRD->pdwAccum[iI],(right - iI + 1) * DWBYTES,-1);
  796. }
  797. #endif
  798. }
  799. #ifndef DISABLE_HRULES
  800. // first check whether to bother with HRULES
  801. // if we didn't allocate a buffer then that means
  802. // we don't want them to run
  803. if (pRD->pRTVert)
  804. {
  805. /*
  806. * Horizontal rules. We scan on DWORDs. These are rather
  807. * coarse, but seem reasonable for a first pass operation.
  808. *
  809. * Step 1 is to find any VERTICAL rules that will pass the
  810. * horizontal test. This allows us to filter vertical rules
  811. * from the horizontal data - we don't want to send them twice!
  812. */
  813. ZeroMemory( pRD->pRTVert, cdwLine * sizeof( short ) );
  814. for( iI = left, pdwIn = pRD->pdwAccum + left; iI <= right; ++iI, ++pdwIn )
  815. {
  816. if (*pdwIn != 0)
  817. continue;
  818. ixOrg = iI;
  819. /* find a run of black */
  820. do {
  821. ++iI;
  822. ++pdwIn;
  823. } while ((iI <= right) && (*pdwIn == 0));
  824. pRD->pRTVert[ixOrg] = (short)(iI - ixOrg);
  825. }
  826. /*
  827. * Start scanning this stripe for horizontal runs.
  828. */
  829. if (pRD->iMaxRules >= (cRuleLim + HRULE_MIN_HCNT))
  830. cRuleLim += HRULE_MIN_HCNT;
  831. cHRules = 0; /* Number of horizontal rules found */
  832. ZeroMemory( pRD->pRTLast, cdwLine * sizeof( short ) );
  833. for (iI = 0; (iI < iLim) && (cHRules < cRuleLim); ++iI, iyPrtLine += iILAdv)
  834. {
  835. int iDW;
  836. int iFirst;
  837. PVOID pv;
  838. plrCur = plr + iI;
  839. pdwIn = pdwBits + iI * idwLine;
  840. iLast = -1;
  841. ZeroMemory( pRD->pRTCur, cdwLine * sizeof( short ) );
  842. ZeroMemory( pRD->ppRCur, cdwLine * sizeof( RULE *) );
  843. for (iDW = plrCur->left; iDW < plrCur->right;++iDW)
  844. {
  845. /* is this the start of a verticle rule already? */
  846. if (pRD->pRTVert[iDW])
  847. {
  848. /* skip over any verticle rules */
  849. iDW += (pRD->pRTVert[iDW] - 1);
  850. continue;
  851. }
  852. /* are there at least two consecutive DWORDS of black */
  853. if ((pdwIn[iDW] != 0) || (pdwIn[iDW+1] != 0))
  854. {
  855. continue;
  856. }
  857. /* yes, see how many. Already got two. */
  858. ixOrg = iDW;
  859. iDW += 2;
  860. while ((iDW <= plrCur->right) && (pdwIn[iDW] == 0))
  861. {
  862. ++iDW;
  863. }
  864. /*
  865. * now remember the run, setting second short of the
  866. * previous run to the start of this and first short
  867. * of this run to its size. Note for the first run
  868. * iLast will be -1, so the offset of the first run
  869. * will be a negative value in pRTCur[0]. If the first
  870. * run starts at offset 0, pRTCur[0] will be positive
  871. * and the offset is not needed.
  872. */
  873. iLen = iDW - ixOrg;
  874. pRD->pRTCur[iLast + 1] = -(short)ixOrg;
  875. pRD->pRTCur[ixOrg] = (short)iLen;
  876. iLast = ixOrg;
  877. }
  878. /*
  879. * Process the segments found along this scanline. Processing
  880. * means either adding to an existing rule, or creating a
  881. * new rule, with possible termination of an existing one.
  882. */
  883. iFirst = -pRD->pRTCur[0];
  884. if( iFirst != 0 )
  885. {
  886. /*
  887. * if the pRTCur[0] is positive, the first scan starts
  888. * at 0 and the first value is a length. Note it
  889. * has already been negated so we check for negative.
  890. */
  891. if (iFirst < 0)
  892. iFirst = 0;
  893. /*
  894. * Found something, so process it. Note that the
  895. * following loop should be executed at least once, since
  896. * iFirst may be 0 the first time through the loop.
  897. */
  898. pdwIn = pdwBits + iI * idwLine; /* Line start address */
  899. do
  900. {
  901. RULE *pRule;
  902. if( pRD->pRTLast[ iFirst ] != pRD->pRTCur[ iFirst ] )
  903. {
  904. /* A new rule - create an entry for it */
  905. if( cHRules < cRuleLim )
  906. {
  907. pRule = &pRD->HRule[ cHRules ];
  908. ++cHRules;
  909. pRule->wxOrg = (WORD)iFirst;
  910. pRule->wxEnd = (WORD)(iFirst + pRD->pRTCur[ iFirst ]);
  911. pRule->wyOrg = (WORD)iyPrtLine;
  912. pRule->wyEnd = pRule->wyOrg;
  913. pRD->ppRCur[ iFirst ] = pRule;
  914. }
  915. else
  916. {
  917. pRD->pRTCur[ iFirst ] = 0; /* NO zapping */
  918. }
  919. }
  920. else
  921. {
  922. /* An extension of an earlier rule */
  923. pRule = pRD->ppRLast[ iFirst ];
  924. if( pRule )
  925. {
  926. /*
  927. * Note that the above if() should not be
  928. * needed, but there have been occasions when
  929. * this code has been executed with pRule = 0,
  930. * which causes all sorts of unpleasantness.
  931. */
  932. pRule->wyEnd = (WORD)iyPrtLine;
  933. pRD->ppRCur[ iFirst ] = pRule;
  934. }
  935. }
  936. // Zap the bits for this horizontal rule.
  937. //
  938. if( (ixOrg = pRD->pRTCur[ iFirst ]) > 0 )
  939. {
  940. pdwOr = pdwIn + iFirst; /* Start address of data */
  941. while( --ixOrg >= 0 )
  942. *pdwOr++ = (DWORD)-1; /* Zap them */
  943. }
  944. } while(iFirst = -pRD->pRTCur[ iFirst + 1 ]);
  945. }
  946. pv = pRD->pRTLast;
  947. pRD->pRTLast = pRD->pRTCur;
  948. pRD->pRTCur = pv;
  949. pv = pRD->ppRLast;
  950. pRD->ppRLast = pRD->ppRCur;
  951. pRD->ppRCur = pv;
  952. } // for iI
  953. /*
  954. * Can now send the horizontal rules, since we have all that
  955. * are of interest.
  956. */
  957. for( iI = 0; iI < cHRules; ++iI )
  958. {
  959. RULE *pRule = &pRD->HRule[ iI ];
  960. vSendRule( pPDev, DWBITS * pRule->wxOrg, pRule->wyOrg,
  961. DWBITS * pRule->wxEnd - 1, pRule->wyEnd );
  962. }
  963. }
  964. #endif // DISABLE_HRULES
  965. #if DBG // gbDoRules
  966. }
  967. #endif
  968. // At this point we need to remove the vertical rules that
  969. // have been sent a scan line at a time. This is done by ANDing
  970. // with the complement of the bit array pdwAccum.
  971. // It is also at this point that we do the data inversion where
  972. // 0 will be white instead of 1.
  973. pdwOr = pRD->pdwAccum;
  974. pdwIn = pdwBits;
  975. plrCur = plr;
  976. for (iI = 0;iI < iLim; iI++)
  977. {
  978. int iCnt = plrCur->right - plrCur->left + 1;
  979. if (iCnt > 0)
  980. {
  981. DWORD *pdwTmp = &pdwIn[plrCur->left];
  982. //
  983. // if no vertical rules were created no point in doing the
  984. // masking so we will use a faster algorithm
  985. //
  986. if (cRuleLim == pRD->iMaxRules)
  987. {
  988. while (iCnt & 3)
  989. {
  990. *pdwTmp++ ^= (DWORD)-1;
  991. iCnt--;
  992. }
  993. iCnt >>= 2;
  994. while (--iCnt >= 0)
  995. {
  996. pdwTmp[0] ^= (DWORD)-1;
  997. pdwTmp[1] ^= (DWORD)-1;
  998. pdwTmp[2] ^= (DWORD)-1;
  999. pdwTmp[3] ^= (DWORD)-1;
  1000. pdwTmp += 4;
  1001. }
  1002. }
  1003. //
  1004. // vertical rules so we better mask with the rules array
  1005. //
  1006. else
  1007. {
  1008. DWORD *pdwTmpOr = &pdwOr[plrCur->left];
  1009. while (iCnt & 3)
  1010. {
  1011. *pdwTmp = ~*pdwTmp & *pdwTmpOr++;
  1012. pdwTmp++;
  1013. iCnt--;
  1014. }
  1015. iCnt >>= 2;
  1016. while (--iCnt >= 0)
  1017. {
  1018. pdwTmp[0] = ~pdwTmp[0] & pdwTmpOr[0];
  1019. pdwTmp[1] = ~pdwTmp[1] & pdwTmpOr[1];
  1020. pdwTmp[2] = ~pdwTmp[2] & pdwTmpOr[2];
  1021. pdwTmp[3] = ~pdwTmp[3] & pdwTmpOr[3];
  1022. pdwTmp += 4;
  1023. pdwTmpOr += 4;
  1024. }
  1025. }
  1026. }
  1027. //
  1028. // if the MaxNumScans == 1 then we need to check for any additional
  1029. // white space created because of the rules removal
  1030. //
  1031. if (pRData->iMaxNumScans == 1)
  1032. {
  1033. while ((plrCur->left <= plrCur->right) && (pdwIn[plrCur->left] == 0))
  1034. ++plrCur->left;
  1035. while ((plrCur->left <= plrCur->right) && (pdwIn[plrCur->right] == 0))
  1036. --plrCur->right;
  1037. }
  1038. //
  1039. // we need to zero out the white margins since they
  1040. // haven't been inverted.
  1041. //
  1042. else
  1043. {
  1044. ZeroMemory(pdwIn,plrCur->left * DWBYTES);
  1045. ZeroMemory(&pdwIn[plrCur->right+1],
  1046. (cdwLine-plrCur->right-1) * DWBYTES);
  1047. }
  1048. pdwIn += idwLine;
  1049. ++plrCur;
  1050. }
  1051. } // bAllWhite
  1052. // If the entire scan is white and device supports multi scan line
  1053. // invert the bits;because for multi scan line support, bits have to
  1054. // be inverted.
  1055. else if (pRData->iMaxNumScans > 1)
  1056. {
  1057. pdwIn = pdwBits;
  1058. for( iI = 0; iI < iLim; ++iI )
  1059. {
  1060. ZeroMemory(pdwIn,cdwLine*DWBYTES);
  1061. pdwIn += idwLine;
  1062. }
  1063. }
  1064. /* advance to next stripe */
  1065. pdwBits += iLim * idwLine; /* Start address next stripe */
  1066. iyPrtLine = pRD->iyPrtLine += iILAdv * iLim;
  1067. plr += iLim;
  1068. #if _LH_DBG
  1069. /*
  1070. * If desired, rule a line across the end of the stripe. This
  1071. * can be helpful during debugging.
  1072. */
  1073. if( _lh_flags & RULE_STRIPE )
  1074. vSendRule( pPDev, 0, iyPrtLine, 2399, iyPrtLine );
  1075. #endif
  1076. }
  1077. return(TRUE);
  1078. }
  1079. /*************************** Module Header ********************************
  1080. * vRuleEndPage
  1081. * Called at the end of a page, and completes any outstanding rules.
  1082. *
  1083. * RETURNS:
  1084. * Nothing
  1085. *
  1086. * HISTORY:
  1087. * 17:25 on Mon 20 May 1991 -by- Lindsay Harris [lindsayh]
  1088. * Created it, specifically for landscape mode.
  1089. *
  1090. ***************************************************************************/
  1091. void
  1092. vRuleEndPage( pPDev )
  1093. PDEV *pPDev;
  1094. {
  1095. /*
  1096. * Scan for any remaining rules that reach to the end of the page.
  1097. * This means that any 1 bits remaining in pdwAccum array have
  1098. * made it, so they should be sent. Only vertical rules will be
  1099. * seen in here - horizontal rules are sent at the end of each stripe.
  1100. */
  1101. register int iIReg; /* Loop parameter */
  1102. int ixOrg; /* Start of last rule, if >= 0 */
  1103. WORD iyOrg; /* Ditto, but for y */
  1104. int iI; /* Loop index */
  1105. int cdwLine; /* DWORDS per line */
  1106. int iyMax; /* Number of scan lines */
  1107. int iCol; /* Column number being processed */
  1108. RULE_DATA *pRD;
  1109. /*
  1110. * NOTE: To meet the PDK ship schedule, the rules finding code
  1111. * has been simplified somewhat. As a consequence of this, this
  1112. * function no longer performs any useful function. Hence, we
  1113. * simply return. We could delete the function call from the
  1114. * rendering code, but at this stage I prefer to leave the
  1115. * call in, since it probably will be needed later.
  1116. */
  1117. //return;
  1118. //!!! NOTE: this code has not be modified to deal with the LEFT/RIGHT rules
  1119. #if _LH_DBG
  1120. if( _lh_flags & NO_RULES )
  1121. return; /* Nothing wanted here */
  1122. #endif
  1123. if( !(pRD = ((PRASTERPDEV)pPDev->pRasterPDEV)->pRuleData) )
  1124. return; /* No doing anything! */
  1125. /* Local Free plrWhite*/
  1126. if( pRD->pRData->plrWhite )
  1127. {
  1128. MemFree( pRD->pRData->plrWhite );
  1129. pRD->pRData->plrWhite = NULL;
  1130. }
  1131. return;
  1132. }
  1133. /****************************** Function Header ****************************
  1134. * vSendRule
  1135. * Function to send a rule command to the printer. We are given the
  1136. * four corner coordinates, from which the command is derived.
  1137. *
  1138. * RETURNS:
  1139. * Nothing.
  1140. *
  1141. * HISTORY:
  1142. * Tuesday 30 November 1993 -by- Norman Hendley [normanh]
  1143. * minor check to allow CaPSL rules - black fill only -
  1144. * 10:57 on Fri 17 May 1991 -by- Lindsay Harris [lindsayh]
  1145. * Created it.
  1146. *
  1147. ***************************************************************************/
  1148. static void
  1149. vSendRule( pPDev, ixOrg, iyOrg, ixEnd, iyEnd )
  1150. PDEV *pPDev;
  1151. int ixOrg; /* The X starting position */
  1152. int iyOrg; /* The Y starting location */
  1153. int ixEnd; /* The X end position */
  1154. int iyEnd; /* The Y end position */
  1155. {
  1156. /*
  1157. * This code is VERY HP LaserJet specific. Basic step is to set
  1158. * the cursor position to (ixOrg, iyOrg), then set the rule length
  1159. * and width before issuing the rule command.
  1160. */
  1161. int iTemp; /* Temporary - for swapping operations */
  1162. RASTERPDEV *pRPDev;
  1163. RULE_DATA *pRD;
  1164. BOOL bNoFillCommand;
  1165. #if _LH_DBG
  1166. if( _lh_flags & NO_SEND_RULES )
  1167. {
  1168. if( _lh_flags & RULE_VERBOSE )
  1169. {
  1170. DbgPrint( "NOT SENDING RULE: (%ld, %ld) - (%ld, %ld)\n",
  1171. ixOrg, iyOrg, ixEnd, iyEnd );
  1172. }
  1173. return; /* Nothing wanted here */
  1174. }
  1175. if( _lh_flags & RULE_VERBOSE )
  1176. {
  1177. DbgPrint( "SENDING RULE: (%ld, %ld) - (%ld, %ld)\n",
  1178. ixOrg, iyOrg, ixEnd, iyEnd );
  1179. }
  1180. #endif
  1181. pRPDev = (PRASTERPDEV)pPDev->pRasterPDEV; /* For convenience */
  1182. pRD = pRPDev->pRuleData;
  1183. /*
  1184. * Make sure the start position is < end position. In landscape
  1185. * this may not happen.
  1186. */
  1187. if( ixOrg > ixEnd )
  1188. {
  1189. /* Swap them */
  1190. iTemp = ixOrg;
  1191. ixOrg = ixEnd;
  1192. ixEnd = iTemp;
  1193. }
  1194. if( iyOrg > iyEnd )
  1195. {
  1196. /* Swap them */
  1197. iTemp = iyOrg;
  1198. iyOrg = iyEnd;
  1199. iyEnd = iTemp;
  1200. }
  1201. if( pPDev->fMode & PF_ROTATE )
  1202. {
  1203. /*
  1204. * We are rotating the bitmap before sending, so we should
  1205. * swap the X and Y coordinates now. This is easier than reversing
  1206. * the function calls later, since we need to adjust nearly every
  1207. * call.
  1208. */
  1209. iTemp = ixOrg;
  1210. ixOrg = iyOrg;
  1211. iyOrg = iTemp;
  1212. iTemp = ixEnd;
  1213. ixEnd = iyEnd;
  1214. iyEnd = iTemp;
  1215. }
  1216. /*
  1217. * Set the start position.
  1218. */
  1219. XMoveTo (pPDev, (ixOrg * pRD->ixScale) - pRD->ixOffset, 0 );
  1220. YMoveTo( pPDev, iyOrg * pRD->iyScale, 0 );
  1221. /*
  1222. * Set size of rule (rectangle area).
  1223. * But, first convert from device units (300 dpi) to master units.
  1224. */
  1225. // Hack for CaPSL & other devices with different rule commands. Unidrv will always
  1226. // send the co-ordinates for a rule. The Chicago CaPSL minidriver relies on this.
  1227. // Check if a fill command exists, if not always send the co-ords. With CaPSL
  1228. // these commands actually do the fill also , black (100% gray) only.
  1229. bNoFillCommand = (!pRPDev->dwRectFillCommand) ?
  1230. TRUE : FALSE;
  1231. iTemp = (ixEnd - ixOrg + 1) * pRD->ixScale;
  1232. if (iTemp != (int)pPDev->dwRectXSize || bNoFillCommand)
  1233. {
  1234. /* A new width, so send the data and remember it for next time */
  1235. pPDev->dwRectXSize = iTemp;
  1236. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETRECTWIDTH));
  1237. }
  1238. iTemp = (iyEnd - iyOrg + 1) * pRD->iyScale;
  1239. if (iTemp != (int)pPDev->dwRectYSize || bNoFillCommand)
  1240. {
  1241. pPDev->dwRectYSize = iTemp;
  1242. WriteChannel( pPDev, COMMANDPTR(pPDev->pDriverInfo,CMD_SETRECTHEIGHT));
  1243. }
  1244. /*
  1245. * Black fill is the maximum grey fill.
  1246. */
  1247. if (!bNoFillCommand)
  1248. {
  1249. pPDev->dwGrayPercentage = pPDev->pGlobals->dwMaxGrayFill;
  1250. WriteChannel (pPDev, COMMANDPTR(pPDev->pDriverInfo,pRPDev->dwRectFillCommand));
  1251. }
  1252. /*
  1253. * If the rule changes the end coordinates, then adjust them now.
  1254. */
  1255. if( pPDev->pGlobals->cxafterfill == CXARF_AT_RECT_X_END )
  1256. {
  1257. XMoveTo(pPDev, ixEnd, MV_GRAPHICS | MV_UPDATE | MV_RELATIVE);
  1258. }
  1259. if( pPDev->pGlobals->cyafterfill == CYARF_AT_RECT_Y_END )
  1260. {
  1261. YMoveTo(pPDev, iyEnd, MV_GRAPHICS | MV_UPDATE | MV_RELATIVE);
  1262. }
  1263. return;
  1264. }