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.
4410 lines
132 KiB
4410 lines
132 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: print.cxx
|
|
*
|
|
* Printer support routines.
|
|
*
|
|
* Copyright (c) 1991-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern "C"
|
|
{
|
|
#include <gl\gl.h>
|
|
#include <gldrv.h>
|
|
#include <dciddi.h>
|
|
};
|
|
|
|
extern "C"
|
|
{
|
|
extern HFASTMUTEX ghfmMemory;
|
|
}
|
|
|
|
#define TYPE1_KEY L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Type 1 Fonts"
|
|
|
|
PTYPEONEINFO gpTypeOneInfo = NULL;
|
|
PTYPEONEINFO GetTypeOneFontList();
|
|
BOOL GetFontPathName( WCHAR *pFullPath, WCHAR *pFileName );
|
|
|
|
extern "C" ULONG ComputeFileviewCheckSum(PVOID, ULONG);
|
|
extern "C" void vUnmapRemoteFonts(FONTFILEVIEW *pFontFileView);
|
|
|
|
extern PW32PROCESS gpidSpool;
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DoFontManagement *
|
|
* *
|
|
* Gives us access to the driver entry point DrvFontManagement. This is *
|
|
* very much an Escape function, except that it needs a font realization. *
|
|
* *
|
|
* Fri 07-May-1993 14:56:12 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
ULONG DoFontManagement(
|
|
DCOBJ &dco,
|
|
ULONG iMode,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut
|
|
)
|
|
{
|
|
ULONG ulRet = 0;
|
|
PVOID pvExtra = NULL;
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
|
|
PFN_DrvFontManagement pfnF = PPFNDRV(pdo,FontManagement);
|
|
|
|
if (pfnF == (PFN_DrvFontManagement) NULL)
|
|
return(ulRet);
|
|
|
|
|
|
if (iMode == QUERYESCSUPPORT)
|
|
{
|
|
// Pass it to the device.
|
|
|
|
return ((*pfnF)
|
|
(
|
|
pdo.bUMPD() ? (SURFOBJ *)pdo.dhpdev() : NULL, //overload pso with dhpdev for UMPD
|
|
NULL,
|
|
iMode,
|
|
cjIn,
|
|
pvIn,
|
|
0,
|
|
NULL
|
|
));
|
|
|
|
}
|
|
|
|
RFONTOBJ rfo(dco,FALSE);
|
|
|
|
if (!rfo.bValid())
|
|
{
|
|
WARNING("gdisrv!DoFontManagement(): could not lock HRFONT\n");
|
|
return(ulRet);
|
|
}
|
|
|
|
// See if we need some extra RAM and translation work.
|
|
|
|
if (iMode == DOWNLOADFACE)
|
|
{
|
|
// How many 16 bit values are there now?
|
|
|
|
int cWords = (int)cjIn / sizeof(WCHAR);
|
|
|
|
// Try to get a buffer of 32 bit entries, since HGLYPHs are bigger.
|
|
|
|
pvExtra = (BALLOC_OVERFLOW1(cWords,HGLYPH)) ? NULL
|
|
: PALLOCMEM(cWords * sizeof(HGLYPH),'mfdG');
|
|
|
|
if (pvExtra == NULL)
|
|
return(ulRet);
|
|
|
|
// Translate the UNICODE to HGYLPHs.
|
|
|
|
if (cWords > 1)
|
|
{
|
|
rfo.vXlatGlyphArray
|
|
(
|
|
((WCHAR *) pvIn) + 1,
|
|
(UINT) (cWords-1),
|
|
((HGLYPH *) pvExtra) + 1
|
|
);
|
|
}
|
|
|
|
// Copy the control word from the app over.
|
|
|
|
*(HGLYPH *) pvExtra = *(WORD *) pvIn;
|
|
|
|
// Adjust the pvIn and cjIn.
|
|
|
|
pvIn = pvExtra;
|
|
cjIn = cWords * sizeof(HGLYPH);
|
|
}
|
|
|
|
|
|
// It is unfortunate that apps call some printing escapes before
|
|
// doing a StartDoc, so there is no real surface in the DC.
|
|
// We fake up a rather poor one here if we need it. The device
|
|
// driver may only dereference the dhpdev from this!
|
|
|
|
SURFOBJ soFake;
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
if (pso == (SURFOBJ *) NULL)
|
|
{
|
|
RtlFillMemory((BYTE *) &soFake,sizeof(SURFOBJ),0);
|
|
soFake.dhpdev = dco.dhpdev();
|
|
soFake.hdev = dco.hdev();
|
|
soFake.iType = (USHORT)STYPE_DEVICE;
|
|
pso = &soFake;
|
|
}
|
|
|
|
// Pass it to the device.
|
|
|
|
ulRet = (*pfnF)
|
|
(
|
|
pso,
|
|
rfo.pfo(),
|
|
iMode,
|
|
cjIn,
|
|
pvIn,
|
|
cjOut,
|
|
pvOut
|
|
);
|
|
|
|
// Free any extra RAM.
|
|
|
|
if (pvExtra != NULL)
|
|
{
|
|
VFREEMEM(pvExtra);
|
|
}
|
|
return(ulRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LockMcdHdrSurfaces
|
|
*
|
|
* Locks kernel-mode handles for DirectDraw surfaces described in the
|
|
* given header.
|
|
*
|
|
* History:
|
|
* Fri Sep 20 14:18:31 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL LockMcdHdrSurfaces(MCDESC_HEADER *pmeh,
|
|
PDD_SURFACE_LOCAL *ppslColor,
|
|
PDD_SURFACE_LOCAL *ppslDepth)
|
|
{
|
|
PDD_SURFACE_LOCAL psl;
|
|
PDD_SURFACE_GLOBAL psg;
|
|
|
|
*ppslColor = *ppslDepth = NULL;
|
|
|
|
if (pmeh->msrfColor.hSurf != NULL)
|
|
{
|
|
*ppslColor = psl = EngLockDirectDrawSurface(pmeh->msrfColor.hSurf);
|
|
if (psl == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
psg = psl->lpGbl;
|
|
|
|
// Update information with trusted values
|
|
pmeh->msrfColor.hSurf = (HANDLE)psl;
|
|
pmeh->msrfColor.lOffset = (ULONG)psg->fpVidMem;
|
|
pmeh->msrfColor.lStride = psg->lPitch;
|
|
pmeh->msrfColor.rclPos.left = psg->xHint;
|
|
pmeh->msrfColor.rclPos.top = psg->yHint;
|
|
pmeh->msrfColor.rclPos.right = psg->xHint+psg->wWidth;
|
|
pmeh->msrfColor.rclPos.bottom = psg->yHint+psg->wHeight;
|
|
}
|
|
|
|
if (pmeh->msrfDepth.hSurf != NULL)
|
|
{
|
|
*ppslDepth = psl = EngLockDirectDrawSurface(pmeh->msrfDepth.hSurf);
|
|
if (psl == NULL)
|
|
{
|
|
if (*ppslColor)
|
|
{
|
|
EngUnlockDirectDrawSurface(*ppslColor);
|
|
*ppslColor = NULL;
|
|
}
|
|
return FALSE;
|
|
}
|
|
psg = psl->lpGbl;
|
|
|
|
// Update information with trusted values
|
|
pmeh->msrfDepth.hSurf = (HANDLE)psl;
|
|
pmeh->msrfDepth.lOffset = (ULONG)psg->fpVidMem;
|
|
pmeh->msrfDepth.lStride = psg->lPitch;
|
|
pmeh->msrfDepth.rclPos.left = psg->xHint;
|
|
pmeh->msrfDepth.rclPos.top = psg->yHint;
|
|
pmeh->msrfDepth.rclPos.right = psg->xHint+psg->wWidth;
|
|
pmeh->msrfDepth.rclPos.bottom = psg->yHint+psg->wHeight;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iMcdSetupExtEscape
|
|
*
|
|
* MCD CreateContext ExtEscape. This special escape allows WNDOBJ to be
|
|
* created in DrvEscape. This is one of the three places where WNDOBJ can
|
|
* be created (the other two are iWndObjSetupExtEscape and DrvSetPixelFormat).
|
|
*
|
|
* See also iWndObjSetupExtEscape().
|
|
*
|
|
* History:
|
|
* Tue Jun 21 17:24:12 1994 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int iMcdSetupExtEscape(
|
|
DCOBJ &dco, // DC user object
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn
|
|
PVOID pvIn, // Points to the input structure required
|
|
int cjOut, // Number of bytes of data pointed to by pvOut
|
|
PVOID pvOut // Points to the output structure
|
|
)
|
|
{
|
|
KFLOATING_SAVE fsFpState;
|
|
MCDESC_HEADER *pmeh = (MCDESC_HEADER *)pvIn;
|
|
MCDESC_HEADER_NTPRIVATE *pmehPriv =
|
|
(MCDESC_HEADER_NTPRIVATE *)((PBYTE)pvIn + sizeof(MCDESC_HEADER));
|
|
|
|
// This command may not be in shared memory. Also, make sure
|
|
// we have entire command structure.
|
|
|
|
if ((!pmehPriv->pBuffer) ||
|
|
(pmehPriv->bufferSize < sizeof(MCDESC_CREATE_CONTEXT)))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
MCDESC_CREATE_CONTEXT *pmccCreate =
|
|
(MCDESC_CREATE_CONTEXT *)(pmehPriv->pBuffer);
|
|
|
|
ASSERTGDI(nEscape == MCDFUNCS,
|
|
"iMcdSetupExtEscape(): not a CreateContext escape\n");
|
|
|
|
// Validate DC surface. Info DC is not allowed.
|
|
|
|
if (!dco.bHasSurface())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(0);
|
|
}
|
|
|
|
// Make sure that we don't have devlock before entering user critical section.
|
|
// Otherwise, it can cause deadlock.
|
|
|
|
if (dco.bDisplay())
|
|
{
|
|
ASSERTGDI(dco.dctp() == DCTYPE_DIRECT,"ERROR it has to be direct");
|
|
CHECKDEVLOCKOUT(dco);
|
|
}
|
|
|
|
// Enter user critical section.
|
|
|
|
USERCRIT usercrit;
|
|
|
|
// Grab the devlock.
|
|
// We don't need to validate the devlock since we do not care if it is full screen.
|
|
|
|
DEVLOCKOBJ dlo(dco);
|
|
|
|
// Redirection DCs should not support escapes. This is actually a tricky
|
|
// case because the dc is DCTYPE_DIRECT but the redirection surface may
|
|
// not be owned by the driver (and in fact the driver may crash if we
|
|
// pass it a redirection surface). So it's best to quit here.
|
|
|
|
if (dco.pdc->bRedirection())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// Assume no WNDOBJ on this call
|
|
|
|
pmehPriv->pwo = (WNDOBJ *)NULL;
|
|
|
|
HWND hwnd = NULL;
|
|
|
|
PEWNDOBJ pwo = NULL;
|
|
|
|
if (pmccCreate->flags & MCDESC_SURFACE_HWND)
|
|
{
|
|
// If it is a display DC, get the hwnd that the hdc is associated with.
|
|
// If it is a printer or memory DC, hwnd is NULL.
|
|
|
|
if (dco.bDisplay() && dco.dctp() == DCTYPE_DIRECT)
|
|
{
|
|
ASSERTGDI(dco.dctp() == DCTYPE_DIRECT,"ERROR it has to be direct really");
|
|
|
|
if (!UserGetHwnd(dco.hdc(), &hwnd, (PVOID *) &pwo, FALSE))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_WINDOW_STYLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pwo)
|
|
{
|
|
// If the WNDOBJ is owned by a different surface (as can happen with
|
|
// dynamic mode changes, where the old driver instance lives as long
|
|
// as the WNDOBJ is alive), simply fail the call.
|
|
|
|
if (pwo->pto->pSurface != dco.pSurface())
|
|
{
|
|
#ifdef OPENGL_MM
|
|
// Under multi-mon the DCOBJ may have the meta-surface while
|
|
// the pto was created with the actual hardware surface.
|
|
// So if the parent hdev of hdev in WNDOBJ is same as hdev in
|
|
// DCOBJ, we will allow to continue since we have replaced
|
|
// meta-PDEV with hardware PDEV. so it's fine.
|
|
|
|
PDEVOBJ pdoOfPwo(pwo->pto->pSurface->hdev());
|
|
|
|
if (pdoOfPwo.hdevParent() != dco.hdev())
|
|
{
|
|
WARNING("iMcdSetupExtEscape: pwo->pto->pSurface != dco.pSurface, so bailing out\n");
|
|
return(FALSE);
|
|
}
|
|
#else
|
|
return(FALSE);
|
|
#endif // OPENGL_MM
|
|
}
|
|
|
|
if (!(pwo->fl & WO_GENERIC_WNDOBJ))
|
|
pmehPriv->pwo = (WNDOBJ *)pwo;
|
|
}
|
|
}
|
|
|
|
// Make sure that DC hwnd matches MCDESC_CREATE_CONTEXT hwnd.
|
|
|
|
if (hwnd != pmccCreate->hwnd)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
// Dispatch the call.
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
#ifdef OPENGL_MM
|
|
|
|
if (pdo.bMetaDriver())
|
|
{
|
|
// We need to change the meta-PDEV into a hardware specific PDEV
|
|
|
|
HDEV hdevDevice = hdevFindDeviceHdev(
|
|
dco.hdev(), (RECTL)dco.erclWindow(), pwo);
|
|
|
|
if (hdevDevice)
|
|
{
|
|
// If the surface is pdev's primary surface, we will replace it with
|
|
// new device pdev's surface.
|
|
|
|
if (pdo.bPrimary(dco.pSurface()))
|
|
{
|
|
PDEVOBJ pdoDevice(hdevDevice);
|
|
|
|
pso = pdoDevice.pSurface()->pSurfobj();
|
|
}
|
|
|
|
// replace meta pdevobj with device specific hdev.
|
|
|
|
pdo.vInit(hdevDevice);
|
|
}
|
|
}
|
|
|
|
#endif // OPENGL_MM
|
|
|
|
if ( !PPFNDRV( pdo, Escape ))
|
|
return(0);
|
|
|
|
// Handle any surfaces
|
|
|
|
// This escape doesn't expect any extra locks
|
|
ASSERTGDI((pmeh->flags & MCDESC_FL_LOCK_SURFACES) == 0,
|
|
"iMcdSetupExtEscape: MCDESC_FL_LOCK_SURFACES set\n");
|
|
|
|
PDD_SURFACE_LOCAL psl[2] = { NULL, NULL };
|
|
|
|
if (pmeh->flags & MCDESC_FL_SURFACES)
|
|
{
|
|
if (!LockMcdHdrSurfaces(pmeh, &psl[0], &psl[1]))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Save floating point state
|
|
// This allows client drivers to do floating point operations
|
|
// If the state were not preserved then we would be corrupting the
|
|
// thread's user-mode FP state
|
|
|
|
int iRet;
|
|
|
|
if (!NT_SUCCESS(KeSaveFloatingPointState(&fsFpState)))
|
|
{
|
|
WARNING("iMcdSetupExtEscape: Unable to save FP state\n");
|
|
iRet = 0;
|
|
goto iMcdSetupExtEscape_Unlock_And_Exit;
|
|
}
|
|
|
|
iRet = (int) pdo.Escape(pso,
|
|
(ULONG)nEscape,
|
|
(ULONG)cjIn,
|
|
pvIn,
|
|
(ULONG)cjOut,
|
|
pvOut);
|
|
|
|
// Restore floating point state
|
|
|
|
KeRestoreFloatingPointState(&fsFpState);
|
|
|
|
// If a new WNDOBJ is created, we need to update the window client regions
|
|
// in the driver.
|
|
|
|
if (gbWndobjUpdate)
|
|
{
|
|
gbWndobjUpdate = FALSE;
|
|
vForceClientRgnUpdate();
|
|
}
|
|
|
|
iMcdSetupExtEscape_Unlock_And_Exit:
|
|
|
|
if (pmeh->flags & MCDESC_FL_SURFACES)
|
|
{
|
|
if (psl[0])
|
|
{
|
|
EngUnlockDirectDrawSurface(psl[0]);
|
|
}
|
|
|
|
if (psl[1])
|
|
{
|
|
EngUnlockDirectDrawSurface(psl[1]);
|
|
}
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iWndObjSetupExtEscape
|
|
*
|
|
* Live video ExtEscape. This special escape allows WNDOBJ to be created
|
|
* in DrvEscape. This is one of the three places where WNDOBJ can be created
|
|
* (the other two are iMcdSetupExtEscape and DrvSetPixelFormat).
|
|
*
|
|
* See also iMcdSetupExtEscape().
|
|
*
|
|
* History:
|
|
* Fri Feb 18 13:25:13 1994 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int iWndObjSetupExtEscape
|
|
(
|
|
DCOBJ &dco, // DC user object
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn
|
|
PVOID pvIn, // Points to the input structure required
|
|
int cjOut, // Number of bytes of data pointed to by pvOut
|
|
PVOID pvOut // Points to the output structure
|
|
)
|
|
{
|
|
ASSERTGDI(nEscape == WNDOBJ_SETUP,
|
|
"iWndObjSetupExtEscape(): not a WndObjSetup escape\n");
|
|
|
|
// Validate DC surface. Info DC is not allowed.
|
|
|
|
if (!dco.bHasSurface())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(0);
|
|
}
|
|
|
|
// Make sure that we don't have devlock before entering user critical section.
|
|
// Otherwise, it can cause deadlock.
|
|
|
|
if (dco.bDisplay())
|
|
{
|
|
ASSERTGDI(dco.dctp() == DCTYPE_DIRECT,"ERROR it has to be direct");
|
|
CHECKDEVLOCKOUT(dco);
|
|
}
|
|
|
|
// Enter user critical section.
|
|
|
|
USERCRIT usercrit;
|
|
|
|
// Grab the devlock.
|
|
// We don't need to validate the devlock since we do not care if it is full screen.
|
|
|
|
DEVLOCKOBJ dlo(dco);
|
|
|
|
// Redirection DCs should not support escapes. This is actually a tricky
|
|
// case because the dc is DCTYPE_DIRECT but the redirection surface may
|
|
// not be owned by the driver (and in fact the driver may crash if we
|
|
// pass it a redirection surface). So it's best to quit here.
|
|
|
|
if (dco.pdc->bRedirection())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
// Dispatch the call.
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
#ifdef OPENGL_MM
|
|
|
|
if (pdo.bMetaDriver())
|
|
{
|
|
// We need to change the meta-PDEV into a hardware specific PDEV
|
|
|
|
HDEV hdevDevice = hdevFindDeviceHdev(
|
|
dco.hdev(), (RECTL)dco.erclWindow(), NULL);
|
|
|
|
if (hdevDevice)
|
|
{
|
|
// If the surface is pdev's primary surface, we will replace it with
|
|
// new device pdev's surface.
|
|
|
|
if (pdo.bPrimary(dco.pSurface()))
|
|
{
|
|
PDEVOBJ pdoDevice(hdevDevice);
|
|
|
|
pso = pdoDevice.pSurface()->pSurfobj();
|
|
}
|
|
|
|
// replace meta pdevobj with device specific hdev.
|
|
|
|
pdo.vInit(hdevDevice);
|
|
}
|
|
}
|
|
|
|
#endif // OPENGL_MM
|
|
|
|
if ( !PPFNDRV( pdo, Escape ))
|
|
return(0);
|
|
|
|
int iRet = (int) pdo.Escape(pso,
|
|
(ULONG)nEscape,
|
|
(ULONG)cjIn,
|
|
pvIn,
|
|
(ULONG)cjOut,
|
|
pvOut);
|
|
|
|
// If a new WNDOBJ is created, we need to update the window client regions
|
|
// in the driver.
|
|
|
|
if (gbWndobjUpdate)
|
|
{
|
|
gbWndobjUpdate = FALSE;
|
|
vForceClientRgnUpdate();
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LookUpWndobjs
|
|
*
|
|
* Looks up WNDOBJs for a list of HDCs. Only performs lookups for
|
|
* HDCs which are for the same device as that given. Returns negative
|
|
* if error, otherwise it returns a bitmask of the HDCs
|
|
* that had a lookup.
|
|
*
|
|
* Fills in DCOBJ table with locked DCs for tested HDCs.
|
|
* Overwrites HDC table with WNDOBJ pointers.
|
|
*
|
|
* History:
|
|
* Mon Oct 14 16:48:13 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int LookUpWndobjs(DCOBJ *pdcoMatch, DCOBJ *pdcoFill, HDC *phdc, int n)
|
|
{
|
|
int iMask;
|
|
HDEV hdevMatch;
|
|
int i;
|
|
|
|
CHECKUSERCRITIN;
|
|
|
|
hdevMatch = pdcoMatch->hdev();
|
|
iMask = 0;
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
pdcoFill->vLock(*phdc);
|
|
if (!pdcoFill->bValid())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (pdcoFill->hdev() != hdevMatch)
|
|
{
|
|
pdcoFill->vUnlock();
|
|
*phdc = NULL;
|
|
}
|
|
else
|
|
{
|
|
HWND hwnd;
|
|
|
|
if (!UserGetHwnd(*phdc, &hwnd, (PVOID *)phdc, FALSE))
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
iMask |= 1 << i;
|
|
}
|
|
}
|
|
|
|
phdc++;
|
|
pdcoFill++;
|
|
}
|
|
|
|
return iMask;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iMcdExtEscape
|
|
*
|
|
* Take the MCD special case ExtEscape out of line to minimize the
|
|
* impact on other ExtEscapes. We need to stick special data into the
|
|
* input buffer. No CLIPOBJ is given to the driver here.
|
|
*
|
|
* History:
|
|
* Tue Jun 21 17:24:12 1994 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int iMcdExtEscape(
|
|
DCOBJ &dco, // DC user object
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn
|
|
PVOID pvIn, // Points to the input structure required
|
|
int cjOut, // Number of bytes of data pointed to by pvOut
|
|
PVOID pvOut // Points to the output structure
|
|
)
|
|
{
|
|
BOOL bSaveSwapEnable;
|
|
KFLOATING_SAVE fsFpState;
|
|
ULONG i;
|
|
int iRet = 0;
|
|
int iMultiMask;
|
|
DCOBJ dcoMulti[MCDESC_MAX_EXTRA_WNDOBJ];
|
|
|
|
ASSERTGDI(nEscape == MCDFUNCS, "iMcdExtEscape(): not an MCD escape\n");
|
|
|
|
// Validate DC surface. Info DC is not allowed.
|
|
|
|
if (!dco.bHasSurface())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return iRet;
|
|
}
|
|
|
|
// Special processing for 3D-DDI escape.
|
|
//
|
|
// The escape requires that the server fill in the pwo engine object pointer
|
|
// before it is passed to the display driver. The client side simply
|
|
// doesn't have a clue what this might be.
|
|
// CAUTION: These object are defined here so that they will live long enough
|
|
// to be valid when control is passed to the driver!
|
|
|
|
// Grab the devlock and lock down wndobj.
|
|
|
|
DEVLOCKOBJ_WNDOBJ dlo(dco);
|
|
|
|
// Redirection DCs should not support escapes. This is actually a tricky
|
|
// case because the dc is DCTYPE_DIRECT but the redirection surface may
|
|
// not be owned by the driver (and in fact the driver may crash if we
|
|
// pass it a redirection surface). So it's best to quit here.
|
|
|
|
if (dco.pdc->bRedirection())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
if (!dlo.bValidDevlock())
|
|
{
|
|
if (!dco.bFullScreen())
|
|
{
|
|
WARNING("iMcdExtEscape(): devlock failed\n");
|
|
return iRet;
|
|
}
|
|
}
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
#ifdef OPENGL_MM
|
|
|
|
if (pdo.bMetaDriver())
|
|
{
|
|
// We need to change the meta-PDEV into a hardware specific PDEV
|
|
|
|
HDEV hdevDevice = hdevFindDeviceHdev(
|
|
dco.hdev(),
|
|
(RECTL)dco.erclWindow(),
|
|
(dlo.bValidWndobj() ? dlo.pwo() : NULL));
|
|
|
|
if (hdevDevice)
|
|
{
|
|
// If the surface is pdev's primary surface, we will replace it with
|
|
// new device pdev's surface.
|
|
|
|
if (pdo.bPrimary(dco.pSurface()))
|
|
{
|
|
PDEVOBJ pdoDevice(hdevDevice);
|
|
|
|
pso = pdoDevice.pSurface()->pSurfobj();
|
|
}
|
|
|
|
// replace meta pdevobj with device specific hdev.
|
|
|
|
pdo.vInit(hdevDevice);
|
|
}
|
|
}
|
|
|
|
#endif // OPENGL_MM
|
|
|
|
// Locate the driver entry point.
|
|
|
|
if ( !PPFNDRV( pdo, Escape ))
|
|
return( iRet );
|
|
|
|
if (pdo.bUMPD())
|
|
return (iRet);
|
|
|
|
// If surfaces are passed through the MCDESC_HEADER then lock them
|
|
MCDESC_HEADER *pmeh = (MCDESC_HEADER *)pvIn;
|
|
MCDESC_HEADER_NTPRIVATE *pmehPriv = (MCDESC_HEADER_NTPRIVATE *)(pmeh+1);
|
|
|
|
PDD_SURFACE_LOCAL psl[2+MCDESC_MAX_LOCK_SURFACES];
|
|
RtlZeroMemory(psl, (2+MCDESC_MAX_LOCK_SURFACES) * sizeof(PDD_SURFACE_LOCAL));
|
|
|
|
// First lock standard surfaces
|
|
if (pmeh->flags & MCDESC_FL_SURFACES)
|
|
{
|
|
if (!LockMcdHdrSurfaces(pmeh, &psl[0], &psl[1]))
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
|
|
// Now check for extra surfaces
|
|
if (pmeh->flags & MCDESC_FL_LOCK_SURFACES)
|
|
{
|
|
HANDLE *phSurf;
|
|
|
|
phSurf = pmehPriv->pLockSurfaces;
|
|
for (i = 0; i < pmeh->cLockSurfaces; i++)
|
|
{
|
|
if ((psl[i+2] = EngLockDirectDrawSurface(*phSurf++)) == NULL)
|
|
{
|
|
goto iMcdExtEscape_Unlock_And_Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Look up any extra WNDOBJs that need to be looked up
|
|
if (pmeh->flags & MCDESC_FL_EXTRA_WNDOBJ)
|
|
{
|
|
iMultiMask = LookUpWndobjs(&dco, dcoMulti, pmehPriv->pExtraWndobj,
|
|
pmeh->cExtraWndobj);
|
|
if (iMultiMask < 0)
|
|
{
|
|
goto iMcdExtEscape_Unlock_And_Exit;
|
|
}
|
|
}
|
|
|
|
// Grow the kernel stack so that OpenGL drivers can use more
|
|
// stack than is provided by default. The call attempts to
|
|
// grow the stack to the maximum possible size
|
|
// The stack will shrink back automatically so there's no cleanup
|
|
// necessary
|
|
|
|
if (!NT_SUCCESS(MmGrowKernelStack((BYTE *)PsGetCurrentThreadStackBase()-
|
|
KERNEL_LARGE_STACK_SIZE+
|
|
KERNEL_LARGE_STACK_COMMIT)))
|
|
{
|
|
WARNING("iMcdExtEscape: Unable to grow stack\n");
|
|
|
|
goto iMcdExtEscape_Unlock_And_Exit;
|
|
}
|
|
|
|
// Ensure that the stack does not shrink back until we release it.
|
|
|
|
bSaveSwapEnable = KeSetKernelStackSwapEnable(FALSE);
|
|
|
|
// We need to get the WNDOBJ for the driver. Note that we pass calls
|
|
// through to the driver even if we don't yet have a WNDOBJ to allow
|
|
// query functions to succeed (before context-creation). Cursor exclusion
|
|
// is not performed in this case, since no drawing is done.
|
|
|
|
{
|
|
DEVEXCLUDEWNDOBJ dxoWnd;
|
|
|
|
if (dlo.bValidWndobj())
|
|
{
|
|
// Put the DDI pwo pointer in the input buffer.
|
|
|
|
PEWNDOBJ pwo;
|
|
|
|
pwo = dlo.pwo();
|
|
|
|
// If the WNDOBJ is owned by a different surface (as can happen with
|
|
// dynamic mode changes, where the old driver instance lives as long
|
|
// as the WNDOBJ is alive), simply fail the call.
|
|
|
|
if (pwo->pto->pSurface != dco.pSurface())
|
|
{
|
|
#ifdef OPENGL_MM
|
|
// Under multi-mon the DCOBJ may have the meta-surface while
|
|
// the pto was created with the actual hardware surface.
|
|
// So if the parent hdev of hdev in WNDOBJ is same as hdev in
|
|
// DCOBJ, we will allow to continue since we have replaced
|
|
// meta-PDEV with hardware PDEV. so it's fine.
|
|
|
|
PDEVOBJ pdoOfPwo(pwo->pto->pSurface->hdev());
|
|
|
|
if (pdoOfPwo.hdevParent() != dco.hdev())
|
|
{
|
|
WARNING("iMcdExtEscape: pwo->pto->pSurface != dco.pSurface, so bailing out\n");
|
|
goto iMcdExtEscape_RestoreSwap;
|
|
}
|
|
#else
|
|
goto iMcdExtEscape_RestoreSwap;
|
|
#endif // OPENGL_MM
|
|
}
|
|
|
|
if (pwo->fl & WO_GENERIC_WNDOBJ)
|
|
pwo = (PEWNDOBJ) NULL;
|
|
|
|
pmehPriv->pwo = (WNDOBJ *) pwo;
|
|
|
|
// Cursor exclusion.
|
|
// Note that we do not early out for empty clip rectangle.
|
|
|
|
if (pwo)
|
|
{
|
|
dxoWnd.vExclude(pwo);
|
|
INC_SURF_UNIQ(dco.pSurface());
|
|
}
|
|
}
|
|
else
|
|
pmehPriv->pwo = (WNDOBJ *) NULL;
|
|
}
|
|
|
|
// Save floating point state
|
|
// This allows client drivers to do floating point operations
|
|
// If the state were not preserved then we would be corrupting the
|
|
// thread's user-mode FP state
|
|
|
|
if (!NT_SUCCESS(KeSaveFloatingPointState(&fsFpState)))
|
|
{
|
|
WARNING("iMcdExtEscape: Unable to save FP state\n");
|
|
goto iMcdExtEscape_RestoreSwap;
|
|
}
|
|
|
|
// Call the driver escape.
|
|
|
|
iRet = (int) pdo.Escape(pso,
|
|
(ULONG)nEscape,
|
|
(ULONG)cjIn,
|
|
pvIn,
|
|
(ULONG)cjOut,
|
|
pvOut);
|
|
|
|
if (pmeh->flags & MCDESC_FL_EXTRA_WNDOBJ)
|
|
{
|
|
iRet = (iRet & (0xffffffff >> MCDESC_MAX_EXTRA_WNDOBJ)) |
|
|
(iMultiMask << (32-MCDESC_MAX_EXTRA_WNDOBJ));
|
|
}
|
|
|
|
// Restore floating point state and stack swap enable state
|
|
|
|
KeRestoreFloatingPointState(&fsFpState);
|
|
|
|
iMcdExtEscape_RestoreSwap:
|
|
|
|
KeSetKernelStackSwapEnable((BOOLEAN)bSaveSwapEnable);
|
|
|
|
iMcdExtEscape_Unlock_And_Exit:
|
|
|
|
if (pmeh->flags & MCDESC_FL_SURFACES)
|
|
{
|
|
if (psl[0])
|
|
{
|
|
EngUnlockDirectDrawSurface(psl[0]);
|
|
}
|
|
|
|
if (psl[1])
|
|
{
|
|
EngUnlockDirectDrawSurface(psl[1]);
|
|
}
|
|
}
|
|
|
|
if (pmeh->flags & MCDESC_FL_LOCK_SURFACES)
|
|
{
|
|
for (i = 0; i < pmeh->cLockSurfaces; i++)
|
|
{
|
|
if (psl[i+2])
|
|
{
|
|
EngUnlockDirectDrawSurface(psl[i+2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iOpenGLExtEscape
|
|
*
|
|
* Take the OpenGL special case ExtEscape out of line to minimize the
|
|
* impact on non-OpenGL ExtEscapes. We need to stick special data into the
|
|
* input buffer. No CLIPOBJ is given to the driver here.
|
|
*
|
|
* History:
|
|
* 20-Jan-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int iOpenGLExtEscape(
|
|
DCOBJ &dco, // DC user object
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn
|
|
PVOID pvIn, // Points to the input structure required
|
|
int cjOut, // Number of bytes of data pointed to by pvOut
|
|
PVOID pvOut // Points to the output structure
|
|
)
|
|
{
|
|
BOOL bSaveSwapEnable;
|
|
KFLOATING_SAVE fsFpState;
|
|
int iRet = 0;
|
|
int iMultiMask;
|
|
DCOBJ dcoMulti[OPENGLCMD_MAXMULTI];
|
|
|
|
ASSERTGDI(
|
|
(nEscape == OPENGL_CMD) || (nEscape == OPENGL_GETINFO),
|
|
"iOpenGLExtEscape(): not an OpenGL escape\n");
|
|
|
|
// Validate DC surface. Info DC is not allowed.
|
|
|
|
if (!dco.bHasSurface())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(0);
|
|
}
|
|
|
|
// Special processing for OPENGL_CMD escape.
|
|
//
|
|
// The OPENGL_CMD escape may require that the server fill in the pxo and
|
|
// pwo engine object pointers before it is passed to the display driver.
|
|
// The client side simply doesn't have a clue what these might be.
|
|
// CAUTION: These object are defined here so that they will live long enough
|
|
// to be valid when control is passed to the driver!
|
|
|
|
EXLATEOBJ xlo;
|
|
XLATEOBJ *pxlo = (XLATEOBJ *) NULL;
|
|
|
|
PDEVOBJ po(dco.hdev());
|
|
ASSERTGDI(po.bValid(), "iOpenGLExtEscape(): bad hdev in DC\n");
|
|
|
|
// Grab the devlock and user crit section
|
|
|
|
DEVLOCKOBJ_WNDOBJ dlo(dco);
|
|
|
|
// Redirection DCs should not support escapes. This is actually a tricky
|
|
// case because the dc is DCTYPE_DIRECT but the redirection surface may
|
|
// not be owned by the driver (and in fact the driver may crash if we
|
|
// pass it a redirection surface). So it's best to quit here.
|
|
|
|
if (dco.pdc->bRedirection())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
if (!dlo.bValidDevlock())
|
|
{
|
|
if (!dco.bFullScreen())
|
|
{
|
|
WARNING("iOpenGLExtEscape(): devlock failed\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Find a target surface, if DDML.
|
|
|
|
PSURFACE pSurface = dco.pSurfaceEff();
|
|
|
|
#ifdef OPENGL_MM
|
|
|
|
if (po.bMetaDriver())
|
|
{
|
|
// We need to change the meta-PDEV into a hardware specific PDEV
|
|
|
|
HDEV hdevDevice = hdevFindDeviceHdev(
|
|
dco.hdev(),
|
|
(RECTL)dco.erclWindow(),
|
|
(dlo.bValidWndobj() ? dlo.pwo() : NULL));
|
|
|
|
if (hdevDevice)
|
|
{
|
|
// If the surface is pdev's primary surface, we will replace it with
|
|
// new device pdev's surface.
|
|
|
|
if (po.bPrimary(dco.pSurface()))
|
|
{
|
|
PDEVOBJ poDevice(hdevDevice);
|
|
|
|
pSurface = poDevice.pSurface();
|
|
}
|
|
|
|
// replace meta pdevobj with device specific hdev.
|
|
|
|
po.vInit(hdevDevice);
|
|
}
|
|
}
|
|
|
|
#endif // OPENGL_MM
|
|
|
|
SURFOBJ *pso = pSurface->pSurfobj();
|
|
|
|
// Locate the driver entry point.
|
|
|
|
if (!PPFNDRV(po, Escape))
|
|
return(0);
|
|
|
|
if (po.bUMPD())
|
|
return (0);
|
|
|
|
// Create a sprite exclusion object. Actual exclusion is performed elsewhere
|
|
// as needed.
|
|
|
|
DEVEXCLUDEWNDOBJ dxoWnd;
|
|
DEVEXCLUDERECT dxoRect;
|
|
|
|
// Grow the kernel stack so that OpenGL drivers can use more
|
|
// stack than is provided by default. The call attempts to
|
|
// grow the stack to the maximum possible size
|
|
// The stack will shrink back automatically so there's no cleanup
|
|
// necessary
|
|
|
|
if (!NT_SUCCESS(MmGrowKernelStack((BYTE *)PsGetCurrentThreadStackBase()-
|
|
KERNEL_LARGE_STACK_SIZE+
|
|
KERNEL_LARGE_STACK_COMMIT)))
|
|
{
|
|
WARNING("iOpenGLExtEscape: Unable to grow stack\n");
|
|
return 0;
|
|
}
|
|
|
|
// Ensure that the stack does not shrink back until we release it.
|
|
|
|
bSaveSwapEnable = KeSetKernelStackSwapEnable(FALSE);
|
|
|
|
// Save floating point state
|
|
// This allows client drivers to do floating point operations
|
|
// If the state were not preserved then we would be corrupting the
|
|
// thread's user-mode FP state
|
|
|
|
if (!NT_SUCCESS(KeSaveFloatingPointState(&fsFpState)))
|
|
{
|
|
WARNING("iOpenGLExtEscape: Unable to save FP state\n");
|
|
goto iOpenGLExtEscape_RestoreSwap;
|
|
}
|
|
|
|
// Handle OPENGL_CMD processing.
|
|
|
|
if ( nEscape == OPENGL_CMD )
|
|
{
|
|
ASSERTGDI(sizeof(OPENGLCMD) == sizeof(OPENGLCMDMULTI),
|
|
"OPENGLCMD doesn't match OPENGLCMDMULTI\n");
|
|
|
|
// Better check input size. We don't want to access violate.
|
|
|
|
if (cjIn < sizeof(OPENGLCMD))
|
|
{
|
|
WARNING("iOpenGLExtEscape(): buffer too small\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
goto iOpenGLExtEscape_RestoreState;
|
|
}
|
|
|
|
DWORD inBuffer[(sizeof(OPENGLCMD) + 128) / sizeof(DWORD)];
|
|
POPENGLCMD poglcmd;
|
|
POPENGLCMDMULTI pomcmd;
|
|
|
|
// Copy pvIn to a private buffer to prevent client process from trashing
|
|
// pwo and pxlo.
|
|
|
|
if (cjIn <= sizeof(inBuffer))
|
|
{
|
|
poglcmd = (POPENGLCMD) inBuffer;
|
|
}
|
|
else
|
|
{
|
|
// may affect performance
|
|
WARNING("iOpenGLExtEscape(): big input buffer\n");
|
|
poglcmd = (POPENGLCMD) PALLOCNOZ(cjIn,'lgoG');
|
|
if (!poglcmd)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto iOpenGLExtEscape_RestoreState;
|
|
}
|
|
}
|
|
|
|
RtlCopyMemory((PBYTE) poglcmd, (PBYTE) pvIn, cjIn);
|
|
|
|
if (poglcmd->fl & OGLCMD_MULTIWNDOBJ)
|
|
{
|
|
pomcmd = (POPENGLCMDMULTI)poglcmd;
|
|
|
|
if (pomcmd->cMulti > OPENGLCMD_MAXMULTI ||
|
|
(DWORD)cjIn < sizeof(OPENGLCMDMULTI)+pomcmd->cMulti*
|
|
sizeof(HDC))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto oglcmd_cleanup;
|
|
}
|
|
|
|
iMultiMask = LookUpWndobjs(&dco, dcoMulti, (HDC *)(poglcmd+1),
|
|
pomcmd->cMulti);
|
|
if (iMultiMask < 0)
|
|
{
|
|
goto oglcmd_cleanup;
|
|
}
|
|
}
|
|
|
|
if ( poglcmd->fl & OGLCMD_NEEDXLATEOBJ )
|
|
{
|
|
switch (po.iDitherFormat())
|
|
{
|
|
case BMF_4BPP:
|
|
case BMF_8BPP:
|
|
{
|
|
XEPALOBJ pal(dco.ppal());
|
|
|
|
if ( pal.bValid() )
|
|
{
|
|
COUNT cColors = (po.iDitherFormat() == BMF_4BPP) ? 16 : 256;
|
|
USHORT aus[256];
|
|
|
|
for (COUNT ii = 0; ii < cColors; ii++)
|
|
aus[ii] = (USHORT) ii;
|
|
|
|
#ifdef OPENGL_MM
|
|
if ( xlo.bMakeXlate(aus, pal, pSurface, cColors, cColors) )
|
|
#else
|
|
if ( xlo.bMakeXlate(aus, pal, dco.pSurfaceEff(), cColors, cColors) )
|
|
#endif // OPENGL_MM
|
|
|
|
pxlo = (XLATEOBJ *) xlo.pxlo();
|
|
}
|
|
|
|
if (!pxlo)
|
|
pxlo = &xloIdent;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pxlo = &xloIdent;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Write the XLATOBJ into the correct places in the input structure.
|
|
|
|
poglcmd->pxo = pxlo;
|
|
|
|
// May need to get the WNDOBJ for the driver.
|
|
|
|
if ((poglcmd->fl & OGLCMD_MULTIWNDOBJ) == 0)
|
|
{
|
|
if (poglcmd->fl & OGLCMD_NEEDWNDOBJ)
|
|
{
|
|
if (!dlo.bValidWndobj() || dlo.pwo()->fl & WO_GENERIC_WNDOBJ)
|
|
{
|
|
WARNING("iOpenGLExtEscape(): invalid WNDOBJ\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
goto oglcmd_cleanup;
|
|
}
|
|
|
|
// If the WNDOBJ is owned by a different surface (as can happen with
|
|
// dynamic mode changes, where the old driver instance lives as long
|
|
// as the WNDOBJ is alive), simply fail the call.
|
|
|
|
if (dlo.pwo()->pto->pSurface != dco.pSurface())
|
|
{
|
|
#ifdef OPENGL_MM
|
|
// Under multi-mon the DCOBJ may have the meta-surface while
|
|
// the pto was created with the actual hardware surface.
|
|
// So if the parent hdev of hdev in WNDOBJ is same as hdev in
|
|
// DCOBJ, we will allow to continue since we have replaced
|
|
// meta-PDEV with hardware PDEV. so it's fine.
|
|
|
|
PDEVOBJ pdoOfPwo(dlo.pwo()->pto->pSurface->hdev());
|
|
|
|
if (pdoOfPwo.hdevParent() != dco.hdev())
|
|
{
|
|
WARNING("iOpenGLExtEscape: pwo->pto->pSurface != dco.pSurface, so bailing out\n");
|
|
goto oglcmd_cleanup;
|
|
}
|
|
#else
|
|
goto oglcmd_cleanup;
|
|
#endif // OPENGL_MM
|
|
}
|
|
|
|
poglcmd->pwo = (WNDOBJ *)dlo.pwo();
|
|
}
|
|
else
|
|
{
|
|
poglcmd->pwo = (WNDOBJ *)NULL;
|
|
}
|
|
}
|
|
|
|
// Cursor exclusion.
|
|
|
|
if (dlo.bValidWndobj())
|
|
{
|
|
// If the driver's WNDOBJ knows about sprites, we assume the driver
|
|
// will take of exclusion.
|
|
|
|
if (!(dlo.pwo()->fl & WO_SPRITE_NOTIFY))
|
|
{
|
|
dxoWnd.vExclude(dlo.pwo());
|
|
}
|
|
INC_SURF_UNIQ(dco.pSurface());
|
|
}
|
|
else
|
|
{
|
|
ERECTL ercl(dco.prgnEffRao()->rcl);
|
|
ECLIPOBJ co(dco.prgnEffRao(), ercl, FALSE);
|
|
|
|
dxoRect.vExclude(dco.hdev(), &co.erclExclude());
|
|
INC_SURF_UNIQ(dco.pSurface());
|
|
}
|
|
|
|
iRet = (int) po.Escape(pso,
|
|
(ULONG)nEscape,
|
|
(ULONG)cjIn,
|
|
(PVOID)poglcmd,
|
|
(ULONG)cjOut,
|
|
pvOut);
|
|
if (poglcmd->fl & OGLCMD_MULTIWNDOBJ)
|
|
{
|
|
iRet = (iRet & (0xffffffff >> OPENGLCMD_MAXMULTI)) |
|
|
(iMultiMask << (32-OPENGLCMD_MAXMULTI));
|
|
}
|
|
|
|
oglcmd_cleanup:
|
|
if (cjIn > sizeof(inBuffer))
|
|
VFREEMEM(poglcmd);
|
|
} // if ( nEscape == OPENGL_CMD )
|
|
else
|
|
{
|
|
// Handle OPENGL_GETINFO processing.
|
|
|
|
iRet = ((int) po.Escape(pso,
|
|
(ULONG)nEscape,
|
|
(ULONG)cjIn,
|
|
pvIn,
|
|
(ULONG)cjOut,
|
|
pvOut));
|
|
}
|
|
|
|
// Restore floating point state
|
|
|
|
iOpenGLExtEscape_RestoreState:
|
|
KeRestoreFloatingPointState(&fsFpState);
|
|
|
|
iOpenGLExtEscape_RestoreSwap:
|
|
KeSetKernelStackSwapEnable((BOOLEAN)bSaveSwapEnable);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* iCheckPassthroughImage
|
|
*
|
|
* Implements the CHECKJPEGFORMAT and CHECKPNGFORMAT escapes on behalf of
|
|
* the driver. Converts the escape into a call to DrvQueryDriverSupport
|
|
* which can pass objects such as XLATEOBJ to the driver that DrvEscape
|
|
* does not have.
|
|
*
|
|
* These escapes are used to validate images with the device so that
|
|
* they can later be sent directly (passthrough) to the device.
|
|
*
|
|
* Returns:
|
|
* QUERYESCSUPPORT returns 1 if escape supported, 0 otherwise.
|
|
* CHECKJPEGFORMAT/CHECKPNGFORMAT returns 1 if image supported, 0 if not
|
|
* supported, and -1 if error.
|
|
*
|
|
* History:
|
|
* 14-Oct-1997 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int iCheckPassthroughImage(
|
|
DCOBJ &dco, // DC user object
|
|
PDEVOBJ &pdo, // PDEV user object
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn
|
|
PVOID pvIn, // Points to the input structure required
|
|
int cjOut, // Number of bytes of data pointed to by pvOut
|
|
PVOID pvOut // Points to the output structure
|
|
)
|
|
{
|
|
int iRet = 0; // not supported
|
|
|
|
if (nEscape == QUERYESCSUPPORT)
|
|
{
|
|
ASSERTGDI((*(ULONG*)pvIn == CHECKJPEGFORMAT) ||
|
|
(*(ULONG*)pvIn == CHECKPNGFORMAT),
|
|
"iCheckPassthroughImage: unknown escape\n");
|
|
|
|
if (*(ULONG*)pvIn == CHECKJPEGFORMAT)
|
|
{
|
|
// Escape is supported if driver has JPEG support.
|
|
|
|
if (dco.bSupportsJPEG() &&
|
|
(PPFNVALID(pdo, QueryDeviceSupport)))
|
|
{
|
|
iRet = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Escape is supported if driver has PNG support.
|
|
|
|
if (dco.bSupportsPNG() &&
|
|
(PPFNVALID(pdo, QueryDeviceSupport)))
|
|
{
|
|
iRet = 1;
|
|
}
|
|
}
|
|
}
|
|
else if (PPFNVALID(pdo, QueryDeviceSupport))
|
|
{
|
|
ASSERTGDI((nEscape == CHECKJPEGFORMAT) || (nEscape == CHECKPNGFORMAT),
|
|
"iCheckPassthroughImage: unknown escape\n");
|
|
|
|
if ((cjOut >= sizeof(ULONG)) && pvOut)
|
|
{
|
|
// There is no surface in metafile DCs. In addition, some
|
|
// apps call printing escape before the StartDoc, also
|
|
// resulting in no real surface in DC.
|
|
//
|
|
// The XLATEOBJ generated in this way may not be valid except
|
|
// for the ICM information (which is all this escape cares
|
|
// about in the XLATEOBJ anyway).
|
|
|
|
XEPALOBJ palDest(dco.pSurface() ? dco.pSurface()->ppal() : NULL);
|
|
XEPALOBJ palDestDC(dco.ppal());
|
|
PALMEMOBJ palTemp;
|
|
XLATEOBJ *pxlo = NULL;
|
|
EXLATEOBJ xlo;
|
|
|
|
// Create the XLATEOBJ so driver can determine the ICM state.
|
|
|
|
if (((nEscape == CHECKJPEGFORMAT) && dco.bSupportsJPEG()) ||
|
|
((nEscape == CHECKPNGFORMAT ) && dco.bSupportsPNG()))
|
|
{
|
|
if (palTemp.bCreatePalette(PAL_BGR, 0, (PULONG) NULL,
|
|
0, 0, 0, PAL_FIXED))
|
|
{
|
|
if (xlo.pInitXlateNoCache(dco.pdc->hcmXform(),
|
|
dco.pdc->lIcmMode(),
|
|
palTemp,
|
|
palDest,
|
|
palDestDC,
|
|
0,
|
|
0,
|
|
0x00FFFFFF))
|
|
{
|
|
pxlo = xlo.pxlo();
|
|
}
|
|
else
|
|
{
|
|
WARNING("ExtEscape(CHECKJPEGFORMAT/CHECKPNGFORMAT): "
|
|
"failed pxlo creation\n");
|
|
|
|
iRet = -1; // error
|
|
}
|
|
}
|
|
}
|
|
|
|
// If XLATEOBJ created, call DrvQueryDriverSupport to validate
|
|
// the image.
|
|
|
|
if (pxlo)
|
|
{
|
|
// There is no surface in metafile DCs. In addition, some
|
|
// apps call printing escape before the StartDoc, also
|
|
// resulting in no real surface in DC.
|
|
//
|
|
// We fake up a rather poor one here if we need it. The
|
|
// device driver may only dereference the dhpdev from this!
|
|
|
|
SURFOBJ soFake;
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
if (pso == (SURFOBJ *) NULL)
|
|
{
|
|
RtlFillMemory((BYTE *) &soFake,sizeof(SURFOBJ),0);
|
|
soFake.dhpdev = dco.dhpdev();
|
|
soFake.hdev = dco.hdev();
|
|
soFake.iType = (USHORT)STYPE_DEVICE;
|
|
pso = &soFake;
|
|
}
|
|
|
|
// Call the Driver.
|
|
|
|
*(ULONG *)pvOut = PPFNDRV(pdo,QueryDeviceSupport)
|
|
(pso,
|
|
pxlo,
|
|
(XFORMOBJ *) NULL,
|
|
(nEscape == CHECKJPEGFORMAT)
|
|
? QDS_CHECKJPEGFORMAT
|
|
: QDS_CHECKPNGFORMAT,
|
|
(ULONG) cjIn,
|
|
pvIn,
|
|
(ULONG) cjOut,
|
|
pvOut) ? 1 : 0;
|
|
|
|
iRet = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("ExtEscape(CHECKJPEGFORMAT/CHECKPNGFORMAT): "
|
|
"invalid output buffer\n");
|
|
|
|
iRet = -1; // error
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreExtEscape *
|
|
* *
|
|
* GreExtEscape() allows applications to access facilities of a particular *
|
|
* device that are not directly available through GDI. GreExtEscape calls *
|
|
* made by an application are translated and sent to the device driver. *
|
|
* *
|
|
* Returns *
|
|
* *
|
|
* The return value specifies the outcome of the function. It is *
|
|
* positive if the function is successful except for the *
|
|
* QUERYESCSUPPORT escape, which only checks for implementation. *
|
|
* The return value is zero if the escape is not implemented. *
|
|
* A negative value indicates an error. *
|
|
* The following list shows common error values: *
|
|
* *
|
|
* *
|
|
* Value Meaning *
|
|
* *
|
|
* SP_ERROR General error. *
|
|
* *
|
|
* SP_OUTOFDISK Not enough disk space is currently *
|
|
* available for spooling, and no more *
|
|
* space will become available. *
|
|
* *
|
|
* *
|
|
* SP_OUTOFMEMORY Not enough memory is available for *
|
|
* spooling. *
|
|
* *
|
|
* *
|
|
* SP_USERABORT User terminated the job through the *
|
|
* Print Manager. *
|
|
* *
|
|
* *
|
|
* COMMENTS *
|
|
* *
|
|
* [1] I assume that if we pass to the driver an Escape number that *
|
|
* it does not support, the driver will handle it gracefully. *
|
|
* No checks are done in the Engine. *
|
|
* [koo 02/13/91]. *
|
|
* [2] The cast on pso may seem redundant. However if you *
|
|
* try it without the (PSURFOBJ) cast, you will find *
|
|
* that cFront objects. The reason for this is beyond *
|
|
* my understanding of C++. *
|
|
* *
|
|
* History: *
|
|
* Fri 07-May-1993 14:58:39 -by- Charles Whitmer [chuckwh] *
|
|
* Added the font management escapes. Made it copy the ATTRCACHE. *
|
|
* *
|
|
* Fri 03-Apr-1992 Wendy Wu [wendywu] *
|
|
* Old escapes are now mapped to GDI functions on the client side. *
|
|
* *
|
|
* Fri 14-Feb-1992 Dave Snipp *
|
|
* Added output buffer size. This is calculated on the client and passed to *
|
|
* us in the message *
|
|
* *
|
|
* Wed 13-Feb-1991 09:17:51 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GreExtEscape(
|
|
HDC hDC, // Identifies the device context.
|
|
int iEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by pvIn.
|
|
LPSTR pvIn, // Points to the input data.
|
|
int cjOut, // Number of bytes of data pointed to by pvOut.
|
|
LPSTR pvOut // Points to the structure to receive output.
|
|
)
|
|
{
|
|
// Locate the surface.
|
|
|
|
DCOBJ dco(hDC);
|
|
|
|
if (!dco.bValid())
|
|
return(0);
|
|
|
|
// PDEVs that have been marked by USER for deletion cannot have escapes
|
|
// going down to them.
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
if (pdo.bDeleted())
|
|
return(0);
|
|
|
|
#if TEXTURE_DEMO
|
|
if (iEscape == 0x031898)
|
|
{
|
|
return(TexTexture(pvIn, cjIn));
|
|
}
|
|
|
|
if ((cjIn >= 4) && (pvIn != NULL) && (iEscape == 0x031899))
|
|
{
|
|
return((int) hdcTexture(*(ULONG*) pvIn));
|
|
}
|
|
#endif
|
|
|
|
// We are responsible for not faulting on any call that we handle.
|
|
// (As are all drivers below us!) Since we handle QUERYESCSUPPORT, we'd
|
|
// better verify the length. [chuckwh]
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// NOTE: If you add more private escape routines, you MUST acquire the
|
|
// DEVLOCK before calling the driver's DrvEscape routine, to allow
|
|
// for dynamic mode changing.
|
|
|
|
// First, get the driver capable override info
|
|
DWORD dwOverride = pdo.dwDriverCapableOverride();
|
|
|
|
if ((iEscape == QUERYESCSUPPORT) && (((ULONG)cjIn) < 4))
|
|
{
|
|
return(0);
|
|
}
|
|
else if ( (iEscape == QUERYESCSUPPORT)
|
|
&&( (*(ULONG*)pvIn == OPENGL_GETINFO)
|
|
||(*(ULONG*)pvIn == OPENGL_CMD)
|
|
||(*(ULONG*)pvIn == MCDFUNCS) )
|
|
&&(dwOverride & DRIVER_NOT_CAPABLE_OPENGL) )
|
|
{
|
|
return (0);
|
|
}
|
|
else if ( (iEscape == OPENGL_CMD) || (iEscape == OPENGL_GETINFO) )
|
|
{
|
|
// If the driver is not capable of doing OpenGL, just return
|
|
if ( (dwOverride & DRIVER_NOT_CAPABLE_OPENGL)
|
|
|| (dco.dctp() != DCTYPE_DIRECT) )
|
|
return 0;
|
|
|
|
return iOpenGLExtEscape(dco, iEscape, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if (iEscape == MCDFUNCS)
|
|
{
|
|
// Don't allow the MCD to be started up on device bitmaps.
|
|
// If the driver is not capable of doing OpenGL, just return
|
|
if ( (dwOverride & DRIVER_NOT_CAPABLE_OPENGL)
|
|
|| (dco.dctp() != DCTYPE_DIRECT) )
|
|
return 0;
|
|
|
|
DWORD inBuffer[((sizeof(MCDESC_HEADER) +
|
|
sizeof(MCDESC_HEADER_NTPRIVATE)) /
|
|
sizeof(DWORD))];
|
|
HANDLE hLockSurfaces[MCDESC_MAX_LOCK_SURFACES];
|
|
HDC hdcExtraWndobj[MCDESC_MAX_EXTRA_WNDOBJ];
|
|
MCDESC_HEADER *pmeh = (MCDESC_HEADER *)inBuffer;
|
|
MCDESC_HEADER_NTPRIVATE *pmehPriv;
|
|
BYTE *pbCmd;
|
|
|
|
// MCD escape protocol involves an
|
|
// MCDESC_HEADER + MCDESC_HEADER_NTPRIVATE structure sent via
|
|
// the escape.
|
|
//
|
|
// If there is shared memory, then the entire command is described
|
|
// in the MCDESC_HEADER. Otherwise, the pBuffer field of the
|
|
// MCDESC_HEADER_NTPRIVATE
|
|
// structure is set to point to the command structure.
|
|
|
|
if (cjIn >= sizeof(MCDESC_HEADER))
|
|
{
|
|
RtlCopyMemory(pmeh,pvIn,sizeof(*pmeh));
|
|
pbCmd = (BYTE *)pvIn+sizeof(MCDESC_HEADER);
|
|
cjIn -= sizeof(MCDESC_HEADER);
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
pmehPriv = (MCDESC_HEADER_NTPRIVATE *)(pmeh+1);
|
|
|
|
// If MCDESC_FL_LOCK_SURFACES is set, the cLockSurfaces field indicates
|
|
// the number of trailing surface handles for locking
|
|
if (pmeh->flags & MCDESC_FL_LOCK_SURFACES)
|
|
{
|
|
int cb;
|
|
|
|
if ((pmeh->cLockSurfaces <= MCDESC_MAX_LOCK_SURFACES) &&
|
|
((cb = sizeof(HANDLE)*pmeh->cLockSurfaces) <= cjIn))
|
|
{
|
|
RtlCopyMemory(hLockSurfaces, pbCmd, cb);
|
|
pmehPriv->pLockSurfaces = hLockSurfaces;
|
|
pbCmd += cb;
|
|
cjIn -= cb;
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmehPriv->pLockSurfaces = NULL;
|
|
}
|
|
|
|
// If MCDESC_FL_EXTRA_WNDOBJ is set, the cExtraWndobj field indicates
|
|
// the number of trailing HDCs to find WNDOBJs for.
|
|
if (pmeh->flags & MCDESC_FL_EXTRA_WNDOBJ)
|
|
{
|
|
int cb;
|
|
|
|
if ((pmeh->cExtraWndobj <= MCDESC_MAX_EXTRA_WNDOBJ) &&
|
|
((cb = sizeof(HDC)*pmeh->cExtraWndobj) <= cjIn))
|
|
{
|
|
RtlCopyMemory(hdcExtraWndobj, pbCmd, cb);
|
|
pmehPriv->pExtraWndobj = hdcExtraWndobj;
|
|
pbCmd += cb;
|
|
cjIn -= cb;
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pmehPriv->pExtraWndobj = NULL;
|
|
}
|
|
|
|
if (!pmeh->hSharedMem)
|
|
{
|
|
pmehPriv->pBuffer = (VOID *)pbCmd;
|
|
pmehPriv->bufferSize = cjIn;
|
|
}
|
|
else
|
|
{
|
|
pmehPriv->pBuffer = (VOID *)NULL;
|
|
pmehPriv->bufferSize = 0;
|
|
}
|
|
|
|
if (pmeh->flags & MCDESC_FL_CREATE_CONTEXT)
|
|
{
|
|
return iMcdSetupExtEscape(dco, iEscape, sizeof(inBuffer), inBuffer,
|
|
cjOut, pvOut);
|
|
}
|
|
else
|
|
{
|
|
return iMcdExtEscape(dco, iEscape, sizeof(inBuffer), inBuffer,
|
|
cjOut, pvOut);
|
|
}
|
|
}
|
|
else if (iEscape == WNDOBJ_SETUP)
|
|
{
|
|
if (dco.dctp() != DCTYPE_DIRECT)
|
|
return 0;
|
|
|
|
return iWndObjSetupExtEscape(dco, iEscape, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if (iEscape == DCICOMMAND)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
// Acquire the DEVLOCK to protect against dynamic mode changes. We still
|
|
// let escapes down if we're in full-screen mode, though.
|
|
|
|
DEVLOCKOBJ dlo;
|
|
|
|
dlo.vLockNoDrawing(dco);
|
|
|
|
// Redirection DCs should not support escapes. This is actually a tricky
|
|
// case because the dc is DCTYPE_DIRECT but the redirection surface may
|
|
// not be owned by the driver (and in fact the driver may crash if we
|
|
// pass it a redirection surface). So it's best to quit here.
|
|
|
|
if (dco.pdc->bRedirection())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// Make sure that a driver can't be called with an escape on a DIB bitmap
|
|
// that it obviously won't own.
|
|
|
|
if (dco.dctp() != DCTYPE_DIRECT)
|
|
{
|
|
if (!dco.bPrinter())
|
|
{
|
|
if ((dco.pSurface() == NULL) ||
|
|
(dco.pSurface()->iType() != STYPE_DEVBITMAP))
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Have to be careful with the printer case since there is no
|
|
// surface if metafile or escape called before StartDoc. Only
|
|
// reject if surface exists and does not match device.
|
|
|
|
if ((dco.pSurface() != NULL) &&
|
|
(dco.pSurface()->dhpdev() != pdo.dhpdev())
|
|
)
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
DRAWPATRECTP PatternRect;
|
|
EXFORMOBJ exo;
|
|
|
|
// Adjust DRAWPATTERNRECT for banding
|
|
|
|
if (iEscape == DRAWPATTERNRECT)
|
|
{
|
|
if (pdo.flGraphicsCaps() & GCAPS_NUP)
|
|
{
|
|
exo.vQuickInit(dco, WORLD_TO_DEVICE);
|
|
|
|
//
|
|
// If app passes us the wrong size return failure.
|
|
// Note: wow always fix up 16bit DRAWPATRECT to 32bit
|
|
// version.
|
|
//
|
|
if (cjIn != sizeof(DRAWPATRECT))
|
|
{
|
|
WARNING(" we are passed in a bad cjIn for DRAWPATTERNRECT\n");
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
PatternRect.DrawPatRect = *(DRAWPATRECT *) pvIn;
|
|
PatternRect.pXformObj = (XFORMOBJ *) (PVOID) &exo;
|
|
|
|
pvIn = (LPSTR)&PatternRect;
|
|
|
|
cjIn = sizeof(DRAWPATRECTP);
|
|
}
|
|
}
|
|
|
|
if (dco.pSurface() && (dco.pSurface())->bBanding())
|
|
{
|
|
if ((cjIn == sizeof(DRAWPATRECT)) || (pdo.flGraphicsCaps() & GCAPS_NUP))
|
|
{
|
|
DRAWPATRECT *pPatternRect = (DRAWPATRECT *) pvIn;
|
|
|
|
// convert position to band coords from page coords.
|
|
|
|
pPatternRect->ptPosition.x -= (dco.ptlPrintBandPos().x);
|
|
pPatternRect->ptPosition.y -= (dco.ptlPrintBandPos().y);
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreExtEscape():DRAWPATRECT - cjIn != sizeof(DRAWPATRECT)\n");
|
|
|
|
// we don't fail, let driver effort for this.
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Pass the calls that require a FONTOBJ off to DoFontManagement.
|
|
|
|
if ( ((iEscape >= 0x100) && (iEscape < 0x3FF)) ||
|
|
((iEscape == QUERYESCSUPPORT) &&
|
|
((*(ULONG*)pvIn >= 0x100) && (*(ULONG*)pvIn < 0x3FF))) )
|
|
{
|
|
return ( (int) DoFontManagement(dco,
|
|
iEscape,
|
|
(ULONG) cjIn,
|
|
(PVOID) pvIn,
|
|
(ULONG) cjOut,
|
|
(PVOID) pvOut));
|
|
}
|
|
|
|
// Handle device compressed image passthrough support (JPEG or PNG images)
|
|
|
|
if ( (iEscape == CHECKJPEGFORMAT) || (iEscape == CHECKPNGFORMAT) ||
|
|
((iEscape == QUERYESCSUPPORT) &&
|
|
((*(ULONG*)pvIn == CHECKJPEGFORMAT) ||
|
|
(*(ULONG*)pvIn == CHECKPNGFORMAT ))
|
|
)
|
|
)
|
|
{
|
|
return ( iCheckPassthroughImage(dco,
|
|
pdo,
|
|
iEscape,
|
|
(ULONG) cjIn,
|
|
(PVOID) pvIn,
|
|
(ULONG) cjOut,
|
|
(PVOID) pvOut));
|
|
}
|
|
|
|
// Inc the target surface for output calls with a valid surface.
|
|
|
|
if (dco.bValidSurf() && (pvOut == (LPSTR) NULL))
|
|
{
|
|
INC_SURF_UNIQ(dco.pSurface());
|
|
}
|
|
|
|
SURFOBJ *pso = dco.pSurface()->pSurfobj();
|
|
|
|
// Handle OpenGL - QUERYSUPPORT escape with multimon system
|
|
|
|
#ifdef OPENGL_MM
|
|
|
|
if (pdo.bMetaDriver())
|
|
{
|
|
if ( (iEscape == QUERYESCSUPPORT) &&
|
|
((*(ULONG *) pvIn == OPENGL_GETINFO) ||
|
|
(*(ULONG *) pvIn == OPENGL_CMD) ||
|
|
(*(ULONG *) pvIn == MCDFUNCS)
|
|
)
|
|
)
|
|
{
|
|
|
|
// We need to change the meta-PDEV into a hardware specific PDEV
|
|
|
|
HDEV hdevDevice = hdevFindDeviceHdev(
|
|
dco.hdev(),
|
|
(RECTL)dco.erclWindow(),
|
|
NULL);
|
|
|
|
if (hdevDevice)
|
|
{
|
|
// If the surface is pdev's primary surface, we will replace it with
|
|
// new device pdev's surface.
|
|
|
|
if (pdo.bPrimary(dco.pSurface()))
|
|
{
|
|
PDEVOBJ pdoDevice(hdevDevice);
|
|
|
|
pso = pdoDevice.pSurface()->pSurfobj();
|
|
}
|
|
|
|
// replace meta pdevobj with device specific hdev.
|
|
|
|
pdo.vInit(hdevDevice);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // OPENGL_MM
|
|
|
|
// Locate the driver entry point.
|
|
|
|
if (!PPFNDRV(pdo, Escape))
|
|
return(0);
|
|
|
|
// There is no surface in metafile DCs. In addition,
|
|
// it is unfortunate that apps call some printing escapes before
|
|
// doing a StartDoc, so there is no real surface in the DC.
|
|
// We fake up a rather poor one here if we need it. The device
|
|
// driver may only dereference the dhpdev from this!
|
|
|
|
SURFOBJ soFake;
|
|
|
|
if (pso == (SURFOBJ *) NULL)
|
|
{
|
|
RtlFillMemory((BYTE *) &soFake,sizeof(SURFOBJ),0);
|
|
soFake.dhpdev = dco.dhpdev();
|
|
soFake.hdev = dco.hdev();
|
|
soFake.iType = (USHORT)STYPE_DEVICE;
|
|
pso = &soFake;
|
|
|
|
// Special case SETCOPYCOUNT if we havn't done a startdoc yet
|
|
|
|
if ((iEscape == SETCOPYCOUNT) && (cjIn >= sizeof(USHORT)))
|
|
{
|
|
// let's remember the call in the dc and wait for start doc
|
|
// since if there is no hardware support, we can simulate it
|
|
// when EMF spooling case.
|
|
|
|
dco.ulCopyCount((ULONG)(*(PUSHORT)pvIn));
|
|
|
|
// check if the driver supports it and let him fill in the actual
|
|
// size in the return buffer.
|
|
|
|
pdo.Escape(pso,iEscape,cjIn,pvIn,cjOut,pvOut);
|
|
|
|
// always behaves as success, since EMF spooling can simulate it.
|
|
|
|
return(1);
|
|
}
|
|
|
|
// Special case post scripts EPS_PRINTING if we havn't done a startdoc yet
|
|
|
|
if ((iEscape == EPSPRINTING) && (cjIn >= sizeof(USHORT)))
|
|
{
|
|
// yes, lets remember the call in the dc and wait for start doc
|
|
|
|
if ((BOOL)*(PUSHORT)pvIn)
|
|
dco.vSetEpsPrintingEscape();
|
|
else
|
|
dco.vClearEpsPrintingEscape();
|
|
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
// Call the Driver.
|
|
|
|
int iRes;
|
|
|
|
iRes = (int) pdo.Escape(pso,
|
|
(ULONG) iEscape,
|
|
(ULONG) cjIn,
|
|
pvIn,
|
|
(ULONG) cjOut,
|
|
pvOut);
|
|
|
|
return(iRes);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreDrawEscape
|
|
*
|
|
* History:
|
|
* 07-Apr-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GreDrawEscape(
|
|
HDC hdc, // Identifies the device context.
|
|
int nEscape, // Specifies the escape function to be performed.
|
|
int cjIn, // Number of bytes of data pointed to by lpIn
|
|
PSTR pstrIn // Points to the input structure required
|
|
)
|
|
{
|
|
LONG lRet = 0;
|
|
DCOBJ dco(hdc);
|
|
|
|
//
|
|
// The DC must be valid and also the surface must be valid in order
|
|
// for the driver to be called
|
|
//
|
|
|
|
if ((dco.bValid()) && (dco.bHasSurface()) && (!dco.pdc->bDIBSection()))
|
|
{
|
|
//
|
|
// We are responsible for not faulting on any call that we handle.
|
|
// (As are all drivers below us!) Since we handle QUERYESCSUPPORT, we'd
|
|
// better verify the length.
|
|
//
|
|
|
|
if ((nEscape == QUERYESCSUPPORT) && (((ULONG) cjIn) < 4))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// see if the device supports it
|
|
//
|
|
|
|
PDEVOBJ pdo(dco.hdev());
|
|
|
|
//
|
|
// Lock the surface and the Rao region, ensure VisRgn up to date.
|
|
//
|
|
|
|
DEVLOCKOBJ dlo(dco);
|
|
|
|
PFN_DrvDrawEscape pfnDrvDrawEscape = PPFNDRV(pdo, DrawEscape);
|
|
|
|
if (pfnDrvDrawEscape != NULL)
|
|
{
|
|
//
|
|
// if it is query escape support, get out early
|
|
//
|
|
|
|
if (nEscape == QUERYESCSUPPORT)
|
|
{
|
|
lRet = (int)(*pfnDrvDrawEscape)(dco.pSurface()->pSurfobj(),
|
|
(ULONG)nEscape,
|
|
(CLIPOBJ *)NULL,
|
|
(RECTL *)NULL,
|
|
(ULONG)cjIn,
|
|
(PVOID)pstrIn);
|
|
}
|
|
else
|
|
{
|
|
if (!dlo.bValid())
|
|
{
|
|
lRet = (int)dco.bFullScreen();
|
|
}
|
|
else
|
|
{
|
|
ERECTL ercl = dco.erclWindow();
|
|
|
|
ECLIPOBJ co(dco.prgnEffRao(), ercl);
|
|
|
|
if (co.erclExclude().bEmpty())
|
|
{
|
|
lRet = (int)TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Exclude any sprites.
|
|
//
|
|
|
|
DEVEXCLUDERECT dxoRect(dco.hdev(), &ercl);
|
|
|
|
//
|
|
// Inc the target surface uniqueness
|
|
//
|
|
|
|
INC_SURF_UNIQ(dco.pSurface());
|
|
|
|
lRet = (int)(*pfnDrvDrawEscape)(dco.pSurface()->pSurfobj(),
|
|
(ULONG)nEscape,
|
|
(CLIPOBJ *)&co,
|
|
(RECTL *)&ercl,
|
|
(ULONG)cjIn,
|
|
(PVOID)pstrIn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(lRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* int APIENTRY GreStartDoc(HDC hdc, DOCINFOW *pDocInfo,BOOL *pbBanding)
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hdc - handle to device context
|
|
* pdi - DOCINFO of output names
|
|
* pbBanding - return banding flag
|
|
*
|
|
* Return Value:
|
|
*
|
|
* if successful return job identifier, else SP_ERROR
|
|
*
|
|
* History:
|
|
* Wed 08-Apr-1992 -by- Patrick Haluptzok [patrickh]
|
|
* lazy surface enable, journal support, remove unnecesary validation.
|
|
*
|
|
* Mon 01-Apr-1991 13:50:23 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GreStartDocInternal(
|
|
HDC hdc,
|
|
DOCINFOW *pDocInfo,
|
|
BOOL *pbBanding,
|
|
INT iDocJob
|
|
)
|
|
{
|
|
int iRet = 0;
|
|
int iJob;
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValid())
|
|
{
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
//
|
|
// Check that this is a printer surface.
|
|
//
|
|
|
|
if ((!po.bDisplayPDEV()) &&
|
|
(po.hSpooler()) &&
|
|
(dco.dctp() == DCTYPE_DIRECT) &&
|
|
(!dco.bHasSurface()))
|
|
{
|
|
// We now try and open the printer up in journal mode. If we fail
|
|
// then we try and open it up in raw mode. If that fails we fail call.
|
|
|
|
if (!po.bUMPD())
|
|
{
|
|
|
|
#define MAX_DOCINFO_DATA_TYPE 80
|
|
DOC_INFO_1W DocInfo;
|
|
WCHAR awchDatatype[MAX_DOCINFO_DATA_TYPE];
|
|
|
|
DocInfo.pDocName = (LPWSTR)pDocInfo->lpszDocName;
|
|
DocInfo.pOutputFile = (LPWSTR)pDocInfo->lpszOutput;
|
|
DocInfo.pDatatype = NULL;
|
|
|
|
// see if the driver wants to define its own data type. If it does,
|
|
// first fill the buffer in with the type requested by the app
|
|
|
|
if (PPFNVALID(po, QuerySpoolType))
|
|
{
|
|
awchDatatype[0] = 0;
|
|
|
|
// did the app specify a data type and will it fit in our buffer
|
|
|
|
if (pDocInfo->lpszDatatype)
|
|
{
|
|
int cjStr = (wcslen(pDocInfo->lpszDatatype) + 1) * sizeof(WCHAR);
|
|
|
|
if (cjStr < (MAX_DOCINFO_DATA_TYPE * sizeof(WCHAR)))
|
|
{
|
|
RtlCopyMemory((PVOID)awchDatatype,(PVOID)pDocInfo->lpszDatatype,cjStr);
|
|
}
|
|
}
|
|
|
|
if ((*PPFNDRV(po, QuerySpoolType))(po.dhpdev(), awchDatatype))
|
|
{
|
|
DocInfo.pDatatype = awchDatatype;
|
|
}
|
|
}
|
|
|
|
// open up the document
|
|
|
|
|
|
iJob = (BOOL)StartDocPrinterW(po.hSpooler(), 1, (LPBYTE)&DocInfo);
|
|
|
|
if (iJob <= 0)
|
|
{
|
|
WARNING("ERROR GreStartDoc failed StartDocPrinter Raw Mode\n");
|
|
return(iJob);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if it is UMPD, StartDocPrinter has been called in user mode already
|
|
iJob = iDocJob;
|
|
}
|
|
|
|
// Lazy surface creation happens now.
|
|
|
|
if (po.bMakeSurface())
|
|
{
|
|
*pbBanding = (po.pSurface())->bBanding();
|
|
|
|
// Put the surface into the DC.
|
|
|
|
dco.pdc->pSurface(po.pSurface());
|
|
|
|
if ( *pbBanding )
|
|
{
|
|
// if banding set Clip rectangle to size of band
|
|
|
|
dco.pdc->sizl((po.pSurface())->sizl());
|
|
dco.pdc->bSetDefaultRegion();
|
|
}
|
|
|
|
BOOL bSucceed = FALSE;
|
|
|
|
PFN_DrvStartDoc pfnDrvStartDoc = PPFNDRV(po, StartDoc);
|
|
|
|
bSucceed = (*pfnDrvStartDoc)(po.pSurface()->pSurfobj(),
|
|
(PWSTR)pDocInfo->lpszDocName,
|
|
iJob);
|
|
|
|
// now, if a SETCOPYCOUNT escape has come through, send it down
|
|
|
|
if (dco.ulCopyCount() != (ULONG)-1)
|
|
{
|
|
ULONG ulCopyCount = dco.ulCopyCount();
|
|
|
|
GreExtEscape(hdc,SETCOPYCOUNT,sizeof(DWORD),
|
|
(LPSTR)&ulCopyCount,0,NULL);
|
|
|
|
dco.ulCopyCount((ULONG)-1);
|
|
}
|
|
|
|
// now, if a EPSPRINTING escape has come through, send it down
|
|
|
|
if (dco.bEpsPrintingEscape())
|
|
{
|
|
SHORT b = 1;
|
|
|
|
GreExtEscape(hdc,EPSPRINTING,sizeof(b),(LPSTR)&b,0,NULL);
|
|
|
|
dco.vClearEpsPrintingEscape();
|
|
}
|
|
|
|
if (bSucceed)
|
|
{
|
|
iRet = iJob;
|
|
dco.vSetSaveDepthStartDoc();
|
|
}
|
|
}
|
|
}
|
|
if (!iRet)
|
|
{
|
|
AbortPrinter(po.hSpooler());
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* NtGdiSetLinkedUFIs
|
|
*
|
|
* History:
|
|
* 12/16/1996 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
#define QUICK_LINKS 4
|
|
|
|
extern "C" BOOL NtGdiSetLinkedUFIs(
|
|
HDC hdc,
|
|
PUNIVERSAL_FONT_ID pufiLinks,
|
|
ULONG uNumUFIs
|
|
)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
UNIVERSAL_FONT_ID pufiQuickLinks[QUICK_LINKS];
|
|
PUNIVERSAL_FONT_ID pufi = NULL;
|
|
|
|
if (!pufiLinks && uNumUFIs)
|
|
return FALSE;
|
|
|
|
if (uNumUFIs > QUICK_LINKS)
|
|
{
|
|
if (!BALLOC_OVERFLOW1(uNumUFIs,UNIVERSAL_FONT_ID))
|
|
{
|
|
pufi = (PUNIVERSAL_FONT_ID)
|
|
PALLOCNOZ(uNumUFIs * sizeof(UNIVERSAL_FONT_ID),'difG');
|
|
}
|
|
|
|
if (pufi == NULL)
|
|
{
|
|
WARNING("NtGdiSetLinkedUFIs: out of memory\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pufi = pufiQuickLinks;
|
|
}
|
|
|
|
__try
|
|
{
|
|
if (pufiLinks)
|
|
{
|
|
ProbeForRead(pufiLinks,
|
|
sizeof(UNIVERSAL_FONT_ID)*uNumUFIs,
|
|
sizeof(DWORD) );
|
|
RtlCopyMemory(pufi,pufiLinks,
|
|
sizeof(UNIVERSAL_FONT_ID)*uNumUFIs);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNINGX(106);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
XDCOBJ dco(hdc);
|
|
|
|
if (dco.bValid())
|
|
{
|
|
bRet = dco.bSetLinkedUFIs(pufi, uNumUFIs);
|
|
dco.vUnlockFast();
|
|
}
|
|
}
|
|
|
|
if (pufi != pufiQuickLinks)
|
|
{
|
|
VFREEMEM(pufi);
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
int APIENTRY NtGdiStartDoc(
|
|
HDC hdc,
|
|
DOCINFOW *pdi,
|
|
BOOL *pbBanding,
|
|
INT iJob
|
|
)
|
|
{
|
|
int iRet = 0;
|
|
BOOL bkmBanding;
|
|
DOCINFOW kmDocInfo;
|
|
ULONG cjStr;
|
|
BOOL bStatus = TRUE;
|
|
|
|
kmDocInfo.cbSize = 0;
|
|
kmDocInfo.lpszDocName = NULL;
|
|
kmDocInfo.lpszOutput = NULL;
|
|
kmDocInfo.lpszDatatype = NULL;
|
|
|
|
//DbgPrint ("NtGdiStartDoc\n");
|
|
|
|
if (pdi != (DOCINFOW *)NULL)
|
|
{
|
|
__try
|
|
{
|
|
LPCWSTR lpszDocName;
|
|
LPCWSTR lpszOutput;
|
|
LPCWSTR lpszDatatype;
|
|
|
|
ProbeForRead(pdi,sizeof(DOCINFOW),sizeof(ULONG));
|
|
|
|
kmDocInfo.cbSize = pdi->cbSize;
|
|
lpszDocName = pdi->lpszDocName;
|
|
lpszOutput = pdi->lpszOutput;
|
|
lpszDatatype = pdi->lpszDatatype;
|
|
|
|
if (lpszDocName != NULL)
|
|
{
|
|
cjStr = (wcslensafe(lpszDocName) + 1) * sizeof(WCHAR);
|
|
kmDocInfo.lpszDocName = (LPWSTR)PALLOCNOZ(cjStr,'pmtG');
|
|
if (kmDocInfo.lpszDocName == NULL)
|
|
{
|
|
bStatus = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ProbeForRead(lpszDocName,cjStr,sizeof(WCHAR));
|
|
RtlCopyMemory((PVOID)kmDocInfo.lpszDocName,(PVOID)lpszDocName,cjStr);
|
|
|
|
// Guarantee NULL termination of string.
|
|
((WCHAR *)kmDocInfo.lpszDocName)[(cjStr/sizeof(WCHAR)) - 1] = L'\0';
|
|
}
|
|
}
|
|
|
|
if (lpszOutput != NULL)
|
|
{
|
|
cjStr = (wcslensafe(lpszOutput) + 1) * sizeof(WCHAR);
|
|
kmDocInfo.lpszOutput = (LPWSTR)PALLOCNOZ(cjStr,'pmtG');
|
|
if (kmDocInfo.lpszOutput == NULL)
|
|
{
|
|
bStatus = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ProbeForRead(lpszOutput,cjStr,sizeof(WCHAR));
|
|
RtlCopyMemory((PVOID)kmDocInfo.lpszOutput,(PVOID)lpszOutput,cjStr);
|
|
|
|
// Guarantee NULL termination of string.
|
|
((WCHAR *)kmDocInfo.lpszOutput)[(cjStr/sizeof(WCHAR)) - 1] = L'\0';
|
|
}
|
|
}
|
|
|
|
// does it contain the new Win95 fields
|
|
|
|
if ((kmDocInfo.cbSize >= sizeof(DOCINFOW)) && (lpszDatatype != NULL))
|
|
{
|
|
__try
|
|
{
|
|
cjStr = (wcslensafe(lpszDatatype) + 1) * sizeof(WCHAR);
|
|
|
|
ProbeForRead(lpszDatatype,cjStr,sizeof(WCHAR));
|
|
kmDocInfo.lpszDatatype = (LPWSTR)PALLOCNOZ(cjStr,'pmtG');
|
|
|
|
if (kmDocInfo.lpszDatatype == NULL)
|
|
{
|
|
bStatus = FALSE;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory((PVOID)kmDocInfo.lpszDatatype,(PVOID)lpszDatatype,cjStr);
|
|
|
|
// Guarantee NULL termination of string.
|
|
((WCHAR *)kmDocInfo.lpszDatatype)[(cjStr/sizeof(WCHAR)) - 1] = L'\0';
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// apps may have forgotten to initialize this. Don't want to fail
|
|
|
|
if (kmDocInfo.lpszDatatype != NULL)
|
|
{
|
|
VFREEMEM(kmDocInfo.lpszDatatype);
|
|
kmDocInfo.lpszDatatype = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// SetLastError(GetExceptionCode());
|
|
|
|
bStatus = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bStatus)
|
|
{
|
|
iRet = GreStartDocInternal(hdc,&kmDocInfo,&bkmBanding, iJob);
|
|
|
|
if (iRet != 0)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(pbBanding,sizeof(BOOL),sizeof(BOOL));
|
|
*pbBanding = bkmBanding;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// SetLastError(GetExceptionCode());
|
|
|
|
iRet = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kmDocInfo.lpszDocName != NULL)
|
|
{
|
|
VFREEMEM(kmDocInfo.lpszDocName);
|
|
}
|
|
|
|
if (kmDocInfo.lpszOutput != NULL)
|
|
{
|
|
VFREEMEM(kmDocInfo.lpszOutput);
|
|
}
|
|
|
|
if (kmDocInfo.lpszDatatype != NULL)
|
|
{
|
|
VFREEMEM(kmDocInfo.lpszDatatype);
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bEndDocInternal
|
|
*
|
|
* History:
|
|
* Tue 22-Sep-1992 -by- Wendy Wu [wendywu]
|
|
* Made it a common routine for EndDoc and AbortDoc.
|
|
*
|
|
* Sun 21-Jun-1992 -by- Patrick Haluptzok [patrickh]
|
|
* surface disable, check for display dc.
|
|
*
|
|
* Mon 01-Apr-1991 13:50:23 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bEndDocInternal(HDC hdc, FLONG fl)
|
|
{
|
|
BOOL bSucceed;
|
|
BOOL bEndPage;
|
|
|
|
ASSERTGDI(((fl & ~ED_ABORTDOC) == 0), "GreEndDoc: invalid fl\n");
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (!dco.bValidSurf())
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE);
|
|
WARNING("GreEndDoc failed - invalid DC\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// before going any futher, restore the DC to it's original level
|
|
|
|
if (dco.lSaveDepth() > dco.lSaveDepthStartDoc())
|
|
GreRestoreDC(hdc,dco.lSaveDepthStartDoc());
|
|
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
if (po.bDisplayPDEV() || po.hSpooler() == (HANDLE)0)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE);
|
|
WARNING("GreEndDoc: Display PDEV or not spooling yet\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
SURFACE *pSurf = dco.pSurface();
|
|
|
|
bEndPage = (*PPFNDRV(po,EndDoc))(pSurf->pSurfobj(), fl);
|
|
|
|
if (!po.bUMPD())
|
|
{
|
|
if (fl & ED_ABORTDOC)
|
|
bSucceed = AbortPrinter(po.hSpooler());
|
|
else
|
|
bSucceed = EndDocPrinter(po.hSpooler());
|
|
}
|
|
else
|
|
bSucceed = TRUE;
|
|
|
|
// Reset pixel format accelerators.
|
|
|
|
dco.ipfdDevMax(-1);
|
|
|
|
// Remove the surface from the DC.
|
|
|
|
dco.pdc->pSurface((SURFACE *) NULL);
|
|
|
|
po.vDisableSurface();
|
|
|
|
return(bSucceed && bEndPage);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiEndDoc()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY NtGdiEndDoc( HDC hdc )
|
|
{
|
|
return(bEndDocInternal(hdc, 0));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiAbortDoc()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY NtGdiAbortDoc( HDC hdc )
|
|
{
|
|
return(bEndDocInternal(hdc, ED_ABORTDOC));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiStartPage()
|
|
*
|
|
* Mon 01-Apr-1991 13:50:23 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY NtGdiStartPage( HDC hdc )
|
|
{
|
|
DCOBJ dco(hdc);
|
|
BOOL bReturn = FALSE;
|
|
|
|
if (dco.bValidSurf())
|
|
{
|
|
if (dco.bHasSurface())
|
|
{
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
//
|
|
// Must be spooling already
|
|
//
|
|
|
|
if (po.hSpooler())
|
|
{
|
|
SURFACE *pSurf = dco.pSurface();
|
|
BOOL bStarted;
|
|
|
|
//
|
|
// if it is not a User Mode Printer,
|
|
// Call the spooler before calling the printer.
|
|
//
|
|
|
|
if (!po.bUMPD())
|
|
{
|
|
bStarted = StartPagePrinter(po.hSpooler());
|
|
}
|
|
else
|
|
{
|
|
bStarted = TRUE;
|
|
}
|
|
|
|
if (bStarted)
|
|
{
|
|
if ((*PPFNDRV(po, StartPage))(pSurf->pSurfobj()))
|
|
{
|
|
//
|
|
// Can't ResetDC in an active page
|
|
//
|
|
|
|
dco.fsSet(DC_RESET);
|
|
|
|
//
|
|
// Reset band position in page (if we are banding)
|
|
//
|
|
dco.vResetPrintBandPos();
|
|
|
|
bReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bEndDocInternal(hdc, ED_ABORTDOC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
return (bReturn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiEndPage()
|
|
*
|
|
* Mon 01-Apr-1991 13:50:23 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY NtGdiEndPage( HDC hdc )
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValidSurf())
|
|
{
|
|
if (dco.bHasSurface())
|
|
{
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
// Must be spooling already.
|
|
|
|
if (!po.bDisplayPDEV() && po.hSpooler())
|
|
{
|
|
SURFACE *pSurf = dco.pSurface();
|
|
|
|
if ((*PPFNDRV(po, SendPage))(pSurf->pSurfobj()))
|
|
{
|
|
BOOL bEndPage;
|
|
|
|
if (po.bUMPD())
|
|
{
|
|
//
|
|
// all the spooler calls have been made at the user mode
|
|
// for User Mode Printer Drivers
|
|
//
|
|
bEndPage = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bEndPage = EndPagePrinter(po.hSpooler());
|
|
}
|
|
|
|
if (bEndPage)
|
|
{
|
|
//
|
|
// Allow ResetDC to function again.
|
|
//
|
|
|
|
dco.fsClr(DC_RESET);
|
|
|
|
//
|
|
// Delete the wndobj and reset the pixel format.
|
|
// Since we don't allow pixel format to change once it
|
|
// is set, we need to reset it internally here to allow a
|
|
// different pixel format in the next page. This means
|
|
// that applications must make the OpenGL rendering
|
|
// context not current before ending a page or a document.
|
|
// They also need to set the pixel format explicitly in
|
|
// the next page if they need it.
|
|
//
|
|
|
|
EWNDOBJ *pwoDelete = pSurf->pwo();
|
|
if (pwoDelete)
|
|
{
|
|
GreDeleteWnd((PVOID) pwoDelete);
|
|
pSurf->pwo((EWNDOBJ *) NULL);
|
|
}
|
|
|
|
//
|
|
// Reset pixel format accelerators.
|
|
//
|
|
|
|
dco.ipfdDevMax(-1);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY GreDoBanding(HDC hdc,BOOL bStart,RECTL *prcl)
|
|
*
|
|
*
|
|
* Tue 20-Dec-1994 14:50:45 by Gerrit van Wingerden
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreDoBanding( HDC hdc, BOOL bStart, POINTL *pptl, PSIZE pSize )
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValidSurf() && (dco.bHasSurface()))
|
|
{
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
// Must be spooling already.
|
|
|
|
if (po.hSpooler())
|
|
{
|
|
SURFACE *pSurf = dco.pSurface();
|
|
|
|
if (pSurf->SurfFlags & BANDING_SURFACE)
|
|
{
|
|
BOOL bSucceed;
|
|
|
|
if ( bStart )
|
|
{
|
|
// DrvStartBanding
|
|
|
|
PFN_DrvStartBanding pfnDrvStartBanding = PPFNDRV(po, StartBanding);
|
|
|
|
bSucceed = (*pfnDrvStartBanding)(pSurf->pSurfobj(),pptl);
|
|
#if DEBUG_BANDING
|
|
DbgPrint("just called DrvStartBanding which returned %s %d %d\n",
|
|
(bSucceed) ? "TRUE" : "FALSE", pptl->x, pptl->y );
|
|
#endif
|
|
pSize->cx = pSurf->so.sizlBitmap.cx;
|
|
pSize->cy = pSurf->so.sizlBitmap.cy;
|
|
|
|
//
|
|
// Set band position in page (if we are banding)
|
|
//
|
|
dco.vSetPrintBandPos(pptl);
|
|
}
|
|
else
|
|
{
|
|
// DrvNextBand
|
|
|
|
PFN_DrvNextBand pfnDrvNextBand = PPFNDRV(po, NextBand);
|
|
|
|
bSucceed = (*pfnDrvNextBand)(pSurf->pSurfobj(), pptl );
|
|
|
|
#if DEBUG_BANDING
|
|
DbgPrint("just called DrvNextBand which returned %s %d %d\n",
|
|
(bSucceed) ? "TRUE" : "FALSE", pptl->x, pptl->y );
|
|
#endif
|
|
|
|
if ( (bSucceed) && ( pptl->x == -1 ) )
|
|
{
|
|
// No more bands.
|
|
|
|
if (!po.bUMPD())
|
|
{
|
|
//
|
|
// all the spooler calls have been made at the user mode
|
|
// for User Mode Printer Drivers
|
|
//
|
|
bSucceed = EndPagePrinter(po.hSpooler());
|
|
}
|
|
|
|
// Allow ResetDC to function again.
|
|
|
|
if (bSucceed)
|
|
{
|
|
dco.fsClr(DC_RESET);
|
|
}
|
|
|
|
// Delete the wndobj and reset the pixel format.
|
|
// Since we don't allow pixel format to change once it is set, we need
|
|
// to reset it internally here to allow a different pixel format in the
|
|
// next page. This means that applications must make the OpenGL
|
|
// rendering context not current before ending a page or a document.
|
|
// They also need to set the pixel format explicitly in the next page
|
|
// if they need it.
|
|
|
|
if (bSucceed)
|
|
{
|
|
EWNDOBJ *pwoDelete = pSurf->pwo();
|
|
if (pwoDelete)
|
|
{
|
|
GreDeleteWnd((PVOID) pwoDelete);
|
|
pSurf->pwo((EWNDOBJ *) NULL);
|
|
}
|
|
|
|
// Reset pixel format accelerators.
|
|
|
|
dco.ipfdDevMax(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !bSucceed )
|
|
{
|
|
WARNING("GreDoBanding failed DrvNextBand\n");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set band position in page (if we are banding)
|
|
//
|
|
dco.vSetPrintBandPos(pptl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bSucceed);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiDoBanding()
|
|
*
|
|
* History:
|
|
* 11-Jan-1995 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
* 01-Mar-1995 -by- Lingyun Wang [lingyunw]
|
|
* Expanded it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY NtGdiDoBanding(
|
|
HDC hdc,
|
|
BOOL bStart,
|
|
POINTL *pptl,
|
|
PSIZE pSize
|
|
)
|
|
{
|
|
POINTL ptTmp;
|
|
SIZE szTmp;
|
|
BOOL bRet = TRUE;
|
|
|
|
bRet = GreDoBanding(hdc,bStart,&ptTmp,&szTmp);
|
|
|
|
if (bRet)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(pptl,sizeof(POINTL), sizeof(DWORD));
|
|
*pptl = ptTmp;
|
|
ProbeForWrite(pSize,sizeof(SIZE), sizeof(DWORD));
|
|
*pSize = szTmp;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// SetLastError(GetExceptionCode());
|
|
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY GreGetPerBandInfo()
|
|
*
|
|
* History:
|
|
* 05-Jan-1997 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
***************************************************************************/
|
|
|
|
ULONG APIENTRY GreGetPerBandInfo(
|
|
HDC hdc,
|
|
PERBANDINFO *ppbi
|
|
)
|
|
{
|
|
ULONG ulRet = GDI_ERROR;
|
|
|
|
//
|
|
// Set default. Assume no repeat, just play one time per one band.
|
|
//
|
|
ppbi->bRepeatThisBand = FALSE;
|
|
|
|
DCOBJ dco(hdc);
|
|
|
|
if (dco.bValidSurf() && (dco.bHasSurface()))
|
|
{
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
if (po.hSpooler())
|
|
{
|
|
SURFACE *pSurf = dco.pSurface();
|
|
|
|
//
|
|
// The surface should be banded.
|
|
//
|
|
if (pSurf->SurfFlags & BANDING_SURFACE)
|
|
{
|
|
PFN_DrvQueryPerBandInfo pfnDrvQueryPerBandInfo = PPFNDRV(po, QueryPerBandInfo);
|
|
|
|
//
|
|
// DrvQueryPerBandInfo is optional fucntion, check it is provided.
|
|
//
|
|
if (pfnDrvQueryPerBandInfo)
|
|
{
|
|
//
|
|
// Call driver.
|
|
//
|
|
ulRet = (*pfnDrvQueryPerBandInfo)(pSurf->pSurfobj(), ppbi);
|
|
|
|
if (ulRet == DDI_ERROR)
|
|
{
|
|
ulRet = GDI_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The function is not provided, that means the driver don't
|
|
// want to repeat more than one time for each band. Just return
|
|
// true, and use default that setted above.
|
|
//
|
|
ulRet = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (ulRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY NtGdiGetPerBandInfo()
|
|
*
|
|
* History:
|
|
* 05-Jan-1997 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
***************************************************************************/
|
|
|
|
ULONG APIENTRY NtGdiGetPerBandInfo(
|
|
HDC hdc,
|
|
PERBANDINFO *ppbi
|
|
)
|
|
{
|
|
PERBANDINFO PerBandInfo;
|
|
ULONG ulRet = GDI_ERROR;
|
|
|
|
if (ppbi)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForRead(ppbi,sizeof(PERBANDINFO),sizeof(ULONG));
|
|
RtlCopyMemory(&PerBandInfo,ppbi,sizeof(PERBANDINFO));
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return (ulRet);
|
|
}
|
|
}
|
|
|
|
ulRet = GreGetPerBandInfo(hdc,&PerBandInfo);
|
|
|
|
if (ulRet && (ulRet != GDI_ERROR))
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(ppbi,sizeof(PERBANDINFO), sizeof(ULONG));
|
|
RtlCopyMemory(ppbi,&PerBandInfo,sizeof(PERBANDINFO));
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
ulRet = GDI_ERROR;
|
|
}
|
|
}
|
|
|
|
return (ulRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY EngCheckAbort
|
|
*
|
|
* History:
|
|
* 01-Apr-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY EngCheckAbort(SURFOBJ *pso)
|
|
{
|
|
// Return FALSE if it's a faked surfobj.
|
|
|
|
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
|
|
|
if (pSurf == NULL || pSurf->hsurf() == 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
return(pSurf->bAbort());
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY NtGdiAnyLinkedFonts()
|
|
*
|
|
* Returns TRUE if there are any linked fonts in the system.
|
|
*
|
|
*
|
|
* History:
|
|
* 12-Dec-1996 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL NtGdiAnyLinkedFonts()
|
|
{
|
|
return(gbAnyLinkedFonts || IS_SYSTEM_EUDC_PRESENT());
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY NtGdiGetLinkedUFIs
|
|
*
|
|
* This API returns UFI's (in order of priority) of all the fonts linked to
|
|
* the font currently in the DC.
|
|
*
|
|
*
|
|
* History:
|
|
* 12-Dec-1996 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" INT NtGdiGetLinkedUFIs(
|
|
HDC hdc,
|
|
PUNIVERSAL_FONT_ID pufiLinkedUFIs,
|
|
INT BufferSize
|
|
)
|
|
{
|
|
INT iRet = 0;
|
|
PUNIVERSAL_FONT_ID pufi = NULL;
|
|
|
|
if (( BufferSize > 0 ) && ( pufiLinkedUFIs != NULL ))
|
|
{
|
|
if (!BALLOC_OVERFLOW1(BufferSize,UNIVERSAL_FONT_ID))
|
|
{
|
|
pufi = (PUNIVERSAL_FONT_ID)
|
|
PALLOCNOZ(BufferSize * sizeof(UNIVERSAL_FONT_ID),'difG');
|
|
}
|
|
|
|
if ( pufi == NULL )
|
|
{
|
|
iRet = -1 ;
|
|
}
|
|
}
|
|
else if (BufferSize && pufiLinkedUFIs == NULL)
|
|
{
|
|
iRet = -1;
|
|
}
|
|
|
|
if ( iRet != -1 )
|
|
{
|
|
{
|
|
XDCOBJ dco(hdc);
|
|
if (dco.bValid())
|
|
{
|
|
RFONTOBJ rfo(dco,FALSE);
|
|
|
|
if (rfo.bValid())
|
|
{
|
|
iRet = rfo.GetLinkedFontUFIs(dco, pufi,BufferSize);
|
|
}
|
|
else
|
|
{
|
|
iRet = -1;
|
|
WARNING("NtGdiGetLinkedUFIS: Invalid RFNTOBJ");
|
|
}
|
|
|
|
dco.vUnlockFast();
|
|
}
|
|
else
|
|
{
|
|
WARNING("NtGdiGetLinkedUFIS: Invalid DC");
|
|
iRet = -1;
|
|
}
|
|
|
|
}
|
|
|
|
if ( iRet > 0 )
|
|
{
|
|
__try
|
|
{
|
|
if (pufiLinkedUFIs)
|
|
{
|
|
ProbeForWrite(pufiLinkedUFIs,
|
|
sizeof(UNIVERSAL_FONT_ID)*BufferSize,
|
|
sizeof(DWORD));
|
|
|
|
RtlCopyMemory(pufiLinkedUFIs,
|
|
pufi,sizeof(UNIVERSAL_FONT_ID)*BufferSize);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNINGX(62);
|
|
iRet = -1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if ( pufi != NULL )
|
|
{
|
|
VFREEMEM( pufi );
|
|
}
|
|
|
|
if ( iRet == -1 )
|
|
{
|
|
// We need to set the last error here to something because the spooler
|
|
// code that calls this relies on there being a non-zero error code
|
|
// in the case of failure. Since we really have no idea I will just
|
|
// set this to ERROR_NOT_ENOUGH_MEMORY which would be the most likely
|
|
// reason for a failure
|
|
|
|
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
ULONG GreGetEmbedFonts()
|
|
{
|
|
PUBLIC_PFTOBJ pfto(gpPFTPrivate);
|
|
|
|
if (!pfto.bValid() || pfto.cFiles() == 0) // no embedded fonts
|
|
return 0;
|
|
|
|
return (pfto.GetEmbedFonts());
|
|
}
|
|
|
|
|
|
BOOL GreChangeGhostFont(VOID *fontID, BOOL bLoad)
|
|
{
|
|
PUBLIC_PFTOBJ pfto(gpPFTPrivate);
|
|
|
|
if (!pfto.bValid() || !pfto.cFiles()) // somehow the private font table is invalid
|
|
return FALSE;
|
|
|
|
return (pfto.ChangeGhostFont(fontID, bLoad));
|
|
}
|
|
|
|
|
|
extern "C" BOOL NtGdiAddEmbFontToDC(HDC hdc, VOID **pFontID)
|
|
{
|
|
VOID *fontID;
|
|
BOOL bRet = TRUE;
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(pFontID, sizeof(VOID *), sizeof(BYTE));
|
|
RtlCopyMemory(&fontID, pFontID, sizeof(VOID *));
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
bRet = FALSE;
|
|
|
|
XDCOBJ dco(hdc);
|
|
|
|
if (dco.bValid())
|
|
{
|
|
PUBLIC_PFTOBJ pfto(gpPFTPrivate);
|
|
|
|
// FonID could be a fake value from hacker to crash the system
|
|
if(pfto.bValid() && pfto.VerifyFontID(fontID))
|
|
bRet = dco.bAddRemoteFont((PFF *)fontID);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreGetUFI
|
|
*
|
|
* History:
|
|
* 18-Jan-1995 -by- Gerrit van Wingerden
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreGetUFI( HDC hdc, PUNIVERSAL_FONT_ID pufi,
|
|
DESIGNVECTOR *pdv, ULONG *pcjDV, ULONG *pulBaseCheckSum,
|
|
FLONG *pfl,
|
|
VOID **pfontID)
|
|
{
|
|
*pfl = 0;
|
|
if (pfontID)
|
|
*pfontID = NULL;
|
|
|
|
BOOL bRet = FALSE;
|
|
XDCOBJ dco(hdc);
|
|
|
|
if(dco.bValid())
|
|
{
|
|
RFONTOBJ rfo(dco,FALSE);
|
|
|
|
if (rfo.bValid())
|
|
{
|
|
rfo.vUFI( pufi );
|
|
|
|
// now on to determine if this is private or public font
|
|
|
|
PFEOBJ pfeo(rfo.ppfe());
|
|
if (pfeo.bValid())
|
|
{
|
|
PFFOBJ pffo(pfeo.pPFF());
|
|
if (pffo.bValid())
|
|
{
|
|
if (pffo.bInPrivatePFT())
|
|
{
|
|
*pfl |= FL_UFI_PRIVATEFONT;
|
|
if (pfontID)
|
|
*pfontID = (VOID*) pfeo.pPFF();
|
|
}
|
|
|
|
if (pffo.bMemFont())
|
|
{
|
|
*pfl |= FL_UFI_MEMORYFONT;
|
|
}
|
|
|
|
if (pffo.pdv())
|
|
{
|
|
*pfl |= FL_UFI_DESIGNVECTOR_PFF;
|
|
if (pdv)
|
|
RtlCopyMemory(pdv, pffo.pdv(), pffo.cjDV());
|
|
if (pcjDV)
|
|
*pcjDV = pffo.cjDV();
|
|
if (pulBaseCheckSum)
|
|
{
|
|
// factor out DV check sum. If we endup using algorithm
|
|
// that couples these two numbers, then BaseCheckSum will
|
|
// have to be remembered at the time of computation.
|
|
|
|
*pulBaseCheckSum = pffo.ulCheckSum();
|
|
|
|
*pulBaseCheckSum -= ComputeFileviewCheckSum(pffo.pdv(), pffo.cjDV());
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreGetUFI: Invalid rfo");
|
|
}
|
|
|
|
dco.vUnlockFast();
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreGetUFI: Invalid DC");
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ppfeGetPFEFromUFI
|
|
*
|
|
* This is used all over the place
|
|
*
|
|
* History:
|
|
* 11-Aug-1997 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
PFE *ppfeGetPFEFromUFIInternal (
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
BOOL bPrivate,
|
|
BOOL bCheckProccess
|
|
)
|
|
{
|
|
PFE *ppfeRet = NULL;
|
|
|
|
PFELINK *ppfel;
|
|
BOOL bThreadMatch = FALSE;
|
|
|
|
PUBLIC_PFTOBJ pfto(bPrivate ? gpPFTPrivate : gpPFTPublic);
|
|
if (!pfto.bValid())
|
|
return ppfeRet;
|
|
|
|
FHOBJ fho(&pfto.pPFT->pfhUFI);
|
|
HASHBUCKET *pbkt;
|
|
|
|
pbkt = fho.pbktSearch( NULL, (UINT*)NULL, pufi );
|
|
|
|
if (!pbkt)
|
|
{
|
|
WARNING1("ppfeGetPFEFromUFI: pbkt is NULL\n");
|
|
return ppfeRet;
|
|
}
|
|
|
|
for(ppfel = pbkt->ppfelEnumHead; ppfel; ppfel = ppfel->ppfelNext)
|
|
{
|
|
PFEOBJ pfeo(ppfel->ppfe);
|
|
|
|
if (UFI_SAME_FACE(pfeo.pUFI(),pufi) && (!bCheckProccess || pfeo.SameProccess()))
|
|
{
|
|
if(pfeo.bDead())
|
|
{
|
|
WARNING("ppfeGetPFEFromUFI: get the pathname to a dead PFE\n");
|
|
}
|
|
else
|
|
{
|
|
if (ppfeRet == NULL)
|
|
{
|
|
bThreadMatch = pfeo.SameThread();
|
|
ppfeRet = ppfel->ppfe;
|
|
}
|
|
else
|
|
{
|
|
// if we get here, it means we have multiple face name and process match.
|
|
// Do more extensive matching using thread ID.
|
|
if (!bThreadMatch && pfeo.SameThread())
|
|
{
|
|
// This is a better candidate.
|
|
// Although spooler can be running multiple threads, the same thread for a given
|
|
// port is used by spooler. However, if multiple printers were sharing the same
|
|
// port, we cannot distinguish.
|
|
|
|
ppfeRet = ppfel->ppfe;
|
|
bThreadMatch = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ppfeRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
PFE *ppfeGetPFEFromUFI (
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
BOOL bPrivate,
|
|
BOOL bCheckProccess
|
|
)
|
|
{
|
|
PFE * pfeRet = NULL;
|
|
|
|
if (bPrivate)
|
|
pfeRet = ppfeGetPFEFromUFIInternal(pufi, TRUE, bCheckProccess);
|
|
if (!pfeRet)
|
|
pfeRet = ppfeGetPFEFromUFIInternal(pufi, FALSE, bCheckProccess);
|
|
return pfeRet;
|
|
}
|
|
|
|
#define SZDLHEADER ALIGN8(offsetof(DOWNLOADFONTHEADER, FileOffsets[1]))
|
|
|
|
|
|
/*********************************Public*Routine*********************************\
|
|
* BOOL GreGetUFIPathname
|
|
*
|
|
* Get the path name and file counts to a given UFI.
|
|
*
|
|
* History:
|
|
* Feb-04-1997 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
\********************************************************************************/
|
|
|
|
BOOL GreGetUFIPathname(
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
ULONG *pcwc,
|
|
LPWSTR pwszPathname,
|
|
ULONG *pcNumFiles,
|
|
FLONG fl,
|
|
BOOL *pbMemFont,
|
|
ULONG *pcjView,
|
|
PVOID pvView,
|
|
BOOL *pbTTC,
|
|
ULONG *piTTC
|
|
)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
PFE *ppfe = ppfeGetPFEFromUFI(pufi, (BOOL)(fl & (FL_UFI_PRIVATEFONT | FL_UFI_MEMORYFONT)), TRUE);
|
|
|
|
if (ppfe == NULL)
|
|
{
|
|
WARNING("GreGetUFIPathname can't find the PFE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
PFFOBJ pffo(ppfe->pPFF);
|
|
|
|
if (pcNumFiles)
|
|
{
|
|
*pcNumFiles = pffo.cNumFiles();
|
|
}
|
|
if (pcwc)
|
|
{
|
|
*pcwc = pffo.cSizeofPaths();
|
|
}
|
|
if (pwszPathname)
|
|
{
|
|
RtlCopyMemory(pwszPathname, pffo.pwszPathname(), pffo.cSizeofPaths() * sizeof(WCHAR));
|
|
}
|
|
|
|
if (pbMemFont)
|
|
{
|
|
*pbMemFont = (BOOL)(ppfe->flPFE & PFE_MEMORYFONT);
|
|
}
|
|
|
|
if (ppfe->flPFE & PFE_MEMORYFONT)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SIZE_T ViewSize = 0;
|
|
ULONG cjView;
|
|
|
|
ASSERTGDI((pffo.ppfvGet()[0])->SpoolerPid == (W32PID)W32GetCurrentPID() || // either the current process
|
|
gpidSpool == (PW32PROCESS)W32GetCurrentProcess(), // or the spooler
|
|
"GreGetUFIPathname: wrong process to access memory font\n");
|
|
|
|
#if 0
|
|
|
|
PVOID pvView1;
|
|
LARGE_INTEGER SectionOffset; SectionOffset.QuadPart = 0;
|
|
|
|
NtStatus = MmMapViewOfSection(
|
|
pffo.ppfvGet()[0]->fv.pSection , // SectionToMap,
|
|
PsGetCurrentProcess(), //
|
|
&pvView1 , // CapturedBase,
|
|
0 , // ZeroBits,
|
|
ViewSize , // CommitSize,
|
|
&SectionOffset , // SectionOffset,
|
|
&ViewSize , // CapturedViewSize,
|
|
ViewUnmap , // InheritDisposition,
|
|
SEC_NO_CHANGE , // AllocationType,
|
|
PAGE_READONLY // Protect
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
//WARNING("could not map mem font to the spooler process\n");
|
|
KdPrint(("could not map mem font to the spooler process\n"));
|
|
*pcjView = 0;
|
|
*ppvView = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
// if this is a memory font, preceeding the font image
|
|
// there is going to be the header stuff in the section,
|
|
// so will need to adjust the pointer. cjView will already contain
|
|
// the correct data corresponding to the size without the header
|
|
|
|
*pcjView = pffo.ppfvGet()[0]->fv.cjView;
|
|
*ppvView = (PVOID)((BYTE *)pvView1 + SZDLHEADER);
|
|
|
|
#endif
|
|
|
|
cjView = pffo.ppfvGet()[0]->fv.cjView;
|
|
|
|
if (pcjView)
|
|
{
|
|
*pcjView = cjView;
|
|
}
|
|
|
|
if (pvView)
|
|
{
|
|
PVOID pvKView;
|
|
|
|
#ifdef _HYDRA_
|
|
// MmMapViewInSessionSpace is internally promoted to
|
|
// MmMapViewInSystemSpace on non-Hydra systems.
|
|
|
|
NtStatus = Win32MapViewInSessionSpace(
|
|
pffo.ppfvGet()[0]->fv.pSection,
|
|
&pvKView,
|
|
&ViewSize);
|
|
#else
|
|
NtStatus = MmMapViewInSystemSpace(
|
|
pffo.ppfvGet()[0]->fv.pSection,
|
|
&pvKView,
|
|
&ViewSize);
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
//WARNING("could not map mem font to the system space\n");
|
|
KdPrint(("could not map mem font to the system space\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
__try
|
|
{
|
|
// if this is a memory font, preceeding the font image
|
|
// there is going to be the header stuff in the section,
|
|
// so will need to adjust the pointer before copying.
|
|
// cjView already corresponds to the correct data
|
|
// without the header
|
|
|
|
ProbeForWrite(pvView, cjView, sizeof(BYTE));
|
|
RtlCopyMemory(pvView, ((BYTE *)pvKView + SZDLHEADER), cjView);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
#ifdef _HYDRA_
|
|
// MmUnmapViewInSessionSpace is internally promoted to
|
|
// MmUnmapViewInSystemSpace on non-Hydra systems.
|
|
|
|
Win32UnmapViewInSessionSpace(pvKView);
|
|
#else
|
|
MmUnmapViewInSystemSpace(pvKView);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (bRet && pbTTC && piTTC)
|
|
{
|
|
*pbTTC = FALSE;
|
|
*piTTC = 0;
|
|
|
|
PFF *pPFF = ppfe->pPFF;
|
|
|
|
if (pPFF->hdev == (HDEV) gppdevTrueType)
|
|
{
|
|
COUNT cFonts = pPFF->cFonts;
|
|
|
|
// if this is a ttc file we need at least 4 faces, eg.
|
|
// foo1, @foo1, foo2, @foo2 ...
|
|
|
|
if ((cFonts >= 4) && !(cFonts & 1))
|
|
{
|
|
ASSERTGDI(ppfe->ufi.Index, "ufi.Index must not be zero\n");
|
|
*piTTC = (ppfe->ufi.Index - 1) / 2;
|
|
*pbTTC = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreForceUFIMapping( HDC hdc, PUNIVERSAL_FONT_ID pufi )
|
|
*
|
|
* History:
|
|
* 3-Mar-1995 -by- Gerrit van Wingerden
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL GreForceUFIMapping( HDC hdc, PUNIVERSAL_FONT_ID pufi)
|
|
{
|
|
XDCOBJ dco(hdc);
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
WARNING("GreForceUFIMapping: Invalid DC");
|
|
return(FALSE);
|
|
}
|
|
|
|
dco.pdc->vForceMapping( pufi );
|
|
|
|
dco.vUnlockFast();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/**********************Public*Routine******************************\
|
|
* NtGdiRemoveMergeFont(HDC hdc, UNIVERSAL_FONT_ID *pufi)
|
|
*
|
|
* History:
|
|
* Jan-27-1997 -by- Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
\******************************************************************/
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiRemoveMergeFont(HDC hdc, UNIVERSAL_FONT_ID *pufi)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
UNIVERSAL_FONT_ID ufiTmp;
|
|
XDCOBJ dco(hdc);
|
|
|
|
if(!dco.bValid())
|
|
{
|
|
WARNING("NtGdiRemoveMergefont bogus HDC\n" );
|
|
return FALSE;
|
|
}
|
|
else if (dco.bDisplay())
|
|
{
|
|
WARNING("NtGdiRemoveMergefont: display DC\n" );
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(pufi != NULL, "Try to remove a font wiht pufi == NULL\n");
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(pufi, sizeof(UNIVERSAL_FONT_ID), sizeof(DWORD));
|
|
ufiTmp = *pufi;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
if (!(bRet = dco.bRemoveMergeFont(ufiTmp)))
|
|
{
|
|
WARNING("NtGdiRemoveMergeFont failed on dco.bRemoveMergeFont\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
dco.vUnlockFast();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* INT GreQueryFonts( PUNIVERSAL_FONT_ID, ULONG, PLARGE_INTEGER )
|
|
*
|
|
* History:
|
|
* 5/24/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
INT GreQueryFonts(
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
ULONG nBufferSize,
|
|
PLARGE_INTEGER pTimeStamp
|
|
)
|
|
{
|
|
|
|
PUBLIC_PFTOBJ pfto;
|
|
return(pfto.QueryFonts(pufi,nBufferSize,pTimeStamp));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* PTYPEONEINFO GetTypeOneFontList()
|
|
*
|
|
* This function returns a pointer to a TYPEONEINFO structure that contains
|
|
* a list of file mapping handles and checksums for the Type1 fontst that are
|
|
* installed in the system. This structure also has a reference count and a
|
|
* time stamp coresponding to the last time fonts were added or removed from
|
|
* the system. The reference count is 1 biased meaning that even if no PDEV's
|
|
* a referencing it, it is still 1.
|
|
*
|
|
* History
|
|
* 8-10-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
****************************************************************************/
|
|
|
|
PTYPEONEINFO GetTypeOneFontList()
|
|
{
|
|
UNICODE_STRING UnicodeRoot;
|
|
PTYPEONEINFO InfoReturn = NULL;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
BOOL bCloseRegistry = FALSE;
|
|
NTSTATUS NtStatus;
|
|
PKEY_FULL_INFORMATION InfoBuffer = NULL;
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = NULL;
|
|
ULONG KeyInfoLength;
|
|
HANDLE KeyRegistry;
|
|
|
|
RtlInitUnicodeString(&UnicodeRoot,TYPE1_KEY);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeRoot,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
NtStatus = ZwOpenKey(&KeyRegistry,
|
|
GENERIC_READ,
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Unable to open TYPE1 key\n");
|
|
goto done;
|
|
}
|
|
|
|
bCloseRegistry = TRUE;
|
|
|
|
NtStatus = ZwQueryKey(KeyRegistry,
|
|
KeyFullInformation,
|
|
(PVOID) NULL,
|
|
0,
|
|
&KeyInfoLength );
|
|
|
|
if ((NtStatus != STATUS_BUFFER_OVERFLOW) &&
|
|
(NtStatus != STATUS_BUFFER_TOO_SMALL))
|
|
{
|
|
WARNING("Unable to query TYPE1 key\n");
|
|
goto done;
|
|
}
|
|
|
|
InfoBuffer = (PKEY_FULL_INFORMATION) PALLOCNOZ(KeyInfoLength,'f1tG');
|
|
|
|
if ( !InfoBuffer )
|
|
{
|
|
WARNING("Unable to alloc mem for TYPE1 info\n");
|
|
goto done;
|
|
}
|
|
|
|
NtStatus = ZwQueryKey(KeyRegistry,
|
|
KeyFullInformation,
|
|
InfoBuffer,
|
|
KeyInfoLength,
|
|
&KeyInfoLength );
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Unable to query TYPE1 key\n");
|
|
goto done;
|
|
}
|
|
|
|
// if there aren't any soft TYPE1 fonts installed then just return now.
|
|
|
|
if ( !InfoBuffer->Values )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
|
|
if (gpTypeOneInfo != NULL )
|
|
{
|
|
if ((gpTypeOneInfo->LastWriteTime.LowPart == InfoBuffer->LastWriteTime.LowPart)&&
|
|
(gpTypeOneInfo->LastWriteTime.HighPart == InfoBuffer->LastWriteTime.HighPart))
|
|
{
|
|
// If the times match then increment the ref count and return
|
|
|
|
InfoReturn = gpTypeOneInfo;
|
|
gpTypeOneInfo->cRef += 1;
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
goto done;
|
|
}
|
|
|
|
gpTypeOneInfo->cRef -= 1;
|
|
|
|
// At this point if gTypeOneInfo->cRef > 0 then there is a PDEV using this
|
|
// info still. If gTypeOneInfo->cRef = 0 then it is okay to delete it.
|
|
// Note that this behavior means we must initialize gTypeOneInfo->cRef to 1.
|
|
|
|
if ( !gpTypeOneInfo->cRef )
|
|
{
|
|
VFREEMEM(gpTypeOneInfo);
|
|
}
|
|
|
|
// Whether someone is using it or not, remove pointer to current type one
|
|
// info so that noone else tries to use it.
|
|
|
|
gpTypeOneInfo = NULL;
|
|
}
|
|
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
|
|
ULONG MaxValueName, MaxValueData, TotalData, Values;
|
|
|
|
MaxValueData = ALIGN4(InfoBuffer->MaxValueDataLen);
|
|
Values = InfoBuffer->Values;
|
|
|
|
TotalData = MaxValueData + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
|
|
if( TotalData < MaxValueData ) // overflow
|
|
{
|
|
TotalData = 0;
|
|
} else {
|
|
unsigned long n = sizeof(ULONG) // checksum
|
|
+ (2 * sizeof(WCHAR) * (MAX_PATH+1)) // PFM & PFB paths
|
|
+ sizeof(FONTFILEVIEW); // mapping structs
|
|
if( Values > MAXIMUM_POOL_ALLOC/n // multiply would overflow
|
|
|| TotalData < (TotalData + Values * n) ) // addition would overflow
|
|
TotalData = 0;
|
|
else
|
|
TotalData += Values * n;
|
|
}
|
|
|
|
// now TotalData contains either:
|
|
// MaxValueData + sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
|
|
// (Values * sizeof(ULONG)) + <--- Room for checksums
|
|
// (Values * 2 * sizeof(WCHAR) * (MAX_PATH + 1)) + <--- PFM/PFB paths
|
|
// Values * sizeof(FONTFILEVIEW); <--- room for mapping structs
|
|
// or it contains a zero because of arithmetic overflow in the size
|
|
// calculation
|
|
|
|
PartialInfo = (TotalData == 0) ? NULL
|
|
: (PKEY_VALUE_PARTIAL_INFORMATION) PALLOCNOZ(TotalData,'f1tG');
|
|
|
|
if ( !PartialInfo )
|
|
{
|
|
WARNING("Unable to allocate memory for TYPE1 info\n");
|
|
goto done;
|
|
}
|
|
|
|
BYTE *ValueData;
|
|
PFONTFILEVIEW FontFileViews;
|
|
WCHAR *FullPFM, *FullPFB;
|
|
ULONG *Checksums;
|
|
ULONG SoftFont,Result;
|
|
|
|
ValueData = &(PartialInfo->Data[0]);
|
|
FullPFM = (WCHAR*) &ValueData[MaxValueData];
|
|
FullPFB = &FullPFM[(MAX_PATH+1)*Values];
|
|
Checksums = (ULONG*) &FullPFB[Values*(MAX_PATH+1)];
|
|
|
|
FontFileViews = (PFONTFILEVIEW) &Checksums[Values];
|
|
|
|
for ( SoftFont = 0; SoftFont < Values; SoftFont ++ )
|
|
{
|
|
WCHAR *TmpValueData;
|
|
COUNT SizeOfString;
|
|
|
|
NtStatus = ZwEnumerateValueKey(KeyRegistry,
|
|
SoftFont,
|
|
KeyValuePartialInformation,
|
|
PartialInfo,
|
|
MaxValueData +
|
|
sizeof(KEY_VALUE_PARTIAL_INFORMATION),
|
|
&Result );
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Unable to enumerate TYPE1 keys\n");
|
|
goto done;
|
|
}
|
|
|
|
TmpValueData = (WCHAR*) ValueData;
|
|
TmpValueData = TmpValueData + wcslen(TmpValueData)+1;
|
|
|
|
SizeOfString = wcslen(TmpValueData);
|
|
|
|
if ( SizeOfString > MAX_PATH )
|
|
{
|
|
WARNING("PFM path too long\n");
|
|
goto done;
|
|
}
|
|
|
|
wcscpy(&FullPFM[SoftFont*(MAX_PATH+1)],TmpValueData);
|
|
|
|
TmpValueData += SizeOfString+1;
|
|
|
|
SizeOfString = wcslen(TmpValueData);
|
|
|
|
if ( SizeOfString > MAX_PATH )
|
|
{
|
|
WARNING("PFB path too long\n");
|
|
goto done;
|
|
}
|
|
|
|
wcscpy(&FullPFB[SoftFont*(MAX_PATH+1)],TmpValueData);
|
|
}
|
|
|
|
// Release key at this point. We are about to call off to the spooler
|
|
// which could take a while and shouldn't be holding the key while we do so.
|
|
|
|
ZwCloseKey(KeyRegistry);
|
|
bCloseRegistry = FALSE;
|
|
|
|
ULONG i, ValidatedTotal,TotalSize;
|
|
|
|
|
|
for ( i = 0, ValidatedTotal = TotalSize = 0; i < SoftFont; i++ )
|
|
{
|
|
BOOL bAbleToLoadFont;
|
|
|
|
bAbleToLoadFont = FALSE;
|
|
|
|
// go through all the PFM's and PFB's and expand them to full paths by
|
|
// calling back to the spooler
|
|
|
|
if (GetFontPathName(&FullPFM[i*(MAX_PATH+1)],&FullPFM[i*(MAX_PATH+1)]) &&
|
|
GetFontPathName(&FullPFB[i*(MAX_PATH+1)],&FullPFB[i*(MAX_PATH+1)]))
|
|
{
|
|
// Compute the checksum that we are goine to give to the PSCRIPT
|
|
// driver to stuff into the IFI metrics. We will use the sum
|
|
// of the checksum of both files.
|
|
|
|
FILEVIEW fv;
|
|
RtlZeroMemory( &fv, sizeof(fv) );
|
|
|
|
// Temporarily map a kernel mode view
|
|
|
|
if (bMapFile(&FullPFM[i*(MAX_PATH+1)], &fv, 0, NULL))
|
|
{
|
|
ULONG sum;
|
|
|
|
sum = ComputeFileviewCheckSum(fv.pvKView, fv.cjView);
|
|
vUnmapFile( &fv);
|
|
|
|
// Temporarily map a kernel mode view
|
|
|
|
if (bMapFile(&FullPFB[i*(MAX_PATH+1)], &fv, 0, NULL))
|
|
{
|
|
sum += ComputeFileviewCheckSum(fv.pvKView, fv.cjView);
|
|
|
|
vUnmapFile( &fv);
|
|
|
|
ValidatedTotal += 2;
|
|
TotalSize += (wcslen(&FullPFM[i*(MAX_PATH+1)]) + 1) * sizeof(WCHAR);
|
|
TotalSize += (wcslen(&FullPFB[i*(MAX_PATH+1)]) + 1) * sizeof(WCHAR);
|
|
Checksums[i] = sum;
|
|
bAbleToLoadFont = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bAbleToLoadFont)
|
|
{
|
|
FullPFM[i*(MAX_PATH+1)] = (WCHAR) 0;
|
|
FullPFB[i*(MAX_PATH+1)] = (WCHAR) 0;
|
|
}
|
|
}
|
|
|
|
TotalSize += ValidatedTotal * sizeof(TYPEONEMAP) + sizeof(TYPEONEINFO);
|
|
|
|
PTYPEONEINFO TypeOneInfo;
|
|
WCHAR *StringBuffer;
|
|
|
|
if (!ValidatedTotal)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
TypeOneInfo = (PTYPEONEINFO) PALLOCMEM(TotalSize,'f1tG');
|
|
StringBuffer = (WCHAR*) &TypeOneInfo->aTypeOneMap[ValidatedTotal];
|
|
|
|
if ( !TypeOneInfo )
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
TypeOneInfo->cRef = 1; // must be one so PDEV stuff doesn't deallocate it unless
|
|
// we explicitly set it to 0
|
|
|
|
TypeOneInfo->cNumFonts = ValidatedTotal/2;
|
|
TypeOneInfo->LastWriteTime = InfoBuffer->LastWriteTime;
|
|
|
|
// loop through everything again packing everything tightly together in memory
|
|
// and setting up the FONTFILEVIEW pointers.
|
|
|
|
UINT CurrentFont;
|
|
|
|
for ( i = 0, CurrentFont = 0; i < SoftFont; i ++ )
|
|
{
|
|
if (FullPFM[i*(MAX_PATH+1)] != (WCHAR) 0)
|
|
{
|
|
wcscpy(StringBuffer,&FullPFM[i*(MAX_PATH+1)]);
|
|
TypeOneInfo->aTypeOneMap[CurrentFont].fv.pwszPath = StringBuffer;
|
|
StringBuffer += wcslen(&FullPFM[i*(MAX_PATH+1)]) + 1;
|
|
|
|
wcscpy(StringBuffer,&FullPFB[i*(MAX_PATH+1)]);
|
|
TypeOneInfo->aTypeOneMap[CurrentFont+1].fv.pwszPath = StringBuffer;
|
|
StringBuffer += wcslen(&FullPFB[i*(MAX_PATH+1)]) + 1;
|
|
|
|
// Both the PFM and PFB share the same checksum since they represent
|
|
// the same font file.
|
|
|
|
TypeOneInfo->aTypeOneMap[CurrentFont].Checksum = Checksums[i];
|
|
TypeOneInfo->aTypeOneMap[CurrentFont+1].Checksum = Checksums[i];
|
|
|
|
CurrentFont += 2;
|
|
}
|
|
}
|
|
|
|
ASSERTGDI(CurrentFont == ValidatedTotal,
|
|
"GetTypeOneFontList:CurrentFont != ValidatedTotal\n");
|
|
|
|
// everything should be set up now just our list into
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
|
|
if ( gpTypeOneInfo )
|
|
{
|
|
// looks like someone snuck in before us. that's okay well use their font
|
|
// list and destroy our own
|
|
VFREEMEM(TypeOneInfo);
|
|
}
|
|
else
|
|
{
|
|
gpTypeOneInfo = TypeOneInfo;
|
|
}
|
|
|
|
gpTypeOneInfo->cRef += 1;
|
|
InfoReturn = gpTypeOneInfo;
|
|
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
done:
|
|
|
|
if ( bCloseRegistry )
|
|
{
|
|
ZwCloseKey(KeyRegistry);
|
|
}
|
|
|
|
if ( InfoBuffer )
|
|
{
|
|
VFREEMEM(InfoBuffer);
|
|
}
|
|
|
|
if ( PartialInfo )
|
|
{
|
|
VFREEMEM(PartialInfo);
|
|
}
|
|
|
|
return(InfoReturn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* EngGetType1FontList
|
|
*
|
|
* Routine Description:
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Called by:
|
|
*
|
|
* Return Value:
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY EngGetType1FontList(
|
|
HDEV hdev,
|
|
TYPE1_FONT *pType1Buffer,
|
|
ULONG cjType1Buffer,
|
|
PULONG pulLocalFonts,
|
|
PULONG pulRemoteFonts,
|
|
LARGE_INTEGER *pLastModified
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
PPDEV ppdev = (PPDEV) hdev;
|
|
|
|
if (!ppdev->TypeOneInfo)
|
|
{
|
|
ppdev->TypeOneInfo = GetTypeOneFontList();
|
|
}
|
|
|
|
PREMOTETYPEONENODE RemoteTypeOne = ppdev->RemoteTypeOne;
|
|
|
|
if (ppdev->TypeOneInfo || RemoteTypeOne )
|
|
{
|
|
*pulRemoteFonts = 0;
|
|
|
|
while (RemoteTypeOne)
|
|
{
|
|
*pulRemoteFonts += 1;
|
|
RemoteTypeOne = RemoteTypeOne->pNext;
|
|
}
|
|
|
|
if ( ppdev->TypeOneInfo )
|
|
{
|
|
*pulLocalFonts = ppdev->TypeOneInfo->cNumFonts;
|
|
*pLastModified = *(&ppdev->TypeOneInfo->LastWriteTime);
|
|
}
|
|
else
|
|
{
|
|
*pulLocalFonts = 0;
|
|
pLastModified->LowPart = 0;
|
|
pLastModified->HighPart = 0;
|
|
}
|
|
|
|
// If buffer is NULL then caller is only querying for time stamp
|
|
// and size of buffer.
|
|
|
|
if (pType1Buffer)
|
|
{
|
|
COUNT Font;
|
|
unsigned long buflen =
|
|
(BALLOC_OVERFLOW1((*pulLocalFonts+*pulRemoteFonts),TYPE1_FONT))
|
|
? 0 : (*pulLocalFonts+*pulRemoteFonts) * sizeof(TYPE1_FONT);
|
|
|
|
|
|
if (cjType1Buffer >= buflen && buflen != 0)
|
|
{
|
|
TYPEONEMAP *pTypeOneMap = ppdev->TypeOneInfo->aTypeOneMap;
|
|
|
|
for (Font = 0;
|
|
ppdev->TypeOneInfo && (Font < ppdev->TypeOneInfo->cNumFonts);
|
|
Font++ )
|
|
{
|
|
pType1Buffer[Font].hPFM = (HANDLE)&pTypeOneMap[Font*2].fv;
|
|
pType1Buffer[Font].hPFB = (HANDLE)&pTypeOneMap[Font*2+1].fv;
|
|
pType1Buffer[Font].ulIdentifier = pTypeOneMap[Font*2+1].Checksum;
|
|
}
|
|
|
|
RemoteTypeOne = ppdev->RemoteTypeOne;
|
|
|
|
while ( RemoteTypeOne )
|
|
{
|
|
pType1Buffer[Font].hPFM = (HANDLE) &(RemoteTypeOne->fvPFM);
|
|
pType1Buffer[Font].hPFB = (HANDLE) &(RemoteTypeOne->fvPFB);
|
|
pType1Buffer[Font].ulIdentifier =
|
|
RemoteTypeOne->pDownloadHeader->Type1ID;
|
|
|
|
Font += 1;
|
|
RemoteTypeOne = RemoteTypeOne->pNext;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("GDI:EngGetType1FontList:pType1Buffer is too small.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EngQueryLocalTime()
|
|
*
|
|
* Fill in the ENG_TIME_FIELDS structure with the current local time.
|
|
* Originaly added for postscript
|
|
*
|
|
* History:
|
|
* 07-Feb-1996 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID EngQueryLocalTime( PENG_TIME_FIELDS ptf )
|
|
{
|
|
TIME_FIELDS tf;
|
|
LARGE_INTEGER li;
|
|
|
|
GreQuerySystemTime(&li);
|
|
GreSystemTimeToLocalTime(&li,&li);
|
|
RtlTimeToTimeFields(&li,&tf);
|
|
|
|
ptf->usYear = tf.Year;
|
|
ptf->usMonth = tf.Month;
|
|
ptf->usDay = tf.Day;
|
|
ptf->usHour = tf.Hour;
|
|
ptf->usMinute = tf.Minute;
|
|
ptf->usSecond = tf.Second;
|
|
ptf->usMilliseconds = tf.Milliseconds;
|
|
ptf->usWeekday = tf.Weekday;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL GreGetBaseUFIBits(UNIVERSAL_FONT_ID *pufi, FONTFILEVIEW **ppfv)
|
|
*
|
|
* History:
|
|
* 17-Jan-1997 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL GreGetBaseUFIBits(UNIVERSAL_FONT_ID *pufi, FONTFILEVIEW *pfv)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// base font is not an old fashioned type1 font
|
|
|
|
ASSERTGDI(!UFI_TYPE1_FONT(pufi), "Base MM Font is old fashioned device font\n");
|
|
|
|
// Stabilize the public PFT for mapping.
|
|
|
|
PUBLIC_PFTOBJ pfto(gpPFTPublic);
|
|
|
|
// base mm font will always be added to gpPFTPublic (not to gpPFTPrivate)
|
|
// on the print server machine (look at NtGdiAddRemoteFontsToDC).
|
|
// Therefore, we shall only look in the public table for it
|
|
|
|
PFE *ppfe = ppfeGetPFEFromUFI(pufi,
|
|
FALSE, // public
|
|
FALSE); // do not check the proccess id
|
|
|
|
if (!ppfe)
|
|
return bRet;
|
|
|
|
PFFOBJ pffo(ppfe->pPFF);
|
|
|
|
#if DBG
|
|
COUNT cNumFiles = pffo.cNumFiles();
|
|
ASSERTGDI(cNumFiles == 1, "GreGetBaseUFIBits cNumFiles != 1\n");
|
|
ASSERTGDI(!wcsncmp(pffo.pwszPathname(), L"REMOTE-", 7), "GreGetBaseUFIBits pathname != REMOTE\n");
|
|
#endif
|
|
|
|
// We need to copy this to a buffer since the PFFOBJ could go away after
|
|
// we release the semaphore. TRUE? Not really. The point is that ppfv is
|
|
// only going to be used during a print job while base font is added to DC.
|
|
// That is, only when DC goes away the base font will be removed so that this
|
|
// ppfv will be around for as long as is necessary to service its mm instances
|
|
// that are used in the same job.
|
|
|
|
*pfv = *(pffo.ppfvGet()[0]);
|
|
|
|
ASSERTGDI(pfv->SpoolerPid == W32GetCurrentPID() || gpidSpool == (PW32PROCESS)W32GetCurrentProcess(),
|
|
"GreGetBaseUFIBits, Pid doesn't match\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* NtGdiAddRemoteMMInstanceToDC(
|
|
*
|
|
* History:
|
|
* 17-Jan-1997 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL NtGdiAddRemoteMMInstanceToDC(
|
|
HDC hdc,
|
|
DOWNLOADDESIGNVECTOR *pddv,
|
|
ULONG cjDDV
|
|
)
|
|
{
|
|
|
|
DOWNLOADDESIGNVECTOR ddv;
|
|
BOOL bRet = FALSE;
|
|
FONTFILEVIEW fv;
|
|
|
|
XDCOBJ dco(hdc);
|
|
|
|
if (!dco.bValid())
|
|
return bRet;
|
|
|
|
if (!dco.bDisplay() && (cjDDV <= sizeof(DOWNLOADDESIGNVECTOR)) )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForRead(pddv,cjDDV, sizeof(BYTE));
|
|
RtlCopyMemory(&ddv, pddv, cjDDV);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("GreAddRemoteMMInstanceToDC, bogus ddv\n");
|
|
}
|
|
|
|
// Now get the pointer to the bits of the base mm font.
|
|
// This will only work because the base font has already been installed
|
|
// on the print server. We always first write the bits for the base font
|
|
// to the spool file and then design vectors for all its instances.
|
|
// Consenquently, as we spool, the base font has already been added
|
|
// and its bits live in virtual memory window allocated by
|
|
// NtGdiAddRemoteFontToDC. We now just get the file view for the bits
|
|
|
|
if (GreGetBaseUFIBits(&ddv.ufiBase, &fv))
|
|
{
|
|
PUBLIC_PFTOBJ pfto;
|
|
|
|
UINT offset = ALIGN8(sizeof(FONTFILEVIEW*));
|
|
FONTFILEVIEW** ppfv = (FONTFILEVIEW**)
|
|
PALLOCMEM( sizeof(FONTFILEVIEW) + offset, 'vffG');
|
|
|
|
if (ppfv == NULL)
|
|
{
|
|
WARNING1("NtGdiAddRemoteMMInstanceToDC out of memory\n");
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// CAUTION
|
|
//
|
|
// The PFF cleanup code has intimate knowledge of this
|
|
// code so be sure you synchronize changes in here and there.
|
|
//
|
|
// We are about to create a FONTFILEVIEW that corresponds to
|
|
// a pool image of a font downloaded for metafile printing.
|
|
// This case is signified by setting FONTFILEVIEW::pszPath
|
|
// to zero. This corresponds to a image loaded once.
|
|
|
|
ppfv[0] = (FONTFILEVIEW*)((BYTE *)ppfv + offset);
|
|
|
|
// the following line of code is crucial:
|
|
// since we set ulRegionSize to zero, the code
|
|
// which does unsecure mem will not be executed for instances
|
|
// but only for the base font. However, ppfv will be freed properly.
|
|
|
|
fv.ulRegionSize = 0;
|
|
|
|
// cRefCountFD should be set to or 1, what should it be?
|
|
// It turns out it does not matter because ulRegionSize
|
|
// is set to zero, so that unmap remote fonts is not called on
|
|
// pdv record, only on the base font.
|
|
|
|
fv.cRefCountFD = 0;
|
|
|
|
*(ppfv[0]) = fv;
|
|
|
|
bRet = pfto.bLoadRemoteFonts(dco, ppfv, 1, &ddv.dv, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreAddRemoteMMInstanceToDC bogus HDC,display DC, or cjDDV\n");
|
|
}
|
|
|
|
dco.vUnlockFast();
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
|
|
/*************Public**Routine**************\
|
|
* BOOL GreUnmapMemFont
|
|
*
|
|
* History:
|
|
* Jul-03-97 Xudong Wu [TessieW]
|
|
* Wrote it
|
|
\*******************************************/
|
|
#if 0
|
|
|
|
BOOL GreUnmapMemFont(PVOID pvView)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
NtStatus = MmUnmapViewOfSection(PsGetCurrentProcess(), (PVOID)((PBYTE)pvView - SZDLHEADER));
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Unmapping memory font's view in application's process space failed");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|