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.

924 lines
32 KiB

  1. notes, comments on existing code and
  2. outline of rewritten moveto commands
  3. which are coordinate independent.
  4. INT
  5. MoveTo(
  6. PDEV *pPDev,
  7. INT iXIn,
  8. INT fFlag
  9. )
  10. /*++
  11. Routine Description:
  12. This function is called to change the X position along the logical (GDIs) X axis.
  13. This function will emit whatever command is needed to accomplish this
  14. regardless of the printer's coordinate system.
  15. I must recast the Xmoveto and Ymoveto commands into this new
  16. paradigm because I want to support font rotations using the
  17. PrintDirection command.
  18. Assumptions:
  19. when making an absolute move, set both standard variables for
  20. x and y. don't know why, maybe for those printers that have
  21. only a moveXandY command.
  22. MV_PHYSICAL is not supported. Only mv to cursor origin is supported.
  23. unidrv5 code assumes if no absolute moves exist, the
  24. default cursor position at StartPage time is the cursor origin.
  25. the supplied movement commands are sufficient to
  26. move the cursor anywhere within the specified imageable area.
  27. the default font is always currently selected. So iDefWidth is correct.
  28. unless overridden explictly by GPD, abs x, y move cannot accept a negative value.
  29. rel x, y moves only accept a positive value, so if in reality they accept
  30. both positive and negative, the negative command must be
  31. treated as a separate command in the opposite direction which prepends
  32. the negative sign in the specification of the command parameter.
  33. unidrv5 code assumes if there is no explicit relative left move command,
  34. you cannot move left. Which means the rel right move command is assumed
  35. to accept only non-negative values.
  36. If only one relative move command direction exists, that direction
  37. is assumed to be right.
  38. Use linefeed spaceing only for positive movements along the y - direction.
  39. and then only if fYMove & FYMOVE_FAVOR_LINEFEEDSPACING
  40. the data tree is not fully populated.
  41. We only know the cursor and Imageable origin for
  42. the two major orientations (Portrait and Landscape).
  43. If we wander from that, using PrintDirection, we must
  44. restrict ourselves to relative moves.
  45. The input (requested move) coordinate system will be the
  46. current GDI coordinates.
  47. see (pPDev->pOrientation->dwRotationAngle == ROTATE_90,
  48. ROTATE_NONE, etc)
  49. The working coordinate system will be the imageable
  50. area in Portrait orientation. This is because there are
  51. values that are invariant in this system:
  52. Xmoveunits and Ymoveunits. We will keep the errors
  53. during and beyond any temp rotations using PrintDirection.
  54. Making the transformation to the working CS:
  55. need the dimensions of the imageable area in Portrait orientation
  56. the input cannot ever be specified wrt cursor origin, since
  57. that makes no sense when the driver is rotating.
  58. So why would the code ever what to do something different
  59. depending on who is rotating? Why would the code
  60. ever care about where the cursor origin is?
  61. ok, the only time the driver cares is becuase the printer
  62. expects the cursor to be at x=0 or y=0 prior to doing something
  63. like emitting a line of graphics or selecting a font.
  64. So just define a special flag MV_CURSOR_ZERO that causes this to happen.
  65. (if <cr> takes us to cursor origin, fine do that, else convert to
  66. logical coordinates and let rest of code handle it.)
  67. Is there such an entity as a cursor origin if there is no
  68. abs move command to get there?
  69. now need to know what commands are available, capabilities
  70. (can accept negative args? move unit, move direction -
  71. up, down, right , left wrt a portrait page)
  72. and for absolute commands, where the location of their
  73. origin is. Note this is dependent on pPDev->pGlobals->bRotateCoordinate,
  74. pPDev->pOrientation->dwRotationAngle and PrintDirection.
  75. How to characterize a printers movement commands for each
  76. of the printers major orientations.
  77. For each supported orientation:
  78. (portrait is always supported, others only if bRotateCoordinate == TRUE.)
  79. The current snapshot should supply cursor origin, imageable origin
  80. so I can compute the cursorOffset wrt imageable origin.
  81. Also look at imageable area, so we know if cursor move command
  82. is valid.
  83. List of absolute cursor move commands and allowed range (neg supported?)
  84. place in a table with directions.
  85. List of relative move commands and and allowed range (neg supported?)
  86. dir abs relative last resort (use only if printdir = 0)
  87. -----------------------------------------
  88. x spaces
  89. -y
  90. -x <cr>
  91. y linefeed
  92. the array accepts either a command index or ptr,
  93. a NULL indicator for not supported
  94. and USE_NEG which means use the opposite directions move command
  95. with a negative argument.
  96. note the dir is wrt Portrait orientation.
  97. such a table exists for portrait (initialized directly from gpd)
  98. then one is synthesized for each supported orientation.
  99. then one is created on the fly starting from the current supported
  100. orientation if PrintDirection is not zero.
  101. Just shift each relative cmd entry up for each 90 deg change in the
  102. print direction. Set all abs entries to NULL.
  103. The GPD will have a new keyword NEG_ALLOWED for the abs and
  104. relative move commands.
  105. CR and other ways to move the cursor will be assumed to be available
  106. in all supported orientations.
  107. these values don't necessarily change as the print direction changes:
  108. *XMoveThreshold (0 , * or inbetween)
  109. *YMoveThreshold (0 , * or inbetween) (when to use abs instead of relative)
  110. *X, YMoveUnit always referenced to the portrait page.
  111. (should really be referred to as ScanDirMoveUnit, and FeedDirMoveUnit)
  112. I then choose the 'best' command to move the cursor
  113. to its requested position.
  114. flowchart please, are there bad combinations and hidden assumptions?
  115. how are quantization errors handled and physical and logical cursor
  116. positions updated?
  117. more special cases:
  118. MV_UPDATE: at least quantize to moveUnits before storing new cursor
  119. position.
  120. MV_RELATIVE: this means movement is relative to current logical cursor
  121. position, doesn't mean use relative move commands.
  122. logic tree:
  123. convert imageable coordinates to cursor origin coordinates.
  124. determine direction we want to move
  125. check existence of abs and relative commands.
  126. initialization:
  127. if we are in a non-zero PrintDirection and uninit flag is set, emit an assert.
  128. the print direction should never be changed before initializing
  129. the cursor's position. (what if there are no initialization commands?)
  130. if abs commands exist AND They can get us to the specified
  131. position just emit the abs command and clear the uninit flag.
  132. else emit abs command to set both X and Y axis to cursor 0. and
  133. clear the uninit flag.
  134. if no abs commands exist, emit <cr> and set cursor position
  135. to (cursor or image org , 0) clear the uninit flag.
  136. even though not strictly correct.
  137. now drop into the relative move portion to attempt to finish the move.
  138. if no dedicated relative move command exists in the desired direction,
  139. check and see if sending <cr> causes a movment in that direction
  140. if so send <cr> and goto top of paragraph.
  141. check to see if sending filler (spaces, nulls) causes a movment in that direction.
  142. if so send them.
  143. cursor origin? should a command be emitted to set the printer to
  144. this position? or should we assume y = 0 (cursor position)
  145. and emit <cr> and we know that will take us to either imageable
  146. origin or cursor origin.
  147. after the first move follow this formula:
  148. abs move unless desired relative move exists
  149. and is favored.
  150. if abs move wasn't used, use relative move.
  151. as implemented above.
  152. logic for last resort moves:
  153. if <CR> needed:
  154. emit <cr> calculate remaining move needed
  155. if spaces needed (pos x direction and over the theshold)
  156. emit correct number of spaces
  157. calculate remaining move
  158. if nulls needed
  159. emit correct number of nulls
  160. update actual and logical cur position
  161. no need to calulate remaining move. nothing else to be done.
  162. if(linefeed needed)
  163. Arguments:
  164. pPDev - Pointer to PDEVICE struct
  165. iXIn - Number of units to move in X direction
  166. fFlag - Specifies the different X move operations
  167. Return Value:
  168. The difference between requested and actual value sent to the device
  169. --*/
  170. /* ------- current code with comments ------------ */
  171. INT
  172. XMoveTo(
  173. PDEV *pPDev,
  174. INT iXIn,
  175. INT fFlag
  176. )
  177. /*++
  178. Routine Description:
  179. This function is called to change the X position along the X axis.
  180. what is the definition of X axis? it is the printer's
  181. logical x-axis. If the printer has a Landscape or Printing Direction command
  182. these will change the logical x-axis.
  183. Arguments:
  184. pPDev - Pointer to PDEVICE struct
  185. iXIn - Number of units to move in X direction
  186. fFlag - Specifies the different X move operations
  187. Return Value:
  188. The difference between requested and actual value sent to the device
  189. --*/
  190. {
  191. int iX, iFineValue, iDiff = 0;
  192. GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
  193. int iScale;
  194. //
  195. // If the position is given in graphics units, convert to master units
  196. //
  197. // ptGrxScale has been adjusted to suit the current orientation.
  198. //
  199. //*\\ ok, this makes sense if X and Y moveto is swapped
  200. // by caller if driver does the rotation.
  201. if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
  202. pPDev->pGlobals->bRotateCoordinate == FALSE)
  203. //*\\ is driver performing the Landscape rotation?
  204. iScale = pPDev->ptGrxScale.y; //*\\ driver is
  205. else
  206. iScale = pPDev->ptGrxScale.x; //*\\ printer is
  207. if ( fFlag & MV_GRAPHICS ) //*\\ iXin is in graphics units
  208. {
  209. iXIn = (iXIn * iScale);
  210. }
  211. //
  212. // Since our print origin may not correspond with the printer's,
  213. // there are times when we need to adjust the value passed in to
  214. // match the desired location on the page.
  215. //
  216. iX = iXIn;
  217. //
  218. // Basically, only adjust if we are doing absolute move
  219. //
  220. //*\\ MV_PHYSICAL means iXIn is wrt to cursor origin not imageable origin.
  221. //*\\ sometimes used by render code to go to cursor origin.
  222. if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
  223. iX += pPDev->sf.ptPrintOffsetM.x;
  224. //*\\ convert iX to cursor cooridinates. note sf.ptPrintOffsetM
  225. //*\\ is defined as ImageableOrigin - CursorOrigin
  226. //
  227. // If it's a relative move, update iX (iX will be the absolute position)
  228. // to reflect the current cursor position
  229. //*\\ note cursor position (ctl.ptCursor) is always wrt the cursor origin.
  230. if ( fFlag & MV_RELATIVE )
  231. iX += pPDev->ctl.ptCursor.x;
  232. //*\\ iX represents the cursor position wrt the cursor origin after
  233. //*\\ the specified move has been executed.
  234. //
  235. // Update, only update our current cursor position and return
  236. // Do nothing if the XMoveTo cmd is called to move to the current position.
  237. //
  238. if ( fFlag & MV_UPDATE )
  239. {
  240. pPDev->ctl.ptCursor.x = iX;
  241. return 0;
  242. }
  243. if ( pPDev->ctl.ptCursor.x == iX )
  244. return 0;
  245. //
  246. // If iX is zero and pGlobals->cxaftercr does not have
  247. // CXCR_AT_GRXDATA_ORIGIN set, then we send CR and reset our
  248. // cursor position to 0, which is the printable x origin
  249. //
  250. //*\\ ignore above comment there is no CXCR_AT_GRXDATA_ORIGIN
  251. //*\\ only at cursor origin or imageable origin.
  252. // if cursor is requested to move to its origin and a <cr> will take it
  253. // to the origin, issue the <cr>.
  254. if (iX == 0 && (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN ||
  255. pPDev->sf.ptPrintOffsetM.x == 0))
  256. {
  257. pPDev->ctl.ptCursor.x = 0;
  258. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
  259. return 0;
  260. }
  261. //
  262. // Check whether we any X move cmd, PF_NO_XMOVE_CMD is set if we did
  263. // not see any relative or absolute x move cmds
  264. //
  265. if( pPDev->fMode & PF_NO_XMOVE_CMD)
  266. {
  267. //
  268. // There is no X move command(abs or relative), so we'll have to simulate
  269. // using blanks or null graphics data (0)
  270. //
  271. //
  272. // We *assume* that when XMoveto is called, the current font is always
  273. // the default font IF the printer has no X movement command.
  274. //
  275. int iRelx = iX - pPDev->ctl.ptCursor.x ;
  276. int iDefWidth;
  277. //
  278. // Convert to Master Units
  279. //
  280. //
  281. // BUG_BUG, Double check that we can use Default Font here when
  282. // we have a custom TTY driver
  283. //
  284. if ( iRelx < 0 )
  285. {
  286. if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
  287. iRelx = iX;
  288. else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
  289. {
  290. ASSERT(pPDev->pGlobals->bRotateCoordinate==FALSE);
  291. //*\\ this means if the printer has no X move commands
  292. // it had better not claim it can perform coordinate rotations.
  293. iRelx = iX - pPDev->pf.ptImageOriginM.x; >>>wrong!!!!<<<
  294. }
  295. WriteChannel( pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN ));
  296. }
  297. //
  298. // Simulate X Move, algorithm is that we always send a blank space
  299. // for every character width, and send graphics null data for
  300. // the remainder.
  301. //
  302. //*\\ potential bugs: what if a different font is selected?
  303. //*\\ font width wasn't originally specified in resolution units
  304. //*\\ so ganesh does a rounding operation. This may not agree
  305. //*\\ with the printers idea of the font width. (x-advance)
  306. //*\\ why isn't requested position tracked? Imagine the cursor only moves
  307. //*\\ in units of 2 master units, a series of 10 1 unit relative move to commands should
  308. //*\\ result in the cursor moving 10 units using 5 actual moves of 2 units each.
  309. //*\\ the assumption here is iRelx is always positive.
  310. // this should be ok, since if there are no dedicated
  311. // movement commands, and the makeshift commands used
  312. // can only move to the right, there is no way to access
  313. // any region to the left of the cursor origin (accessed via <cr>).
  314. iDefWidth = pPDev->ptDefaultFont.x * iScale;
  315. if (iDefWidth)
  316. {
  317. while( iRelx >= iDefWidth )
  318. {
  319. WriteSpoolBuf( pPDev, (LPSTR)" ", 1 );
  320. iRelx -= iDefWidth;
  321. }
  322. }
  323. else
  324. TERSE (("XMoveTo: iDefWidth = 0\n"));
  325. //
  326. // Send the remaining partial space via FineXMoveTo.
  327. //
  328. iDiff = iRelx;
  329. fFlag |= MV_FINE; // Use graphics mode to reach point
  330. }
  331. else
  332. {
  333. DWORD dwTestValue = abs(iX - pPDev->ctl.ptCursor.x);
  334. COMMAND *pCmd;
  335. //
  336. // X movement commmands are available, so use them.
  337. // We need to decide here whether relative or absolute command
  338. // are favored
  339. //
  340. // General assumption: if dwTestValue > dwXMoveThreshold,
  341. // absolute command will be favored
  342. //
  343. //
  344. // BUG_BUG, if we are stripping blanks, we need to check whether
  345. // it's legal to move in Graphics mode. If it's not, we have
  346. // to get out of graphics mode before moving.
  347. //
  348. // buggy!, buggy! buggy!
  349. //*\\ avoid using absolute moves for negative values?
  350. // yet its ok to use negative values the first time?
  351. // what happens if negative abs move is the only way
  352. // to reach that portion of the printable area?
  353. // if you set dwXMoveThreshold to a non-zero value,
  354. // you had better have relative movement commands
  355. //
  356. if (((pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED) ||
  357. (dwTestValue > pPDev->pGlobals->dwXMoveThreshold &&
  358. iX > 0)) &&
  359. (pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVEABSOLUTE)) != NULL)
  360. {
  361. //
  362. // if the move units are less (coarser) than the master units then we need to
  363. // check whether the new position will end up being the same as the
  364. // original position. If so, no point in sending another command.
  365. //
  366. // I think ptDeviceFac is the number of master units covered
  367. // by one move unit.
  368. if (!(pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED) &&
  369. (pPDev->ptDeviceFac.x > 1) &&
  370. ((iX - (iX % pPDev->ptDeviceFac.x)) == pPDev->ctl.ptCursor.x))
  371. //*\\ I would have rewritten the last condition as:
  372. // (iX / pPDev->ptDeviceFac.x == pPDev->ctl.ptCursor.x / pPDev->ptDeviceFac.x)
  373. // ptCursor is the quantized cursor position in master units, not
  374. // where the app expects the cursor to be.
  375. {
  376. iDiff = iX - pPDev->ctl.ptCursor.x; // having the caller keep track of
  377. // this is just plain wrong. you know it will be dropped. since one
  378. // caller cannot transfer the error to the next caller.
  379. }
  380. else
  381. {
  382. //*\\ what is this: ctl.ptAbsolutePos ? this is the standard variable
  383. //*\\ why isn't ctl.ptCursor updated ? it is at the very end of this function.
  384. pPDev->ctl.ptAbsolutePos.x = iX;
  385. //
  386. // 3/13/97 ZhanW
  387. // set up DestY as well in case it's needed (ex. FE printers).
  388. // In that case, truncation error (iDiff) is not a concern.
  389. // This is for backward compatibility with FE Win95 and FE NT4
  390. // minidrivers.
  391. //
  392. //*\\ note: WriteChannel returns amount moved in
  393. // device units which can be converted to master units
  394. // by multiplying by pPDev->ptDeviceFac.x
  395. pPDev->ctl.ptAbsolutePos.y = pPDev->ctl.ptCursor.y;
  396. iDiff = WriteChannelEx(pPDev,
  397. pCmd,
  398. pPDev->ctl.ptAbsolutePos.x,
  399. pPDev->ptDeviceFac.x);
  400. if (pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED)
  401. pPDev->ctl.dwCursorMode &= ~CURSOR_X_UNINITIALIZED;
  402. }
  403. }
  404. else // code assumes relative moves exist if iX is negative
  405. {
  406. //
  407. // Use relative command to send move request
  408. //
  409. INT iRelRightValue = 0;
  410. if( iX < pPDev->ctl.ptCursor.x ) // when is ptCursor initialized? to (0,0) at DrvStartPage().
  411. // what command actually ensured the cursor was set to (0,0)?
  412. // absolutely none - its should be part of the StartPage command.
  413. // If the printer has no absolute movement command,
  414. // the StartPage command should include a command to set
  415. // the cursor to position (0,0). If the cursor position cannot
  416. // be set to (0,0), then this code is invalid.
  417. {
  418. //
  419. // Relative move left
  420. //
  421. if (pCmd = COMMANDPTR(pDrvInfo,CMD_XMOVERELLEFT))
  422. {
  423. //
  424. // Optimize to avoid sending 0-move cmd.
  425. //
  426. // note all args for relative moves are positive.
  427. if ((pPDev->ctl.ptRelativePos.x =
  428. pPDev->ctl.ptCursor.x - iX) < pPDev->ptDeviceFac.x)
  429. iDiff = pPDev->ctl.ptRelativePos.x;
  430. else
  431. iDiff = WriteChannelEx(pPDev,
  432. pCmd,
  433. pPDev->ctl.ptRelativePos.x,
  434. pPDev->ptDeviceFac.x);
  435. iDiff = -iDiff;
  436. }
  437. else
  438. {
  439. //
  440. // No Relative left move cmd, use <CR> to reach start
  441. // Will try to use relative right move cmd to send later
  442. // assumption is if no rel left move command exists,
  443. // printing in the negative quadrant is impossible.
  444. // because abs moves are never used even if they
  445. // accept negative args.
  446. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
  447. if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
  448. iRelRightValue = iX; //*\\ what if this value is negative?
  449. else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
  450. {
  451. ASSERT(pPDev->pGlobals->bRotateCoordinate==FALSE);
  452. // assumes printers that support relative right, but not left
  453. // move commands
  454. // do not rotate the cooridinate system. Kind of strange?
  455. // this is regardless of whether they support abs move.
  456. iRelRightValue = iX - pPDev->pf.ptImageOriginM.x;
  457. }
  458. }
  459. }
  460. else
  461. {
  462. //
  463. // Relative right move
  464. // UNIITIALZIED is an invalid position, set to zero
  465. //
  466. iRelRightValue = iX - pPDev->ctl.ptCursor.x;
  467. }
  468. if( iRelRightValue > 0 )
  469. {
  470. if (pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVERELRIGHT))
  471. {
  472. //
  473. // optimize to avoid 0-move cmd
  474. //
  475. if ((pPDev->ctl.ptRelativePos.x = iRelRightValue) <
  476. pPDev->ptDeviceFac.x)
  477. iDiff = iRelRightValue;
  478. else
  479. iDiff = WriteChannelEx(pPDev,
  480. pCmd,
  481. pPDev->ctl.ptRelativePos.x,
  482. pPDev->ptDeviceFac.x);
  483. }
  484. else
  485. iDiff = iRelRightValue; //*\\ that's it? no attempt to move cursor?
  486. }
  487. }
  488. }
  489. //
  490. // Peform fine move command
  491. //
  492. if ( (fFlag & MV_FINE) && iDiff > 0 )
  493. iDiff = FineXMoveTo( pPDev, iDiff );
  494. //
  495. // Update our current cursor position
  496. //
  497. pPDev->ctl.ptCursor.x = iX - iDiff ;
  498. if( fFlag & MV_GRAPHICS )
  499. {
  500. iDiff = (iDiff / iScale);
  501. }
  502. if (pPDev->fMode & PF_RESELECTFONT_AFTER_XMOVE)
  503. {
  504. VResetFont(pPDev);
  505. }
  506. return( iDiff);
  507. }
  508. INT
  509. YMoveTo(
  510. PDEV *pPDev,
  511. INT iYIn,
  512. INT fFlag
  513. )
  514. /*++
  515. Routine Description:
  516. This function is called to change the Y position.
  517. Arguments:
  518. pPDev - Pointer to PDEVICE struct
  519. iYIn - Number of units to move in Y direction
  520. fFlag - Specifies the different Y move operations
  521. Return Value:
  522. The difference between requested and actual value sent to the device
  523. --*/
  524. {
  525. INT iY, iDiff = 0;
  526. DWORD dwTestValue;
  527. GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
  528. COMMAND *pAbsCmd;
  529. INT iScale;
  530. //
  531. // Convert to Master Units if the given units is in Graphics Units
  532. // ptGrxScale has been adjusted to suit the current orientation.
  533. //
  534. if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
  535. pPDev->pGlobals->bRotateCoordinate == FALSE)
  536. iScale = pPDev->ptGrxScale.x;
  537. else
  538. iScale = pPDev->ptGrxScale.y;
  539. if ( fFlag & MV_GRAPHICS )
  540. {
  541. iYIn = (iYIn * iScale);
  542. }
  543. //
  544. // Since our print origin may not correspond with the printer's,
  545. // there are times when we need to adjust the value passed in to
  546. // match the desired location on the page.
  547. //
  548. iY = iYIn;
  549. //
  550. // Basically, only adjust if we are doing absolute move
  551. //
  552. if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
  553. iY += pPDev->sf.ptPrintOffsetM.y;
  554. //
  555. // Adjust iY to be the absolute position
  556. //
  557. if( fFlag & MV_RELATIVE )
  558. iY += pPDev->ctl.ptCursor.y;
  559. //
  560. // Update, only update our current cursor position and return
  561. // Do nothing if the YMoveTo cmd is called to move to the current position.
  562. //
  563. if( fFlag & MV_UPDATE )
  564. {
  565. pPDev->ctl.ptCursor.y = iY;
  566. return 0;
  567. }
  568. if( pPDev->ctl.ptCursor.y == iY )
  569. return 0;
  570. //
  571. // General assumption: if dwTestValue > dwYMoveThreshold,
  572. // absolute Y move command will be favored. Also, for iY < 0,
  573. // use relative command since some printers like old LaserJet have
  574. // printable area above y=0 accessable only through relative move cmds.
  575. //
  576. //
  577. // BUG_BUG, if we are stripping blanks, we need to check whether
  578. // it's legal to move in Graphics mode. If it's not, we have
  579. // to get out of graphics mode before moving.
  580. //
  581. dwTestValue = abs(iY - pPDev->ctl.ptCursor.y);
  582. if (((pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED) ||
  583. (dwTestValue > pPDev->pGlobals->dwYMoveThreshold &&
  584. iY > 0)) &&
  585. (pAbsCmd = COMMANDPTR(pDrvInfo, CMD_YMOVEABSOLUTE)) != NULL)
  586. {
  587. //! if neg move is the first one, then an absolute move
  588. // is issued even though the code explicitly says this is
  589. // a Bad thing.
  590. // if there are no relative commands and a negative move
  591. // is specified, bad things will happen.
  592. //
  593. // if the move units are less than the master units then we need to
  594. // check whether the new position will end up being the same as the
  595. // original position. If so, no point in sending another command.
  596. //
  597. if (!(pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED) &&
  598. (pPDev->ptDeviceFac.y > 1) &&
  599. ((iY - (iY % pPDev->ptDeviceFac.y)) == pPDev->ctl.ptCursor.y))
  600. {
  601. iDiff = iY - pPDev->ctl.ptCursor.y;
  602. }
  603. else
  604. {
  605. pPDev->ctl.ptAbsolutePos.y = iY;
  606. pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x;
  607. iDiff = WriteChannelEx(pPDev,
  608. pAbsCmd,
  609. pPDev->ctl.ptAbsolutePos.y,
  610. pPDev->ptDeviceFac.y);
  611. if (pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED)
  612. pPDev->ctl.dwCursorMode &= ~CURSOR_Y_UNINITIALIZED;
  613. }
  614. }
  615. else
  616. {
  617. //
  618. // Use Relavite Y-move commands
  619. //
  620. //
  621. // FYMOVE_SEND_CR_FIRST indicates that it's required to send a CR
  622. // before each line-spacing command
  623. //
  624. // what does this mean? that the cursor must be at x=0
  625. // before doing a y-move? or a <cr> must be sent
  626. // before doing a y-move?
  627. // if the latter, calling XMoveTo does not ensure the <cr>
  628. // is sent. First, the x pos may already be 0 or
  629. // an absolute X move command may be used as would
  630. // be the case if the distance moved exceeded the threshold.
  631. if ( pPDev->fYMove & FYMOVE_SEND_CR_FIRST )
  632. XMoveTo( pPDev, 0, MV_PHYSICAL );
  633. //
  634. // Use line spacing if that is preferred
  635. //
  636. if ( (pPDev->fYMove & FYMOVE_FAVOR_LINEFEEDSPACING) &&
  637. iY - pPDev->ctl.ptCursor.y > 0 &&
  638. pPDev->arCmdTable[CMD_SETLINESPACING] != NULL &&
  639. pPDev->arCmdTable[CMD_LINEFEED] != NULL )
  640. {
  641. INT iLineSpacing;
  642. DWORD dwMaxLineSpacing = pPDev->pGlobals->dwMaxLineSpacing;
  643. while ( dwTestValue )
  644. {
  645. iLineSpacing =(INT)(dwTestValue > dwMaxLineSpacing ?
  646. dwMaxLineSpacing : dwTestValue);
  647. if (pPDev->ctl.lLineSpacing == -1 || <== meaningless check.
  648. iLineSpacing != pPDev->ctl.lLineSpacing )
  649. {
  650. pPDev->ctl.lLineSpacing = iLineSpacing;
  651. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_SETLINESPACING));
  652. }
  653. //
  654. // Send the LF
  655. //
  656. WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_LINEFEED));
  657. dwTestValue -= (DWORD)iLineSpacing;
  658. }
  659. }
  660. else
  661. {
  662. //
  663. // Use relative command
  664. //
  665. PCOMMAND pCmd;
  666. if ( iY <= pPDev->ctl.ptCursor.y )
  667. {
  668. //
  669. // If there is no RELATIVE UP cmd, do nothing and return
  670. //
  671. if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELUP))
  672. {
  673. //
  674. // optimize to avoid 0-move cmd
  675. //
  676. if ((pPDev->ctl.ptRelativePos.y =
  677. pPDev->ctl.ptCursor.y - iY) < pPDev->ptDeviceFac.y)
  678. iDiff = pPDev->ctl.ptRelativePos.y;
  679. else
  680. iDiff = WriteChannelEx(pPDev,
  681. pCmd,
  682. pPDev->ctl.ptRelativePos.y,
  683. pPDev->ptDeviceFac.y);
  684. iDiff = -iDiff;
  685. }
  686. else
  687. // Do nothing since we can't simulate it
  688. iDiff = (iY - pPDev->ctl.ptCursor.y );
  689. // my interpretation of iDiff is you add iDiff to
  690. // the printers cursor position to get where
  691. // you really wanted to be.
  692. }
  693. else
  694. {
  695. if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELDOWN))
  696. {
  697. pPDev->ctl.ptRelativePos.y = iY - pPDev->ctl.ptCursor.y;
  698. //
  699. // optimize to avoid 0-move cmd
  700. //
  701. if (pPDev->ctl.ptRelativePos.y < pPDev->ptDeviceFac.y)
  702. iDiff = pPDev->ctl.ptRelativePos.y;
  703. else
  704. iDiff = WriteChannelEx(pPDev,
  705. pCmd,
  706. pPDev->ctl.ptRelativePos.y,
  707. pPDev->ptDeviceFac.y);
  708. }
  709. else // can't move at all.
  710. iDiff = (iY - pPDev->ctl.ptCursor.y );
  711. }
  712. }
  713. }
  714. //
  715. // Update our current cursor position
  716. //
  717. pPDev->ctl.ptCursor.y = iY - iDiff;
  718. if( fFlag & MV_GRAPHICS )
  719. {
  720. iDiff = (iDiff / iScale);
  721. }
  722. return (iDiff);
  723. }