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.
3102 lines
98 KiB
3102 lines
98 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: pdevobj.cxx
|
|
*
|
|
* Non-inline methods of PDEVOBJ objects.
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern DRVFN gadrvfnPanning[];
|
|
extern ULONG gcdrvfnPanning;
|
|
|
|
//
|
|
// This flag is TRUE if the default GUI stock font is partially intialized.
|
|
// During stock font initialization there is no display driver and therefore
|
|
// we do not have one of the parameters (vertical DPI) needed to compute
|
|
// the font height. Therefore, we do it when the first display driver is
|
|
// initialized.
|
|
//
|
|
|
|
extern BOOL gbFinishDefGUIFontInit;
|
|
|
|
//
|
|
// This is size of DirectDraw context which we keep in PDEV.
|
|
//
|
|
|
|
extern DWORD gdwDirectDrawContext;
|
|
|
|
// Use this as the default height if LOGFONTs provided by DEVINFO do not
|
|
// specify.
|
|
|
|
#define DEFAULT_POINT_SIZE 12L
|
|
#define DEFAULT_DPI 72L
|
|
|
|
#if ((HT_PATSIZE_2x2 != HTPAT_SIZE_2x2) || \
|
|
(HT_PATSIZE_2x2_M != HTPAT_SIZE_2x2_M) || \
|
|
(HT_PATSIZE_4x4 != HTPAT_SIZE_4x4) || \
|
|
(HT_PATSIZE_4x4_M != HTPAT_SIZE_4x4_M) || \
|
|
(HT_PATSIZE_6x6 != HTPAT_SIZE_6x6) || \
|
|
(HT_PATSIZE_6x6_M != HTPAT_SIZE_6x6_M) || \
|
|
(HT_PATSIZE_8x8 != HTPAT_SIZE_8x8) || \
|
|
(HT_PATSIZE_8x8_M != HTPAT_SIZE_8x8_M) || \
|
|
(HT_PATSIZE_10x10 != HTPAT_SIZE_10x10) || \
|
|
(HT_PATSIZE_10x10_M != HTPAT_SIZE_10x10_M) || \
|
|
(HT_PATSIZE_12x12 != HTPAT_SIZE_12x12) || \
|
|
(HT_PATSIZE_12x12_M != HTPAT_SIZE_12x12_M) || \
|
|
(HT_PATSIZE_14x14 != HTPAT_SIZE_14x14) || \
|
|
(HT_PATSIZE_14x14_M != HTPAT_SIZE_14x14_M) || \
|
|
(HT_PATSIZE_16x16 != HTPAT_SIZE_16x16) || \
|
|
(HT_PATSIZE_16x16_M != HTPAT_SIZE_16x16_M) || \
|
|
(HT_PATSIZE_SUPERCELL != HTPAT_SIZE_SUPERCELL) || \
|
|
(HT_PATSIZE_SUPERCELL_M != HTPAT_SIZE_SUPERCELL_M) || \
|
|
(HT_PATSIZE_USER != HTPAT_SIZE_USER))
|
|
#error * HT_PATSIZE different in winddi.h and ht.h *
|
|
#endif
|
|
|
|
#if ((HT_FLAG_SQUARE_DEVICE_PEL != HIF_SQUARE_DEVICE_PEL) || \
|
|
(HT_FLAG_HAS_BLACK_DYE != HIF_HAS_BLACK_DYE) || \
|
|
(HT_FLAG_ADDITIVE_PRIMS != HIF_ADDITIVE_PRIMS))
|
|
#error * HT_FLAG different in winddi.h and ht.h *
|
|
#endif
|
|
|
|
//
|
|
// Global linked list of all PDEVs in the system.
|
|
//
|
|
|
|
extern "C"
|
|
{
|
|
extern HFASTMUTEX ghfmMemory;
|
|
}
|
|
|
|
|
|
PPDEV gppdevList = NULL;
|
|
PPDEV gppdevTrueType = NULL;
|
|
PPDEV gppdevATMFD = NULL;
|
|
|
|
VOID
|
|
vDeleteBitmapClone(
|
|
SURFOBJ *pso
|
|
);
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bMakeSurface ()
|
|
*
|
|
* Asks the device driver to create a surface for the PDEV. This function
|
|
* can be called even if the PDEV already has a surface.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bMakeSurface()
|
|
{
|
|
TRACE_INIT(("PDEVOBJ::bMakeSurface: ENTERING\n"));
|
|
|
|
BOOL bRet;
|
|
|
|
if (ppdev->pSurface != NULL)
|
|
return(TRUE);
|
|
|
|
HSURF hTemp = (HSURF) 0;
|
|
|
|
// Ask the driver for a surface.
|
|
|
|
PDEVOBJ po((HDEV)ppdev);
|
|
|
|
GreEnterMonitoredSection(ppdev, WD_DEVLOCK);
|
|
hTemp = (*PPFNDRV(po,EnableSurface))(ppdev->dhpdev);
|
|
GreExitMonitoredSection(ppdev, WD_DEVLOCK);
|
|
|
|
if (hTemp == (HSURF) 0)
|
|
{
|
|
WARNING("EnableSurface on device return hsurf 0\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
SURFREF sr(hTemp);
|
|
ASSERTGDI(sr.bValid(),"Bad surface for device");
|
|
|
|
// Mark this as a device surface.
|
|
|
|
sr.ps->vPDEVSurface();
|
|
sr.vKeepIt();
|
|
ppdev->pSurface = sr.ps;
|
|
|
|
// For 1.0 compatibility, set the pSurface iFormat to iDitherFormat. This can
|
|
// be changed to an ASSERT if we no longer wants to support NT 1.0 drivers,
|
|
// which has BMF_DEVICE in the iFormat for device surfaces.
|
|
|
|
if (sr.ps->iFormat() == BMF_DEVICE)
|
|
{
|
|
sr.ps->iFormat(ppdev->devinfo.iDitherFormat);
|
|
ASSERTGDI(ppdev->devinfo.iDitherFormat != BMF_DEVICE,
|
|
"ERROR iformat is hosed\n");
|
|
}
|
|
|
|
// Put the PDEV's palette in the main device surface.
|
|
// Reference count the palette, it has a new user.
|
|
|
|
ppdev->pSurface->ppal(ppdev->ppalSurf);
|
|
|
|
// If this is surface for layered driver, mark it as mirrored surface.
|
|
|
|
if (flGraphicsCaps() & GCAPS_LAYERED)
|
|
{
|
|
sr.ps->vSetMirror();
|
|
}
|
|
|
|
HmgShareLock((HOBJ) ppdev->ppalSurf->hGet(), PAL_TYPE);
|
|
|
|
TRACE_INIT(("PDEVOBJ::bMakeSurface: SUCCESS\n"));
|
|
|
|
// We move the mouse point off-screen in order to set an initial position and
|
|
// to fix a common driver bug, which is to show uninitialized garbage until
|
|
// the first DrvSetPointerShape call occurs.
|
|
|
|
if (bDisplayPDEV())
|
|
{
|
|
GreMovePointer(po.hdev(), -1, -1, MP_PROCEDURAL);
|
|
}
|
|
|
|
// Enable PDEV components.
|
|
|
|
bRet = DxDdEnableDirectDraw(po.hdev(),TRUE);
|
|
|
|
// Filter the driver hooks after DirectDraw has loaded but before we
|
|
// enable sprites, so that the filter can filter DirectX calls and
|
|
// the sprite code gets the filtered result.
|
|
|
|
vFilterDriverHooks();
|
|
|
|
bRet &= bSpEnableSprites(po.hdev());
|
|
|
|
vEnableSynchronize(po.hdev());
|
|
|
|
vNotify(DN_DRAWING_BEGIN, NULL);
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bEnableHalftone(pca)
|
|
*
|
|
* Creates and initializes a device halftone info. The space is allocated
|
|
* by the halftone.dll with heapCreate() and heapAlloc() calls. All
|
|
* the halftone resources are managed by the halftone.dll.
|
|
*
|
|
* History:
|
|
* 07-Nov-1991 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
COLORADJUSTMENT gcaDefault =
|
|
{
|
|
sizeof(COLORADJUSTMENT), // WORD caSize
|
|
0, // WORD caFlags
|
|
ILLUMINANT_DEFAULT, // WORD caIlluminantIndex
|
|
HT_DEF_RGB_GAMMA, // WORD caRedPowerGamma
|
|
HT_DEF_RGB_GAMMA, // WORD caGreenPowerGamma
|
|
HT_DEF_RGB_GAMMA, // WORD caBluePowerGamma
|
|
REFERENCE_BLACK_DEFAULT, // WORD caReferenceBlack
|
|
REFERENCE_WHITE_DEFAULT, // WORD caReferenceWhite
|
|
CONTRAST_ADJ_DEFAULT, // SHORT caContrast
|
|
BRIGHTNESS_ADJ_DEFAULT, // SHORT caBrightness
|
|
COLORFULNESS_ADJ_DEFAULT, // SHORT caColorfulness
|
|
REDGREENTINT_ADJ_DEFAULT, // SHORT caRedGreenTint
|
|
};
|
|
|
|
BOOL PDEVOBJ::bEnableHalftone(PCOLORADJUSTMENT pca)
|
|
{
|
|
ASSERTGDI(pDevHTInfo() == NULL, "bEnableHalftone: pDevHTInfo not null\n");
|
|
|
|
//
|
|
// Create a halftone palette based on the format specified in GDIINFO.
|
|
//
|
|
|
|
PALMEMOBJ palHT;
|
|
if (!palHT.bCreateHTPalette(GdiInfo()->ulHTOutputFormat, GdiInfo()))
|
|
return(FALSE);
|
|
|
|
//
|
|
// Create the device halftone info.
|
|
//
|
|
|
|
HTINITINFO htInitInfo;
|
|
HALFTONEPATTERN HTPat;
|
|
|
|
htInitInfo.Version = HTINITINFO_VERSION;
|
|
htInitInfo.Flags = (WORD)(ppdev->GdiInfo.flHTFlags & 0xFFFF);
|
|
htInitInfo.CMYBitMask8BPP = (BYTE)((ppdev->GdiInfo.flHTFlags &
|
|
HT_FLAG_8BPP_CMY332_MASK) >> 24);
|
|
htInitInfo.bReserved = 0;
|
|
|
|
if (ppdev->GdiInfo.ulHTPatternSize <= HTPAT_SIZE_MAX_INDEX)
|
|
htInitInfo.HTPatternIndex = (BYTE)ppdev->GdiInfo.ulHTPatternSize;
|
|
else
|
|
htInitInfo.HTPatternIndex = HTPAT_SIZE_DEFAULT;
|
|
|
|
PCOLORINFO pci = &GdiInfo()->ciDevice;
|
|
htInitInfo.DevicePowerGamma = (UDECI4)((pci->RedGamma + pci->GreenGamma +
|
|
pci->BlueGamma) / 3);
|
|
htInitInfo.DeviceRGamma = (UDECI4)pci->RedGamma;
|
|
htInitInfo.DeviceGGamma = (UDECI4)pci->GreenGamma;
|
|
htInitInfo.DeviceBGamma = (UDECI4)pci->BlueGamma;
|
|
|
|
htInitInfo.HTCallBackFunction = NULL;
|
|
htInitInfo.pHalftonePattern = NULL;
|
|
htInitInfo.pInputRGBInfo = NULL;
|
|
|
|
if (htInitInfo.HTPatternIndex == HTPAT_SIZE_USER) {
|
|
|
|
if ((ppdev->GdiInfo.cxHTPat >= HT_USERPAT_CX_MIN) &&
|
|
(ppdev->GdiInfo.cxHTPat <= HT_USERPAT_CX_MAX) &&
|
|
(ppdev->GdiInfo.cyHTPat >= HT_USERPAT_CY_MIN) &&
|
|
(ppdev->GdiInfo.cyHTPat <= HT_USERPAT_CY_MAX) &&
|
|
(ppdev->GdiInfo.pHTPatA) &&
|
|
(ppdev->GdiInfo.pHTPatB) &&
|
|
(ppdev->GdiInfo.pHTPatC)) {
|
|
|
|
HTPat.cbSize = sizeof(HALFTONEPATTERN);
|
|
HTPat.Flags = 0;
|
|
HTPat.Width = (WORD)ppdev->GdiInfo.cxHTPat;
|
|
HTPat.Height = (WORD)ppdev->GdiInfo.cyHTPat;
|
|
HTPat.pHTPatA = (LPBYTE)ppdev->GdiInfo.pHTPatA;
|
|
HTPat.pHTPatB = (LPBYTE)ppdev->GdiInfo.pHTPatB;
|
|
HTPat.pHTPatC = (LPBYTE)ppdev->GdiInfo.pHTPatC;
|
|
|
|
htInitInfo.pHalftonePattern = &HTPat;
|
|
|
|
} else {
|
|
|
|
htInitInfo.HTPatternIndex = HTPAT_SIZE_DEFAULT;
|
|
}
|
|
}
|
|
|
|
CIEINFO cie;
|
|
|
|
cie.Red.x = (DECI4)pci->Red.x;
|
|
cie.Red.y = (DECI4)pci->Red.y;
|
|
cie.Red.Y = (DECI4)pci->Red.Y;
|
|
|
|
cie.Green.x = (DECI4)pci->Green.x;
|
|
cie.Green.y = (DECI4)pci->Green.y;
|
|
cie.Green.Y = (DECI4)pci->Green.Y;
|
|
|
|
cie.Blue.x = (DECI4)pci->Blue.x;
|
|
cie.Blue.y = (DECI4)pci->Blue.y;
|
|
cie.Blue.Y = (DECI4)pci->Blue.Y;
|
|
|
|
cie.Cyan.x = (DECI4)pci->Cyan.x;
|
|
cie.Cyan.y = (DECI4)pci->Cyan.y;
|
|
cie.Cyan.Y = (DECI4)pci->Cyan.Y;
|
|
|
|
cie.Magenta.x = (DECI4)pci->Magenta.x;
|
|
cie.Magenta.y = (DECI4)pci->Magenta.y;
|
|
cie.Magenta.Y = (DECI4)pci->Magenta.Y;
|
|
|
|
cie.Yellow.x = (DECI4)pci->Yellow.x;
|
|
cie.Yellow.y = (DECI4)pci->Yellow.y;
|
|
cie.Yellow.Y = (DECI4)pci->Yellow.Y;
|
|
|
|
cie.AlignmentWhite.x = (DECI4)pci->AlignmentWhite.x;
|
|
cie.AlignmentWhite.y = (DECI4)pci->AlignmentWhite.y;
|
|
cie.AlignmentWhite.Y = (DECI4)pci->AlignmentWhite.Y;
|
|
|
|
htInitInfo.pDeviceCIEInfo = &cie;
|
|
|
|
SOLIDDYESINFO DeviceSolidDyesInfo;
|
|
|
|
DeviceSolidDyesInfo.MagentaInCyanDye = (UDECI4)pci->MagentaInCyanDye;
|
|
DeviceSolidDyesInfo.YellowInCyanDye = (UDECI4)pci->YellowInCyanDye;
|
|
DeviceSolidDyesInfo.CyanInMagentaDye = (UDECI4)pci->CyanInMagentaDye;
|
|
DeviceSolidDyesInfo.YellowInMagentaDye = (UDECI4)pci->YellowInMagentaDye;
|
|
DeviceSolidDyesInfo.CyanInYellowDye = (UDECI4)pci->CyanInYellowDye;
|
|
DeviceSolidDyesInfo.MagentaInYellowDye = (UDECI4)pci->MagentaInYellowDye;
|
|
|
|
htInitInfo.pDeviceSolidDyesInfo = &DeviceSolidDyesInfo;
|
|
|
|
htInitInfo.DeviceResXDPI = (WORD)ppdev->GdiInfo.ulLogPixelsX;
|
|
htInitInfo.DeviceResYDPI = (WORD)ppdev->GdiInfo.ulLogPixelsY;
|
|
htInitInfo.DevicePelsDPI = (WORD)ppdev->GdiInfo.ulDevicePelsDPI;
|
|
|
|
if (pca == NULL)
|
|
htInitInfo.DefHTColorAdjustment = gcaDefault;
|
|
else
|
|
htInitInfo.DefHTColorAdjustment = *pca;
|
|
|
|
if (HT_CreateDeviceHalftoneInfo(&htInitInfo,
|
|
(PPDEVICEHALFTONEINFO)&(ppdev->pDevHTInfo)) <= 0L)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
|
ppdev->pDevHTInfo = NULL;
|
|
return(FALSE);
|
|
}
|
|
|
|
// Check if halftone palette is the same as the device palette.
|
|
//
|
|
// For now, don't do display devices because dynamic mode changes may
|
|
// cause their palette to change at any time.
|
|
|
|
vHTPalIsDevPal(FALSE);
|
|
if (!bDisplayPDEV())
|
|
{
|
|
XEPALOBJ palSurf(ppalSurf());
|
|
if (palHT.bEqualEntries(palSurf))
|
|
vHTPalIsDevPal(TRUE);
|
|
}
|
|
|
|
// Keep the halftone palette since this function won't fail.
|
|
|
|
((DEVICEHALFTONEINFO *)pDevHTInfo())->DeviceOwnData = (ULONG_PTR)palHT.hpal();
|
|
palHT.vSetPID(OBJECT_OWNER_PUBLIC);
|
|
palHT.vKeepIt();
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bDisableHalftone()
|
|
*
|
|
* Delete the device halftone info structure.
|
|
*
|
|
* History:
|
|
* 07-Nov-1991 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bDisableHalftone()
|
|
{
|
|
ASSERTGDI((pDevHTInfo() != NULL), "bDisableHalftone: DevHTInfo null\n");
|
|
|
|
DEVICEHALFTONEINFO *pDevHTInfo_ = (DEVICEHALFTONEINFO *)pDevHTInfo();
|
|
|
|
if (fl(PDEV_ALLOCATEDBRUSHES))
|
|
{
|
|
for(int iPat = 0; iPat < HS_DDI_MAX; iPat++)
|
|
{
|
|
bDeleteSurface(ppdev->ahsurf[iPat]);
|
|
}
|
|
}
|
|
|
|
ppdev->pDevHTInfo = NULL;
|
|
|
|
// Delete the halftone palette.
|
|
|
|
BOOL bStatusPal = bDeletePalette((HPAL)pDevHTInfo_->DeviceOwnData);
|
|
BOOL bStatusHT = HT_DestroyDeviceHalftoneInfo(pDevHTInfo_);
|
|
|
|
return(bStatusPal && bStatusHT);
|
|
}
|
|
|
|
ULONG gaaulPat[HS_DDI_MAX][8] = {
|
|
|
|
// Scans have to be DWORD aligned:
|
|
|
|
{ 0x00, // ........ HS_HORIZONTAL 0
|
|
0x00, // ........
|
|
0x00, // ........
|
|
0xff, // ********
|
|
0x00, // ........
|
|
0x00, // ........
|
|
0x00, // ........
|
|
0x00 }, // ........
|
|
|
|
{ 0x08, // ....*... HS_VERTICAL 1
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08 }, // ....*...
|
|
|
|
{ 0x80, // *....... HS_FDIAGONAL 2
|
|
0x40, // .*......
|
|
0x20, // ..*.....
|
|
0x10, // ...*....
|
|
0x08, // ....*...
|
|
0x04, // .....*..
|
|
0x02, // ......*.
|
|
0x01 }, // .......*
|
|
|
|
{ 0x01, // .......* HS_BDIAGONAL 3
|
|
0x02, // ......*.
|
|
0x04, // .....*..
|
|
0x08, // ....*...
|
|
0x10, // ...*....
|
|
0x20, // ..*.....
|
|
0x40, // .*......
|
|
0x80 }, // *.......
|
|
|
|
{ 0x08, // ....*... HS_CROSS 4
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0xff, // ********
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08, // ....*...
|
|
0x08 }, // ....*...
|
|
|
|
{ 0x81, // *......* HS_DIAGCROSS 5
|
|
0x42, // .*....*.
|
|
0x24, // ..*..*..
|
|
0x18, // ...**...
|
|
0x18, // ...**...
|
|
0x24, // ..*..*..
|
|
0x42, // .*....*.
|
|
0x81 } // *......*
|
|
};
|
|
|
|
|
|
/**************************************************************************\
|
|
* PDEVOBJ::bCreateDefaultBrushes()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bCreateDefaultBrushes()
|
|
{
|
|
SIZEL sizl;
|
|
LONG i;
|
|
|
|
sizl.cx = 8;
|
|
sizl.cy = 8;
|
|
|
|
for (i = 0; i < HS_DDI_MAX; i++)
|
|
{
|
|
ppdev->ahsurf[i] = (HSURF) EngCreateBitmap(sizl,
|
|
(LONG) sizeof(ULONG),
|
|
BMF_1BPP,
|
|
BMF_TOPDOWN,
|
|
&gaaulPat[i][0]);
|
|
|
|
if (ppdev->ahsurf[i] == NULL)
|
|
{
|
|
TRACE_INIT(("Failed bCreateDefaultBrushes - BAD !"));
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bCreateHalftoneBrushes()
|
|
*
|
|
* History:
|
|
* The standard patterns for the NT/window has following order
|
|
*
|
|
* Index 0 - Horizontal Line
|
|
* Index 1 - Vertical Line
|
|
* Index 2 - 45 degree line going up
|
|
* Index 3 - 45 degree line going down
|
|
* Index 4 - Horizontal/Vertical cross
|
|
* Index 5 - 45 degree line up/down cross
|
|
* Index 6 - 30 degree line going up
|
|
* Index 7 - 30 degree line going down
|
|
* Index 8 - 0% Lightness (BLACK)
|
|
* Index 9 - 11% Lightness (very light Gray)
|
|
* Index 10 - 22% Lightness
|
|
* Index 11 - 33% Lightness
|
|
* Index 12 - 44% Lightness
|
|
* Index 13 - 56% Lightness
|
|
* Index 14 - 67% Lightness
|
|
* Index 15 - 78% Lightness
|
|
* Index 16 - 89% Lightness
|
|
* Index 17 - 100% Lightness (White)
|
|
* Index 18 - 50% Lightness (GRAY)
|
|
*
|
|
*Return Value:
|
|
*
|
|
* return value is total patterns created, if return value is <= 0 then an
|
|
* error occurred.
|
|
*
|
|
*
|
|
*Author:
|
|
*
|
|
* 10-Mar-1992 Tue 20:30:44 created -by- Daniel Chou (danielc)
|
|
*
|
|
* 24-Nov-1992 -by- Eric Kutter [erick] and DanielChou (danielc)
|
|
* moved from printers\lib
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bCreateHalftoneBrushes()
|
|
{
|
|
STDMONOPATTERN SMP;
|
|
LONG cbPat;
|
|
LONG cb2;
|
|
INT cPatRet;
|
|
|
|
static BYTE HTStdPatIndex[HS_DDI_MAX] = {
|
|
|
|
HT_SMP_HORZ_LINE,
|
|
HT_SMP_VERT_LINE,
|
|
HT_SMP_DIAG_45_LINE_DOWN,
|
|
HT_SMP_DIAG_45_LINE_UP,
|
|
HT_SMP_HORZ_VERT_CROSS,
|
|
HT_SMP_DIAG_45_CROSS
|
|
};
|
|
|
|
// better initialize the halftone stuff if it isn't already
|
|
|
|
if ((pDevHTInfo() == NULL) && !bEnableHalftone(NULL))
|
|
return(FALSE);
|
|
|
|
cbPat = (LONG)sizeof(LPBYTE) * (LONG)(HS_DDI_MAX + 1);
|
|
|
|
// go through all the standard patterns
|
|
|
|
for(cPatRet = 0; cPatRet < HS_DDI_MAX;)
|
|
{
|
|
|
|
// We will using default 0.01" line width and 10 lines per inch
|
|
// halftone default
|
|
|
|
SMP.Flags = SMP_TOPDOWN;
|
|
SMP.ScanLineAlignBytes = BMF_ALIGN_DWORD;
|
|
SMP.PatternIndex = HTStdPatIndex[cPatRet];
|
|
SMP.LineWidth = 8;
|
|
SMP.LinesPerInch = 15;
|
|
|
|
// Get the cx/cy size of the pattern and total bytes required
|
|
// to stored the pattern
|
|
|
|
SMP.pPattern = NULL; /* To find the size */
|
|
|
|
if ((cbPat = HT_CreateStandardMonoPattern((PDEVICEHALFTONEINFO)pDevHTInfo(), &SMP)) <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// create the bitmap
|
|
//
|
|
|
|
DEVBITMAPINFO dbmi;
|
|
|
|
|
|
dbmi.iFormat = BMF_1BPP;
|
|
dbmi.cxBitmap = SMP.cxPels;
|
|
dbmi.cyBitmap = SMP.cyPels;
|
|
dbmi.hpal = (HPALETTE) 0;
|
|
dbmi.fl = BMF_TOPDOWN;
|
|
|
|
SURFMEM SurfDimo;
|
|
|
|
SurfDimo.bCreateDIB(&dbmi, NULL);
|
|
|
|
if (!SurfDimo.bValid())
|
|
{
|
|
break;
|
|
}
|
|
|
|
SurfDimo.vKeepIt();
|
|
SurfDimo.vSetPID(OBJECT_OWNER_PUBLIC);
|
|
|
|
ppdev->ahsurf[cPatRet] = SurfDimo.ps->hsurf();
|
|
SMP.pPattern = (PBYTE)SurfDimo.ps->pvBits();
|
|
|
|
//
|
|
// advance the count now so we clean up as appropriate
|
|
//
|
|
|
|
++cPatRet;
|
|
|
|
// now set the bits
|
|
|
|
if ((cb2 = HT_CreateStandardMonoPattern((PDEVICEHALFTONEINFO)pDevHTInfo(), &SMP)) != cbPat)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we failed, we had better delete what we created.
|
|
|
|
if (cPatRet < HS_DDI_MAX)
|
|
{
|
|
while (cPatRet-- > 0)
|
|
{
|
|
bDeleteSurface(ppdev->ahsurf[cPatRet]);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
setfl(TRUE, PDEV_ALLOCATEDBRUSHES);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* FLONG flRaster(ulTechnology, flGraphicsCaps)
|
|
*
|
|
* Computes the appropriate Win3.1 style 'flRaster' flags for the device
|
|
* given GDIINFO data.
|
|
*
|
|
* History:
|
|
* 1-Feb-1993 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
FLONG flRaster(ULONG ulTechnology, FLONG flGraphicsCaps)
|
|
{
|
|
// Flags Win32 never sets:
|
|
// -----------------------
|
|
//
|
|
// RC_BANDING -- Banding is always transparent to programmer
|
|
// RC_SCALING -- Special scaling support is never required
|
|
// RC_GDI20_OUTPUT -- Win2.0 state blocks in device contexts not supported
|
|
// RC_SAVEBITMAP -- Bitmap saving is transparent and SaveScreenBitmap not
|
|
// exported
|
|
// RC_DEVBITS -- Drivers don't export BitmapBits or SelectBitmap
|
|
|
|
// Flags Win32 always sets:
|
|
// ------------------------
|
|
|
|
FLONG fl = (RC_BIGFONT | // All devices support fonts > 64k
|
|
RC_GDI20_OUTPUT | // We handle most Win 2.0 features
|
|
|
|
// Set that not-terribly-well documented text flag:
|
|
|
|
RC_OP_DX_OUTPUT); // Can do opaque ExtTextOuts with dx array
|
|
|
|
// Line printers and pen plotters can't support any bitmap BitBlt's:
|
|
|
|
if ((ulTechnology != DT_PLOTTER) && (ulTechnology != DT_CHARSTREAM))
|
|
{
|
|
fl |= (RC_BITBLT | // Can transfer bitmaps
|
|
RC_BITMAP64 | // Can support bitmaps > 64k
|
|
RC_DI_BITMAP | // Support SetDIBIts and GetDIBits
|
|
RC_DIBTODEV | // Support SetDIBitsToDevice
|
|
RC_STRETCHBLT | // Support StretchBlts
|
|
RC_STRETCHDIB); // Support SetchDIBits
|
|
}
|
|
|
|
// Printers can't journal FloodFill cals, so only allow raster displays:
|
|
|
|
if (ulTechnology == DT_RASDISPLAY)
|
|
fl |= RC_FLOODFILL;
|
|
|
|
// Set palette flag from capabilities bit:
|
|
|
|
if (flGraphicsCaps & GCAPS_PALMANAGED)
|
|
fl |= RC_PALETTE;
|
|
|
|
return(fl);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* HACK
|
|
*
|
|
*/
|
|
|
|
LPWSTR
|
|
EngGetPrinterDataFileName(
|
|
HDEV hdev)
|
|
{
|
|
|
|
return ((PPDEV)hdev)->pwszDataFile;
|
|
}
|
|
|
|
/*
|
|
*
|
|
* HACK
|
|
*
|
|
*/
|
|
|
|
LPWSTR
|
|
EngGetDriverName(
|
|
HDEV hdev)
|
|
{
|
|
return ((PPDEV)hdev)->pldev->pGdiDriverInfo->DriverName.Buffer;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EngQueryAttribute
|
|
*
|
|
* This is the engine entry point for device drivers to query device
|
|
* attributes.
|
|
*
|
|
* hDev must always be a valid device.
|
|
*
|
|
* This call will return TRUE for success and FALSE for failure.
|
|
*
|
|
* QDA_ACCELERATION_LEVEL:
|
|
* pvIn - ignored
|
|
* pvInSize - ignored
|
|
* pvOut - pointer to DWORD
|
|
* pvOutSize - sizeof(DWORD)
|
|
*
|
|
* The current device acceleration level is returned in pvOut. Please
|
|
* see ??? for a discussion of acceleration levels.
|
|
*
|
|
* NOTE: we should have an enumeration in winddi.h for acceleration
|
|
* levels.
|
|
*
|
|
*
|
|
* History:
|
|
* 07-Nov-1998 -by- Bart House bhouse
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
EngQueryDeviceAttribute(
|
|
HDEV hdev,
|
|
ENG_DEVICE_ATTRIBUTE devAttr,
|
|
VOID * pvIn,
|
|
ULONG ulInSize,
|
|
VOID * pvOut,
|
|
ULONG ulOutSize)
|
|
{
|
|
BOOL bResult = FALSE; // assume failure
|
|
PPDEV ppdev = (PPDEV) hdev;
|
|
|
|
if(pvOut != NULL)
|
|
{
|
|
|
|
switch(devAttr)
|
|
{
|
|
|
|
case QDA_ACCELERATION_LEVEL:
|
|
if(ulOutSize == sizeof(DWORD))
|
|
{
|
|
*((DWORD *) pvOut) = ppdev->dwDriverAccelerationLevel;
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngQueryDeviceAttribute -- bad ulOutSize");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
WARNING("EngQueryDeviceAttribute -- unknown device attribte");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("EngQueryDeviceAttribute -- pvOut is NULL");
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::PDEVOBJ
|
|
*
|
|
* Create a PDEVOBJ based on given HDEV.
|
|
*
|
|
* History:
|
|
* 1-Apr-1998 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// Should be in header to share with icmapi.cxx and ddraw.cxx
|
|
|
|
#define MAX_COLORTABLE 256
|
|
|
|
PDEVOBJ::PDEVOBJ
|
|
(
|
|
HDEV hdevOrg,
|
|
FLONG fl
|
|
)
|
|
{
|
|
GDIFunctionID(PDEVOBJ::PDEVOBJ<clone>);
|
|
|
|
INT i;
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: ENTERING\n"));
|
|
|
|
ppdev = (PDEV *) NULL;
|
|
|
|
PDEVOBJ pdoOrg(hdevOrg);
|
|
|
|
//
|
|
// Validate input.
|
|
//
|
|
// 1) Only GCH_CLONE_DISPLAY supported.
|
|
// 2) hdevOrg should be valid.
|
|
// 3) hdevOrg should be display device.
|
|
//
|
|
if ((fl != GCH_CLONE_DISPLAY) || (!pdoOrg.bValid()) || (!pdoOrg.bDisplayPDEV()))
|
|
{
|
|
WARNING("Failed to validate input parameter\n");
|
|
return;
|
|
}
|
|
|
|
DEVLOCKOBJ dlo(pdoOrg);
|
|
|
|
ppdev = (PDEV *) PALLOCMEM(sizeof(PDEV) - sizeof(DWORD) + gdwDirectDrawContext, 'veDG');
|
|
|
|
if (ppdev == NULL)
|
|
{
|
|
WARNING("Failed allocation of PDEV\n");
|
|
return;
|
|
}
|
|
|
|
PDEV *ppdevOrg = (PDEV *) pdoOrg.hdev();
|
|
|
|
ppdev->pldev = ppdevOrg->pldev;
|
|
ppdev->ppdevParent = ppdev;
|
|
ppdev->ulTag = 'Pdev';
|
|
|
|
PDEVOBJ pdo((HDEV) ppdev);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: Mirroring original hdev info to clone\n"));
|
|
|
|
//
|
|
// Copy fields which can be copied from original.
|
|
//
|
|
|
|
ppdev->pfnDrvSetPointerShape = ppdevOrg->pfnDrvSetPointerShape; // Accelerator
|
|
ppdev->pfnDrvMovePointer = ppdevOrg->pfnDrvMovePointer; // Accelerator
|
|
ppdev->pfnMovePointer = ppdevOrg->pfnMovePointer; // Accelerator
|
|
ppdev->pfnSync = ppdevOrg->pfnSync; // Accelerator
|
|
ppdev->pfnSyncSurface = ppdevOrg->pfnSyncSurface; // Accelerator
|
|
ppdev->pfnSetPalette = ppdevOrg->pfnSetPalette;
|
|
ppdev->pfnNotify = ppdevOrg->pfnNotify;
|
|
|
|
ppdev->dhpdev = ppdevOrg->dhpdev;
|
|
|
|
ppdev->ppalSurf = ppdevOrg->ppalSurf;
|
|
ppdev->devinfo = ppdevOrg->devinfo;
|
|
ppdev->GdiInfo = ppdevOrg->GdiInfo;
|
|
ppdev->hSpooler = ppdevOrg->hSpooler;
|
|
ppdev->pDesktopId = ppdevOrg->pDesktopId;
|
|
ppdev->pGraphicsDevice = ppdevOrg->pGraphicsDevice;
|
|
ppdev->ptlOrigin = ppdevOrg->ptlOrigin;
|
|
|
|
if (ppdevOrg->ppdevDevmode)
|
|
{
|
|
DWORD dwSize = ppdevOrg->ppdevDevmode->dmSize +
|
|
ppdevOrg->ppdevDevmode->dmDriverExtra;
|
|
|
|
ppdev->ppdevDevmode = (PDEVMODEW) PALLOCNOZ(dwSize,GDITAG_DEVMODE);
|
|
|
|
if (ppdev->ppdevDevmode)
|
|
{
|
|
RtlMoveMemory(ppdev->ppdevDevmode,
|
|
ppdevOrg->ppdevDevmode,
|
|
dwSize);
|
|
}
|
|
else
|
|
{
|
|
goto ERROR_RETURN;
|
|
}
|
|
}
|
|
|
|
ppdev->flAccelerated = ppdevOrg->flAccelerated;
|
|
|
|
ppdev->ptlPointer = ppdevOrg->ptlPointer;
|
|
|
|
ppdev->hlfntDefault = ppdevOrg->hlfntDefault;
|
|
ppdev->hlfntAnsiVariable = ppdevOrg->hlfntAnsiVariable;
|
|
ppdev->hlfntAnsiFixed = ppdevOrg->hlfntAnsiFixed;
|
|
|
|
ppdev->pSurface = ppdevOrg->pSurface;
|
|
|
|
for (i = 0; i < HS_DDI_MAX; i++)
|
|
{
|
|
ppdev->ahsurf[i] = ppdevOrg->ahsurf[i];
|
|
}
|
|
|
|
ppdev->pwszDataFile = ppdevOrg->pwszDataFile;
|
|
|
|
if (ppdevOrg->pvGammaRampTable)
|
|
{
|
|
ppdev->pvGammaRampTable = (LPVOID) PALLOCNOZ(
|
|
MAX_COLORTABLE * sizeof(WORD) * 3,
|
|
'mciG');
|
|
|
|
if (ppdev->pvGammaRampTable)
|
|
{
|
|
RtlCopyMemory(ppdev->pvGammaRampTable,
|
|
ppdevOrg->pvGammaRampTable,
|
|
MAX_COLORTABLE * sizeof(WORD) * 3);
|
|
}
|
|
else
|
|
{
|
|
goto ERROR_RETURN;
|
|
}
|
|
}
|
|
|
|
ppdev->sizlMeta = ppdevOrg->sizlMeta;
|
|
ppdev->pfnUnfilteredBitBlt = ppdevOrg->pfnUnfilteredBitBlt;
|
|
ppdev->dwDriverCapableOverride
|
|
= ppdevOrg->dwDriverCapableOverride;
|
|
ppdev->dwDriverAccelerationLevel
|
|
= ppdevOrg->dwDriverAccelerationLevel;
|
|
|
|
RtlCopyMemory(ppdev->apfn,ppdevOrg->apfn,sizeof(ppdev->apfn));
|
|
|
|
//
|
|
// If the DDI is hooked, we want to make sure that we don't copy
|
|
// the Sp function pointers from ppdevOrg, but get the driver function
|
|
// pointers from the SPRITESTATE instead. See vSpHook for details.
|
|
//
|
|
|
|
if (pdoOrg.pSpriteState()->bHooked)
|
|
{
|
|
SPRITESTATE *pState = pdoOrg.pSpriteState();
|
|
|
|
ppdev->apfn[INDEX_DrvStrokePath] = (PFN) pState->pfnStrokePath;
|
|
ppdev->apfn[INDEX_DrvFillPath] = (PFN) pState->pfnFillPath;
|
|
ppdev->apfn[INDEX_DrvBitBlt] = (PFN) pState->pfnBitBlt;
|
|
ppdev->apfn[INDEX_DrvCopyBits] = (PFN) pState->pfnCopyBits;
|
|
ppdev->apfn[INDEX_DrvStretchBlt] = (PFN) pState->pfnStretchBlt;
|
|
ppdev->apfn[INDEX_DrvTextOut] = (PFN) pState->pfnTextOut;
|
|
ppdev->apfn[INDEX_DrvLineTo] = (PFN) pState->pfnLineTo;
|
|
ppdev->apfn[INDEX_DrvTransparentBlt] = (PFN) pState->pfnTransparentBlt;
|
|
ppdev->apfn[INDEX_DrvAlphaBlend] = (PFN) pState->pfnAlphaBlend;
|
|
ppdev->apfn[INDEX_DrvPlgBlt] = (PFN) pState->pfnPlgBlt;
|
|
ppdev->apfn[INDEX_DrvGradientFill] = (PFN) pState->pfnGradientFill;
|
|
ppdev->apfn[INDEX_DrvStretchBltROP] = (PFN) pState->pfnStretchBltROP;
|
|
ppdev->apfn[INDEX_DrvSaveScreenBits] = (PFN) pState->pfnSaveScreenBits;
|
|
ppdev->apfn[INDEX_DrvDrawStream] = (PFN) pState->pfnDrawStream;
|
|
}
|
|
|
|
//
|
|
// Set up the fields can not just copied from original.
|
|
//
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: Setup new hdev info for clone\n"));
|
|
|
|
//
|
|
// PDEVOBJ.cPdevRefs and PDEVOBJ.cPdevOpenRefs.
|
|
//
|
|
|
|
ppdev->cPdevRefs = 1; // Number of clients.
|
|
ppdev->cPdevOpenRefs = 1; // OpenCount
|
|
|
|
//
|
|
// Setup flags.
|
|
//
|
|
// We only inherit the flag which still has valid in clone, too.
|
|
//
|
|
|
|
ppdev->fl = ppdevOrg->fl & (PDEV_DISPLAY |
|
|
PDEV_GAMMARAMP_TABLE |
|
|
PDEV_META_DEVICE |
|
|
PDEV_DRIVER_PUNTED_CALL);
|
|
|
|
//
|
|
// PDEVOBJ.hsemDevLock
|
|
//
|
|
|
|
if ((ppdev->hsemDevLock = GreCreateSemaphore()) == NULL)
|
|
goto ERROR_RETURN;
|
|
|
|
//
|
|
// we now load font info only when needed. The driver still must have
|
|
// setup the default font information.
|
|
//
|
|
|
|
bGotFonts(FALSE);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: Create pointer semaphore\n"));
|
|
|
|
//
|
|
// PDEVOBJ.hsemPoiner
|
|
//
|
|
|
|
ppdev->hsemPointer = GreCreateSemaphore();
|
|
if (!ppdev->hsemPointer)
|
|
goto ERROR_RETURN;
|
|
|
|
//
|
|
// Enable DirectDraw (for clone).
|
|
//
|
|
|
|
if (!DxDdEnableDirectDraw(pdo.hdev(),FALSE))
|
|
goto ERROR_RETURN;
|
|
|
|
//
|
|
// Adjust original pdev as cloned.
|
|
//
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: Processing onto new hdev as clone\n"));
|
|
|
|
//
|
|
// Mark new pdev as clone.
|
|
//
|
|
|
|
pdo.bCloneDriver(TRUE);
|
|
|
|
//
|
|
// NOTE: AFTER HERE, ERROR_RETURN COULD NOT BE ALLOWED
|
|
//
|
|
|
|
#ifdef DDI_WATCHDOG
|
|
|
|
//
|
|
// !!! Hack - since watchdog creation requires access to DEVICE_OBJECT now
|
|
// we have to delay watchdog creation till hCreateHDEV where PDEV gets associated
|
|
// with DEVICE_OBJECT. It would be nice to have it here though.
|
|
//
|
|
|
|
ppdev->pWatchdogData = NULL;
|
|
|
|
#endif // DDI_WATCHDOG
|
|
|
|
// PDEVOBJ.ppdevNext.
|
|
//
|
|
// Finally, everything done, so put this on global list.
|
|
//
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: Insert new hdev to global list\n"));
|
|
|
|
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
|
|
|
|
ppdev->ppdevNext = gppdevList;
|
|
gppdevList = ppdev;
|
|
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: LEAVING with success\n"));
|
|
|
|
return;
|
|
|
|
ERROR_RETURN:
|
|
|
|
if (ppdev->hsemDevLock)
|
|
{
|
|
GreDeleteSemaphore(ppdev->hsemDevLock);
|
|
}
|
|
|
|
if (ppdev->ppdevDevmode)
|
|
{
|
|
VFREEMEM(ppdev->ppdevDevmode);
|
|
}
|
|
|
|
if (ppdev->pvGammaRampTable)
|
|
{
|
|
VFREEMEM(ppdev->pvGammaRampTable);
|
|
}
|
|
|
|
DxDdDisableDirectDraw(pdo.hdev(),FALSE);
|
|
|
|
VFREEMEM(ppdev);
|
|
|
|
ppdev = (PDEV *) NULL;
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ_: LEAVING with error\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::PDEVOBJ
|
|
*
|
|
* Allocates and initializes a PDEV, i.e. takes the reference count from
|
|
* zero to one.
|
|
*
|
|
* The object must be completely constructed, otherwise completely destroyed.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
PDEVOBJ::PDEVOBJ
|
|
(
|
|
PLDEV pldev,
|
|
PDEVMODEW pdriv,
|
|
PWSZ pwszLogAddr,
|
|
PWSZ pwszDataFile,
|
|
PWSZ pwszDeviceName,
|
|
HANDLE hSpool,
|
|
PREMOTETYPEONENODE pRemoteTypeOne,
|
|
PGDIINFO pMirroredGdiInfo,
|
|
PDEVINFO pMirroredDevInfo,
|
|
BOOL bUMPD,
|
|
DWORD dwCapableOverride,
|
|
ULONG dwAccelerationLevel
|
|
)
|
|
{
|
|
GDIFunctionID(PDEVOBJ::PDEVOBJ);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: ENTERING\n"));
|
|
|
|
if (bUMPD)
|
|
{
|
|
ppdev = (PDEV *) EngAllocMem(FL_ZERO_MEMORY,sizeof(PDEV) - sizeof(DWORD) + gdwDirectDrawContext, 'veDG');
|
|
}
|
|
else
|
|
{
|
|
ppdev = (PDEV *) PALLOCMEM(sizeof(PDEV) - sizeof(DWORD) + gdwDirectDrawContext, 'veDG');
|
|
}
|
|
|
|
if (ppdev == NULL)
|
|
{
|
|
WARNING("Failed allocation of PDEV\n");
|
|
return;
|
|
}
|
|
|
|
ppdev->ppdevParent = ppdev;
|
|
ppdev->pldev = pldev;
|
|
ppdev->ulTag = 'Pdev';
|
|
ppdev->dwDriverCapableOverride = dwCapableOverride;
|
|
ppdev->dwDriverAccelerationLevel = dwAccelerationLevel;
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: Calling driver to initialize PDEV\n"));
|
|
|
|
PDEVOBJ pdo((HDEV) ppdev);
|
|
|
|
//
|
|
// Create semaphores so the device can be locked.
|
|
//
|
|
|
|
if (ppdev->pldev->ldevType != LDEV_FONT)
|
|
{
|
|
ppdev->hsemDevLock = GreCreateSemaphore();
|
|
if (!ppdev->hsemDevLock)
|
|
goto ERROR_RETURN;
|
|
}
|
|
|
|
if ( dwCapableOverride & DRIVER_NOT_CAPABLE_GDI )
|
|
{
|
|
//
|
|
// If the driver is not capable of GDI, then it is similar to
|
|
// DRIVER_ACCELERATIONS_NONE. Reset the level we stored in PDEV
|
|
//
|
|
ppdev->dwDriverAccelerationLevel = DRIVER_ACCELERATIONS_NONE;
|
|
}
|
|
|
|
//
|
|
// fill in the dispatch table. If we've been told to allow no
|
|
// driver accelerations, redirect everything to the panning driver,
|
|
// which handles this case.
|
|
//
|
|
if ((ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) &&
|
|
(dwDriverAccelerationsLevel() == DRIVER_ACCELERATIONS_NONE))
|
|
{
|
|
//
|
|
// Fill in function table with Panning driver versions.
|
|
//
|
|
bFillFunctionTable(gadrvfnPanning,
|
|
gcdrvfnPanning,
|
|
&ppdev->apfn[0]);
|
|
}
|
|
else
|
|
{
|
|
RtlMoveMemory(&(ppdev->apfn[0]),
|
|
&(ppdev->pldev->apfn[0]),
|
|
sizeof(PFN) * INDEX_LAST);
|
|
}
|
|
|
|
//
|
|
// if we are doing a ResetDC then we need to transfer over remote type 1
|
|
// fonts from previous PDEV
|
|
//
|
|
|
|
ppdev->RemoteTypeOne = pRemoteTypeOne;
|
|
|
|
//
|
|
// HACK - temporary
|
|
//
|
|
|
|
ppdev->pwszDataFile = pwszDataFile;
|
|
|
|
//
|
|
// If this is a Mirroring driver, we want to pass in the global GDIINFO
|
|
// and DEVINFO as returned by the primary driver.
|
|
//
|
|
|
|
if (pMirroredGdiInfo)
|
|
{
|
|
ppdev->GdiInfo = *pMirroredGdiInfo;
|
|
ppdev->devinfo = *pMirroredDevInfo;
|
|
}
|
|
|
|
//
|
|
// Ask the device driver to create a PDEV.
|
|
//
|
|
|
|
UMDHPDEV *pUMdhpdev;
|
|
|
|
pdo.bUMPD(bUMPD);
|
|
|
|
if (bUMPD)
|
|
{
|
|
//
|
|
// NOTE: we store the umpdCookie in dhpdev so that we can pass the
|
|
// cookie to the UM UMPD layer during DrvEnablePDEV
|
|
//
|
|
ppdev->dhpdev = (DHPDEV) pldev->umpdCookie;
|
|
}
|
|
|
|
ppdev->dhpdev = pdo.EnablePDEV (
|
|
pdriv, // Driver Data.
|
|
pwszLogAddr, // Logical Address.
|
|
HS_DDI_MAX, // Count of standard patterns.
|
|
ppdev->ahsurf, // Buffer for standard patterns
|
|
sizeof(GDIINFO), // Size of GdiInfo
|
|
&ppdev->GdiInfo, // Buffer for GdiInfo
|
|
sizeof(DEVINFO), // Number of bytes in devinfo.
|
|
&ppdev->devinfo, // Device info.
|
|
(HDEV)ppdev, // Data File
|
|
pwszDeviceName, // Device Name
|
|
hSpool); // Base driver handle
|
|
|
|
if (ppdev->dhpdev)
|
|
{
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: PDEV initialized by the driver\n"));
|
|
|
|
if (ppdev->pldev->ldevType != LDEV_FONT)
|
|
{
|
|
//
|
|
// Make sure that units are in MicroMeters for HorzSize, VertSize
|
|
//
|
|
|
|
if ( (LONG)ppdev->GdiInfo.ulHorzSize <= 0 )
|
|
{
|
|
if ( (LONG)ppdev->GdiInfo.ulHorzSize == 0)
|
|
{
|
|
// Calculate the ulHorzSize using Default DPI.
|
|
// Width in mm = (ulHorzRes / DEFAULT_DPI) * 25.4
|
|
|
|
ppdev->GdiInfo.ulHorzSize = (254 *
|
|
(LONG)ppdev->GdiInfo.ulHorzRes) / (10*DEFAULT_DPI);
|
|
}
|
|
else
|
|
ppdev->GdiInfo.ulHorzSize = (ULONG)(-(LONG)ppdev->GdiInfo.ulHorzSize);
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulHorzSize *= 1000;
|
|
}
|
|
|
|
if ( (LONG)ppdev->GdiInfo.ulVertSize <= 0 )
|
|
{
|
|
if ( (LONG)ppdev->GdiInfo.ulVertSize == 0)
|
|
{
|
|
// Calculate the ulVertSize using Default DPI.
|
|
// Height in mm = (ulVertRes / DEFAULT_DPI) * 25.4
|
|
|
|
ppdev->GdiInfo.ulVertSize = (254 *
|
|
(LONG)ppdev->GdiInfo.ulVertRes) / (10*DEFAULT_DPI);
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulVertSize = (ULONG)(-(LONG)ppdev->GdiInfo.ulVertSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulVertSize *= 1000;
|
|
}
|
|
|
|
//
|
|
// For compatibility, all displays will have constant style
|
|
// values (plus this helps us because we know the values won't
|
|
// change asynchronously because of dynamic mode changes):
|
|
//
|
|
|
|
if (ppdev->GdiInfo.ulTechnology == DT_RASDISPLAY)
|
|
{
|
|
ppdev->GdiInfo.xStyleStep = 1;
|
|
ppdev->GdiInfo.yStyleStep = 1;
|
|
ppdev->GdiInfo.denStyleStep = 3;
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
if (ppdev->GdiInfo.xStyleStep == 0)
|
|
WARNING("Device gave xStyleStep of 0");
|
|
if (ppdev->GdiInfo.yStyleStep == 0)
|
|
WARNING("Device gave yStyleStep of 0");
|
|
if (ppdev->GdiInfo.denStyleStep == 0)
|
|
WARNING("Device gave denStyleStep of 0");
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Compute the appropriate raster flags:
|
|
//
|
|
|
|
ppdev->GdiInfo.flRaster = flRaster(ppdev->GdiInfo.ulTechnology,
|
|
ppdev->devinfo.flGraphicsCaps);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: Creating the default palette\n"));
|
|
|
|
//
|
|
// The default palette is stored in devinfo in the pdev.
|
|
// This will be the palette we use for the main surface enabled.
|
|
//
|
|
|
|
ASSERTGDI(ppdev->devinfo.hpalDefault != 0,
|
|
"ERROR_RETURN devinfo.hpalDefault invalid");
|
|
|
|
{
|
|
EPALOBJ palDefault(ppdev->devinfo.hpalDefault);
|
|
|
|
ASSERTGDI(palDefault.bValid(), "ERROR_RETURN hpalDefault invalid");
|
|
|
|
//
|
|
// Bug #68071: display drivers often set the ulPrimaryOrder
|
|
// field wrong (because of wrong sample code we gave them),
|
|
// which causes red to be switched with blue in halftone
|
|
// colors. We fix this by ignoring the ulPrimaryOrder that they
|
|
// pass us and instead compute it from the Palette.
|
|
//
|
|
// 19-Mar-1999 Fri 12:10:22 updated -by- Daniel Chou (danielc)
|
|
// Many ohter drivers also set ulPrimaryOrder wrong when the
|
|
// surface format >= 16BPP, here we should check for all
|
|
// devices, not just display, so we removed following line
|
|
// that only check for the display. This make it check on
|
|
// every pdev.
|
|
//
|
|
// if (ppdev->GdiInfo.ulTechnology == DT_RASDISPLAY)
|
|
//
|
|
|
|
{
|
|
if (!(palDefault.bIsIndexed()))
|
|
{
|
|
//
|
|
// 6 possibilities here: to be safe we should account for all of them.
|
|
// This code can probably be made simpler if we assume that the
|
|
// values of the PRIMARY_ORDER_xxx constants won't change, but it's
|
|
// not that big a deal.
|
|
//
|
|
if ((palDefault.flRed() > palDefault.flGre()) &&
|
|
(palDefault.flRed() > palDefault.flBlu()))
|
|
{
|
|
if (palDefault.flGre() > palDefault.flBlu())
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_ABC;
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_ACB;
|
|
}
|
|
}
|
|
else if ((palDefault.flGre() > palDefault.flRed()) &&
|
|
(palDefault.flGre() > palDefault.flBlu()))
|
|
{
|
|
if (palDefault.flRed() > palDefault.flBlu())
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_BAC;
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_BCA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Blue must be greatest (leftmost)
|
|
if (palDefault.flRed() > palDefault.flGre())
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_CAB;
|
|
}
|
|
else
|
|
{
|
|
ppdev->GdiInfo.ulPrimaryOrder = PRIMARY_ORDER_CBA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ppdev->GdiInfo.flRaster & RC_PALETTE)
|
|
{
|
|
//
|
|
// Attempt to make it palette managed.
|
|
//
|
|
if(!CreateSurfacePal(palDefault,
|
|
PAL_MANAGED,
|
|
ppdev->GdiInfo.ulNumColors,
|
|
ppdev->GdiInfo.ulNumPalReg))
|
|
{
|
|
goto ERROR_RETURN;
|
|
}
|
|
}
|
|
|
|
ppalSurf(palDefault.ppalGet());
|
|
|
|
//
|
|
// Leave a reference count of 1 on this palette.
|
|
//
|
|
|
|
palDefault.ppalSet(NULL);
|
|
}
|
|
|
|
//
|
|
// if the driver didn't fill in the brushes, we'll do it.
|
|
//
|
|
// if it's a display driver, we'll overwrite its brushes with our
|
|
// own, regardless of whether it already filled in the brushes or
|
|
// not. Note that it's okay even if a display driver filled in
|
|
// these values -- the driver already had to keep its own copy of
|
|
// the handles and will clean them up at DrvDisablePDEV time.
|
|
// Supplying our own defaults also simplifies GreDynamicModeChange.
|
|
//
|
|
|
|
if ( (ppdev->ahsurf[0] == NULL) ||
|
|
(ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) ||
|
|
(ppdev->pldev->ldevType == LDEV_DEVICE_MIRROR) )
|
|
{
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: Creating brushes dor the driver\n"));
|
|
|
|
if (ppdev->pldev->ldevType == LDEV_DEVICE_PRINTER)
|
|
{
|
|
if (!bCreateHalftoneBrushes())
|
|
goto ERROR_RETURN;
|
|
}
|
|
else
|
|
{
|
|
// WINBUG #55204 2-1-2000 bhouse Look into whether we leak default brushes
|
|
//
|
|
// Andre Vachon
|
|
// 6-6-95 Kernel mode cleanup
|
|
//
|
|
// The old behaviour is the call the halftoneBrushes function
|
|
// It ends up in a bunch of very complex halftoning code that I have
|
|
// no idea what it does.
|
|
// For now, to clean up drivers in kernel mode, replace this call
|
|
// with a simple function that will create the 6 bitmaps just
|
|
// like display drivers did.
|
|
|
|
// Where do these ever get cleaned up?!? I see where the
|
|
// halftone brushes get cleaned up, but not these.
|
|
|
|
if (!bCreateDefaultBrushes())
|
|
goto ERROR_RETURN;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the hSpooler first
|
|
//
|
|
|
|
hSpooler(hSpool);
|
|
|
|
//
|
|
// Create a semaphore of the mouse pointer
|
|
// (only for the driver will handle cursor)
|
|
//
|
|
|
|
if ( (ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) ||
|
|
(ppdev->pldev->ldevType == LDEV_DEVICE_META) ||
|
|
(ppdev->pldev->ldevType == LDEV_DEVICE_MIRROR) )
|
|
{
|
|
//
|
|
// Mouse pointer accelerators.
|
|
//
|
|
|
|
ppdev->pfnDrvMovePointer =
|
|
(PFN_DrvMovePointer) PPFNDRV(pdo,MovePointer);
|
|
ppdev->pfnDrvSetPointerShape =
|
|
(PFN_DrvSetPointerShape) PPFNDRV(pdo,SetPointerShape);
|
|
|
|
//
|
|
// Init fmPointer
|
|
//
|
|
|
|
SEMOBJ so(ghsemDriverMgmt);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: Create pointer semaphore\n"));
|
|
|
|
ppdev->hsemPointer = GreCreateSemaphore();
|
|
if (!ppdev->hsemPointer)
|
|
goto ERROR_RETURN;
|
|
|
|
//
|
|
// Mark the PDEV as a display.
|
|
//
|
|
|
|
ppdev->fl |= PDEV_DISPLAY;
|
|
}
|
|
|
|
ppdev->pfnSetPalette = PPFNDRV(pdo, SetPalette);
|
|
ppdev->pfnSync = PPFNDRV(pdo, Synchronize);
|
|
ppdev->pfnSyncSurface = PPFNDRV(pdo, SynchronizeSurface);
|
|
ppdev->pfnNotify = PPFNDRV(pdo, Notify);
|
|
|
|
//
|
|
// we now load font info only when needed. The driver still must have
|
|
// setup the default font information.
|
|
//
|
|
|
|
bGotFonts(FALSE);
|
|
|
|
//
|
|
// If any of the LOGFONTs in DEVINFO do not specify a height,
|
|
// substitute the default.
|
|
//
|
|
|
|
LONG lHeightDefault = (DEFAULT_POINT_SIZE * ppdev->GdiInfo.ulLogPixelsY) / POINTS_PER_INCH ;
|
|
ENUMLOGFONTEXDVW elfw;
|
|
|
|
if ( ppdev->devinfo.lfDefaultFont.lfHeight == 0 )
|
|
ppdev->devinfo.lfDefaultFont.lfHeight = lHeightDefault;
|
|
|
|
if ( ppdev->devinfo.lfAnsiVarFont.lfHeight == 0 )
|
|
ppdev->devinfo.lfAnsiVarFont.lfHeight = lHeightDefault;
|
|
|
|
if ( ppdev->devinfo.lfAnsiFixFont.lfHeight == 0 )
|
|
ppdev->devinfo.lfAnsiFixFont.lfHeight = lHeightDefault;
|
|
|
|
//
|
|
// Create LFONTs from the LOGFONTs in the DEVINFO.
|
|
// the LOGFONTs should become EXTLOGFONTWs
|
|
//
|
|
|
|
vConvertLogFontW(&elfw, &(ppdev->devinfo.lfDefaultFont));
|
|
|
|
#ifdef FE_SB
|
|
// We are doing away with the concept of default device fonts for display
|
|
// drivers since it doesnt make sense. Assuming this change gets approved
|
|
// I will remove these before SUR ships.
|
|
|
|
if ( ppdev->GdiInfo.ulTechnology == DT_RASDISPLAY )
|
|
{
|
|
ppdev->hlfntDefault = STOCKOBJ_SYSFONT;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if ((ppdev->hlfntDefault
|
|
= (HLFONT) hfontCreate(&elfw,
|
|
LF_TYPE_DEVICE_DEFAULT,
|
|
LF_FLAG_STOCK,
|
|
NULL)) == HLFONT_INVALID)
|
|
{
|
|
ppdev->hlfntDefault = STOCKOBJ_SYSFONT;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set to public.
|
|
//
|
|
|
|
if (!GreSetLFONTOwner(ppdev->hlfntDefault, OBJECT_OWNER_PUBLIC))
|
|
{
|
|
//
|
|
// If it failed, get rid of the LFONT and resort to System font.
|
|
//
|
|
|
|
bDeleteFont(ppdev->hlfntDefault, TRUE);
|
|
ppdev->hlfntDefault = STOCKOBJ_SYSFONT;
|
|
}
|
|
}
|
|
}
|
|
|
|
vConvertLogFontW(&elfw, &(ppdev->devinfo.lfAnsiVarFont));
|
|
|
|
if ((ppdev->hlfntAnsiVariable
|
|
= (HLFONT) hfontCreate(&elfw,
|
|
LF_TYPE_ANSI_VARIABLE,
|
|
LF_FLAG_STOCK,
|
|
NULL)) == HLFONT_INVALID)
|
|
{
|
|
ppdev->hlfntAnsiVariable = STOCKOBJ_SYSFONT;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set to public.
|
|
//
|
|
|
|
if (!GreSetLFONTOwner(ppdev->hlfntAnsiVariable, OBJECT_OWNER_PUBLIC))
|
|
{
|
|
//
|
|
// If it failed, get rid of the LFONT and resort to System font.
|
|
//
|
|
|
|
bDeleteFont(ppdev->hlfntAnsiVariable, TRUE);
|
|
ppdev->hlfntAnsiVariable = STOCKOBJ_SYSFONT;
|
|
}
|
|
}
|
|
|
|
vConvertLogFontW(&elfw, &(ppdev->devinfo.lfAnsiFixFont));
|
|
|
|
if ((ppdev->hlfntAnsiFixed
|
|
= (HLFONT) hfontCreate(&elfw,
|
|
LF_TYPE_ANSI_FIXED,
|
|
LF_FLAG_STOCK,
|
|
NULL)) == HLFONT_INVALID)
|
|
{
|
|
ppdev->hlfntAnsiFixed = STOCKOBJ_SYSFIXEDFONT;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set to public.
|
|
//
|
|
|
|
if (!GreSetLFONTOwner(ppdev->hlfntAnsiFixed, OBJECT_OWNER_PUBLIC))
|
|
{
|
|
//
|
|
// If it failed, get rid of the LFONT and resort to System Fixed font.
|
|
//
|
|
|
|
bDeleteFont(ppdev->hlfntAnsiFixed, TRUE);
|
|
ppdev->hlfntAnsiFixed = STOCKOBJ_SYSFIXEDFONT;
|
|
}
|
|
}
|
|
|
|
#ifdef DRIVER_DEBUG
|
|
LFONTOBJ lfo1(ppdev->hlfntDefault);
|
|
DbgPrint("GRE!PDEVOBJ(): Device default font\n");
|
|
if (lfo1.bValid())
|
|
{
|
|
lfo1.vDump();
|
|
}
|
|
DbgPrint("GRE!PDEVOBJ(): Ansi variable font\n");
|
|
LFONTOBJ lfo2(ppdev->hlfntAnsiVariable);
|
|
if (lfo2.bValid())
|
|
{
|
|
lfo2.vDump();
|
|
}
|
|
DbgPrint("GRE!PDEVOBJ(): Ansi fixed font\n");
|
|
LFONTOBJ lfo3(ppdev->hlfntAnsiFixed);
|
|
if (lfo3.bValid())
|
|
{
|
|
lfo3.vDump();
|
|
}
|
|
#endif
|
|
//
|
|
// (see bInitDefaultGuiFont() in stockfnt.cxx)
|
|
//
|
|
// If we haven't yet computed the adjusted height of the
|
|
// DEFAULT_GUI_FONT stock object, do so now. We couldn't do
|
|
// this during normal stock font initialization because the
|
|
// display driver had not yet been loaded.
|
|
//
|
|
|
|
if ( gbFinishDefGUIFontInit &&
|
|
(ppdev->pldev->ldevType == LDEV_DEVICE_DISPLAY) )
|
|
{
|
|
LFONTOBJ lfo(STOCKOBJ_DEFAULTGUIFONT);
|
|
|
|
if (lfo.bValid())
|
|
{
|
|
lfo.plfw()->lfHeight = -(LONG)((lfo.plfw()->lfHeight * ppdev->GdiInfo.ulLogPixelsY + 36) / 72);
|
|
}
|
|
|
|
gbFinishDefGUIFontInit = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the PDEV fields.
|
|
//
|
|
|
|
ppdev->cPdevRefs = 1;
|
|
ppdev->cPdevOpenRefs = 1;
|
|
|
|
//
|
|
// Before adding a display PDEV to the PDEV list, make sure it's
|
|
// disabled. We do this to protect against GreFlush walking the
|
|
// PDEV list and calling the driver before we've even finished calling
|
|
// DrvEnableSurface. We mark the PDEV as enabled when all initialization
|
|
// is complete.
|
|
//
|
|
|
|
if (pdo.bDisplayPDEV())
|
|
{
|
|
pdo.bDisabled(TRUE);
|
|
|
|
// Once the pdev has been disabled we can safely update
|
|
// magic colors in an indexed palette. DrvEnableMDEV will
|
|
// update the palette when the display is reenabled.
|
|
vResetSurfacePalette(hdev());
|
|
}
|
|
|
|
//
|
|
// Just stick it at the start of the list.
|
|
// Make sure this list is protected by the driver semaphore
|
|
//
|
|
|
|
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
|
|
|
|
ppdev->ppdevNext = gppdevList;
|
|
gppdevList = ppdev;
|
|
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
|
|
TRACE_INIT(("PDEVOBJ::PDEVOBJ: list of display pdevs %08lx\n", gppdevList));
|
|
|
|
//
|
|
// NOTE after this point, the object will be "permanent" and will
|
|
// end up being destroyed by the destructor
|
|
//
|
|
|
|
#ifdef DDI_WATCHDOG
|
|
|
|
//
|
|
// !!! Hack - since watchdog creation requires access to DEVICE_OBJECT now
|
|
// we have to delay watchdog creation till hCreateHDEV where PDEV gets associated
|
|
// with DEVICE_OBJECT. It would be nice to have it here though.
|
|
//
|
|
|
|
ppdev->pWatchdogData = NULL;
|
|
|
|
#endif // DDI_WATCHDOG
|
|
|
|
//
|
|
// Inform the driver that the PDEV is complete.
|
|
//
|
|
|
|
pdo.CompletePDEV(ppdev->dhpdev,hdev());
|
|
|
|
//
|
|
// We will return with success indicated by a non-NULL ppdev.
|
|
//
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
WARNING("Device failed DrvEnablePDEV\n");
|
|
goto ERROR_RETURN;
|
|
}
|
|
|
|
ERROR_RETURN:
|
|
|
|
if (ppdev->hsemDevLock)
|
|
{
|
|
GreDeleteSemaphore(ppdev->hsemDevLock);
|
|
}
|
|
|
|
if (ppdev->pDevHTInfo != NULL)
|
|
{
|
|
bDisableHalftone();
|
|
}
|
|
|
|
#if defined(_WIN64)
|
|
vDeleteWOW64HTPATSIZEUSERAllocations();
|
|
#endif
|
|
|
|
if (!bUMPD)
|
|
{
|
|
VFREEMEM(ppdev);
|
|
}
|
|
else
|
|
{
|
|
EngFreeMem(ppdev);
|
|
}
|
|
|
|
ppdev = (PDEV *) NULL;
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::cFonts()
|
|
*
|
|
* History:
|
|
* 3-Feb-1994 -by- Gerrit van Wingerden
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG PDEVOBJ::cFonts()
|
|
{
|
|
ULONG_PTR id;
|
|
|
|
//
|
|
// see if the device already told us how many fonts it has
|
|
//
|
|
|
|
if (ppdev->devinfo.cFonts == (ULONG)-1)
|
|
{
|
|
PDEVOBJ pdo(hdev());
|
|
|
|
//
|
|
// if not query the device to see how many there are
|
|
//
|
|
|
|
if (PPFNDRV(pdo,QueryFont) != NULL)
|
|
{
|
|
ppdev->devinfo.cFonts = (ULONG)(ULONG_PTR)(*PPFNDRV(pdo,QueryFont))(dhpdev(),0,0,&id);
|
|
}
|
|
else
|
|
{
|
|
ppdev->devinfo.cFonts = 0;
|
|
}
|
|
}
|
|
|
|
return(ppdev->devinfo.cFonts);
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bGetDeviceFonts()
|
|
*
|
|
* History:
|
|
* 27-Jul-1992 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bGetDeviceFonts()
|
|
{
|
|
|
|
ASSERTGDI(!bGotFonts(),"PDEVOBJ::bGetDeviceFonts - already gotten\n");
|
|
|
|
//
|
|
// mark that we have gotten the fonts.
|
|
//
|
|
|
|
bGotFonts(TRUE);
|
|
|
|
//
|
|
// need an ldevobj for calling the device
|
|
//
|
|
|
|
PDEVOBJ pdo(hdev());
|
|
|
|
//
|
|
// compute the number of device fonts
|
|
//
|
|
|
|
cFonts();
|
|
|
|
//
|
|
// If there are any device fonts, load the device fonts into the public PFT table.
|
|
//
|
|
|
|
if (ppdev->devinfo.cFonts)
|
|
{
|
|
DEVICE_PFTOBJ pfto; // get the device font table
|
|
if (!pfto.bLoadFonts(this))
|
|
{
|
|
WARNING("PDEVOBJ(): couldn't load device fonts\n");
|
|
ppdev->devinfo.cFonts = 0;
|
|
}
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* FilteredBitBlt()
|
|
*
|
|
* This call allows only simple PATCOPY blts down to the driver; the rest
|
|
* are handled by GDI.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL FilteredBitBlt
|
|
(
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
SURFOBJ *psoMsk,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc,
|
|
POINTL *pptlMsk,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrush,
|
|
ROP4 rop4
|
|
)
|
|
{
|
|
PFN_DrvBitBlt pfnBitBlt = EngBitBlt;
|
|
|
|
// Allow only solid color blts and SRCCOPY blts to be accelerated:
|
|
|
|
if ((rop4 == 0xcccc) ||
|
|
((rop4 == 0xf0f0) && (pbo->iSolidColor != 0xffffffff)))
|
|
{
|
|
PDEVOBJ po(psoDst->hdev);
|
|
pfnBitBlt = po.ppdev->pfnUnfilteredBitBlt;
|
|
}
|
|
|
|
return(pfnBitBlt(psoDst, psoSrc, psoMsk, pco, pxlo, prclDst, pptlSrc,
|
|
pptlMsk, pbo, pptlBrush, rop4));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PDEVOBJ::vFilterDriverHooks()
|
|
*
|
|
* Disables driver functionality as appropriate. This routine is used to
|
|
* disable buggy functionality in third-party drivers.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vFilterDriverHooks()
|
|
{
|
|
SYSTEM_GDI_DRIVER_INFORMATION* pGdiDriverInfo;
|
|
LPWSTR pDriverName;
|
|
ULONG ulDriverVersion;
|
|
SURFACE* pSurface;
|
|
DWORD dwLevel;
|
|
DWORD dwOverride;
|
|
|
|
pGdiDriverInfo = ppdev->pldev->pGdiDriverInfo;
|
|
pSurface = ppdev->pSurface;
|
|
|
|
// Only do this for real drivers.
|
|
|
|
if (pGdiDriverInfo == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ulDriverVersion = ppdev->pldev->ulDriverVersion;
|
|
|
|
// Make 'pDriverName' point after the last backslash in the fully
|
|
// qualified driver name:
|
|
|
|
pDriverName = wcsrchr(pGdiDriverInfo->DriverName.Buffer, L'\\');
|
|
|
|
if (pDriverName != NULL)
|
|
pDriverName++;
|
|
else
|
|
pDriverName = pGdiDriverInfo->DriverName.Buffer;
|
|
|
|
if (!_wcsicmp(pDriverName, L"stbv128.dll"))
|
|
{
|
|
// The STB nVidia driver started falling around build 1796.
|
|
// It falls over in the driver on calls from DrawCaptionButtons/
|
|
// BitBltSysBmp/NtGdiBitBlt. It appears to have a problem when
|
|
// compatible bitmaps are used while DirectDraw is enabled. As
|
|
// of build 1796, we changed DirectDraw so that it initializes
|
|
// the driver a boot time instead of when the first DirectX
|
|
// application is started. This appears to have exposed a bug
|
|
// in the driver with compatible bitmaps while DirectDraw is
|
|
// enabled.
|
|
// Note: The driver we tested where this problem occured is
|
|
// STBV128.dll, version(ulDriverVersion) 131072
|
|
// Note: we also tried to disable DrvEnableDirectDraw. But it seems
|
|
// this is not the right fix. The crash occured as well.
|
|
|
|
ppdev->apfn[INDEX_DrvCreateDeviceBitmap] = NULL;
|
|
}
|
|
else if (!_wcsicmp(pDriverName, L"s3disp.dll"))
|
|
{
|
|
// Bug#178375, NT4 driver s3disp crashes on SetPointShape(). It
|
|
// sometimes scans past the end of the pointer buffer.
|
|
|
|
ppdev->apfn[INDEX_DrvSetPointerShape] = NULL;
|
|
}
|
|
else if ((!_wcsicmp(pDriverName, L"rrctrl1.dll")) ||
|
|
(!_wcsicmp(pDriverName, L"rrctrl2.dll")) ||
|
|
(!_wcsicmp(pDriverName, L"rrctrl3.dll")) ||
|
|
(!_wcsicmp(pDriverName, L"rrctrl4.dll")) ||
|
|
(!_wcsicmp(pDriverName, L"rrctrl5.dll")) ||
|
|
(!_wcsicmp(pDriverName, L"rrctrl6.dll")))
|
|
{
|
|
// Bug#333453, Quarterdeck/Symantec Rapid Remote driver tries
|
|
// to hook all functionality exported by real display driver,
|
|
// but doesn't support the new NT5 functions. Limit the driver
|
|
// to >= level 2 accelerations (which also disables DFBs, so
|
|
// we don't need to worry about them hooking unsupported functions
|
|
// there as well).
|
|
|
|
if (dwDriverAccelerationsLevel() < 2)
|
|
vSetDriverAccelerationsLevel(2);
|
|
}
|
|
|
|
if (bDisplayPDEV())
|
|
{
|
|
dwLevel = dwDriverAccelerationsLevel();
|
|
|
|
dwOverride = dwDriverCapableOverride();
|
|
|
|
if ( dwOverride & DRIVER_NOT_CAPABLE_GDI )
|
|
{
|
|
// If the driver is not capable of GDI, then it is similar to
|
|
// DRIVER_ACCELERATIONS_NONE. Reset the level we stored in PDEV
|
|
|
|
dwLevel = DRIVER_ACCELERATIONS_NONE;
|
|
|
|
vSetDriverAccelerationsLevel(dwLevel);
|
|
}
|
|
|
|
if (dwLevel < DRIVER_ACCELERATIONS_NONE)
|
|
{
|
|
if (dwLevel >= 1)
|
|
{
|
|
// Disable hardware pointers and device bitmaps:
|
|
|
|
ppdev->apfn[INDEX_DrvSetPointerShape] = NULL;
|
|
ppdev->apfn[INDEX_DrvCreateDeviceBitmap] = NULL;
|
|
}
|
|
if (dwLevel >= 2)
|
|
{
|
|
// Disable the more sophisticated GDI drawing routines:
|
|
|
|
pSurface->flags(pSurface->flags() & ~(HOOK_STRETCHBLT |
|
|
HOOK_PLGBLT |
|
|
HOOK_FILLPATH |
|
|
HOOK_STROKEANDFILLPATH |
|
|
HOOK_LINETO |
|
|
HOOK_STRETCHBLTROP |
|
|
HOOK_TRANSPARENTBLT |
|
|
HOOK_ALPHABLEND |
|
|
HOOK_GRADIENTFILL));
|
|
}
|
|
if (dwLevel >= 3)
|
|
{
|
|
// Disable all DirectDraw and Direct3D accelerations:
|
|
//
|
|
// Handle by DxDdSetAccelLeve().
|
|
}
|
|
if (dwLevel >= 4)
|
|
{
|
|
// The only GDI accelerations we allow here are the base-line
|
|
// GDI accelerations: DrvTextOut, DrvBitBlt, DrvCopyBits, and
|
|
// DrvStrokePath.
|
|
//
|
|
// NOTE: We also specifically allow DrvMovePointer and
|
|
// GCAPS_PANNING in case the driver is panning the
|
|
// display. (It would be bad if the display doesn't
|
|
// pan when the user enables safe mode!)
|
|
|
|
pSurface->flags(pSurface->flags() & (SURF_FLAGS |
|
|
HOOK_COPYBITS |
|
|
HOOK_BITBLT |
|
|
HOOK_TEXTOUT |
|
|
HOOK_SYNCHRONIZE |
|
|
HOOK_STROKEPATH));
|
|
|
|
ppdev->devinfo.flGraphicsCaps &= (GCAPS_PALMANAGED |
|
|
GCAPS_MONO_DITHER |
|
|
GCAPS_COLOR_DITHER |
|
|
GCAPS_PANNING |
|
|
GCAPS_LAYERED);
|
|
|
|
ppdev->devinfo.flGraphicsCaps2 &= (GCAPS2_SYNCFLUSH |
|
|
GCAPS2_SYNCTIMER);
|
|
|
|
ppdev->apfn[INDEX_DrvSaveScreenBits] = NULL;
|
|
ppdev->apfn[INDEX_DrvEscape] = NULL;
|
|
ppdev->apfn[INDEX_DrvDrawEscape] = NULL;
|
|
ppdev->apfn[INDEX_DrvResetPDEV] = NULL;
|
|
ppdev->apfn[INDEX_DrvSetPixelFormat] = NULL;
|
|
ppdev->apfn[INDEX_DrvDescribePixelFormat] = NULL;
|
|
ppdev->apfn[INDEX_DrvSwapBuffers] = NULL;
|
|
|
|
// Use filtered Blt function.
|
|
|
|
ppdev->pfnUnfilteredBitBlt
|
|
= (PFN_DrvBitBlt) ppdev->apfn[INDEX_DrvBitBlt];
|
|
ppdev->apfn[INDEX_DrvBitBlt] = (PFN) FilteredBitBlt;
|
|
}
|
|
|
|
if ( dwOverride & DRIVER_NOT_CAPABLE_OPENGL )
|
|
{
|
|
// Disable OpenGL routines here
|
|
|
|
ppdev->apfn[INDEX_DrvSetPixelFormat] = NULL;
|
|
ppdev->apfn[INDEX_DrvDescribePixelFormat] = NULL;
|
|
ppdev->apfn[INDEX_DrvSwapBuffers] = NULL;
|
|
}
|
|
|
|
//
|
|
// Disable all escapes.
|
|
//
|
|
|
|
if ( dwOverride & DRIVER_NOT_CAPABLE_ESCAPE )
|
|
{
|
|
ppdev->apfn[INDEX_DrvEscape] = NULL;
|
|
ppdev->apfn[INDEX_DrvDrawEscape] = NULL;
|
|
}
|
|
|
|
// Call DirectDraw to set accel level.
|
|
|
|
DxDdSetAccelLevel(hdev(),dwLevel,dwOverride);
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(dwLevel == 5,
|
|
"No-accelerations flag should be modified to reflect change");
|
|
|
|
// This case was handled by loading the panning driver.
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PDEVOBJ::vProfileDriver()
|
|
*
|
|
* Profiles the driver to determine what accelerations it supports.
|
|
*
|
|
* Note that for the multi-mon PDEV, this returns the acceleration
|
|
* capabilities of the primary monitor.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#define PROFILE_DIMENSION 40
|
|
|
|
VOID PDEVOBJ::vProfileDriver()
|
|
{
|
|
DEVBITMAPINFO dbmi;
|
|
EBLENDOBJ eBlendObj;
|
|
CLIPOBJ coClip;
|
|
SURFACE* psurfScreen;
|
|
BRUSHOBJ boTransparent;
|
|
BOOL b;
|
|
HSURF hsurf;
|
|
RECTL rclBlt;
|
|
|
|
// We only profile display devices. We could actually do this for
|
|
// printer devices as well, but we would have to re-clear the surface
|
|
// after we did our drawing to it.
|
|
|
|
if (!bDisplayPDEV())
|
|
return;
|
|
|
|
DEVLOCKOBJ dlo(*this);
|
|
|
|
psurfScreen = pSurface();
|
|
|
|
XEPALOBJ palScreen(ppalSurf());
|
|
XEPALOBJ palRGB(gppalRGB);
|
|
XEPALOBJ palDefault(ppalDefault);
|
|
|
|
// We create the surface fairly big to try and get past drivers that
|
|
// create device surfaces only for 'large' bitmaps. To test the
|
|
// driver, we only have to blt a thin strip, though.
|
|
|
|
rclBlt.left = 0;
|
|
rclBlt.top = 0;
|
|
rclBlt.right = 16;
|
|
rclBlt.bottom = 1;
|
|
|
|
// Fake up a trivial clip object:
|
|
|
|
RtlZeroMemory(&coClip, sizeof(coClip));
|
|
coClip.iDComplexity = DC_TRIVIAL;
|
|
coClip.rclBounds = rclBlt;
|
|
|
|
// Ignore any random stuff the driver might have set. We're going
|
|
// to verify for ourselves what they support!
|
|
|
|
GdiInfo()->flShadeBlend = 0;
|
|
|
|
// Check whatever we can using a 32bpp surface:
|
|
|
|
{
|
|
SURFMEM SurfDimo;
|
|
EXLATEOBJ xlo32To32;
|
|
EXLATEOBJ xloScreenTo32;
|
|
EXLATEOBJ xlo32ToScreen;
|
|
|
|
// Test for per-pixel alpha acceleration.
|
|
|
|
dbmi.iFormat = BMF_32BPP;
|
|
dbmi.hpal = palRGB.hpal();
|
|
dbmi.cxBitmap = PROFILE_DIMENSION;
|
|
dbmi.cyBitmap = PROFILE_DIMENSION;
|
|
dbmi.fl = BMF_TOPDOWN;
|
|
|
|
if (SurfDimo.bCreateDIB(&dbmi, NULL))
|
|
{
|
|
if ((xlo32To32.bInitXlateObj(NULL, DC_ICM_OFF, palRGB, palRGB,
|
|
palDefault, palDefault, 0, 0, 0)) &&
|
|
(xloScreenTo32.bInitXlateObj(NULL, DC_ICM_OFF, palScreen, palRGB,
|
|
palDefault, palDefault, 0, 0, 0)) &&
|
|
(xlo32ToScreen.bInitXlateObj(NULL, DC_ICM_OFF, palRGB, palScreen,
|
|
palDefault, palDefault, 0, 0, 0)))
|
|
{
|
|
eBlendObj.BlendFunction.BlendOp = AC_SRC_OVER;
|
|
eBlendObj.BlendFunction.BlendFlags = 0;
|
|
eBlendObj.BlendFunction.AlphaFormat = AC_SRC_ALPHA;
|
|
eBlendObj.BlendFunction.SourceConstantAlpha = 0xff;
|
|
eBlendObj.pxloSrcTo32 = xlo32To32.pxlo();
|
|
eBlendObj.pxloDstTo32 = xloScreenTo32.pxlo();
|
|
eBlendObj.pxlo32ToDst = xlo32ToScreen.pxlo();
|
|
|
|
vDriverPuntedCall(FALSE);
|
|
|
|
b = PPFNGET(*this, AlphaBlend, psurfScreen->flags())
|
|
(psurfScreen->pSurfobj(),
|
|
SurfDimo.ps->pSurfobj(),
|
|
&coClip,
|
|
xlo32ToScreen.pxlo(),
|
|
&rclBlt,
|
|
&rclBlt,
|
|
&eBlendObj);
|
|
|
|
if ((b) && (!bDriverPuntedCall()))
|
|
{
|
|
// WARNING("----- Per-pixel accelerated\n");
|
|
GdiInfo()->flShadeBlend |= SB_PIXEL_ALPHA;
|
|
vAccelerated(ACCELERATED_PIXEL_ALPHA);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note that since we didn't apply 'vKeepIt()', the SURFMEM and
|
|
// EXLATEOBJ destructors will clean up.
|
|
}
|
|
|
|
// Check whatever we can using a compatible surface:
|
|
|
|
hsurf = hsurfCreateCompatibleSurface(hdev(),
|
|
psurfScreen->iFormat(),
|
|
0,
|
|
PROFILE_DIMENSION,
|
|
PROFILE_DIMENSION,
|
|
TRUE);
|
|
if (hsurf)
|
|
{
|
|
SURFREF sr(hsurf);
|
|
ASSERTGDI(sr.bValid(), "Driver returned invalid surface");
|
|
|
|
EXLATEOBJ xloScreenToScreen;
|
|
EXLATEOBJ xloScreenTo32;
|
|
EXLATEOBJ xlo32ToScreen;
|
|
|
|
if ((xloScreenToScreen.bInitXlateObj(NULL, DC_ICM_OFF, palScreen, palScreen,
|
|
palDefault, palDefault, 0, 0, 0)) &&
|
|
(xloScreenTo32.bInitXlateObj(NULL, DC_ICM_OFF, palScreen, palRGB,
|
|
palDefault, palDefault, 0, 0, 0)) &&
|
|
(xlo32ToScreen.bInitXlateObj(NULL, DC_ICM_OFF, palRGB, palScreen,
|
|
palDefault, palDefault, 0, 0, 0)))
|
|
{
|
|
// Test for constant-alpha acceleration.
|
|
|
|
eBlendObj.BlendFunction.BlendOp = AC_SRC_OVER;
|
|
eBlendObj.BlendFunction.BlendFlags = 0;
|
|
eBlendObj.BlendFunction.AlphaFormat = 0;
|
|
eBlendObj.BlendFunction.SourceConstantAlpha = 0x85;
|
|
eBlendObj.pxloSrcTo32 = xloScreenTo32.pxlo();
|
|
eBlendObj.pxloDstTo32 = xloScreenTo32.pxlo();
|
|
eBlendObj.pxlo32ToDst = xlo32ToScreen.pxlo();
|
|
|
|
vDriverPuntedCall(FALSE);
|
|
|
|
b = PPFNGET(*this, AlphaBlend, psurfScreen->flags())
|
|
(psurfScreen->pSurfobj(),
|
|
sr.ps->pSurfobj(),
|
|
&coClip,
|
|
xloScreenToScreen.pxlo(),
|
|
&rclBlt,
|
|
&rclBlt,
|
|
&eBlendObj);
|
|
|
|
if ((b) && (!bDriverPuntedCall()))
|
|
{
|
|
// WARNING("----- Constant alpha accelerated\n");
|
|
GdiInfo()->flShadeBlend |= SB_CONST_ALPHA;
|
|
vAccelerated(ACCELERATED_CONSTANT_ALPHA);
|
|
}
|
|
}
|
|
|
|
// Test for transparent blt acceleration.
|
|
|
|
boTransparent.iSolidColor = 1;
|
|
boTransparent.flColorType = 0;
|
|
|
|
vDriverPuntedCall(FALSE);
|
|
|
|
b = PPFNGET(*this, TransparentBlt, psurfScreen->flags())
|
|
(psurfScreen->pSurfobj(),
|
|
sr.ps->pSurfobj(),
|
|
NULL,
|
|
NULL,
|
|
&rclBlt,
|
|
&rclBlt,
|
|
1,
|
|
NULL);
|
|
|
|
if ((b) && (!bDriverPuntedCall()))
|
|
{
|
|
// WARNING("----- Transparent blt accelerated\n");
|
|
vAccelerated(ACCELERATED_TRANSPARENT_BLT);
|
|
}
|
|
}
|
|
|
|
// Cleanup.
|
|
|
|
bDeleteSurface(hsurf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PDEVOBJ::vDisableSurface()
|
|
*
|
|
* Disables the surface for the pdev.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* cutype The CLEANUPTYPE parameter (default value CLEANUP_NONE)
|
|
* is used specify special processing during process cleanup
|
|
* and session cleanup.
|
|
*
|
|
* It may be one of the following values:
|
|
*
|
|
* Value: Description
|
|
*
|
|
* CLEANUP_NONE Default. No special processing.
|
|
*
|
|
* CLEANUP_PROCESS The process cleanup code is used to do
|
|
* special handling of UMPD; during process
|
|
* cleanup it is not necessary or desirable
|
|
* to callback to user-mode to delete
|
|
* user-mode resources.
|
|
*
|
|
* CLEANUP_SESSION The session cleanup (i.e., hydra shutdown)
|
|
* code does special handling of HMGR
|
|
* objects deleted previously by session
|
|
* cleanup code, but for which stale pointer
|
|
* may exist in the PDEV.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vDisableSurface(CLEANUPTYPE cutype)
|
|
{
|
|
TRACE_INIT(("PDEVOBJ::vDisableSurface: ENTERING\n"));
|
|
|
|
//
|
|
// Locate the LDEV.
|
|
//
|
|
|
|
PDEVOBJ pdo(hdev());
|
|
|
|
//
|
|
// Disable the surface. Note we don't have to
|
|
// fix up the palette because it doesn't get
|
|
// reference counted when put in the palette.
|
|
//
|
|
|
|
//
|
|
// On clone PDEV, those stuff never be enabled.
|
|
//
|
|
|
|
if (!bCloneDriver())
|
|
{
|
|
vDisableSynchronize(hdev());
|
|
}
|
|
|
|
vSpDisableSprites(hdev(), cutype);
|
|
|
|
//
|
|
// Notify DirectDraw to be disabled.
|
|
//
|
|
|
|
DxDdDisableDirectDraw(hdev(),!bCloneDriver());
|
|
|
|
if (ppdev->pSurface != NULL)
|
|
{
|
|
SURFREF su(ppdev->pSurface);
|
|
|
|
ppdev->pSurface = NULL;
|
|
|
|
//
|
|
// Cannot call user-mode driver to delete surface if the user-mode
|
|
// process is gone (i.e., during process or session cleanup).
|
|
//
|
|
|
|
if (!pdo.bUMPD() || (cutype == CLEANUP_NONE))
|
|
{
|
|
su.vUnreference();
|
|
|
|
(*PPFNDRV(pdo,DisableSurface))(ppdev->dhpdev);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we are here, then this is process or session cleanup
|
|
// and the PDEV is a user-mode driver. Even though the user-mode
|
|
// portions of the surface are cleaned up as part of the user-mode
|
|
// cleanup, we still need to delete the kernel-mode portion of the
|
|
// surface.
|
|
//
|
|
|
|
su.bDeleteSurface(cutype);
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("PDEVOBJ::vDisableSurface: LEAVING\n"));
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::vReferencePdev()
|
|
*
|
|
* Adds a reference to the PDEV.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vReferencePdev()
|
|
{
|
|
GDIFunctionID(PDEVOBJ::vReferencePdev);
|
|
|
|
SEMOBJ so(ghsemDriverMgmt);
|
|
|
|
ppdev->cPdevRefs++;
|
|
}
|
|
|
|
extern "C" void vUnmapRemoteFonts(FONTFILEVIEW *);
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* VOID vMarkSurfacesWithHDEV.
|
|
*
|
|
* Sets hdev of all surfaces in Handle table which reference the PDEV passed
|
|
* in to 0.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID vMarkSurfacesWithHDEV(PDEV *ppdev)
|
|
{
|
|
SURFACE *pSurface = NULL;
|
|
HOBJ hobj = 0;
|
|
|
|
MLOCKFAST mlo; // Take HandleManager lock so HmgSafeNextObjt can be called
|
|
|
|
while (pSurface = (SURFACE*)HmgSafeNextObjt(hobj,SURF_TYPE))
|
|
{
|
|
hobj = (HOBJ) pSurface->hGet();
|
|
|
|
if (pSurface->hdev() == (HDEV)ppdev)
|
|
{
|
|
KdPrint(("WARNING: Surface (%p) is owned by HDEV (%p). This HDEV is going to be freed\n", pSurface, ppdev));
|
|
pSurface->hdev((HDEV)0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::vUnreferencePdev()
|
|
*
|
|
* Removes a reference to the PDEV. Deletes the PDEV if all references are
|
|
* gone.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* cutype The CLEANUPTYPE parameter (default value CLEANUP_NONE)
|
|
* is used specify special processing during process cleanup
|
|
* and session cleanup.
|
|
*
|
|
* It may be one of the following values:
|
|
*
|
|
* Value: Description
|
|
*
|
|
* CLEANUP_NONE Default. No special processing.
|
|
*
|
|
* CLEANUP_PROCESS The process cleanup code is used to do
|
|
* special handling of UMPD; during process
|
|
* cleanup it is not necessary or desirable
|
|
* to callback to user-mode to delete
|
|
* user-mode resources.
|
|
*
|
|
* CLEANUP_SESSION The session cleanup (i.e., hydra
|
|
* shutdown) code does special handling of
|
|
* HMGR objects deleted previously by session
|
|
* cleanup code, but for which stale pointer
|
|
* may exist in the PDEV (for example, palettes).
|
|
*
|
|
* Note: special session cleanup handling is usually only needed for HMGR
|
|
* objects for which the PDEV has cached a pointer. Objects referenced
|
|
* via a handle are safe if they are locked via the HMGR table (if the
|
|
* object has already been deleted, then the handle is invalid and the
|
|
* lock attempt will fail).
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vUnreferencePdev(CLEANUPTYPE cutype)
|
|
{
|
|
GDIFunctionID(PDEVOBJ::vUnreferencePdev);
|
|
|
|
HANDLE hSpooler = NULL;
|
|
ULONG cPdevRefs;
|
|
BOOL bUMPD = ppdev->fl & PDEV_UMPD;
|
|
|
|
//
|
|
// Decrement reference count and remove from list if last reference.
|
|
// This must be done under the protection of the driver mgmt semaphore.
|
|
//
|
|
|
|
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
|
|
|
|
cPdevRefs = --(ppdev->cPdevRefs);
|
|
|
|
if (cPdevRefs == 0)
|
|
{
|
|
TRACE_INIT(("PDEVOBJ::vCommonDelete: destroying a PDEV\n"));
|
|
|
|
//
|
|
// Delete it from the list.
|
|
//
|
|
|
|
if (gppdevList == ppdev)
|
|
{
|
|
gppdevList = ppdev->ppdevNext;
|
|
}
|
|
else
|
|
{
|
|
PDEV *pp;
|
|
|
|
for (pp = gppdevList; pp != NULL; pp = pp->ppdevNext)
|
|
{
|
|
if (pp->ppdevNext == ppdev)
|
|
{
|
|
pp->ppdevNext = ppdev->ppdevNext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// If this is DDML driver, make sure one other PDEV referecnes
|
|
// this PDEV as parent.
|
|
//
|
|
|
|
if (bMetaDriver())
|
|
{
|
|
PDEV *pp;
|
|
|
|
for (pp = gppdevList; pp != NULL; pp = pp->ppdevNext)
|
|
{
|
|
if (pp->ppdevParent == ppdev)
|
|
{
|
|
WARNING("Deleting parent PDEV which still used\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
GreReleaseSemaphoreEx(ghsemDriverMgmt);
|
|
|
|
//
|
|
// If last reference, delete the PDEV and its resources. We do this
|
|
// outside of the driver mgmt semaphore because it could cause a
|
|
// deadlock if we need to call back to user-mode (i.e., UMPD).
|
|
//
|
|
|
|
if (cPdevRefs == 0)
|
|
{
|
|
//
|
|
// Since we are going to delete this PDEV, there shouldn't be any
|
|
// active RFONTs lying around for this PDEV.
|
|
//
|
|
|
|
ASSERTGDI(ppdev->prfntActive == NULL,
|
|
"active rfonts on pdev being deleted!\n");
|
|
|
|
//
|
|
// Ordinarily, we would grab the ghsemRFONTList semaphore because
|
|
// we are going to access the RFONT list. However, since we're in
|
|
// the process of tearing down the PDEV, we don't really need to.
|
|
//
|
|
|
|
//
|
|
// Delete all the rfonts on the PDEV.
|
|
//
|
|
|
|
PRFONT prfnt;
|
|
while ( (prfnt = ppdev->prfntInactive) != (PRFONT) NULL )
|
|
{
|
|
RFONTTMPOBJ rflo(prfnt);
|
|
PFFOBJ pffo(rflo.pPFF());
|
|
|
|
ASSERTGDI (
|
|
pffo.bValid(),
|
|
"bad HPFF"
|
|
);
|
|
|
|
rflo.bDeleteRFONT(this, &pffo); // bDelete keeps the list head ptrs updated
|
|
}
|
|
|
|
//
|
|
// If device fonts exist, remove them
|
|
//
|
|
|
|
if ((ppdev->devinfo.cFonts != 0) && bGotFonts())
|
|
{
|
|
PFF *pPFF = 0;
|
|
PFF **ppPFF;
|
|
|
|
GreAcquireSemaphoreEx(ghsemPublicPFT, SEMORDER_PUBLICPFT, NULL);
|
|
|
|
DEVICE_PFTOBJ pfto;
|
|
pPFF = pfto.pPFFGet(hdev(), &ppPFF);
|
|
|
|
if (!pfto.bUnloadWorkhorse(pPFF, ppPFF, ghsemPublicPFT, 0))
|
|
{
|
|
WARNING("couldn't unload device fonts\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// If a type one font list exists dereference it
|
|
//
|
|
|
|
if(ppdev->TypeOneInfo)
|
|
{
|
|
PTYPEONEINFO FreeTypeOneInfo;
|
|
|
|
FreeTypeOneInfo = NULL;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
ppdev->TypeOneInfo->cRef -= 1;
|
|
|
|
if(!ppdev->TypeOneInfo->cRef)
|
|
{
|
|
//
|
|
// Don't free pool while holding a mutex.
|
|
//
|
|
|
|
FreeTypeOneInfo = ppdev->TypeOneInfo;
|
|
}
|
|
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (FreeTypeOneInfo)
|
|
{
|
|
VFREEMEM(FreeTypeOneInfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If any remote type one fonts exist free those
|
|
//
|
|
|
|
PREMOTETYPEONENODE RemoteTypeOne = ppdev->RemoteTypeOne;
|
|
|
|
while(RemoteTypeOne)
|
|
{
|
|
PVOID Tmp = (PVOID) RemoteTypeOne;
|
|
|
|
//
|
|
// ulRegionSize and hSpoolerSecure will be stored in the PFM fileview
|
|
//
|
|
|
|
RemoteTypeOne->fvPFM.cRefCountFD = 1;
|
|
vUnmapRemoteFonts(&RemoteTypeOne->fvPFM);
|
|
RemoteTypeOne = RemoteTypeOne->pNext;
|
|
VFREEMEM(Tmp);
|
|
|
|
WARNING1("Freeing Type1\n");
|
|
}
|
|
|
|
//
|
|
// Delete GammaRamp table, if allocated.
|
|
//
|
|
|
|
if (ppdev->fl & PDEV_GAMMARAMP_TABLE)
|
|
{
|
|
VFREEMEM(ppdev->pvGammaRampTable);
|
|
}
|
|
|
|
if (ppdev->ppdevDevmode)
|
|
{
|
|
VFREEMEM(ppdev->ppdevDevmode);
|
|
}
|
|
|
|
if (!bCloneDriver())
|
|
{
|
|
//
|
|
// Destroy the LFONTs.
|
|
//
|
|
|
|
if (ppdev->hlfntDefault != STOCKOBJ_SYSFONT)
|
|
bDeleteFont(ppdev->hlfntDefault, TRUE);
|
|
|
|
if (ppdev->hlfntAnsiVariable != STOCKOBJ_SYSFONT)
|
|
bDeleteFont(ppdev->hlfntAnsiVariable, TRUE);
|
|
|
|
if (ppdev->hlfntAnsiFixed != STOCKOBJ_SYSFIXEDFONT)
|
|
bDeleteFont(ppdev->hlfntAnsiFixed, TRUE);
|
|
|
|
//
|
|
// Delete the patterns if they are created by the graphics engine on the
|
|
// behalf of the driver.
|
|
// This is what happends for all display drivers.
|
|
//
|
|
|
|
if (ppdev->fl & PDEV_DISPLAY)
|
|
{
|
|
for (int iPat = 0; iPat < HS_DDI_MAX; iPat++)
|
|
{
|
|
bDeleteSurface(ppdev->ahsurf[iPat]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Disable the surface for the pdev.
|
|
//
|
|
|
|
vDisableSurface(cutype);
|
|
|
|
//
|
|
// Destroy the device halftone info.
|
|
//
|
|
|
|
if (ppdev->pDevHTInfo != NULL)
|
|
{
|
|
bDisableHalftone();
|
|
}
|
|
|
|
#if defined(_WIN64)
|
|
vDeleteWOW64HTPATSIZEUSERAllocations();
|
|
#endif
|
|
//
|
|
// Nuke the realized gray pattern brush (used to draw the
|
|
// drag rectangles). Normally, the EBRUSHOBJ destructor
|
|
// will decrement the realized brush ref counts. However,
|
|
// the EBRUSHOBJ cached in the PDEV is allocated as part
|
|
// of the PDEV so never invokes a destructor. Therefore,
|
|
// we need to force the realized brushes out explicitly.
|
|
//
|
|
|
|
pbo()->vNuke();
|
|
|
|
if (!bCloneDriver())
|
|
{
|
|
//
|
|
// Unreference the palette we used for this PDEV.
|
|
//
|
|
// If session cleanup (i.e., Hydra) the palettes are already
|
|
// deleted; therefore, should skip.
|
|
//
|
|
|
|
if (cutype != CLEANUP_SESSION)
|
|
{
|
|
if (ppdev->ppalSurf)
|
|
{
|
|
DEC_SHARE_REF_CNT(ppdev->ppalSurf);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Disable the driver's PDEV.
|
|
//
|
|
// We do this odd check to ensure that the driver's DrvDisablePDEV
|
|
// address isn't the same as its DrvEnablePDEV address because an
|
|
// early beta NetMeeting driver had a bug where its table entries
|
|
// for INDEX_DrvEnablePDEV and INDEX_DrvDisablePDEV were the same
|
|
// (this was in SP3 before we enabled dynamic mode changes for
|
|
// DDML drivers). We made a change recently (this is still before
|
|
// SP3 has shipped, which enabled the DDML) so that we refuse to
|
|
// load DDML drivers that don't have GCAPS_LAYERRED set -- but we
|
|
// have to load the driver first before we can check GCAPS_LAYERED.
|
|
// So if it doesn't have GCAPS_LAYERED set, we have to unload the
|
|
// driver -- but this old NetMeeting driver had a bad DisablePDEV
|
|
// routine!
|
|
//
|
|
// At any rate, to work around the problem where someone has the
|
|
// beta version of the NetMeeting driver installed (which shipped
|
|
// with the IE4 beta and has the DisablePDEV bug) and then upgrades
|
|
// to retail SP3, we simply don't call the driver's bad DisablePDEV
|
|
// routine. The driver will likely leak memory, but this happens
|
|
// only once per boot and is better than a blue screen.
|
|
//
|
|
|
|
if (PPFNDRV((*this),DisablePDEV) != (PFN_DrvDisablePDEV)
|
|
PPFNDRV((*this),EnablePDEV))
|
|
{
|
|
//
|
|
// If the user mode process is gone (i.e, during session
|
|
// or process cleanup), don't callout to user mode.
|
|
//
|
|
|
|
if (!bUMPD || (cutype == CLEANUP_NONE))
|
|
(*PPFNDRV((*this),DisablePDEV))(ppdev->dhpdev);
|
|
}
|
|
|
|
//
|
|
// Remove the LDEV reference.
|
|
//
|
|
if (!bUMPD)
|
|
ldevUnloadImage(ppdev->pldev);
|
|
else
|
|
UMPD_ldevUnloadImage(ppdev->pldev);
|
|
|
|
// If this PDEV referenced an enabled physical device
|
|
// then release its usage for this session.
|
|
if (!bDisabled() && ppdev->pGraphicsDevice != NULL)
|
|
{
|
|
bSetDeviceSessionUsage(ppdev->pGraphicsDevice, FALSE);
|
|
}
|
|
}
|
|
|
|
TRACE_INIT(("PDEVOBJ::vCommonDelete: Closing Device handle.\n"));
|
|
|
|
if (ppdev->fl & PDEV_PRINTER)
|
|
{
|
|
//
|
|
// note the spool handle so we can close connection outside
|
|
// of the spooler management semaphore
|
|
//
|
|
|
|
hSpooler = ppdev->hSpooler;
|
|
}
|
|
|
|
#ifdef DDI_WATCHDOG
|
|
|
|
//
|
|
// Stop and free all watchdogs.
|
|
//
|
|
|
|
GreDeleteWatchdogs(ppdev->pWatchdogData, WD_NUMBER);
|
|
ppdev->pWatchdogData = NULL;
|
|
|
|
#endif // DDI_WATCHDOG
|
|
|
|
//
|
|
// Free the locks as one of the last steps, in case any of the
|
|
// above decides to try and acquire the locks.
|
|
//
|
|
|
|
//
|
|
// If hsemDevLock points "shared devlock", don't delete it.
|
|
//
|
|
if (!(ppdev->fl & PDEV_SHARED_DEVLOCK))
|
|
{
|
|
if (ppdev->hsemDevLock)
|
|
{
|
|
GreDeleteSemaphore(ppdev->hsemDevLock);
|
|
}
|
|
}
|
|
|
|
if (ppdev->fl & PDEV_DISPLAY)
|
|
{
|
|
GreDeleteSemaphore(ppdev->hsemPointer);
|
|
}
|
|
|
|
// See if there are any surfaces in the handle table still referencing
|
|
// this PDEV. If so mark them such that the bDeleteSurface call will
|
|
// not touch anything which refers the PDEV.
|
|
|
|
vMarkSurfacesWithHDEV(ppdev);
|
|
|
|
//
|
|
// Free the PDEV.
|
|
//
|
|
|
|
if (!bUMPD)
|
|
{
|
|
VFREEMEM(ppdev);
|
|
}
|
|
else
|
|
{
|
|
EngFreeMem(ppdev);
|
|
}
|
|
|
|
ppdev = (PDEV *) NULL;
|
|
}
|
|
|
|
//
|
|
// this needs to be done outside of the driver management semaphore
|
|
//
|
|
|
|
if (!bUMPD && hSpooler)
|
|
{
|
|
ClosePrinter(hSpooler);
|
|
}
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::vSync()
|
|
*
|
|
* If the surface hooks synchronization then call the hook. Note, if
|
|
* provided we will call DrvSynchronizeSurface otherwise we will call
|
|
* DrvSynchronize.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vSync(
|
|
SURFOBJ* pso,
|
|
RECTL* prcl,
|
|
FLONG fl)
|
|
{
|
|
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
|
|
|
if(pSurf->flags() & HOOK_SYNCHRONIZE)
|
|
{
|
|
if (!bDisabled())
|
|
{
|
|
FREASSERTGDI(ppdev->pfnSyncSurface || ppdev->pfnSync,
|
|
"Surface has HOOK_SYNCHRONIZE flags, but both ppdev->pfnSyncSurface and ppdev->pfnSync are NULL\n");
|
|
if(ppdev->pfnSyncSurface != NULL)
|
|
(ppdev->pfnSyncSurface)(pso, prcl, fl);
|
|
else
|
|
(ppdev->pfnSync)(pso->dhpdev, prcl);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::vNotify()
|
|
*
|
|
* If the driver supplies DrvNotify, then call it.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vNotify(
|
|
ULONG iType,
|
|
PVOID pvData)
|
|
{
|
|
if(ppdev->pfnNotify != NULL)
|
|
{
|
|
(ppdev->pfnNotify)(ppdev->pSurface->pSurfobj(), iType, pvData);
|
|
}
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::bDisabled()
|
|
*
|
|
* Marks a PDEV as enabled or disabled, and modifies all updates the
|
|
* cached state in all affected DCs.
|
|
*
|
|
* NOTE: This assumes the DEVLOCK is held.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL PDEVOBJ::bDisabled
|
|
(
|
|
BOOL bDisable
|
|
)
|
|
{
|
|
HDEV hdev;
|
|
HOBJ hobj;
|
|
DC *pdc;
|
|
|
|
ASSERTGDI(bDisplayPDEV(), "Expected only display devices");
|
|
|
|
SETFLAG(bDisable, ppdev->fl, PDEV_DISABLED);
|
|
|
|
hdev = (HDEV) ppdev;
|
|
|
|
//
|
|
// We have to hold the handle manager lock while we traverse all
|
|
// the handle manager objects.
|
|
//
|
|
|
|
MLOCKFAST mo;
|
|
|
|
hobj = 0;
|
|
while (pdc = (DC*) HmgSafeNextObjt(hobj, DC_TYPE))
|
|
{
|
|
hobj = (HOBJ) pdc->hGet();
|
|
|
|
if ((pdc->dctp() == DCTYPE_DIRECT) &&
|
|
(pdc->hdev() == hdev))
|
|
{
|
|
pdc->bInFullScreen(bDisable);
|
|
}
|
|
}
|
|
|
|
return(ppdev->fl & PDEV_DISABLED);
|
|
}
|
|
|
|
#if DBG
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::AssertDevLock()
|
|
*
|
|
* This routine verifies that the DevLock is held.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vAssertDevLock()
|
|
{
|
|
|
|
#if !defined(_GDIPLUS_)
|
|
|
|
ASSERTGDI(!bDisplayPDEV() ||
|
|
GreIsSemaphoreOwnedByCurrentThread(hsemDevLock()),
|
|
"PDEVOBJ: Devlock not held");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::AssertNoDevLock()
|
|
*
|
|
* This routine verifies that the DevLock is not held.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vAssertNoDevLock()
|
|
{
|
|
#if !defined(_GDIPLUS_)
|
|
|
|
ASSERTGDI(!bDisplayPDEV() ||
|
|
!GreIsSemaphoreOwnedByCurrentThread(hsemDevLock()),
|
|
"PDEVOBJ: Devlock held");
|
|
|
|
#endif
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::AssertDynaLock()
|
|
*
|
|
* This routine verifies that appropriate locks are held before accessing
|
|
* DC fields that may otherwise be changed asynchronously by the dynamic
|
|
* mode-change code.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID PDEVOBJ::vAssertDynaLock()
|
|
{
|
|
//
|
|
// One of the following conditions is enough to allow the thread
|
|
// to safely access fields that may be modified by the dyanmic
|
|
// mode changing:
|
|
//
|
|
// 1. It's a non-display device -- this will not change modes;
|
|
// 2. That the USER semaphore is held;
|
|
// 3. That the DEVLOCK is held for this object;
|
|
// 4. That the DEVLOCK is held for this object's parent;
|
|
// 5. That the Palette semaphore is held;
|
|
// 6. That the Handle Manager semaphore is held;
|
|
// 7. That the Pointer semaphore is held;
|
|
// 8. That the driver management semaphore is held;
|
|
// 9. That the parent's pointer Semaphore is held.
|
|
// 10. The pdev is being torn down (i.e., cPdevRefs == 0).
|
|
//
|
|
|
|
#if !defined(_GDIPLUS_)
|
|
|
|
ASSERTGDI(!bDisplayPDEV() ||
|
|
(ppdev->cPdevRefs == 0) ||
|
|
UserIsUserCritSecIn() ||
|
|
GreIsSemaphoreOwnedByCurrentThread(hsemDevLock()) ||
|
|
GreIsSemaphoreOwnedByCurrentThread(
|
|
ppdev->ppdevParent->hsemDevLock) ||
|
|
GreIsSemaphoreSharedByCurrentThread(ghsemShareDevLock) ||
|
|
GreIsSemaphoreOwnedByCurrentThread(ghsemPalette) ||
|
|
GreIsSemaphoreOwnedByCurrentThread(ghsemHmgr) ||
|
|
GreIsSemaphoreOwnedByCurrentThread(hsemPointer()) ||
|
|
GreIsSemaphoreOwnedByCurrentThread(ghsemDriverMgmt) ||
|
|
((ppdev->ppdevParent != NULL) &&
|
|
GreIsSemaphoreOwnedByCurrentThread(ppdev->ppdevParent->hsemPointer)),
|
|
"PDEVOBJ: A dynamic mode change lock must be held to access this field");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/******************************Member*Function*****************************\
|
|
* PDEVOBJ::ppfn()
|
|
*
|
|
* This routine verifies that appropriate locks are held before accessing
|
|
* the dispatch table for a PDEV for function pointers that could otherwise
|
|
* be changed asynchronously by a dynamic mode change.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
PFN PDEVOBJ::ppfn(ULONG i)
|
|
{
|
|
//
|
|
// Font producers and some types of font consumers are not allowed to
|
|
// do dynamic mode changes. As such, accessing the dispatch table
|
|
// entries specific to those types of drivers does not have to occur
|
|
// under a lock.
|
|
//
|
|
// Note that if this list is expanded, it should also be changed in
|
|
// 'bMatchEnoughForDynamicModeChange':
|
|
//
|
|
|
|
if ((i != INDEX_DrvQueryFontCaps) &&
|
|
(i != INDEX_DrvLoadFontFile) &&
|
|
(i != INDEX_DrvQueryFontFile) &&
|
|
(i != INDEX_DrvGetGlyphMode))
|
|
{
|
|
vAssertDynaLock();
|
|
}
|
|
|
|
return(ppdev->apfn[i]);
|
|
}
|
|
|
|
#endif
|