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

notes, comments on existing code and
outline of rewritten moveto commands
which are coordinate independent.
INT
MoveTo(
PDEV *pPDev,
INT iXIn,
INT fFlag
)
/*++
Routine Description:
This function is called to change the X position along the logical (GDIs) X axis.
This function will emit whatever command is needed to accomplish this
regardless of the printer's coordinate system.
I must recast the Xmoveto and Ymoveto commands into this new
paradigm because I want to support font rotations using the
PrintDirection command.
Assumptions:
when making an absolute move, set both standard variables for
x and y. don't know why, maybe for those printers that have
only a moveXandY command.
MV_PHYSICAL is not supported. Only mv to cursor origin is supported.
unidrv5 code assumes if no absolute moves exist, the
default cursor position at StartPage time is the cursor origin.
the supplied movement commands are sufficient to
move the cursor anywhere within the specified imageable area.
the default font is always currently selected. So iDefWidth is correct.
unless overridden explictly by GPD, abs x, y move cannot accept a negative value.
rel x, y moves only accept a positive value, so if in reality they accept
both positive and negative, the negative command must be
treated as a separate command in the opposite direction which prepends
the negative sign in the specification of the command parameter.
unidrv5 code assumes if there is no explicit relative left move command,
you cannot move left. Which means the rel right move command is assumed
to accept only non-negative values.
If only one relative move command direction exists, that direction
is assumed to be right.
Use linefeed spaceing only for positive movements along the y - direction.
and then only if fYMove & FYMOVE_FAVOR_LINEFEEDSPACING
the data tree is not fully populated.
We only know the cursor and Imageable origin for
the two major orientations (Portrait and Landscape).
If we wander from that, using PrintDirection, we must
restrict ourselves to relative moves.
The input (requested move) coordinate system will be the
current GDI coordinates.
see (pPDev->pOrientation->dwRotationAngle == ROTATE_90,
ROTATE_NONE, etc)
The working coordinate system will be the imageable
area in Portrait orientation. This is because there are
values that are invariant in this system:
Xmoveunits and Ymoveunits. We will keep the errors
during and beyond any temp rotations using PrintDirection.
Making the transformation to the working CS:
need the dimensions of the imageable area in Portrait orientation
the input cannot ever be specified wrt cursor origin, since
that makes no sense when the driver is rotating.
So why would the code ever what to do something different
depending on who is rotating? Why would the code
ever care about where the cursor origin is?
ok, the only time the driver cares is becuase the printer
expects the cursor to be at x=0 or y=0 prior to doing something
like emitting a line of graphics or selecting a font.
So just define a special flag MV_CURSOR_ZERO that causes this to happen.
(if <cr> takes us to cursor origin, fine do that, else convert to
logical coordinates and let rest of code handle it.)
Is there such an entity as a cursor origin if there is no
abs move command to get there?
now need to know what commands are available, capabilities
(can accept negative args? move unit, move direction -
up, down, right , left wrt a portrait page)
and for absolute commands, where the location of their
origin is. Note this is dependent on pPDev->pGlobals->bRotateCoordinate,
pPDev->pOrientation->dwRotationAngle and PrintDirection.
How to characterize a printers movement commands for each
of the printers major orientations.
For each supported orientation:
(portrait is always supported, others only if bRotateCoordinate == TRUE.)
The current snapshot should supply cursor origin, imageable origin
so I can compute the cursorOffset wrt imageable origin.
Also look at imageable area, so we know if cursor move command
is valid.
List of absolute cursor move commands and allowed range (neg supported?)
place in a table with directions.
List of relative move commands and and allowed range (neg supported?)
dir abs relative last resort (use only if printdir = 0)
-----------------------------------------
x spaces
-y
-x <cr>
y linefeed
the array accepts either a command index or ptr,
a NULL indicator for not supported
and USE_NEG which means use the opposite directions move command
with a negative argument.
note the dir is wrt Portrait orientation.
such a table exists for portrait (initialized directly from gpd)
then one is synthesized for each supported orientation.
then one is created on the fly starting from the current supported
orientation if PrintDirection is not zero.
Just shift each relative cmd entry up for each 90 deg change in the
print direction. Set all abs entries to NULL.
The GPD will have a new keyword NEG_ALLOWED for the abs and
relative move commands.
CR and other ways to move the cursor will be assumed to be available
in all supported orientations.
these values don't necessarily change as the print direction changes:
*XMoveThreshold (0 , * or inbetween)
*YMoveThreshold (0 , * or inbetween) (when to use abs instead of relative)
*X, YMoveUnit always referenced to the portrait page.
(should really be referred to as ScanDirMoveUnit, and FeedDirMoveUnit)
I then choose the 'best' command to move the cursor
to its requested position.
flowchart please, are there bad combinations and hidden assumptions?
how are quantization errors handled and physical and logical cursor
positions updated?
more special cases:
MV_UPDATE: at least quantize to moveUnits before storing new cursor
position.
MV_RELATIVE: this means movement is relative to current logical cursor
position, doesn't mean use relative move commands.
logic tree:
convert imageable coordinates to cursor origin coordinates.
determine direction we want to move
check existence of abs and relative commands.
initialization:
if we are in a non-zero PrintDirection and uninit flag is set, emit an assert.
the print direction should never be changed before initializing
the cursor's position. (what if there are no initialization commands?)
if abs commands exist AND They can get us to the specified
position just emit the abs command and clear the uninit flag.
else emit abs command to set both X and Y axis to cursor 0. and
clear the uninit flag.
if no abs commands exist, emit <cr> and set cursor position
to (cursor or image org , 0) clear the uninit flag.
even though not strictly correct.
now drop into the relative move portion to attempt to finish the move.
if no dedicated relative move command exists in the desired direction,
check and see if sending <cr> causes a movment in that direction
if so send <cr> and goto top of paragraph.
check to see if sending filler (spaces, nulls) causes a movment in that direction.
if so send them.
cursor origin? should a command be emitted to set the printer to
this position? or should we assume y = 0 (cursor position)
and emit <cr> and we know that will take us to either imageable
origin or cursor origin.
after the first move follow this formula:
abs move unless desired relative move exists
and is favored.
if abs move wasn't used, use relative move.
as implemented above.
logic for last resort moves:
if <CR> needed:
emit <cr> calculate remaining move needed
if spaces needed (pos x direction and over the theshold)
emit correct number of spaces
calculate remaining move
if nulls needed
emit correct number of nulls
update actual and logical cur position
no need to calulate remaining move. nothing else to be done.
if(linefeed needed)
Arguments:
pPDev - Pointer to PDEVICE struct
iXIn - Number of units to move in X direction
fFlag - Specifies the different X move operations
Return Value:
The difference between requested and actual value sent to the device
--*/
/* ------- current code with comments ------------ */
INT
XMoveTo(
PDEV *pPDev,
INT iXIn,
INT fFlag
)
/*++
Routine Description:
This function is called to change the X position along the X axis.
what is the definition of X axis? it is the printer's
logical x-axis. If the printer has a Landscape or Printing Direction command
these will change the logical x-axis.
Arguments:
pPDev - Pointer to PDEVICE struct
iXIn - Number of units to move in X direction
fFlag - Specifies the different X move operations
Return Value:
The difference between requested and actual value sent to the device
--*/
{
int iX, iFineValue, iDiff = 0;
GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
int iScale;
//
// If the position is given in graphics units, convert to master units
//
// ptGrxScale has been adjusted to suit the current orientation.
//
//*\\ ok, this makes sense if X and Y moveto is swapped
// by caller if driver does the rotation.
if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
pPDev->pGlobals->bRotateCoordinate == FALSE)
//*\\ is driver performing the Landscape rotation?
iScale = pPDev->ptGrxScale.y; //*\\ driver is
else
iScale = pPDev->ptGrxScale.x; //*\\ printer is
if ( fFlag & MV_GRAPHICS ) //*\\ iXin is in graphics units
{
iXIn = (iXIn * iScale);
}
//
// Since our print origin may not correspond with the printer's,
// there are times when we need to adjust the value passed in to
// match the desired location on the page.
//
iX = iXIn;
//
// Basically, only adjust if we are doing absolute move
//
//*\\ MV_PHYSICAL means iXIn is wrt to cursor origin not imageable origin.
//*\\ sometimes used by render code to go to cursor origin.
if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
iX += pPDev->sf.ptPrintOffsetM.x;
//*\\ convert iX to cursor cooridinates. note sf.ptPrintOffsetM
//*\\ is defined as ImageableOrigin - CursorOrigin
//
// If it's a relative move, update iX (iX will be the absolute position)
// to reflect the current cursor position
//*\\ note cursor position (ctl.ptCursor) is always wrt the cursor origin.
if ( fFlag & MV_RELATIVE )
iX += pPDev->ctl.ptCursor.x;
//*\\ iX represents the cursor position wrt the cursor origin after
//*\\ the specified move has been executed.
//
// Update, only update our current cursor position and return
// Do nothing if the XMoveTo cmd is called to move to the current position.
//
if ( fFlag & MV_UPDATE )
{
pPDev->ctl.ptCursor.x = iX;
return 0;
}
if ( pPDev->ctl.ptCursor.x == iX )
return 0;
//
// If iX is zero and pGlobals->cxaftercr does not have
// CXCR_AT_GRXDATA_ORIGIN set, then we send CR and reset our
// cursor position to 0, which is the printable x origin
//
//*\\ ignore above comment there is no CXCR_AT_GRXDATA_ORIGIN
//*\\ only at cursor origin or imageable origin.
// if cursor is requested to move to its origin and a <cr> will take it
// to the origin, issue the <cr>.
if (iX == 0 && (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN ||
pPDev->sf.ptPrintOffsetM.x == 0))
{
pPDev->ctl.ptCursor.x = 0;
WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
return 0;
}
//
// Check whether we any X move cmd, PF_NO_XMOVE_CMD is set if we did
// not see any relative or absolute x move cmds
//
if( pPDev->fMode & PF_NO_XMOVE_CMD)
{
//
// There is no X move command(abs or relative), so we'll have to simulate
// using blanks or null graphics data (0)
//
//
// We *assume* that when XMoveto is called, the current font is always
// the default font IF the printer has no X movement command.
//
int iRelx = iX - pPDev->ctl.ptCursor.x ;
int iDefWidth;
//
// Convert to Master Units
//
//
// BUG_BUG, Double check that we can use Default Font here when
// we have a custom TTY driver
//
if ( iRelx < 0 )
{
if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
iRelx = iX;
else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
{
ASSERT(pPDev->pGlobals->bRotateCoordinate==FALSE);
//*\\ this means if the printer has no X move commands
// it had better not claim it can perform coordinate rotations.
iRelx = iX - pPDev->pf.ptImageOriginM.x; >>>wrong!!!!<<<
}
WriteChannel( pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN ));
}
//
// Simulate X Move, algorithm is that we always send a blank space
// for every character width, and send graphics null data for
// the remainder.
//
//*\\ potential bugs: what if a different font is selected?
//*\\ font width wasn't originally specified in resolution units
//*\\ so ganesh does a rounding operation. This may not agree
//*\\ with the printers idea of the font width. (x-advance)
//*\\ why isn't requested position tracked? Imagine the cursor only moves
//*\\ in units of 2 master units, a series of 10 1 unit relative move to commands should
//*\\ result in the cursor moving 10 units using 5 actual moves of 2 units each.
//*\\ the assumption here is iRelx is always positive.
// this should be ok, since if there are no dedicated
// movement commands, and the makeshift commands used
// can only move to the right, there is no way to access
// any region to the left of the cursor origin (accessed via <cr>).
iDefWidth = pPDev->ptDefaultFont.x * iScale;
if (iDefWidth)
{
while( iRelx >= iDefWidth )
{
WriteSpoolBuf( pPDev, (LPSTR)" ", 1 );
iRelx -= iDefWidth;
}
}
else
TERSE (("XMoveTo: iDefWidth = 0\n"));
//
// Send the remaining partial space via FineXMoveTo.
//
iDiff = iRelx;
fFlag |= MV_FINE; // Use graphics mode to reach point
}
else
{
DWORD dwTestValue = abs(iX - pPDev->ctl.ptCursor.x);
COMMAND *pCmd;
//
// X movement commmands are available, so use them.
// We need to decide here whether relative or absolute command
// are favored
//
// General assumption: if dwTestValue > dwXMoveThreshold,
// absolute command will be favored
//
//
// BUG_BUG, if we are stripping blanks, we need to check whether
// it's legal to move in Graphics mode. If it's not, we have
// to get out of graphics mode before moving.
//
// buggy!, buggy! buggy!
//*\\ avoid using absolute moves for negative values?
// yet its ok to use negative values the first time?
// what happens if negative abs move is the only way
// to reach that portion of the printable area?
// if you set dwXMoveThreshold to a non-zero value,
// you had better have relative movement commands
//
if (((pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED) ||
(dwTestValue > pPDev->pGlobals->dwXMoveThreshold &&
iX > 0)) &&
(pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVEABSOLUTE)) != NULL)
{
//
// if the move units are less (coarser) than the master units then we need to
// check whether the new position will end up being the same as the
// original position. If so, no point in sending another command.
//
// I think ptDeviceFac is the number of master units covered
// by one move unit.
if (!(pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED) &&
(pPDev->ptDeviceFac.x > 1) &&
((iX - (iX % pPDev->ptDeviceFac.x)) == pPDev->ctl.ptCursor.x))
//*\\ I would have rewritten the last condition as:
// (iX / pPDev->ptDeviceFac.x == pPDev->ctl.ptCursor.x / pPDev->ptDeviceFac.x)
// ptCursor is the quantized cursor position in master units, not
// where the app expects the cursor to be.
{
iDiff = iX - pPDev->ctl.ptCursor.x; // having the caller keep track of
// this is just plain wrong. you know it will be dropped. since one
// caller cannot transfer the error to the next caller.
}
else
{
//*\\ what is this: ctl.ptAbsolutePos ? this is the standard variable
//*\\ why isn't ctl.ptCursor updated ? it is at the very end of this function.
pPDev->ctl.ptAbsolutePos.x = iX;
//
// 3/13/97 ZhanW
// set up DestY as well in case it's needed (ex. FE printers).
// In that case, truncation error (iDiff) is not a concern.
// This is for backward compatibility with FE Win95 and FE NT4
// minidrivers.
//
//*\\ note: WriteChannel returns amount moved in
// device units which can be converted to master units
// by multiplying by pPDev->ptDeviceFac.x
pPDev->ctl.ptAbsolutePos.y = pPDev->ctl.ptCursor.y;
iDiff = WriteChannelEx(pPDev,
pCmd,
pPDev->ctl.ptAbsolutePos.x,
pPDev->ptDeviceFac.x);
if (pPDev->ctl.dwCursorMode & CURSOR_X_UNINITIALIZED)
pPDev->ctl.dwCursorMode &= ~CURSOR_X_UNINITIALIZED;
}
}
else // code assumes relative moves exist if iX is negative
{
//
// Use relative command to send move request
//
INT iRelRightValue = 0;
if( iX < pPDev->ctl.ptCursor.x ) // when is ptCursor initialized? to (0,0) at DrvStartPage().
// what command actually ensured the cursor was set to (0,0)?
// absolutely none - its should be part of the StartPage command.
// If the printer has no absolute movement command,
// the StartPage command should include a command to set
// the cursor to position (0,0). If the cursor position cannot
// be set to (0,0), then this code is invalid.
{
//
// Relative move left
//
if (pCmd = COMMANDPTR(pDrvInfo,CMD_XMOVERELLEFT))
{
//
// Optimize to avoid sending 0-move cmd.
//
// note all args for relative moves are positive.
if ((pPDev->ctl.ptRelativePos.x =
pPDev->ctl.ptCursor.x - iX) < pPDev->ptDeviceFac.x)
iDiff = pPDev->ctl.ptRelativePos.x;
else
iDiff = WriteChannelEx(pPDev,
pCmd,
pPDev->ctl.ptRelativePos.x,
pPDev->ptDeviceFac.x);
iDiff = -iDiff;
}
else
{
//
// No Relative left move cmd, use <CR> to reach start
// Will try to use relative right move cmd to send later
// assumption is if no rel left move command exists,
// printing in the negative quadrant is impossible.
// because abs moves are never used even if they
// accept negative args.
WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_CARRIAGERETURN));
if (pPDev->pGlobals->cxaftercr == CXCR_AT_CURSOR_X_ORIGIN)
iRelRightValue = iX; //*\\ what if this value is negative?
else if (pPDev->pGlobals->cxaftercr == CXCR_AT_PRINTABLE_X_ORIGIN)
{
ASSERT(pPDev->pGlobals->bRotateCoordinate==FALSE);
// assumes printers that support relative right, but not left
// move commands
// do not rotate the cooridinate system. Kind of strange?
// this is regardless of whether they support abs move.
iRelRightValue = iX - pPDev->pf.ptImageOriginM.x;
}
}
}
else
{
//
// Relative right move
// UNIITIALZIED is an invalid position, set to zero
//
iRelRightValue = iX - pPDev->ctl.ptCursor.x;
}
if( iRelRightValue > 0 )
{
if (pCmd = COMMANDPTR(pDrvInfo, CMD_XMOVERELRIGHT))
{
//
// optimize to avoid 0-move cmd
//
if ((pPDev->ctl.ptRelativePos.x = iRelRightValue) <
pPDev->ptDeviceFac.x)
iDiff = iRelRightValue;
else
iDiff = WriteChannelEx(pPDev,
pCmd,
pPDev->ctl.ptRelativePos.x,
pPDev->ptDeviceFac.x);
}
else
iDiff = iRelRightValue; //*\\ that's it? no attempt to move cursor?
}
}
}
//
// Peform fine move command
//
if ( (fFlag & MV_FINE) && iDiff > 0 )
iDiff = FineXMoveTo( pPDev, iDiff );
//
// Update our current cursor position
//
pPDev->ctl.ptCursor.x = iX - iDiff ;
if( fFlag & MV_GRAPHICS )
{
iDiff = (iDiff / iScale);
}
if (pPDev->fMode & PF_RESELECTFONT_AFTER_XMOVE)
{
VResetFont(pPDev);
}
return( iDiff);
}
INT
YMoveTo(
PDEV *pPDev,
INT iYIn,
INT fFlag
)
/*++
Routine Description:
This function is called to change the Y position.
Arguments:
pPDev - Pointer to PDEVICE struct
iYIn - Number of units to move in Y direction
fFlag - Specifies the different Y move operations
Return Value:
The difference between requested and actual value sent to the device
--*/
{
INT iY, iDiff = 0;
DWORD dwTestValue;
GPDDRIVERINFO *pDrvInfo = pPDev->pDriverInfo;
COMMAND *pAbsCmd;
INT iScale;
//
// Convert to Master Units if the given units is in Graphics Units
// ptGrxScale has been adjusted to suit the current orientation.
//
if (pPDev->pOrientation && pPDev->pOrientation->dwRotationAngle != ROTATE_NONE &&
pPDev->pGlobals->bRotateCoordinate == FALSE)
iScale = pPDev->ptGrxScale.x;
else
iScale = pPDev->ptGrxScale.y;
if ( fFlag & MV_GRAPHICS )
{
iYIn = (iYIn * iScale);
}
//
// Since our print origin may not correspond with the printer's,
// there are times when we need to adjust the value passed in to
// match the desired location on the page.
//
iY = iYIn;
//
// Basically, only adjust if we are doing absolute move
//
if ( !(fFlag & (MV_RELATIVE | MV_PHYSICAL)) )
iY += pPDev->sf.ptPrintOffsetM.y;
//
// Adjust iY to be the absolute position
//
if( fFlag & MV_RELATIVE )
iY += pPDev->ctl.ptCursor.y;
//
// Update, only update our current cursor position and return
// Do nothing if the YMoveTo cmd is called to move to the current position.
//
if( fFlag & MV_UPDATE )
{
pPDev->ctl.ptCursor.y = iY;
return 0;
}
if( pPDev->ctl.ptCursor.y == iY )
return 0;
//
// General assumption: if dwTestValue > dwYMoveThreshold,
// absolute Y move command will be favored. Also, for iY < 0,
// use relative command since some printers like old LaserJet have
// printable area above y=0 accessable only through relative move cmds.
//
//
// BUG_BUG, if we are stripping blanks, we need to check whether
// it's legal to move in Graphics mode. If it's not, we have
// to get out of graphics mode before moving.
//
dwTestValue = abs(iY - pPDev->ctl.ptCursor.y);
if (((pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED) ||
(dwTestValue > pPDev->pGlobals->dwYMoveThreshold &&
iY > 0)) &&
(pAbsCmd = COMMANDPTR(pDrvInfo, CMD_YMOVEABSOLUTE)) != NULL)
{
//! if neg move is the first one, then an absolute move
// is issued even though the code explicitly says this is
// a Bad thing.
// if there are no relative commands and a negative move
// is specified, bad things will happen.
//
// if the move units are less than the master units then we need to
// check whether the new position will end up being the same as the
// original position. If so, no point in sending another command.
//
if (!(pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED) &&
(pPDev->ptDeviceFac.y > 1) &&
((iY - (iY % pPDev->ptDeviceFac.y)) == pPDev->ctl.ptCursor.y))
{
iDiff = iY - pPDev->ctl.ptCursor.y;
}
else
{
pPDev->ctl.ptAbsolutePos.y = iY;
pPDev->ctl.ptAbsolutePos.x = pPDev->ctl.ptCursor.x;
iDiff = WriteChannelEx(pPDev,
pAbsCmd,
pPDev->ctl.ptAbsolutePos.y,
pPDev->ptDeviceFac.y);
if (pPDev->ctl.dwCursorMode & CURSOR_Y_UNINITIALIZED)
pPDev->ctl.dwCursorMode &= ~CURSOR_Y_UNINITIALIZED;
}
}
else
{
//
// Use Relavite Y-move commands
//
//
// FYMOVE_SEND_CR_FIRST indicates that it's required to send a CR
// before each line-spacing command
//
// what does this mean? that the cursor must be at x=0
// before doing a y-move? or a <cr> must be sent
// before doing a y-move?
// if the latter, calling XMoveTo does not ensure the <cr>
// is sent. First, the x pos may already be 0 or
// an absolute X move command may be used as would
// be the case if the distance moved exceeded the threshold.
if ( pPDev->fYMove & FYMOVE_SEND_CR_FIRST )
XMoveTo( pPDev, 0, MV_PHYSICAL );
//
// Use line spacing if that is preferred
//
if ( (pPDev->fYMove & FYMOVE_FAVOR_LINEFEEDSPACING) &&
iY - pPDev->ctl.ptCursor.y > 0 &&
pPDev->arCmdTable[CMD_SETLINESPACING] != NULL &&
pPDev->arCmdTable[CMD_LINEFEED] != NULL )
{
INT iLineSpacing;
DWORD dwMaxLineSpacing = pPDev->pGlobals->dwMaxLineSpacing;
while ( dwTestValue )
{
iLineSpacing =(INT)(dwTestValue > dwMaxLineSpacing ?
dwMaxLineSpacing : dwTestValue);
if (pPDev->ctl.lLineSpacing == -1 || <== meaningless check.
iLineSpacing != pPDev->ctl.lLineSpacing )
{
pPDev->ctl.lLineSpacing = iLineSpacing;
WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_SETLINESPACING));
}
//
// Send the LF
//
WriteChannel(pPDev, COMMANDPTR(pDrvInfo, CMD_LINEFEED));
dwTestValue -= (DWORD)iLineSpacing;
}
}
else
{
//
// Use relative command
//
PCOMMAND pCmd;
if ( iY <= pPDev->ctl.ptCursor.y )
{
//
// If there is no RELATIVE UP cmd, do nothing and return
//
if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELUP))
{
//
// optimize to avoid 0-move cmd
//
if ((pPDev->ctl.ptRelativePos.y =
pPDev->ctl.ptCursor.y - iY) < pPDev->ptDeviceFac.y)
iDiff = pPDev->ctl.ptRelativePos.y;
else
iDiff = WriteChannelEx(pPDev,
pCmd,
pPDev->ctl.ptRelativePos.y,
pPDev->ptDeviceFac.y);
iDiff = -iDiff;
}
else
// Do nothing since we can't simulate it
iDiff = (iY - pPDev->ctl.ptCursor.y );
// my interpretation of iDiff is you add iDiff to
// the printers cursor position to get where
// you really wanted to be.
}
else
{
if (pCmd = COMMANDPTR(pDrvInfo, CMD_YMOVERELDOWN))
{
pPDev->ctl.ptRelativePos.y = iY - pPDev->ctl.ptCursor.y;
//
// optimize to avoid 0-move cmd
//
if (pPDev->ctl.ptRelativePos.y < pPDev->ptDeviceFac.y)
iDiff = pPDev->ctl.ptRelativePos.y;
else
iDiff = WriteChannelEx(pPDev,
pCmd,
pPDev->ctl.ptRelativePos.y,
pPDev->ptDeviceFac.y);
}
else // can't move at all.
iDiff = (iY - pPDev->ctl.ptCursor.y );
}
}
}
//
// Update our current cursor position
//
pPDev->ctl.ptCursor.y = iY - iDiff;
if( fFlag & MV_GRAPHICS )
{
iDiff = (iDiff / iScale);
}
return (iDiff);
}