|
|
/******************************Module*Header*******************************\
* Module Name: xformgdi.cxx * * Contains all the mapping and coordinate functions. * * Created: 09-Nov-1990 16:49:36 * Author: Wendy Wu [wendywu] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
#define UNITS_PER_MILLIMETER_LOMETRIC 10 // .1 mm/unit
#define UNITS_PER_MILLIMETER_HIMETRIC 100 // .01 mm/unit
#define UNITS_PER_METER_LOENGLISH 3937 // (100 units/in) / (0.0254 m/in)
#define UNITS_PER_METER_HIENGLISH 39370 // (1000 units/in) / (0.0254 mm/in)
#define UNITS_PER_METER_TWIPS 56693 // (1440 units/in) / (0.0254 mm/in)
#if DBG
int giXformLevel = 0; #endif
extern "C" BOOL ProbeAndConvertXFORM( XFORML *kpXform, XFORML *pXform );
/******************************Public*Routine******************************\
* GreGetMapMode(hdc) * * Get the mapping mode of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
int APIENTRY GreGetMapMode( HDC hdc) { DWORD dw = 0; XDCOBJ dco( hdc );
if(dco.bValid()) { dw = dco.ulMapMode(); dco.vUnlockFast(); } else { WARNING("Invalid DC passed to GreGetMapMode\n"); }
return(dw); }
/******************************Public*Routine******************************\
* GreGetViewportExt(hdc,pSize) * * Get the viewport extents of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetViewportExt( HDC hdc, PSIZE pSize) { return(GreGetDCPoint(hdc,DCPT_VPEXT,(PPOINTL)pSize)); }
/******************************Public*Routine******************************\
* GreGetViewportOrg(hdc,pPoint) * * Get the viewport origin of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetViewportOrg( HDC hdc, LPPOINT pPoint) { return(GreGetDCPoint(hdc,DCPT_VPORG,(PPOINTL)pPoint)); }
/******************************Public*Routine******************************\
* GreGetWindowExt(hdc,pSize) * * Get the window extents of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetWindowExt( HDC hdc, PSIZE pSize) { return(GreGetDCPoint(hdc,DCPT_WNDEXT,(PPOINTL)pSize)); }
/******************************Public*Routine******************************\
* GreGetWindowOrg(hdc,pPoint) * * Get the window origin of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetWindowOrg( HDC hdc, LPPOINT pPoint) { return(GreGetDCPoint(hdc,DCPT_WNDORG,(PPOINTL)pPoint)); }
/******************************Public*Routine******************************\
* GreSetViewportOrg(hdc,x,y,pPoint) * * Set the viewport origin of the specified dc. * * 15-Sep-1992 -by- Gerrit van Wingerden [gerritv] * Modified since xforms have moved to client side and this routine is * now only called by usersrv. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreSetViewportOrg( HDC hdc, int x, int y, LPPOINT pPoint) {
DCOBJ dcox(hdc); // lock the dc object
if (!dcox.bValid()) // check if lock is valid
return(FALSE);
if (MIRRORED_DC(dcox.pdc)) x = -x;
if (BLTOFXOK(x) && BLTOFXOK(y)) { if (!dcox.pdc->bValidPtlCurrent()) { ASSERTGDI(dcox.pdc->bValidPtfxCurrent(), "Both CPs invalid?");
EXFORMOBJ exoDtoW(dcox, DEVICE_TO_WORLD);
if (exoDtoW.bValid()) exoDtoW.bXform(&dcox.ptfxCurrent(), &dcox.ptlCurrent(), 1);
dcox.pdc->vValidatePtlCurrent(); }
// After the transform, the device space CP will be invalid:
dcox.pdc->vInvalidatePtfxCurrent();
// x, y of viewport origin can fit into 28 bits.
// If we get here it means we've been called by USER and Viewport
// and Window extents should be (1,1) and Window Orgs should be zero,
// and the world transform shouldn't be set either.
DONTUSE(pPoint); // pPoint is now ignored
EXFORMOBJ xoWtoD(dcox, WORLD_TO_DEVICE); EFLOATEXT efDx((LONG) x); EFLOATEXT efDy((LONG) y);
efDx.vTimes16(); efDy.vTimes16(); ASSERTGDI(xoWtoD.efM11().bIs16() || (MIRRORED_DC(dcox.pdc) && xoWtoD.efM11().bIsNeg16()), "efM11 not 16 in GreSetViewportOrg or -16 in Mirroring Mode" ); ASSERTGDI( xoWtoD.efM22().bIs16(), "efM22 not 16 in GreSetViewportOrg" );
dcox.pdc->flSet_flXform( DEVICE_TO_WORLD_INVALID | PAGE_XLATE_CHANGED); //xoWtoD.vSetTranslations( efDx, efDy );
dcox.pdc->lViewportOrgX(x); dcox.pdc->lViewportOrgY(y);
xoWtoD.vInit(dcox, DEVICE_TO_WORLD);
return(TRUE);
} else return(FALSE); }
/******************************Public*Routine******************************\
* GreSetWindowOrg(hdc,x,y,pPoint) * * Set the window origin of the specified dc. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreSetWindowOrg( HDC hdc, int x, int y, LPPOINT pPoint) {
DCOBJ dcox(hdc); // lock the dc object
if (!dcox.bValid()) // check if lock is valid
return(FALSE);
// If we get here it means we've been called by USER and Viewport
// and Window extents should be (1,1) and Viewport Orgs should be zero,
// and the world transform shouldn't be set either.
DONTUSE(pPoint); // pPoint is now ignored
EXFORMOBJ xoWtoD(dcox, WORLD_TO_DEVICE); EFLOATEXT efDx((LONG) -x); EFLOATEXT efDy((LONG) -y);
efDx.vTimes16(); efDy.vTimes16();
ASSERTGDI( xoWtoD.efM11().bIs16() || (MIRRORED_DC(dcox.pdc) && xoWtoD.efM11().bIsNeg16()), "efM11 not 16 in GreSetViewportOrg" );
ASSERTGDI( xoWtoD.efM22().bIs16(), "efM22 not 16 in GreSetViewportOrg" );
if (!dcox.pdc->bValidPtlCurrent()) { ASSERTGDI(dcox.pdc->bValidPtfxCurrent(), "Both CPs invalid?");
EXFORMOBJ exoDtoW(dcox, DEVICE_TO_WORLD);
if (exoDtoW.bValid()) exoDtoW.bXform(&dcox.ptfxCurrent(), &dcox.ptlCurrent(), 1);
dcox.pdc->vValidatePtlCurrent(); }
// After the transform, the device space CP will be invalid:
dcox.pdc->vInvalidatePtfxCurrent();
dcox.pdc->flSet_flXform( DEVICE_TO_WORLD_INVALID | PAGE_XLATE_CHANGED); //xoWtoD.vSetTranslations( efDx, efDy );
//
// save in DC for USER. Caution: these valuse must be restored before app
// uses DC again
//
dcox.pdc->lWindowOrgX(x); dcox.pdc->lWindowOrgY(y); dcox.pdc->SetWindowOrgAndMirror(x);
xoWtoD.vInit(dcox, DEVICE_TO_WORLD);
return( TRUE );
}
/******************************Public*Routine******************************\
* NtGdiConvertMetafileRect: * * Transform a RECT from inclusive-exclusive to inclusive-inclusive for * a rectangle recorded in a metafile. * * Arguments: * * hdc - current device context * rect - rtectangle to convert * * Return Value: * * MRI_OK,MRI_NULLBOX,MRI_ERROR * * History: * * 9-Apr-1996 -by- Mark Enstrom [marke] * \**************************************************************************/
LONG APIENTRY NtGdiConvertMetafileRect( HDC hdc, PRECTL prect ) { LONG lResult = MRI_ERROR; RECTL rclMeta;
//
// copy in rect structure
//
__try { rclMeta = ProbeAndReadStructure(prect,RECTL); lResult = MRI_OK; } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(22); }
if (lResult == MRI_OK) { //
// attempt to lock DC
//
DCOBJ dco(hdc);
if (dco.bValid()) { ERECTFX rectFX; BOOL bResult;
//
// DC must be in compatible mode
//
ASSERTGDI(dco.pdc->iGraphicsMode() == GM_COMPATIBLE, "NtGdiConvertMetafileRect: Map Mode is not GM_COMPATIBLE");
//
// transform rectangle points to device FX
//
{ EXFORMOBJ xo(dco,XFORM_WORLD_TO_DEVICE);
bResult = xo.bXform((PPOINTL)&rclMeta,(PPOINTFIX)&rectFX,2); }
if (bResult) { //
// order device point rectangle
//
rectFX.vOrder();
//
// adjust lower and right points for exclusive to inclusive
//
rectFX.xRight -= 16; rectFX.yBottom -= 16;
//
// check for empty rectFX
//
if ((rectFX.xRight < rectFX.xLeft) || (rectFX.yBottom < rectFX.yTop)) { lResult = MRI_NULLBOX; }
//
// convert back to logical space
//
EXFORMOBJ xoDev(dco,XFORM_DEVICE_TO_WORLD);
bResult = xoDev.bXform((PPOINTFIX)&rectFX,(PPOINTL)&rclMeta,2);
//
// Write results to caller's buffer
//
if (bResult) { __try { ProbeAndWriteStructure(prect,rclMeta,RECT); } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(8); lResult = MRI_ERROR; } } else { lResult = MRI_ERROR; } } else { lResult = MRI_ERROR; } } else { lResult = MRI_ERROR; } }
if (lResult == MRI_ERROR) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); }
return(lResult); }
/******************************Public*Routine******************************\
* * * History: * 02-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreTransformPoints( HDC hdc, PPOINT pptIn, PPOINT pptOut, int c, int iMode ) { XFORMPRINT(1,"GreTransformPoints, iMode = %ld\n",iMode);
BOOL bResult = FALSE;
DCOBJ dco(hdc); // lock the dc object
if (dco.bValid()) // check if lock is valid
{ if (c <= 0) // check if there are points to convert
{ bResult = TRUE; } else { EXFORMOBJ xo(dco, (iMode == XFP_DPTOLP) ? XFORM_DEVICE_TO_WORLD : XFORM_WORLD_TO_DEVICE);
if (xo.bValid()) { switch (iMode) { case XFP_DPTOLP: case XFP_LPTODP: bResult = xo.bXform((PPOINTL)pptIn, (PPOINTL)pptOut, c); break;
case XFP_LPTODPFX: bResult = xo.bXform((PPOINTL)pptIn, (PPOINTFIX)pptOut, c); break;
default: WARNING("Invalid mode passed to GreTranformPoints\n"); break; } } } } return(bResult); }
/******************************Public*Routine******************************\
* GreDPtoLP(hdc,ppt,nCount) * * Convert the given device points into logical points. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreDPtoLP( HDC hdc, LPPOINT ppt, int nCount) { return(GreTransformPoints(hdc,ppt,ppt,nCount,XFP_DPTOLP)); }
/******************************Public*Routine******************************\
* GreLPtoDP(hdc,ppt,nCount) * * Convert the given logical points into device points. * * History: * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreLPtoDP( HDC hdc, LPPOINT ppt, int nCount) { return(GreTransformPoints(hdc,ppt,ppt,nCount,XFP_LPTODP)); }
/******************************Private*Routine*****************************\
* bWorldMatrixInRange(pmx) * * See if the coefficients of the world transform matrix are within * our minimum and maximum range. * * History: * 27-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL bWorldMatrixInRange(PMATRIX pmx) {
BOOL bRet;
#if defined(_AMD64_) || defined(_IA64_) || defined(BUILD_WOW6432)
/*
EFLOAT ef = pmx->efM11; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE);
ef = pmx->efM12; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE);
ef = pmx->efM21; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE);
ef = pmx->efM22; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE);
ef = pmx->efDx; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE);
ef = pmx->efDy; ef.vAbs(); if ((ef < (FLOAT)MIN_WORLD_XFORM) || (ef > (FLOAT)MIN_WORLD_XFORM)) return(FALSE); */
bRet = TRUE;
#else
bRet = ((pmx->efM11.bExpLessThan(MAX_WORLD_XFORM_EXP)) && (pmx->efM12.bExpLessThan(MAX_WORLD_XFORM_EXP)) && (pmx->efM21.bExpLessThan(MAX_WORLD_XFORM_EXP)) && (pmx->efM22.bExpLessThan(MAX_WORLD_XFORM_EXP)) && (pmx->efDx.bExpLessThan(MAX_WORLD_XFORM_EXP)) && (pmx->efDy.bExpLessThan(MAX_WORLD_XFORM_EXP))) ;
#endif
if (bRet) { // at this point bRet == TRUE. We have to figure out the cases
// when the determinant is zero and set bRet to FALSE;
// We do what we can to avoid multiplications in common cases
// when figuring out if this is a singular trasform
if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero()) { if (pmx->efM11.bIsZero() || pmx->efM22.bIsZero()) bRet = FALSE; } else if (pmx->efM11.bIsZero() && pmx->efM22.bIsZero()) { if (pmx->efM12.bIsZero() || pmx->efM21.bIsZero()) bRet = FALSE; } else // general case, have to do multiplications
{ EFLOAT ef = pmx->efM11; ef *= pmx->efM22;
EFLOAT ef1 = pmx->efM12; ef1 *= pmx->efM21;
ef -= ef1; // determinant.
if (ef.bIsZero()) { bRet = FALSE; } } }
return bRet; }
/******************************Public*Routine******************************\
* GreGetDeviceWidth(hdc) * * Get the device surface width of the specified dc. * * History: * 26-Jan-1998 -by- Mohamed Hassanin [mhamid] * Wrote it. \**************************************************************************/ LONG APIENTRY GreGetDeviceWidth(HDC hdc) { DCOBJ dco(hdc);
if (dco.bValid() != FALSE) { return (dco.pdc->GetDeviceWidth()); } else { WARNING("Invalid DC passed to GreGetDeviceWidth\n"); }
return (GDI_ERROR); }
/******************************Public*Routine******************************\
* GreMirrorWindowOrg(hdc) * * Mirror the Window X Org. By calling MirrorWindowOrg * * History: * 26-Jan-1998 -by- Mohamed Hassanin [mhamid] * Wrote it. \**************************************************************************/ BOOL APIENTRY GreMirrorWindowOrg(HDC hdc) { DCOBJ dco(hdc);
if (dco.bValid() != FALSE) { dco.pdc->MirrorWindowOrg(); return (TRUE); }
return (FALSE); } /******************************Public*Routine******************************\
* GreGetLayout * * * History: * Fri 12-Sep-1991 11:29 -by- Mohamed Hassanin [MHamid] * Wrote it. \**************************************************************************/ DWORD APIENTRY GreGetLayout(HDC hdc) { DWORD dwRet = GDI_ERROR;
DCOBJ dco(hdc);
if (dco.bValid() != FALSE) { dwRet = dco.pdc->dwLayout(); }
return(dwRet); }
/******************************Public*Routine******************************\
* GreSetLayout * * * History: * Fri 12-Sep-1991 11:29 -by- Mohamed Hassanin [MHamid] * Wrote it. \**************************************************************************/ DWORD APIENTRY GreSetLayout ( HDC hdc, LONG wox, DWORD dwLayout) { DCOBJ dco( hdc ); if( !dco.bValid() ) { WARNING("Xform update invalid hdc\n"); return(GDI_ERROR); } return dco.pdc->dwSetLayout(wox, dwLayout); }
/******************************Public*Routine******************************\
* GreXformUpdate * * Updates the server's copy of the WtoD transform, transform related flags, * and viewport and window extents. * * History: * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Wrote it. \**************************************************************************/
BOOL GreXformUpdate ( HDC hdc, FLONG flXform, LONG wex, LONG wey, LONG vex, LONG vey, LONG mapMode, PVOID pvMatrix ) { DCOBJ dco( hdc );
if( !dco.bValid() ) { WARNING("Xform update invalid hdc\n"); return(FALSE); }
// Copy window and viewport extents
dco.pdc->vSet_szlWindowExt( wex, wey ); dco.pdc->vSet_szlViewportExt( vex, vey ); dco.pdc->ulMapMode( mapMode );
// Save current position
ASSERTGDI(dco.bValid(), "DC not valid");
if (!dco.pdc->bValidPtlCurrent()) { ASSERTGDI(dco.pdc->bValidPtfxCurrent(), "Both CPs invalid?");
EXFORMOBJ exoDtoW(dco, DEVICE_TO_WORLD);
if (exoDtoW.bValid()) exoDtoW.bXform(&dco.ptfxCurrent(), &dco.ptlCurrent(), 1);
dco.pdc->vValidatePtlCurrent(); }
// Set the flags
dco.pdc->flResetflXform( flXform ); dco.pdc->flSet_flXform( DEVICE_TO_WORLD_INVALID );
// Set the new world transform
RtlCopyMemory( (PVOID) &dco.pdc->mxWorldToDevice(), pvMatrix, sizeof( MATRIX )); RtlCopyMemory( (PVOID) &dco.pdc->mxUserWorldToDevice(), pvMatrix, sizeof( MATRIX ));
// After the transform, the device space CP will be invalid:
dco.pdc->vInvalidatePtfxCurrent();
if( flXform & INVALIDATE_ATTRIBUTES ) { EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
dco.pdc->vRealizeLineAttrs(exo); dco.pdc->vXformChange(TRUE); }
return (TRUE); }
/******************************Member*Function*****************************\
* vConvertXformToMatrix * * Convert a xform structure into a matrix struct. * * History: * 27-Mar-1991 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
VOID vConvertXformToMatrix(CONST XFORML *pxf, PMATRIX pmx) { pmx->efM11 = pxf->eM11; // overloading operator = which covert
pmx->efM12 = pxf->eM12; // IEEE float to our internal EFLOAT
pmx->efM21 = pxf->eM21; pmx->efM22 = pxf->eM22; pmx->efDx = pxf->eDx; pmx->efDy = pxf->eDy; #if DBG
if (!pmx->efDx.bEfToL(pmx->fxDx)) WARNING("vConvertXformToMatrix:translation dx overflowed\n"); if (!pmx->efDy.bEfToL(pmx->fxDy)) WARNING("vConvertXformToMatrix:translation dy overflowed\n"); #else
pmx->efDx.bEfToL(pmx->fxDx); pmx->efDy.bEfToL(pmx->fxDy); #endif
pmx->flAccel = XFORM_FORMAT_LTOL;
if ((pmx->efDx == pmx->efDy) && pmx->efDy.bIsZero()) pmx->flAccel |= XFORM_NO_TRANSLATION;
if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero()) { pmx->flAccel |= XFORM_SCALE; if (pmx->efM11.bIs1() && pmx->efM22.bIs1()) pmx->flAccel |= XFORM_UNITY; }
}
/******************************Private*Routine*****************************\
* vMakeIso() * * Shrink viewport extents in one direction to match the aspect ratio of * the window. * * History: * * 05-Dec-1994 -by- Eric Kutter [erick] * Moved back to the server * * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Modified for client side use. * * 09-Nov-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
VOID DC::vMakeIso() { LONG lVpExt; EFLOAT efRes, efTemp, efTemp1;
// Calculate the pixel aspect ratio efRes = ASPECTY / ASPECTX.
if(lVirtualDevicePixelCx() != 0) { //
// if lVirtualDeviceCx/Cy are set, use these, they are in micrometers
// Otherwise use their millimeters counter part
//
if ((lVirtualDeviceCx()) != 0 && (lVirtualDeviceCy() != 0)) { efTemp = lVirtualDevicePixelCx(); efTemp1 = lVirtualDeviceCy();
LONG lTemp = EngMulDiv(lVirtualDevicePixelCy(), lVirtualDeviceCx(), lVirtualDevicePixelCx()); efRes = lTemp; efRes /= efTemp1; } else { efRes = lVirtualDevicePixelCy() * lVirtualDeviceMmCx(); efTemp = lVirtualDevicePixelCx(); efTemp1 = lVirtualDeviceMmCy();
efRes /= efTemp; efRes /= efTemp1; } } else { PDEVOBJ po(hdev()); ASSERTGDI(po.bValid(), "Invalid PDEV\n");
efRes = (LONG)po.ulLogPixelsY(); efTemp = (LONG)po.ulLogPixelsX(); efRes /= efTemp; }
// Our goal is to make the following formula true
// VpExt.cy / VpExt.cx = (WdExt.cy / WdExt.cx) * (ASPECTY / ASPECTX)
// Let's calculate VpExt.cy assuming VpExt.cx is the limiting factor.
// VpExt.cy = (WdExt.cy * VpExt.cx) / WdExt.cx * efRes
EFLOATEXT efVpExt = lWindowExtCy(); efTemp = lViewportExtCx(); efTemp1 = lWindowExtCx(); efVpExt *= efTemp; efVpExt /= efTemp1; efVpExt *= efRes; efVpExt.bEfToL(lVpExt); // convert efloat to long
lVpExt = ABS(lVpExt);
// Shrink y if the |original VpExt.cy| > the |calculated VpExt.cy|
// The original signs of the extents are preserved.
if (lViewportExtCy() > 0) { if (lViewportExtCy() >= lVpExt) { lViewportExtCy(lVpExt); return; } } else { if (-lViewportExtCy() >= lVpExt) { lViewportExtCy(-lVpExt); return; } }
// We know VpExt.cy is the real limiting factor. Let's calculate the correct
// VpExt.cx.
// VpExt.cx = (WdExt.cx * VpExt.cy) / WdExt.cy / Res
efVpExt = lWindowExtCx(); efTemp = lViewportExtCy(); efTemp1 = lWindowExtCy(); efVpExt *= efTemp; efVpExt /= efTemp1; efVpExt /= efRes; efVpExt.bEfToL(lVpExt);
lVpExt = ABS(lVpExt);
if(lViewportExtCx() > 0 ) lViewportExtCx(lVpExt); else lViewportExtCx(-lVpExt);
}
/**************************************************************************\
* NtGdiScaleViewportExtEx() * * History: * 07-Jun-1995 -by- Andre Vachon [andreva] * Wrote it. \**************************************************************************/
BOOL NtGdiScaleViewportExtEx( HDC hdc, int xNum, int xDenom, int yNum, int yDenom, LPSIZE pszOut ) { BOOL bRet = FALSE;
DCOBJ dcox(hdc);
if (dcox.bValid()) { BOOL bNoExcept = TRUE;
//
// NOTE: NT 3.51 compatibility.
// Even if the API failed (returned FALSE), the viewport was returned
// properly - stay compatible with this.
//
if (pszOut) { __try { ProbeForWrite(pszOut,sizeof(SIZE), sizeof(DWORD)); *pszOut = dcox.pdc->szlViewportExt(); } __except(EXCEPTION_EXECUTE_HANDLER) { // SetLastError(GetExceptionCode());
bNoExcept = FALSE; } }
if (bNoExcept == TRUE) { // can't change extent if fixed scale
if (dcox.ulMapMode() <= MM_MAX_FIXEDSCALE) { bRet = TRUE; } else { LONG lx, ly; if ((xDenom != 0) && (yDenom != 0) && ((lx = (dcox.pdc->lViewportExtCx() * xNum) / xDenom) != 0) && ((ly = (dcox.pdc->lViewportExtCy() * yNum) / yDenom) != 0)) { dcox.pdc->lViewportExtCx(lx); dcox.pdc->lViewportExtCy(ly); dcox.pdc->MirrorWindowOrg(); dcox.pdc->vPageExtentsChanged(); bRet = TRUE; } } } }
return(bRet); }
/******************************Public*Routine******************************\
* GreScaleWindowExtEx() * * History: * 02-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL GreScaleWindowExtEx( HDC hdc, int xNum, int xDenom, int yNum, int yDenom, PSIZE psizl) { BOOL bRet = FALSE;
DCOBJ dcox(hdc); // lock the dc object
if (dcox.bValid()) // check if lock is valid
{ if (psizl != (LPSIZE)NULL) { *psizl = dcox.pdc->szlWindowExt(); // fetch old extent
if (MIRRORED_DC(dcox.pdc)) psizl->cx = -psizl->cx; }
// can't change extent if fixed scale
if (dcox.ulMapMode() <= MM_MAX_FIXEDSCALE) { bRet = TRUE; } else { LONG lx, ly; if ((xDenom != 0) && (yDenom != 0) && ((lx = (dcox.pdc->lWindowExtCx() * xNum) / xDenom) != 0) && ((ly = (dcox.pdc->lWindowExtCy() * yNum) / yDenom) != 0)) { dcox.pdc->lWindowExtCx(lx); dcox.pdc->lWindowExtCy(ly); dcox.pdc->MirrorWindowOrg(); dcox.pdc->vPageExtentsChanged(); bRet = TRUE; } } } return(bRet); }
/******************************Private*Routine*****************************\
* vComputePageXform * * Compute the page to device scaling factors. * * History: * 05-Dec-1994 -by- Eric Kutter [erick] * Moved back to the server * * * 15-Dec-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
VOID DC::vComputePageXform() { EFLOAT ef; EFLOATEXT efTemp;
ef = LTOFX(lViewportExtCx()); efTemp = lWindowExtCx(); ef /= efTemp; efM11PtoD(ef);
ef = LTOFX(lViewportExtCy()); efTemp = lWindowExtCy(); ef /= efTemp; efM22PtoD(ef); }
/******************************Public*Routine******************************\
* * int EngMulDiv * I am surprised that there is no system service routine to do this. * anyway I am just fixing the old routine * * History: * 15-Dec-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/
int EngMulDiv( int a, int b, int c) { LONGLONG ll; int iSign = 1;
if (a < 0) { iSign = -iSign; a = -a; } if (b < 0) { iSign = -iSign; b = -b; }
if (c != 0) { if (c < 0) { iSign = -iSign; c = -c; }
ll = (LONGLONG)a; ll *= b; ll += (c/2); // used to add (c+1)/2 which is wrong
ll /= c;
// at this point ll is guaranteed to be > 0. Thus we will do
// unsigned compare in the next step which generates two less instructions
// on x86 [bodind]
if ((ULONGLONG)ll > (ULONG)INT_MAX) // check for overflow:
{ if (iSign > 0) return INT_MAX; else return INT_MIN; } else { if (iSign > 0) return ((int)ll); else return (-(int)ll); } } else { ASSERTGDI(c, "EngMulDiv - c == 0\n"); ASSERTGDI(a | b, "EngMulDiv - a|b == 0\n");
if (iSign > 0) return INT_MAX; else return INT_MIN; } } /******************************Public*Routine******************************\
* dwSetLayout * * Mirror the dc, by offsetting the window origin. If wox == -1, then the * window origin becomes mirrored by the DC window width as follows : * -((Device_Surface_Width * WindowExtX) / ViewportExtX) + LogicalWindowOrgX * * Otherwise mirroring is done by the specified wox amount : * (wox - Current Window X-Origin) * * The function also changes windowExt.cx to be -1 so that positive x will * go from right to left. * * History: * 09-Dec-1997 -by- Mohammed Abdel-Hamid [mhamid] * Wrote it. \**************************************************************************/
DWORD DC::dwSetLayout(LONG wox, DWORD dwDefLayout) {
POINTL ptWOrg, ptVOrg; SIZEL SzWExt, SzVExt; DWORD dwOldLayout;
dwOldLayout = dwLayout(); dwLayout(dwDefLayout); if ((dwOldLayout & LAYOUT_ORIENTATIONMASK) == (dwDefLayout & LAYOUT_ORIENTATIONMASK)) { return dwOldLayout; }
vGet_szlWindowExt(&SzWExt); vGet_ptlViewportOrg(&ptVOrg);
if (dwDefLayout & LAYOUT_RTL) { //Set the rtl layout
ulMapMode(MM_ANISOTROPIC); ASSERTGDI((SzWExt.cx > 0), "GreSetLayout WExt.cx < 0 Check it"); } else { ASSERTGDI((SzWExt.cx < 0), "GreSetLayout WExt.cx > 0 Check it"); }
SzWExt.cx = -SzWExt.cx; vSet_szlWindowExt(&SzWExt);
ptVOrg.x = -ptVOrg.x; vSet_ptlViewportOrg(&ptVOrg);
if (wox == -1) { MirrorWindowOrg(); } else { vGet_ptlWindowOrg(&ptWOrg); ptWOrg.x = wox - ptWOrg.x; vSet_ptlWindowOrg(&ptWOrg); }
//
// TA_CENTER equals 6 (0110 Bin) and TA_RIGHT equals 2 (0010 Binary) numerically.
// so be careful not to do 'flTextAlign() & TA_CENTER'
// since this will succeed for RIGHT aligned DCs
// and as a result, the TA_RIGHT bit won't get cleared. [samera]
//
if ((flTextAlign()&TA_CENTER) != TA_CENTER) { flTextAlign(flTextAlign() ^ (TA_RIGHT)); } if (bClockwise()) { vClearClockwise(); } else { vSetClockwise(); } vPageExtentsChanged(); return dwOldLayout; }
EFLOAT ef16 = {EFLOAT_16};
/******************************Public*Routine******************************\
* DC::iSetMapMode() * * History: * 07-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
int DC::iSetMapMode( int iMode) { int iOldMode; DWORD dwOldLayout = 0;
// If the new map mode is not MM_ANISOTROPIC
// And the DC in a mirrored mode
// Then Turn off the mirroring and turn it on back after
// Setting the new mode.
if (iMode != MM_ANISOTROPIC) { dwOldLayout = dwLayout(); if (dwOldLayout & LAYOUT_ORIENTATIONMASK) { dwSetLayout(-1 , 0); } }
// If set to the old map mode, don't bother setting it again except
// with MM_ISOTROPIC in which the extents might have been changed.
iOldMode = ulMapMode();
if ((iMode != iOldMode) || (iMode == MM_ISOTROPIC)) { if (iMode == MM_TEXT) { lWindowExtCx(1); lWindowExtCy(1); lViewportExtCx(1); lViewportExtCy(1); ulMapMode(iMode);
// We don't want to recalculate M11 and M22 in vUpdateWtoDXform().
// Set them correctly here so we can just recalculate translations
// in vUpdateWtoDXform().
efM11PtoD(ef16); efM22PtoD(ef16); mxWorldToDevice().efM11 = ef16; mxWorldToDevice().efM22 = ef16; mxWorldToDevice().flAccel = XFORM_FORMAT_LTOFX | XFORM_UNITY | XFORM_SCALE; RtlCopyMemory( (PVOID) &mxUserWorldToDevice(), (PVOID) &mxWorldToDevice(), sizeof( MATRIX ));
vSetFlagsMM_TEXT(); } else if (iMode == MM_ANISOTROPIC) { ulMapMode(iMode); vSetFlagsMM_ISO_OR_ANISO(); } else if ((iMode < MM_MIN) || (iMode > MM_MAX)) { return(0); } else if (lVirtualDevicePixelCx() == 0) { PDEVOBJ po(hdev()); ASSERTGDI(po.bValid(), "Invalid PDEV\n");
// Protect against dynamic mode changes while we compute values
// using ulHorzSize and ulVertSize:
DEVLOCKOBJ dlo(po);
// Get the size of the surface
lViewportExtCx(po.GdiInfo()->ulHorzRes); lViewportExtCy(-(LONG)po.GdiInfo()->ulVertRes);
// Get the size of the device
switch (iMode) { case MM_LOMETRIC: //
// n um. * (1 mm. / 1000 um.) * (10 LoMetric units/1 mm.) = y LoMet
//
lWindowExtCx((po.GdiInfo()->ulHorzSize + 50)/100); lWindowExtCy((po.GdiInfo()->ulVertSize + 50)/100); vSetFlagsMM_FIXED(); break;
case MM_HIMETRIC: //
// n um. * (1 mm. / 1000 um.) * (100 HiMetric units/1 mm.) = y HiMet
//
lWindowExtCx((po.GdiInfo()->ulHorzSize + 5)/10); lWindowExtCy((po.GdiInfo()->ulVertSize + 5)/10); vSetFlagsMM_FIXED(); break;
case MM_LOENGLISH: //
// n um. * (1 in. / 25400 um.) * (100 LoEng units/1 in.) = y LoEng
//
lWindowExtCx((po.GdiInfo()->ulHorzSize + 127)/254); lWindowExtCy((po.GdiInfo()->ulVertSize + 127)/254); vSetFlagsMM_FIXED(); break;
case MM_HIENGLISH: //
// n um. * (1 in. / 25400 um.) * (1000 HiEng units/1 in.) = m HiEng
//
lWindowExtCx(EngMulDiv(po.GdiInfo()->ulHorzSize, 10, 254)); lWindowExtCy(EngMulDiv(po.GdiInfo()->ulVertSize, 10, 254)); vSetFlagsMM_FIXED(); break;
case MM_TWIPS: //
// n um. * (1 in. / 25400 um.) * (1440 Twips/1 in.) = m Twips
//
lWindowExtCx(EngMulDiv(po.GdiInfo()->ulHorzSize, 144, 2540)); lWindowExtCy(EngMulDiv(po.GdiInfo()->ulVertSize, 144, 2540));
// If it's cached earlier, use it.
#if defined(_AMD64_) || defined(_IA64_) || defined(BUILD_WOW6432)
if (efM11_TWIPS().e == (FLOAT)0) #else
if (efM11_TWIPS().i.lMant == 0) #endif
{ vComputePageXform(); efM11_TWIPS(efM11PtoD()); efM22_TWIPS(efM22PtoD()); } ulMapMode(MM_TWIPS);
// We don't want to recalculate M11 and M22 in vUpdateWtoDXform().
// Set them correctly here so we can just recalculate translations
// in vUpdateWtoDXform().
efM11PtoD(efM11_TWIPS()); efM22PtoD(efM22_TWIPS()); mxWorldToDevice().efM11 = efM11_TWIPS(); mxWorldToDevice().efM22 = efM22_TWIPS(); mxWorldToDevice().flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE; RtlCopyMemory( (PVOID) &mxUserWorldToDevice(), (PVOID) &mxWorldToDevice(), sizeof( MATRIX ));
vSetFlagsMM_FIXED_CACHED(); goto JUST_RETURN; //
// we need to pass thru mirroring code if
// it is enabled so the followingis commented for
// the above line
// return(iOldMode);
//
case MM_ISOTROPIC: lWindowExtCx((po.GdiInfo()->ulHorzSize + 50)/100); lWindowExtCy((po.GdiInfo()->ulVertSize + 50)/100); vSetFlagsMM_ISO_OR_ANISO(); break;
default: return(0); }
ulMapMode(iMode); vPageExtentsChanged(); } else { // Get the size of the virtual surface
lViewportExtCx(lVirtualDevicePixelCx()); lViewportExtCy(-lVirtualDevicePixelCy());
// Get the size of the virtual device
switch (iMode) { case MM_LOMETRIC: //
// n mm. * (10 LoMetric units/1 mm.) = y LoMet
//
lWindowExtCx(10 * lVirtualDeviceMmCx()); lWindowExtCy(10 * lVirtualDeviceMmCy()); vSetFlagsMM_FIXED(); break;
case MM_HIMETRIC: //
// n mm. * (100 HiMetric units/1 mm.) = y HiMet
//
lWindowExtCx(100 * lVirtualDeviceMmCx()); lWindowExtCy(100 * lVirtualDeviceMmCy()); vSetFlagsMM_FIXED(); break;
case MM_LOENGLISH: //
// n mm. * (10 in./254 mm.) * (100 LoEng/1 in.) = y LoEng
//
lWindowExtCx(EngMulDiv(lVirtualDeviceMmCx(),1000, 254)); lWindowExtCy(EngMulDiv(lVirtualDeviceMmCy(),1000, 254)); vSetFlagsMM_FIXED(); break;
case MM_HIENGLISH: //
// n mm. * (10 in./254 mm.) * (1000 LoEng/1 in.) = y LoEng
//
lWindowExtCx(EngMulDiv(lVirtualDeviceMmCx(),10000, 254)); lWindowExtCy(EngMulDiv(lVirtualDeviceMmCy(),10000, 254)); vSetFlagsMM_FIXED(); break;
case MM_TWIPS: //
// n mm. * (10 in./254 mm.) * (1440 Twips/1 in.) = y Twips
//
lWindowExtCx(EngMulDiv(lVirtualDeviceMmCx(),14400, 254)); lWindowExtCy(EngMulDiv(lVirtualDeviceMmCy(),14400, 254)); vSetFlagsMM_FIXED(); break;
case MM_ISOTROPIC: //
// n mm. * (10 LoMetric units/1 mm.) = y LoMet
//
lWindowExtCx(10 * lVirtualDeviceMmCx()); lWindowExtCy(10 * lVirtualDeviceMmCy()); vSetFlagsMM_ISO_OR_ANISO(); break;
default: return(0); }
ulMapMode(iMode); vPageExtentsChanged();
} JUST_RETURN: // If turned the mirroring off then turn it on back.
if (dwOldLayout & LAYOUT_ORIENTATIONMASK) { //And then set it again.
dwSetLayout(-1 , dwOldLayout); } }
return(iOldMode); }
/******************************Public*Routine******************************\
* NtGdiSetVirtualResolution() * * Set the virtual resolution of the specified dc. * The virtual resolution is used to compute transform matrix only. * If the virtual units are all zeros, the default physical units are used. * Otherwise, non of the units can be zero. * * Currently used by metafile component only. * * History: * * 05-Dec-1994 -by- Eric Kutter [erick] * Moved back to the server * * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Modified for client side use. * * Tue Aug 27 13:04:11 1991 -by- Hock San Lee [hockl] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiSetVirtualResolution( HDC hdc, int cxVirtualDevicePixel, // Width of the virtual device in pels
int cyVirtualDevicePixel, // Height of the virtual device in pels
int cxVirtualDeviceMm, // Width of the virtual device in millimeters
int cyVirtualDeviceMm) // Height of the virtual device in millimeters
{ XFORMPRINT(1,"GreSetVirtualResolution\n",0);
BOOL bRet = FALSE;
// The units must be all zeros or all non-zeros.
if ((cxVirtualDevicePixel != 0 && cyVirtualDevicePixel != 0 && cxVirtualDeviceMm != 0 && cyVirtualDeviceMm != 0) || (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 && cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0)) { // now lock down the DC
DCOBJ dcox(hdc); // lock the dc object
if (dcox.bValid()) // check if lock is valid
{
dcox.pdc->lVirtualDevicePixelCx(cxVirtualDevicePixel); dcox.pdc->lVirtualDevicePixelCy(cyVirtualDevicePixel);
dcox.pdc->lVirtualDeviceMmCx(cxVirtualDeviceMm); dcox.pdc->lVirtualDeviceMmCy(cyVirtualDeviceMm);
bRet = TRUE; } }
return(bRet); }
/******************************Public*Routine******************************\
* NtGdiSetSizeDevice() * * This is to compensate insufficient precision in SetVirtualResolution * * Modified for client side use. * * 5/17/99 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/ BOOL APIENTRY NtGdiSetSizeDevice( HDC hdc, int cxVirtualDevice, // Width of the virtual device in micrometers
int cyVirtualDevice) // Height of the virtual device in micrometers
{ BOOL bRet = FALSE;
// The units must be all zeros or all non-zeros.
if ((cxVirtualDevice != 0) && (cyVirtualDevice != 0)) { // now lock down the DC
DCOBJ dcox(hdc); // lock the dc object
if (dcox.bValid()) // check if lock is valid
{
dcox.pdc->lVirtualDeviceCx(cxVirtualDevice); dcox.pdc->lVirtualDeviceCy(cyVirtualDevice);
bRet = TRUE; } }
return(bRet); }
/******************************Public*Routine******************************\
* GreGetTransform() * * History: * 05-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL GreGetTransform( HDC hdc, DWORD iXform, XFORML *pxf) { XFORMPRINT(1,"GreGetTransform - iXform = %ld\n",iXform);
BOOL bRet = FALSE;
// now lock down the DC
DCOBJ dcox(hdc);
if (dcox.bValid()) {
EXFORMOBJ xo(dcox,iXform); MATRIX mx;
if (!xo.bValid() && (iXform == XFORM_PAGE_TO_DEVICE)) { xo.vInitPageToDevice(dcox,&mx); }
if (xo.bValid()) { xo.vGetCoefficient(pxf);
bRet = TRUE; } }
return(bRet); }
/******************************Public*Routine******************************\
* XformUpdate * * Sends update transform information to the server. * * History: * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Wrote it. \**************************************************************************/
VOID EXFORMOBJ::vInit( XDCOBJ& dco, ULONG iXform) { XFORMPRINT(1,"EXFORMOBJ::vInit - iXform = %lx\n",iXform);
if (dco.pdc->bDirtyXform()) { // Save current position
if (!dco.pdc->bValidPtlCurrent()) { ASSERTGDI(dco.pdc->bValidPtfxCurrent(), "Both CPs invalid?");
EXFORMOBJ exoDtoW(dco.pdc->mxDeviceToWorld());
if (exoDtoW.bValid()) exoDtoW.bXform(&dco.ptfxCurrent(), &dco.ptlCurrent(), 1);
dco.pdc->vValidatePtlCurrent(); }
// update the transforms
dco.pdc->vUpdateWtoDXform();
// After the transform, the device space CP will be invalid:
dco.pdc->vInvalidatePtfxCurrent();
if( dco.pdc->flXform() & INVALIDATE_ATTRIBUTES) {
EXFORMOBJ exoWtoD(dco.pdc->mxWorldToDevice());
dco.pdc->vRealizeLineAttrs(exoWtoD); dco.pdc->vXformChange(TRUE); dco.pdc->flClr_flXform(INVALIDATE_ATTRIBUTES); }
dco.pdc->flSet_flXform(DEVICE_TO_WORLD_INVALID); }
switch (iXform) { case XFORM_WORLD_TO_DEVICE: pmx = &dco.pdc->mxWorldToDevice(); XFORMPRINT(2,"EXFORM::vInit - WtoD, pmx = %p\n",pmx); break;
case XFORM_DEVICE_TO_WORLD: pmx = &dco.pdc->mxDeviceToWorld();
if (dco.pdc->flXform() & DEVICE_TO_WORLD_INVALID) { if (bInverse(dco.pdc->mxWorldToDevice())) { dco.pdc->flClr_flXform(DEVICE_TO_WORLD_INVALID); RtlCopyMemory( (PVOID)&dco.pdc->mxUserDeviceToWorld(), (PVOID)pmx, sizeof( MATRIX ) );
} else { pmx = (PMATRIX)NULL; } XFORMPRINT(2,"EXFORM::vInit - DtoW was dirty, pmx = %p\n",pmx); } break;
case XFORM_WORLD_TO_PAGE: XFORMPRINT(2,"EXFORM::vInit - WtoP, pmx = %p\n",pmx); pmx = &dco.pdc->mxWorldToPage(); break;
default: XFORMPRINT(2,"EXFORM::vInit - NULL",pmx); pmx = NULL; break; } }
/******************************Public*Routine******************************\
* EXFORMOBJ::vInitPageToDevice() * * History: * 05-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
VOID EXFORMOBJ::vInitPageToDevice( XDCOBJ& dco, PMATRIX pmx_) { pmx = pmx_;
pmx->efM11 = dco.pdc->efM11PtoD(); pmx->efM12.vSetToZero(); pmx->efM21.vSetToZero(); pmx->efM22 = dco.pdc->efM22PtoD(); pmx->efDx = dco.pdc->efDxPtoD(); pmx->efDy = dco.pdc->efDyPtoD(); pmx->efDx.bEfToL(pmx->fxDx); pmx->efDy.bEfToL(pmx->fxDy);
vComputeWtoDAccelFlags(); }
/******************************Private*Routine*****************************\
* vUpdateWtoDXform * * Update the world to device transform. * * History: * * 15-Dec-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
VOID DC::vUpdateWtoDXform() { PMATRIX pmx = &mxWorldToDevice();
if (bDirtyXlateOrExt()) { if (bPageExtentsChanged()) { // Recalculate the scaling factors for the page to device xform.
// M11 = ViewportExt.cx / WindowExt.cx
// M22 = ViewportExt.cy / WindowExt.cy
if (ulMapMode() == MM_ISOTROPIC) vMakeIso();
if ((lWindowExtCx() == lViewportExtCx()) && (lWindowExtCy() == lViewportExtCy())) { efM11PtoD(ef16); efM22PtoD(ef16);
pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_UNITY | XFORM_SCALE;
flSet_flXform(PAGE_TO_DEVICE_SCALE_IDENTITY); } else { EFLOATEXT ef1; EFLOATEXT ef2; ef1 = LTOFX(lViewportExtCx()); ef2 = lWindowExtCx(); ef1 /= ef2; efM11PtoD(ef1);
ef1 = LTOFX(lViewportExtCy()); ef2 = lWindowExtCy(); ef1 /= ef2; efM22PtoD(ef1);
pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE; flClr_flXform(PAGE_TO_DEVICE_SCALE_IDENTITY | PAGE_TO_DEVICE_IDENTITY); }
if (efM11PtoD().bIsNegative()) flSet_flXform(PTOD_EFM11_NEGATIVE); else flClr_flXform(PTOD_EFM11_NEGATIVE);
if (efM22PtoD().bIsNegative()) flSet_flXform(PTOD_EFM22_NEGATIVE); else flClr_flXform(PTOD_EFM22_NEGATIVE); }
// Recalculate the translations for the page to device xform.
// Dx = ViewportOrg.x - (ViewportExt.cx / WindowExt.cx) * WindowOrg.x
// (ViewportExt.cx / WindowExt.cx) = efM11
// Dy = ViewportOrg.y - (ViewportExt.cy / WindowExt.cy) * WindowOrg.cy
// (ViewportExt.cy / WindowExt.cy) = efM22
if ((lWindowOrgX() == 0) && (lWindowOrgY() == 0)) { if ((lViewportOrgX() == 0) && (lViewportOrgY() == 0)) { EFLOAT efZ; efZ.vSetToZero();
efDxPtoD(efZ); efDyPtoD(efZ); pmx->fxDx = 0; pmx->fxDy = 0; pmx->flAccel |= XFORM_NO_TRANSLATION;
if (bPageToDeviceScaleIdentity()) flSet_flXform(PAGE_TO_DEVICE_IDENTITY); } else { efDxPtoD(LTOFX(lViewportOrgX())); efDyPtoD(LTOFX(lViewportOrgY()));
pmx->fxDx = LTOFX(lViewportOrgX()); pmx->fxDy = LTOFX(lViewportOrgY());
pmx->flAccel &= ~XFORM_NO_TRANSLATION; flClr_flXform(PAGE_TO_DEVICE_IDENTITY); } } else { flClr_flXform(PAGE_TO_DEVICE_IDENTITY); pmx->flAccel &= ~XFORM_NO_TRANSLATION; if (bPageToDeviceScaleIdentity()) { efDxPtoD(LTOFX(-lWindowOrgX())); efDyPtoD(LTOFX(-lWindowOrgY()));
if ((lViewportOrgX() != 0) || (lViewportOrgY() != 0)) { goto ADD_VIEWPORT_ORG; }
pmx->fxDx = LTOFX(-lWindowOrgX()); pmx->fxDy = LTOFX(-lWindowOrgY()); } else { { EFLOATEXT ef; ef = -lWindowOrgX(); ef *= efrM11PtoD(); efDxPtoD(ef);
ef = -lWindowOrgY(); ef *= efrM22PtoD(); efDyPtoD(ef); }
if ((lViewportOrgX()!= 0) || (lViewportOrgY() != 0)) { ADD_VIEWPORT_ORG:
EFLOATEXT efXVO(LTOFX(lViewportOrgX())); efXVO += efrDxPtoD(); efDxPtoD(efXVO);
EFLOATEXT efYVO(LTOFX(lViewportOrgY())); efYVO += efrDyPtoD(); efDyPtoD(efYVO); }
efDxPtoD().bEfToL(pmx->fxDx); efDyPtoD().bEfToL(pmx->fxDy); } }
if (bWorldToPageIdentity()) { // Copy the PAGE_TO_DEVICE xform to WORLD_TO_DEVICE.
// pmx->fxDx, fxDy and flAccel has been set earlier in this routine.
pmx->efM11 = efM11PtoD(); pmx->efM22 = efM22PtoD(); pmx->efM12.vSetToZero(); pmx->efM21.vSetToZero(); pmx->efDx = efDxPtoD(); pmx->efDy = efDyPtoD();
if (bPageToDeviceIdentity()) pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION; else if (bPageToDeviceScaleIdentity()) pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE | XFORM_UNITY; else pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE;
flClr_flXform(PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED | WORLD_XFORM_CHANGED);
RtlCopyMemory( (PVOID) &mxUserWorldToDevice(), pmx, sizeof( MATRIX ));
return; } } else { if (bWorldToPageIdentity()) { // World transform has changed to identity.
pmx->efM11 = efM11PtoD(); pmx->efM22 = efM22PtoD(); pmx->efM12.vSetToZero(); pmx->efM21.vSetToZero(); pmx->efDx = efDxPtoD(); pmx->efDy = efDyPtoD();
efDxPtoD().bEfToL(pmx->fxDx); efDyPtoD().bEfToL(pmx->fxDy);
if (bPageToDeviceIdentity()) pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE | XFORM_UNITY | XFORM_NO_TRANSLATION; else if (bPageToDeviceScaleIdentity()) pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE | XFORM_UNITY; else pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE;
flClr_flXform(PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED | WORLD_XFORM_CHANGED);
RtlCopyMemory( (PVOID) &mxUserWorldToDevice(), pmx, sizeof( MATRIX )); return; } }
// Multiply the world to page and page to device xform together.
PMATRIX pmxWtoP = &mxWorldToPage();
if (bPageToDeviceScaleIdentity()) { RtlCopyMemory(pmx, pmxWtoP, offsetof(MATRIX, flAccel)); pmx->efM11.vTimes16(); pmx->efM12.vTimes16(); pmx->efM21.vTimes16(); pmx->efM22.vTimes16(); pmx->efDx.vTimes16(); pmx->efDy.vTimes16(); } else { pmx->efM11.eqMul(pmxWtoP->efM11,efM11PtoD()); pmx->efM21.eqMul(pmxWtoP->efM21,efM11PtoD()); pmx->efM12.eqMul(pmxWtoP->efM12,efM22PtoD()); pmx->efM22.eqMul(pmxWtoP->efM22,efM22PtoD());
pmx->efDx.eqMul(pmxWtoP->efDx,efM11PtoD()); pmx->efDy.eqMul(pmxWtoP->efDy,efM22PtoD()); }
pmx->efDx += efrDxPtoD(); pmx->efDx.bEfToL(pmx->fxDx);
pmx->efDy += efrDyPtoD(); pmx->efDy.bEfToL(pmx->fxDy);
if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero()) { if (pmx->efM11.bIs16() && pmx->efM22.bIs16()) pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE | XFORM_UNITY; else pmx->flAccel = XFORM_FORMAT_LTOFX | XFORM_SCALE; } else { pmx->flAccel = XFORM_FORMAT_LTOFX; }
if ((pmx->fxDx == 0) && (pmx->fxDy == 0)) pmx->flAccel |= XFORM_NO_TRANSLATION;
flClr_flXform(PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED | WORLD_XFORM_CHANGED);
RtlCopyMemory((PVOID)&mxUserWorldToDevice(),pmx,sizeof(MATRIX));
}
/******************************Private*Routine*****************************\
* bWordXformIdentity * * See is a world transform matrix is identity. * * History: * * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Modified for client side use. * * 26-Dec-1990 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL bWorldXformIdentity(CONST XFORML *pxf) { return((pxf->eM11 == IEEE_1_0F) && (pxf->eM12 == IEEE_0_0F) && (pxf->eM21 == IEEE_0_0F) && (pxf->eM22 == IEEE_1_0F) && (pxf->eDx == IEEE_0_0F) && (pxf->eDy == IEEE_0_0F)); }
/******************************Public*Routine******************************\
* NtGdiModifyWorldTransform() * * History: * 01-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiModifyWorldTransform( HDC hdc, LPXFORM pxf, DWORD iXform ) { XFORMPRINT(1,"GreModifyWorldTransform - iXform = %ld\n",iXform);
ASSERTGDI(sizeof(XFORM) == sizeof(XFORML),"sizeof(XFORM) != sizeof(XFORML)\n");
BOOL bRet = FALSE;
DCOBJ dcox(hdc);
if (dcox.bValid()) { XFORML xf;
if (pxf) { bRet = ProbeAndConvertXFORM((XFORML *)pxf, &xf); } else { // must be identity to allow pxf == NULL
bRet = (iXform == MWT_IDENTITY); }
if (bRet) { bRet = dcox.bModifyWorldTransform(&xf,iXform); } }
return(bRet); }
/******************************Public*Routine******************************\
* XDCOBJ::bModifyWorldTransform() * * History: * 07-Dec-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL XDCOBJ::bModifyWorldTransform( CONST XFORML *pxf, ULONG iMode) { BOOL bRet = FALSE; MATRIX mx;
switch (iMode) { case MWT_SET: if (!bWorldXformIdentity(pxf)) { vConvertXformToMatrix(pxf, &mx);
if (bWorldMatrixInRange(&mx)) // check if the new world xform is
{ // within the min, max range.
RtlCopyMemory(&pdc->mxWorldToPage(), &mx, offsetof(MATRIX, flAccel)); RtlCopyMemory(&pdc->mxUserWorldToPage(), &mx, offsetof(MATRIX, flAccel)); pdc->vClrWorldXformIdentity(); bRet = TRUE; } break; } //MWT_IDENTITY must follow MWT_SET. This will fall through if it is identity
case MWT_IDENTITY: if (!pdc->bWorldToPageIdentity()) { RtlCopyMemory(&pdc->mxWorldToPage(), &gmxIdentity_LToL, offsetof(MATRIX, flAccel)); RtlCopyMemory(&pdc->mxUserWorldToPage(), &gmxIdentity_LToL, offsetof(MATRIX, flAccel)); pdc->vSetWorldXformIdentity(); } bRet = TRUE; break;
case MWT_LEFTMULTIPLY: case MWT_RIGHTMULTIPLY: vConvertXformToMatrix(pxf,&mx);
if (!pdc->bWorldToPageIdentity()) { EXFORMOBJ xoWtoP(*this,XFORM_WORLD_TO_PAGE);
if (!xoWtoP.bMultToWorld(&mx, iMode)) break; }
if (!bWorldMatrixInRange(&mx)) // check if the new world xform is
break; // within the min, max range.
RtlCopyMemory( &pdc->mxWorldToPage(), &mx, offsetof(MATRIX, flAccel)); RtlCopyMemory( &pdc->mxUserWorldToPage(), &mx, offsetof(MATRIX, flAccel));
// Check if the resultant matrix is identity.
if (memcmp(&mx, &gmxIdentity_LToL, offsetof(MATRIX, flAccel))) { pdc->vClrWorldXformIdentity(); } else { pdc->vSetWorldXformIdentity(); } bRet = TRUE; break;
default: WARNING("invalid mode passed to GreModifyWorldTransform\n"); break; }
return(bRet); }
/******************************Public*Routine******************************\
* GreCombineTransform * * Concatenate two transforms together by (*pxfSrc1) x (*pxfSrc2). * * History: * * 6-Aug-1992 -by- Gerrit van Wingerden [gerritv] * Modified for client side use. * * 24-Jan-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL GreCombineTransform( XFORML *pxfDst, XFORML *pxfSrc1, XFORML *pxfSrc2) { MATRIX mx1,mx2,mxDst;
vConvertXformToMatrix(pxfSrc1, &mx1); vConvertXformToMatrix(pxfSrc2, &mx2);
EXFORMOBJ xoDst(mxDst);
if (!xoDst.bMultiply(&mx1, &mx2)) return(FALSE);
xoDst.flAccel(XFORM_FORMAT_LTOL);
xoDst.vGetCoefficient(pxfDst); return(TRUE); }
/******************************Public*Routine******************************\
* NtGdiUpdateTransform * * This routine flushes the current transform * * History: * 7/2/98 -by- Lingyun Wang [lingyunw] \**************************************************************************/
BOOL NtGdiUpdateTransform(HDC hdc) { BOOL bRet = TRUE;
// update the transforms
XDCOBJ dco(hdc);
if (dco.bValid()) { dco.pdc->vUpdateWtoDXform();
dco.vUnlock(); } else { bRet = FALSE; }
return (bRet);
}
|