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.
3911 lines
108 KiB
3911 lines
108 KiB
/******************Module*Header********************************************\
|
|
* Module Name: dcquery.c *
|
|
* *
|
|
* Client side stubs for functions that query the DC in the server. *
|
|
* *
|
|
* Created: 05-Jun-1991 01:43:56 *
|
|
* Author: Charles Whitmer [chuckwh] *
|
|
* *
|
|
* Copyright (c) 1991-1999 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#if DBG
|
|
FLONG gflDebug = 0;
|
|
#endif
|
|
|
|
// This macro retrieves the current code page, carefully masking off the
|
|
// charset:
|
|
|
|
#define GET_CODE_PAGE(hdc,pDcAttr) \
|
|
((!(pDcAttr->ulDirty_ & DIRTY_CHARSET) ? pDcAttr->iCS_CP \
|
|
: NtGdiGetCharSet(hdc)) & 0xffff)
|
|
BOOL bIsDBCSString(LPCSTR psz, int cc);
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vOutlineTextMetricWToOutlineTextMetricA
|
|
*
|
|
* Convert from OUTLINETEXTMETRICA (ANSI structure) to OUTLINETEXTMETRICW
|
|
* (UNICODE structure).
|
|
*
|
|
* Note:
|
|
* This function is capable of converting in place (in and out buffers
|
|
* can be the same).
|
|
*
|
|
* Returns:
|
|
* TTRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 02-Mar-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vOutlineTextMetricWToOutlineTextMetricA (
|
|
LPOUTLINETEXTMETRICA potma,
|
|
OUTLINETEXTMETRICW * potmw,
|
|
TMDIFF * ptmd
|
|
)
|
|
{
|
|
// Size.
|
|
|
|
potma->otmSize = potmw->otmSize;
|
|
|
|
// Convert the textmetrics.
|
|
|
|
vTextMetricWToTextMetricStrict(
|
|
&potma->otmTextMetrics,
|
|
&potmw->otmTextMetrics);
|
|
|
|
potma->otmTextMetrics.tmFirstChar = ptmd->chFirst;
|
|
potma->otmTextMetrics.tmLastChar = ptmd->chLast;
|
|
potma->otmTextMetrics.tmDefaultChar = ptmd->chDefault;
|
|
potma->otmTextMetrics.tmBreakChar = ptmd->chBreak;
|
|
|
|
// for Win 64 we need to copy these fields one by one due to alignement difference
|
|
|
|
potma->otmFiller = potmw->otmFiller;
|
|
potma->otmPanoseNumber = potmw->otmPanoseNumber;
|
|
potma->otmfsSelection = potmw->otmfsSelection;
|
|
potma->otmfsType = potmw->otmfsType;
|
|
potma->otmsCharSlopeRise = potmw->otmsCharSlopeRise;
|
|
potma->otmsCharSlopeRun = potmw->otmsCharSlopeRun;
|
|
potma->otmItalicAngle = potmw->otmItalicAngle;
|
|
potma->otmEMSquare = potmw->otmEMSquare;
|
|
potma->otmAscent = potmw->otmAscent;
|
|
potma->otmDescent = potmw->otmDescent;
|
|
potma->otmLineGap = potmw->otmLineGap;
|
|
potma->otmsCapEmHeight = potmw->otmsCapEmHeight;
|
|
potma->otmsXHeight = potmw->otmsXHeight;
|
|
potma->otmrcFontBox = potmw->otmrcFontBox;
|
|
potma->otmMacAscent = potmw->otmMacAscent;
|
|
potma->otmMacDescent = potmw->otmMacDescent;
|
|
potma->otmMacLineGap = potmw->otmMacLineGap;
|
|
potma->otmusMinimumPPEM = potmw->otmusMinimumPPEM;
|
|
potma->otmptSubscriptSize = potmw->otmptSubscriptSize;
|
|
potma->otmptSubscriptOffset = potmw->otmptSubscriptOffset;
|
|
potma->otmptSuperscriptSize = potmw->otmptSuperscriptSize;
|
|
potma->otmptSuperscriptOffset = potmw->otmptSuperscriptOffset;
|
|
potma->otmsStrikeoutSize = potmw->otmsStrikeoutSize;
|
|
potma->otmsStrikeoutPosition = potmw->otmsStrikeoutPosition;
|
|
potma->otmsUnderscoreSize = potmw->otmsUnderscoreSize;
|
|
potma->otmsUnderscorePosition = potmw->otmsUnderscorePosition;
|
|
|
|
// set the offsets to zero for now, this will be changed later if
|
|
// the caller wanted strings as well
|
|
|
|
potma->otmpFamilyName = NULL;
|
|
potma->otmpFaceName = NULL;
|
|
potma->otmpStyleName = NULL;
|
|
potma->otmpFullName = NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vGenerateANSIString
|
|
*
|
|
* Effects: Generates Ansi string which consists of consecutive ansi chars
|
|
* [iFirst, iLast] inclusive. The string is stored in the buffer
|
|
* puchBuf that the user must ensure is big enough
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
* 24-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vGenerateAnsiString(UINT iFirst, UINT iLast, PUCHAR puchBuf)
|
|
{
|
|
// Generate string (terminating NULL not needed).
|
|
|
|
ASSERTGDI((iFirst <= iLast) && (iLast < 256), "gdi!_vGenerateAnsiString\n");
|
|
|
|
for ( ; iFirst <= iLast; iFirst++)
|
|
*puchBuf++ = (UCHAR) iFirst;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bSetUpUnicodeString
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 25-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bSetUpUnicodeString(
|
|
IN UINT iFirst, // first ansi char
|
|
IN UINT iLast, // last char
|
|
IN PUCHAR puchTmp, // buffer for an intermediate ansi string
|
|
OUT PWCHAR pwc, // output fuffer with a unicode string
|
|
IN UINT dwCP // ansi codepage
|
|
)
|
|
{
|
|
UINT c = iLast - iFirst + 1;
|
|
vGenerateAnsiString(iFirst,iLast,puchTmp);
|
|
return MultiByteToWideChar(
|
|
dwCP, 0,
|
|
puchTmp,c,
|
|
pwc, c*sizeof(WCHAR));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetAspectRatioFilterEx *
|
|
* GetBrushOrgEx *
|
|
* *
|
|
* Client side stubs which all get mapped to GetPoint. *
|
|
* *
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote them. *
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetAspectRatioFilterEx(HDC hdc,LPSIZE psizl)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetDCPoint(hdc,DCPT_ASPECTRATIOFILTER,(PPOINTL) psizl));
|
|
}
|
|
|
|
BOOL APIENTRY GetBrushOrgEx(HDC hdc,LPPOINT pptl)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PDC_ATTR pdcattr;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
|
|
|
|
if ((pdcattr != NULL) && (pptl != (LPPOINT)NULL))
|
|
{
|
|
*pptl = *((LPPOINT)&pdcattr->ptlBrushOrigin);
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
return(bRet);
|
|
|
|
}
|
|
|
|
BOOL APIENTRY GetDCOrgEx(HDC hdc,LPPOINT pptl)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetDCPoint(hdc,DCPT_DCORG,(PPOINTL)pptl));
|
|
}
|
|
|
|
// The old GetDCOrg is here because it was in the Beta and we are afraid
|
|
// to remove it now. It would be nice to remove it.
|
|
|
|
DWORD APIENTRY GetDCOrg(HDC hdc)
|
|
{
|
|
hdc;
|
|
return(0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* Client side stub for GetCurrentPositionEx.
|
|
*
|
|
* Wed 02-Sep-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCurrentPositionEx(HDC hdc,LPPOINT pptl)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
PDC_ATTR pDcAttr;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if ((pDcAttr) && (pptl != (LPPOINT)NULL))
|
|
{
|
|
bRet = TRUE;
|
|
|
|
if (pDcAttr->ulDirty_ & DIRTY_PTLCURRENT)
|
|
{
|
|
// If the logical-space version of the current position is invalid,
|
|
// then the device-space version of the current position is
|
|
// guaranteed to be valid. So we can reverse the current transform
|
|
// on that to compute the logical-space version:
|
|
|
|
*((POINTL*)pptl) = pDcAttr->ptfxCurrent;
|
|
|
|
pptl->x = FXTOL(pptl->x);
|
|
pptl->y = FXTOL(pptl->y);
|
|
bRet = DPtoLP(hdc,pptl,1);
|
|
|
|
if (bRet)
|
|
{
|
|
pDcAttr->ptlCurrent = *((POINTL*)pptl);
|
|
pDcAttr->ulDirty_ &= ~DIRTY_PTLCURRENT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*((POINTL*)pptl) = pDcAttr->ptlCurrent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetPixel *
|
|
* *
|
|
* Client side stub. *
|
|
* *
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
DWORD APIENTRY GetPixel(HDC hdc,int x,int y)
|
|
{
|
|
PDC_ATTR pdca;
|
|
COLORREF ColorRet = CLR_INVALID;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE);
|
|
|
|
if (pdca)
|
|
{
|
|
//
|
|
// if the color is not a PaletteIndex and
|
|
// ICM is on then translate
|
|
//
|
|
|
|
ColorRet = NtGdiGetPixel(hdc,x,y);
|
|
|
|
if ( bNeedTranslateColor(pdca)
|
|
&&
|
|
( IS_32BITS_COLOR(pdca->lIcmMode)
|
|
||
|
|
((ColorRet != CLR_INVALID) &&
|
|
!(ColorRet & 0x01000000))
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// translate back color to original.
|
|
//
|
|
COLORREF NewColor;
|
|
|
|
BOOL bStatus = IcmTranslateCOLORREF(hdc,
|
|
pdca,
|
|
ColorRet,
|
|
&NewColor,
|
|
ICM_BACKWARD);
|
|
if (bStatus)
|
|
{
|
|
ColorRet = NewColor;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(ColorRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetDeviceCaps
|
|
*
|
|
* We store the device caps for primary display dc and its compatible memory dcs
|
|
* in the shared handle table.
|
|
*
|
|
* for printer dcs and meta dcs, we cache the dev info in the LDC structure.
|
|
*
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetDeviceCaps(HDC hdc,int iCap)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PDEVCAPS pCachedDevCaps = NULL;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (IS_ALTDC_TYPE(hdc))
|
|
{
|
|
PLDC pldc;
|
|
|
|
// For the 16-bit metafile DC, returns only technology. return 0 for win3.1 compat.
|
|
|
|
if (IS_METADC16_TYPE(hdc))
|
|
return(iCap == TECHNOLOGY ? DT_METAFILE : 0);
|
|
|
|
DC_PLDC(hdc,pldc,bRet);
|
|
|
|
if (!(pldc->fl & LDC_CACHED_DEVCAPS))
|
|
{
|
|
bRet = NtGdiGetDeviceCapsAll (hdc, &pldc->DevCaps);
|
|
|
|
if (bRet)
|
|
{
|
|
pCachedDevCaps = &pldc->DevCaps;
|
|
pldc->fl |= LDC_CACHED_DEVCAPS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCachedDevCaps = &pldc->DevCaps;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PDC_ATTR pDcAttr;
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (pDcAttr)
|
|
{
|
|
ULONG fl = pDcAttr->ulDirty_;
|
|
|
|
if (!(fl & DC_PRIMARY_DISPLAY))
|
|
{
|
|
return(NtGdiGetDeviceCaps(hdc,iCap));
|
|
}
|
|
else
|
|
{
|
|
pCachedDevCaps = pGdiDevCaps;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (0);
|
|
}
|
|
|
|
// actual code - copied from gre\miscgdi.cxx
|
|
switch (iCap)
|
|
{
|
|
case DRIVERVERSION: // Version = 0100h for now
|
|
return(pCachedDevCaps->ulVersion);
|
|
|
|
case TECHNOLOGY: // Device classification
|
|
return(pCachedDevCaps->ulTechnology);
|
|
|
|
case HORZSIZE: // Horizontal size in millimeters
|
|
return(pCachedDevCaps->ulHorzSizeM);
|
|
|
|
case VERTSIZE: // Vertical size in millimeters
|
|
return(pCachedDevCaps->ulVertSizeM);
|
|
|
|
case HORZRES: // Horizontal width in pixels
|
|
return(pCachedDevCaps->ulHorzRes);
|
|
|
|
case VERTRES: // Vertical height in pixels
|
|
return(pCachedDevCaps->ulVertRes);
|
|
|
|
case BITSPIXEL: // Number of bits per pixel
|
|
return(pCachedDevCaps->ulBitsPixel);
|
|
|
|
case PLANES: // Number of planes
|
|
return(pCachedDevCaps->ulPlanes);
|
|
|
|
case NUMBRUSHES: // Number of brushes the device has
|
|
return(-1);
|
|
|
|
case NUMPENS: // Number of pens the device has
|
|
return(pCachedDevCaps->ulNumPens);
|
|
|
|
case NUMMARKERS: // Number of markers the device has
|
|
return(0);
|
|
|
|
case NUMFONTS: // Number of fonts the device has
|
|
return(pCachedDevCaps->ulNumFonts);
|
|
|
|
case NUMCOLORS: // Number of colors in color table
|
|
return(pCachedDevCaps->ulNumColors);
|
|
|
|
case PDEVICESIZE: // Size required for the device descriptor
|
|
return(0);
|
|
|
|
case CURVECAPS: // Curves capabilities
|
|
return(CC_CIRCLES |
|
|
CC_PIE |
|
|
CC_CHORD |
|
|
CC_ELLIPSES |
|
|
CC_WIDE |
|
|
CC_STYLED |
|
|
CC_WIDESTYLED |
|
|
CC_INTERIORS |
|
|
CC_ROUNDRECT);
|
|
|
|
case LINECAPS: // Line capabilities
|
|
return(LC_POLYLINE |
|
|
LC_MARKER |
|
|
LC_POLYMARKER |
|
|
LC_WIDE |
|
|
LC_STYLED |
|
|
LC_WIDESTYLED |
|
|
LC_INTERIORS);
|
|
|
|
case POLYGONALCAPS: // Polygonal capabilities
|
|
return(PC_POLYGON |
|
|
PC_RECTANGLE |
|
|
PC_WINDPOLYGON |
|
|
PC_TRAPEZOID |
|
|
PC_SCANLINE |
|
|
PC_WIDE |
|
|
PC_STYLED |
|
|
PC_WIDESTYLED |
|
|
PC_INTERIORS);
|
|
|
|
case TEXTCAPS: // Text capabilities
|
|
return(pCachedDevCaps->ulTextCaps);
|
|
|
|
case CLIPCAPS: // Clipping capabilities
|
|
return(CP_RECTANGLE);
|
|
|
|
case RASTERCAPS: // Bitblt capabilities
|
|
return(pCachedDevCaps->ulRasterCaps);
|
|
|
|
case SHADEBLENDCAPS: // shade and blend capabilities
|
|
return(pCachedDevCaps->ulShadeBlendCaps);
|
|
|
|
case ASPECTX: // Length of X leg
|
|
return(pCachedDevCaps->ulAspectX);
|
|
|
|
case ASPECTY: // Length of Y leg
|
|
return(pCachedDevCaps->ulAspectY);
|
|
|
|
case ASPECTXY: // Length of hypotenuse
|
|
return(pCachedDevCaps->ulAspectXY);
|
|
|
|
case LOGPIXELSX: // Logical pixels/inch in X
|
|
return(pCachedDevCaps->ulLogPixelsX);
|
|
|
|
case LOGPIXELSY: // Logical pixels/inch in Y
|
|
return(pCachedDevCaps->ulLogPixelsY);
|
|
|
|
case SIZEPALETTE: // # entries in physical palette
|
|
return(pCachedDevCaps->ulSizePalette);
|
|
|
|
case NUMRESERVED: // # reserved entries in palette
|
|
return(20);
|
|
|
|
case COLORRES:
|
|
return(pCachedDevCaps->ulColorRes);
|
|
|
|
case PHYSICALWIDTH: // Physical Width in device units
|
|
return(pCachedDevCaps->ulPhysicalWidth);
|
|
|
|
case PHYSICALHEIGHT: // Physical Height in device units
|
|
return(pCachedDevCaps->ulPhysicalHeight);
|
|
|
|
case PHYSICALOFFSETX: // Physical Printable Area x margin
|
|
return(pCachedDevCaps->ulPhysicalOffsetX);
|
|
|
|
case PHYSICALOFFSETY: // Physical Printable Area y margin
|
|
return(pCachedDevCaps->ulPhysicalOffsetY);
|
|
|
|
case VREFRESH: // Vertical refresh rate of the device
|
|
return(pCachedDevCaps->ulVRefresh);
|
|
|
|
case DESKTOPHORZRES: // Width of entire virtual desktop
|
|
return(pCachedDevCaps->ulDesktopHorzRes);
|
|
|
|
case DESKTOPVERTRES: // Height of entire virtual desktop
|
|
return(pCachedDevCaps->ulDesktopVertRes);
|
|
|
|
case BLTALIGNMENT: // Preferred blt alignment
|
|
return(pCachedDevCaps->ulBltAlignment);
|
|
|
|
case COLORMGMTCAPS: // Color Management capabilities
|
|
return(pCachedDevCaps->ulColorManagementCaps);
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetDeviceCapsP
|
|
*
|
|
* Private version to get HORSIZE and VERTSIZE in micrometers
|
|
* Copied from GetDeviceCaps
|
|
*
|
|
* \**************************************************************************/
|
|
int GetDeviceCapsP(HDC hdc,int iCap)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PDEVCAPS pCachedDevCaps = NULL;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (IS_ALTDC_TYPE(hdc))
|
|
{
|
|
PLDC pldc;
|
|
|
|
DC_PLDC(hdc,pldc,bRet);
|
|
|
|
if (!(pldc->fl & LDC_CACHED_DEVCAPS))
|
|
{
|
|
bRet = NtGdiGetDeviceCapsAll (hdc, &pldc->DevCaps);
|
|
|
|
if (bRet)
|
|
{
|
|
pCachedDevCaps = &pldc->DevCaps;
|
|
pldc->fl |= LDC_CACHED_DEVCAPS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCachedDevCaps = &pldc->DevCaps;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PDC_ATTR pDcAttr;
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (pDcAttr)
|
|
{
|
|
ULONG fl = pDcAttr->ulDirty_;
|
|
|
|
if (!(fl & DC_PRIMARY_DISPLAY))
|
|
{
|
|
return(NtGdiGetDeviceCaps(hdc,iCap));
|
|
}
|
|
else
|
|
{
|
|
pCachedDevCaps = pGdiDevCaps;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (0);
|
|
}
|
|
|
|
// actual code - copied from gre\miscgdi.cxx
|
|
switch (iCap)
|
|
{
|
|
case HORZSIZEP: // Horizontal size
|
|
return(pCachedDevCaps->ulHorzSize);
|
|
|
|
case VERTSIZEP: // Vertical size
|
|
return(pCachedDevCaps->ulVertSize);
|
|
|
|
|
|
default:
|
|
return(0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetNearestColor *
|
|
* *
|
|
* Client side stub. *
|
|
* *
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
COLORREF APIENTRY GetNearestColor(HDC hdc,COLORREF color)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetNearestColor(hdc,color));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetArcDirection
|
|
*
|
|
* Client side stub.
|
|
*
|
|
* Fri 09-Apr-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetArcDirection(HDC hdc)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(GetDCDWord(hdc,DDW_ARCDIRECTION,0));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetMiterLimit
|
|
*
|
|
* Client side stub.
|
|
*
|
|
* Fri 09-Apr-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetMiterLimit(HDC hdc, PFLOAT peMiterLimit)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetMiterLimit(hdc,FLOATPTRARG(peMiterLimit)));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetSystemPaletteUse *
|
|
* *
|
|
* Client side stub. *
|
|
* *
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
UINT APIENTRY GetSystemPaletteUse(HDC hdc)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetSystemPaletteUse(hdc));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetClipBox *
|
|
* *
|
|
* Client side stub. *
|
|
* *
|
|
* Fri 07-Jun-1991 18:01:50 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetClipBox(HDC hdc,LPRECT prcl)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetAppClipBox(hdc,prcl));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetTextMetrics(HDC hdc,LPTEXTMETRIC ptm)
|
|
*
|
|
* calls to the unicode version
|
|
*
|
|
* History:
|
|
* 21-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetTextMetricsA(HDC hdc,LPTEXTMETRICA ptm)
|
|
{
|
|
PDC_ATTR pDcAttr;
|
|
BOOL bRet = FALSE;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (pDcAttr)
|
|
{
|
|
CFONT * pcf;
|
|
TMW_INTERNAL tmw;
|
|
|
|
ASSERTGDI(pDcAttr->hlfntNew,"GetTextMetricsW - hf is NULL\n");
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID)NULL,0, TRUE);
|
|
|
|
bRet = bGetTextMetricsWInternal(hdc,&tmw,sizeof(tmw),pcf);
|
|
|
|
// pcfLocateCFONT added a reference so now we need to remove it
|
|
|
|
if (pcf)
|
|
{
|
|
DEC_CFONT_REF(pcf);
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
|
|
if (bRet)
|
|
{
|
|
vTextMetricWToTextMetric(ptm, &tmw);
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetTextMetricsW(HDC hdc,LPTEXTMETRICW ptmw)
|
|
*
|
|
* History:
|
|
* 21-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetTextMetricsW(HDC hdc,LPTEXTMETRICW ptmw)
|
|
{
|
|
PDC_ATTR pDcAttr;
|
|
BOOL bRet = FALSE;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
if (pDcAttr)
|
|
{
|
|
CFONT * pcf;
|
|
|
|
ASSERTGDI(pDcAttr->hlfntNew,"GetTextMetricsW - hf is NULL\n");
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID) NULL,0, TRUE);
|
|
|
|
bRet = bGetTextMetricsWInternal(hdc,(TMW_INTERNAL *)ptmw,sizeof(TEXTMETRICW),pcf);
|
|
|
|
// pcfLocateCFONT added a reference so now we need to remove it
|
|
|
|
if (pcf)
|
|
{
|
|
DEC_CFONT_REF(pcf);
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetTextMetricsW(HDC hdc,LPTEXTMETRICW ptmw)
|
|
*
|
|
* History:
|
|
* 21-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetTextMetricsWInternal(
|
|
HDC hdc,
|
|
TMW_INTERNAL *ptmw,
|
|
int cjTM,
|
|
CFONT *pcf
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if (ptmw)
|
|
{
|
|
// if no pcf or we havn't cached the metrics
|
|
|
|
if ((pcf == NULL) || !(pcf->fl & CFONT_CACHED_METRICS))
|
|
{
|
|
TMW_INTERNAL tmw;
|
|
PDC_ATTR pDcAttr;
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
bRet = NtGdiGetTextMetricsW(hdc,&tmw,sizeof(tmw));
|
|
|
|
if (bRet)
|
|
{
|
|
memcpy(ptmw,&tmw,cjTM);
|
|
|
|
if (pcf)
|
|
{
|
|
// we succeeded and we have a pcf so cache the data
|
|
|
|
pcf->tmw = tmw;
|
|
|
|
pcf->fl |= CFONT_CACHED_METRICS;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy(ptmw,&pcf->tmw,cjTM);
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetTextExtentPoint32A (hdc,psz,c,psizl) *
|
|
* GetTextExtentPointA (hdc,psz,c,psizl) *
|
|
* *
|
|
* Computes the text extent. The new 32 bit version returns the "correct" *
|
|
* extent without an extra per for bitmap simulations. The other is *
|
|
* Windows 3.1 compatible. Both just set a flag and pass the call to *
|
|
* bGetTextExtentA. *
|
|
* *
|
|
* History: *
|
|
* Thu 14-Jan-1993 04:11:26 -by- Charles Whitmer [chuckwh] *
|
|
* Added code to compute it on the client side. *
|
|
* *
|
|
* 07-Aug-1991 -by- Bodin Dresevic [BodinD] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
// not in kernel, it is ok to do this much on the stack:
|
|
#define CAPTURE_STRING_SIZE 130
|
|
|
|
BOOL GetTextExtentPointAInternal(HDC hdc,LPCSTR psz,int c,LPSIZE psizl, FLONG fl)
|
|
{
|
|
CFONT *pcf;
|
|
INT bRet;
|
|
PWSZ pwszCapt;
|
|
PDC_ATTR pDcAttr;
|
|
DWORD dwCP;
|
|
WCHAR awcCaptureBuffer[CAPTURE_STRING_SIZE];
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (c <= 0)
|
|
{
|
|
// empty string, just return 0 for the extent
|
|
|
|
if (c == 0)
|
|
{
|
|
psizl->cx = 0;
|
|
psizl->cy = 0;
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
if (!pDcAttr)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
return(bRet);
|
|
}
|
|
|
|
dwCP = GET_CODE_PAGE(hdc, pDcAttr);
|
|
|
|
if(guintDBCScp == dwCP)
|
|
{
|
|
QueryFontAssocStatus();
|
|
|
|
if(fFontAssocStatus &&
|
|
((c == 1) || ((c == 2 && *(psz) && *((LPCSTR)(psz + 1)) == '\0'))))
|
|
{
|
|
//
|
|
// If this function is called with only 1 char, and font association
|
|
// is enabled, we should forcely convert the chars to Unicode with
|
|
// codepage 1252.
|
|
// This is for enabling to output Latin-1 chars ( > 0x80 in Ansi codepage )
|
|
// Because, normally font association is enabled, we have no way to output
|
|
// those charactres, then we provide the way, if user call TextOutA() with
|
|
// A character and ansi font, we tempotary disable font association.
|
|
// This might be Windows 3.1 (Korean/Taiwanese) version compatibility..
|
|
//
|
|
dwCP = 1252;
|
|
}
|
|
}
|
|
|
|
|
|
if((dwCP == CP_ACP) ||
|
|
(dwCP == guintAcp) ||
|
|
(dwCP == guintDBCScp)
|
|
)
|
|
{
|
|
#ifdef LANGPACK
|
|
if (!gbLpk || (*fpLpkUseGDIWidthCache)(hdc, psz, c, pDcAttr->lTextAlign , FALSE))
|
|
{
|
|
#endif
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID)psz,c,TRUE);
|
|
if (pcf != NULL)
|
|
{
|
|
BOOL bExit = TRUE;
|
|
|
|
if(dwCP == guintDBCScp)
|
|
{
|
|
if (pcf->wd.sDBCSInc) // dbcs fixed pitch base font
|
|
{
|
|
bRet = bComputeTextExtentDBCS(pDcAttr,pcf,psz,c,fl,psizl);
|
|
}
|
|
else if (!bIsDBCSString(psz,c))
|
|
{
|
|
// linked case, base font is a latin font, but linked font
|
|
// perhaps is a FE font. We know that base font is a latin font
|
|
// because for FE proportional fonts we would never create pcf.
|
|
// We are looking for this special case when the application asked
|
|
// for Latin Face Name in the logfont, and a FE charset, but the string
|
|
// passed in lackily does not contain DBCS glyphs.
|
|
|
|
bRet = bComputeTextExtent(pDcAttr,pcf,(PVOID) psz,c,fl,psizl,TRUE);
|
|
}
|
|
else
|
|
{
|
|
bExit = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = bComputeTextExtent(pDcAttr,pcf,(PVOID) psz,c,fl,psizl,TRUE);
|
|
}
|
|
|
|
DEC_CFONT_REF(pcf);
|
|
|
|
if(bExit)
|
|
{
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
return(bRet);
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
#ifdef LANGPACK
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Allocate the string buffer
|
|
|
|
if (c <= CAPTURE_STRING_SIZE)
|
|
{
|
|
pwszCapt = awcCaptureBuffer;
|
|
}
|
|
else
|
|
{
|
|
pwszCapt = LOCALALLOC(c * sizeof(WCHAR));
|
|
}
|
|
|
|
if (pwszCapt)
|
|
{
|
|
|
|
c = MultiByteToWideChar(dwCP, 0, psz,c, pwszCapt, c*sizeof(WCHAR));
|
|
|
|
if (c)
|
|
{
|
|
#ifdef LANGPACK
|
|
if(gbLpk)
|
|
{
|
|
bRet = (*fpLpkGetTextExtentExPoint)(hdc, pwszCapt, c, -1, NULL, NULL,
|
|
psizl, fl, 0);
|
|
}
|
|
else
|
|
#endif
|
|
bRet = NtGdiGetTextExtent(hdc,
|
|
(LPWSTR)pwszCapt,
|
|
c,
|
|
psizl,
|
|
fl);
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (pwszCapt != awcCaptureBuffer)
|
|
LOCALFREE(pwszCapt);
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
BOOL APIENTRY GetTextExtentPointA(HDC hdc,LPCSTR psz,int c,LPSIZE psizl)
|
|
{
|
|
return GetTextExtentPointAInternal(hdc,psz,c,psizl,GGTE_WIN3_EXTENT);
|
|
}
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentPoint32A(HDC hdc,LPCSTR psz,int c,LPSIZE psizl)
|
|
{
|
|
return GetTextExtentPointAInternal(hdc,psz,c,psizl,0);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DWORD WINAPI GetCharacterPlacementA
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 27-Jul-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
DWORD WINAPI GetCharacterPlacementA
|
|
(
|
|
HDC hdc,
|
|
LPCSTR psz,
|
|
int nCount,
|
|
int nMaxExtent,
|
|
LPGCP_RESULTSA pgcpa,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
#define GCP_GLYPHS 80
|
|
|
|
WCHAR *pwsz = NULL;
|
|
WCHAR awc[GCP_GLYPHS];
|
|
GCP_RESULTSW gcpw;
|
|
DWORD dwRet;
|
|
BOOL bOk = TRUE;
|
|
int nBuffer;
|
|
SIZE size;
|
|
DWORD dwCP;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
size.cx = size.cy = 0;
|
|
|
|
// nMaxExtent == -1 means that there is no MaxExtent
|
|
|
|
if (!psz || (nCount <= 0) || ((nMaxExtent < 0) && (nMaxExtent != -1)))
|
|
{
|
|
WARNING("gdi!_GetCharactherPlacementA, bad parameters \n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!pgcpa)
|
|
{
|
|
// just call GetTextExtentA, can usually be done on the client side
|
|
|
|
if (!GetTextExtentPointA(hdc, psz, nCount, &size))
|
|
{
|
|
WARNING("GetCharacterPlacementW, GetTextExtentPointA failed\n");
|
|
return 0;
|
|
}
|
|
|
|
// now backwards compatible win95 hack, chop off 32 bit values to 16 bits
|
|
|
|
return (DWORD)((USHORT)size.cx) | (DWORD)(size.cy << 16);
|
|
}
|
|
|
|
// chop off nCount, win95 does it
|
|
|
|
if (nCount > (int)pgcpa->nGlyphs)
|
|
nCount = (int)pgcpa->nGlyphs;
|
|
|
|
// unicode string buffer will at least be this many WCHAR's long:
|
|
|
|
nBuffer = nCount;
|
|
|
|
// now go on to compute the size of the GCP_RESULTSW that is required
|
|
// to receive the results. If lpOutString is not NULL the structures
|
|
// will have different pointers else they will be the same.
|
|
|
|
gcpw.lpOrder = pgcpa->lpOrder ;
|
|
gcpw.lpDx = pgcpa->lpDx ;
|
|
gcpw.lpCaretPos = pgcpa->lpCaretPos;
|
|
gcpw.lpClass = pgcpa->lpClass ;
|
|
gcpw.lpGlyphs = pgcpa->lpGlyphs ;
|
|
gcpw.nGlyphs = pgcpa->nGlyphs ;
|
|
gcpw.nMaxFit = pgcpa->nMaxFit ;
|
|
|
|
if (pgcpa->lpOutString)
|
|
{
|
|
nBuffer += nBuffer; // take into account space for gcpw.lpOutString
|
|
}
|
|
else
|
|
{
|
|
gcpw.lpOutString = NULL;
|
|
gcpw.lStructSize = pgcpa->lStructSize;
|
|
}
|
|
|
|
// now allocate memory (if needed) for the unicode string and for
|
|
// gcpw.lpOutString if needed.
|
|
|
|
if (nBuffer <= GCP_GLYPHS)
|
|
pwsz = awc;
|
|
else
|
|
pwsz = LOCALALLOC(nBuffer * sizeof(WCHAR));
|
|
|
|
if (pwsz)
|
|
{
|
|
if (pgcpa->lpOutString)
|
|
{
|
|
gcpw.lpOutString = &pwsz[nCount];
|
|
|
|
// we have replaced the ansi string by unicode string, this adds
|
|
// nCount bytes to the size of the structure.
|
|
|
|
gcpw.lStructSize = pgcpa->lStructSize + nCount;
|
|
}
|
|
|
|
// convert Ansi To Unicode based on the code page of the font selected in DC
|
|
|
|
if
|
|
(
|
|
gcpw.nGlyphs = MultiByteToWideChar((dwCP = GetCodePage(hdc)), 0,
|
|
psz, nCount,
|
|
pwsz, nCount*sizeof(WCHAR))
|
|
)
|
|
{
|
|
|
|
// If this is a DBCS font then we need to patch up the DX array since
|
|
// there will be two DX values for each DBCS character. It is okay
|
|
// to do this in place since GetCharacterPlacement modifies the DX
|
|
// array anyway.
|
|
|
|
if((dwFlags & GCP_JUSTIFYIN) &&
|
|
(gcpw.lpDx) &&
|
|
IS_ANY_DBCS_CODEPAGE(dwCP))
|
|
{
|
|
INT *pDxNew, *pDxOld;
|
|
const char *pDBCSString;
|
|
|
|
for(pDxNew = pDxOld = gcpw.lpDx, pDBCSString = psz;
|
|
pDBCSString < psz + nCount;
|
|
pDBCSString++
|
|
)
|
|
{
|
|
if(IsDBCSLeadByteEx(dwCP,*pDBCSString))
|
|
{
|
|
pDBCSString++;
|
|
pDxOld++;
|
|
}
|
|
*pDxNew++ = *pDxOld++;
|
|
}
|
|
}
|
|
|
|
#ifdef LANGPACK
|
|
if (gbLpk)
|
|
{
|
|
// If the LPK is loaded then pass the caller nGlyphs because it may generate
|
|
// Glyphs more than nCount.
|
|
gcpw.nGlyphs = pgcpa->nGlyphs;
|
|
dwRet = (*fpLpkGetCharacterPlacement)(hdc, pwsz, nCount,nMaxExtent,
|
|
&gcpw, dwFlags, 0);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
dwRet = NtGdiGetCharacterPlacementW(hdc,pwsz,nCount,nMaxExtent,
|
|
&gcpw, dwFlags);
|
|
}
|
|
|
|
|
|
if (dwRet)
|
|
{
|
|
// copy out the data.... we use the original value of nCount
|
|
// when specifying an output buffer size for the lpOutString buffer
|
|
// since nCount on return will be Unicode character count which
|
|
// may not be the same as DBCS character count
|
|
|
|
int nOriginalCount = nCount;
|
|
|
|
pgcpa->nGlyphs = nCount = gcpw.nGlyphs;
|
|
pgcpa->nMaxFit = gcpw.nMaxFit;
|
|
if (pgcpa->lpOutString)
|
|
{
|
|
if
|
|
(
|
|
!WideCharToMultiByte(
|
|
(UINT)dwCP, // UINT CodePage
|
|
0, // DWORD dwFlags
|
|
gcpw.lpOutString, // LPWSTR lpWideCharStr
|
|
gcpw.nMaxFit, // int cchWideChar
|
|
pgcpa->lpOutString, // LPSTR lpMultiByteStr
|
|
nOriginalCount, // int cchMultiByte
|
|
NULL, // LPSTR lpDefaultChar
|
|
NULL) // LPBOOL lpUsedDefaultChar
|
|
)
|
|
{
|
|
bOk = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bOk = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
bOk = FALSE;
|
|
}
|
|
|
|
if (pwsz != awc)
|
|
LOCALFREE(pwsz);
|
|
}
|
|
else
|
|
{
|
|
bOk = FALSE;
|
|
}
|
|
|
|
return (bOk ? dwRet : 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DWORD WINAPI GetCharacterPlacementW
|
|
* look at gdi32.def, just points to NtGdiGetCharacterPlacementW
|
|
*
|
|
* History:
|
|
* 26-Jul-1995 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
#if LANGPACK
|
|
|
|
DWORD WINAPI GetCharacterPlacementW
|
|
(
|
|
HDC hdc,
|
|
LPCWSTR pwsz,
|
|
int nCount,
|
|
int nMaxExtent,
|
|
LPGCP_RESULTSW pgcpw,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
SIZE size;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
size.cx = size.cy = 0;
|
|
|
|
// nMaxExtent == -1 means that there is no MaxExtent
|
|
|
|
if (!pwsz || (nCount <= 0) || ((nMaxExtent < 0) && (nMaxExtent != -1)))
|
|
{
|
|
WARNING("gdi!_GetCharactherPlacementW, bad parameters \n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!pgcpw)
|
|
{
|
|
// just call GetTextExtentW, can usually be done on the client side
|
|
|
|
if (!GetTextExtentPointW(hdc, pwsz, nCount, &size))
|
|
{
|
|
WARNING("GetCharacterPlacementW, GetTextExtentPointW failed\n");
|
|
return 0;
|
|
}
|
|
|
|
// now backwards compatible win95 hack, chop off 32 bit values to 16 bits
|
|
|
|
return (DWORD)((USHORT)size.cx) | (DWORD)(size.cy << 16);
|
|
}
|
|
|
|
// chop off nCount, win95 does it
|
|
|
|
if (nCount > (int)pgcpw->nGlyphs)
|
|
nCount = (int)pgcpw->nGlyphs;
|
|
|
|
if(gbLpk)
|
|
{
|
|
return((*fpLpkGetCharacterPlacement)(hdc,pwsz,nCount,nMaxExtent,pgcpw,
|
|
dwFlags,-1));
|
|
}
|
|
else
|
|
{
|
|
|
|
return NtGdiGetCharacterPlacementW(hdc,
|
|
(LPWSTR) pwsz,
|
|
nCount,
|
|
nMaxExtent,
|
|
pgcpw,
|
|
dwFlags);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bGetCharWidthA *
|
|
* *
|
|
* Client side stub for the various GetCharWidth*A functions. *
|
|
* *
|
|
* History: *
|
|
* Sat 16-Jan-1993 03:08:42 -by- Charles Whitmer [chuckwh] *
|
|
* Added code to do it on the client side. *
|
|
* *
|
|
* 28-Aug-1991 -by- Bodin Dresevic [BodinD] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
#define GCW_WIN3_INT (GCW_WIN3 | GCW_INT)
|
|
#define GCW_WIN3_16INT (GCW_WIN3 | GCW_INT | GCW_16BIT)
|
|
|
|
#define GCW_SIZE(fl) ((fl >> 16) & 0xffff)
|
|
#define GCWFL(fltype,szType) (fltype | (sizeof(szType) << 16))
|
|
|
|
BOOL bGetCharWidthA
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst,
|
|
UINT iLast,
|
|
ULONG fl,
|
|
PVOID pvBuf
|
|
)
|
|
{
|
|
PDC_ATTR pDcAttr;
|
|
LONG cwc;
|
|
CFONT *pcf = NULL;
|
|
PUCHAR pch;
|
|
PWCHAR pwc;
|
|
BOOL bRet = FALSE;
|
|
ULONG cjWidths;
|
|
DWORD dwCP;
|
|
BOOL bDBCSCodePage;
|
|
WCHAR awc[MAX_PATH];
|
|
PVOID pvResultBuffer;
|
|
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (!pDcAttr)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(bRet);
|
|
}
|
|
|
|
dwCP = GET_CODE_PAGE(hdc, pDcAttr);
|
|
|
|
bDBCSCodePage = IS_ANY_DBCS_CODEPAGE(dwCP);
|
|
|
|
// do parameter validation, check that in chars are indeed ascii
|
|
|
|
|
|
if ((bDBCSCodePage && !IsValidDBCSRange(iFirst,iLast)) ||
|
|
(!bDBCSCodePage &&
|
|
((iFirst > iLast) || (iLast & 0xffffff00))) ||
|
|
(pvBuf == NULL))
|
|
{
|
|
WARNING("gdi!_bGetCharWidthA parameters \n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(bRet);
|
|
}
|
|
cwc = (LONG)(iLast - iFirst + 1);
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
if ((dwCP == CP_ACP) ||
|
|
(dwCP == guintAcp)
|
|
|| (dwCP == guintDBCScp)
|
|
)
|
|
|
|
{
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,iFirst,(PVOID) NULL,(UINT) cwc, TRUE);
|
|
}
|
|
|
|
if (pcf != (CFONT *) NULL)
|
|
{
|
|
BOOL bExit = TRUE;
|
|
|
|
if(dwCP == guintDBCScp)
|
|
{
|
|
if (pcf->wd.sDBCSInc) // dbcs fixed pitch base font
|
|
{
|
|
bRet = bComputeCharWidthsDBCS (pcf,iFirst,iLast,fl,pvBuf);
|
|
}
|
|
else if (iLast < 0x80)
|
|
{
|
|
// linked case, base font is a latin font, but linked font
|
|
// perhaps is a FE font. We know that base font is a latin font
|
|
// because for FE proportional fonts we would never create pcf.
|
|
// We are looking for this special case when the application asked
|
|
// for Latin Face Name in the logfont, and a FE charset, but the string
|
|
// passed in lackily does not contain DBCS glyphs.
|
|
|
|
bRet = bComputeCharWidths(pcf,iFirst,iLast,fl,pvBuf);
|
|
}
|
|
else
|
|
{
|
|
bExit = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = bComputeCharWidths(pcf,iFirst,iLast,fl,pvBuf);
|
|
}
|
|
|
|
DEC_CFONT_REF(pcf);
|
|
|
|
if(bExit)
|
|
{
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
return(bRet);
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
|
|
// Let the server do it.
|
|
|
|
cjWidths = cwc * GCW_SIZE(fl);
|
|
|
|
//
|
|
// Non kernel mode call
|
|
//
|
|
|
|
// What if user's buffer is set up for 16 bit return?? Then we need
|
|
// to allocate buffer for 32 bit date and convert to user's buffer after
|
|
// the call
|
|
|
|
pvResultBuffer = pvBuf;
|
|
|
|
|
|
if (fl & GCW_16BIT)
|
|
{
|
|
// User's buffer is 16 bit, make 32 a bit
|
|
// temp buffer
|
|
|
|
pvResultBuffer = LOCALALLOC(cwc * sizeof(LONG));
|
|
|
|
if (pvResultBuffer == NULL) {
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return(bRet);
|
|
}
|
|
}
|
|
|
|
// Kernel mode, use users buffer for return data
|
|
// convert to unicode
|
|
|
|
if(bDBCSCodePage)
|
|
{
|
|
bRet = bSetUpUnicodeStringDBCS(iFirst,
|
|
iLast,
|
|
(PUCHAR) pvResultBuffer,
|
|
awc,
|
|
dwCP,
|
|
GetCurrentDefaultChar(hdc));
|
|
}
|
|
else
|
|
{
|
|
bRet = bSetUpUnicodeString(iFirst,iLast,pvResultBuffer,awc,dwCP);
|
|
}
|
|
|
|
if(bRet)
|
|
{
|
|
bRet = NtGdiGetCharWidthW(hdc,
|
|
0,
|
|
cwc,
|
|
awc,
|
|
(LONG)(fl & (GCW_INT | GCW_WIN3)),
|
|
pvResultBuffer);
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
//
|
|
// May need to convert to 16 bit user buffer
|
|
//
|
|
|
|
if (fl & GCW_16BIT)
|
|
{
|
|
|
|
PWORD pw = pvBuf;
|
|
PDWORD pi = (int *)pvResultBuffer;
|
|
PDWORD piEnd = pi + cwc;
|
|
|
|
ASSERTGDI(pvResultBuffer != pvBuf, "Local buffer not allocated properly");
|
|
|
|
while (pi != piEnd)
|
|
{
|
|
*pw++ = (WORD)(*pi++);
|
|
}
|
|
|
|
LOCALFREE(pvResultBuffer);
|
|
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetCharWidthA
|
|
*
|
|
* History:
|
|
* 25-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharWidthA
|
|
(
|
|
IN HDC hdc,
|
|
IN UINT iFirst,
|
|
IN UINT iLast,
|
|
OUT LPINT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
return bGetCharWidthA(hdc,iFirst,iLast,GCWFL(GCW_WIN3_INT,int),(PVOID)lpWidths);
|
|
}
|
|
|
|
BOOL APIENTRY GetCharWidth32A
|
|
(
|
|
IN HDC hdc,
|
|
IN UINT iFirst,
|
|
IN UINT iLast,
|
|
OUT LPINT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return bGetCharWidthA(hdc,iFirst,iLast,GCWFL(GCW_INT,int),(PVOID)lpWidths);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetCharWidthFloatA
|
|
*
|
|
* History:
|
|
* 22-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharWidthFloatA
|
|
(
|
|
IN HDC hdc,
|
|
IN UINT iFirst,
|
|
IN UINT iLast,
|
|
OUT PFLOAT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
return bGetCharWidthA(hdc,iFirst,iLast,GCWFL(0,FLOAT),(PVOID)lpWidths);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bGetCharWidthW
|
|
*
|
|
* GetCharWidthW and GetCharWidthFloatW
|
|
*
|
|
* History:
|
|
* 28-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetCharWidthW
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst, // unicode value
|
|
UINT iLast, // unicode value
|
|
ULONG fl,
|
|
PVOID pvBuf
|
|
)
|
|
{
|
|
LONG cwc;
|
|
BOOL bRet = FALSE;
|
|
|
|
// do parameter validation, check that in chars are indeed unicode
|
|
|
|
if ((pvBuf == (PVOID)NULL) || (iFirst > iLast) || (iLast & 0xffff0000))
|
|
{
|
|
WARNING("gdi!_bGetCharWidthW parameters \n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(bRet);
|
|
}
|
|
|
|
cwc = (LONG)(iLast - iFirst + 1);
|
|
|
|
if(iLast < 0x80)
|
|
{
|
|
CFONT *pcf = NULL;
|
|
PDC_ATTR pDcAttr;
|
|
DWORD dwCP;
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (!pDcAttr)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
dwCP = GET_CODE_PAGE(hdc, pDcAttr);
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
if ((dwCP == CP_ACP) ||
|
|
(dwCP == guintAcp)
|
|
|| (dwCP == guintDBCScp)
|
|
)
|
|
|
|
{
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,iFirst,(PVOID) NULL,(UINT) cwc, TRUE);
|
|
}
|
|
|
|
if (pcf != NULL)
|
|
{
|
|
bRet = bComputeCharWidths(pcf,iFirst,iLast,fl,pvBuf);
|
|
|
|
DEC_CFONT_REF(pcf);
|
|
|
|
if(bRet)
|
|
{
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
return (bRet);
|
|
}
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
}
|
|
|
|
//
|
|
// kernel mode
|
|
//
|
|
|
|
bRet = NtGdiGetCharWidthW(
|
|
hdc,
|
|
iFirst,
|
|
cwc,
|
|
NULL,
|
|
(LONG)(fl & (GCW_INT | GCW_WIN3)),
|
|
pvBuf);
|
|
|
|
return(bRet);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetCharWidthFloatW
|
|
*
|
|
* History:
|
|
* 22-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharWidthFloatW
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst,
|
|
UINT iLast,
|
|
PFLOAT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
return bGetCharWidthW(hdc,iFirst,iLast,0,(PVOID)lpWidths);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetCharWidthW
|
|
*
|
|
* History:
|
|
* 25-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharWidthW
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst,
|
|
UINT iLast,
|
|
LPINT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
return bGetCharWidthW(hdc,iFirst,iLast,GCW_WIN3_INT,(PVOID)lpWidths);
|
|
}
|
|
|
|
BOOL APIENTRY GetCharWidth32W
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst,
|
|
UINT iLast,
|
|
LPINT lpWidths
|
|
)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
return bGetCharWidthW(hdc,iFirst,iLast,GCW_INT,(PVOID)lpWidths);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* WINGDIAPI BOOL WINAPI GetCharWidthI(HDC, UINT, UINT, PWCHAR, LPINT);
|
|
*
|
|
* if pgi == NULL use the consecutive range
|
|
* giFirst, giFirst + 1, ...., giFirst + cgi - 1
|
|
*
|
|
* if pgi != NULL ignore giFirst and use cgi indices pointed to by pgi
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL WINAPI GetCharWidthI(
|
|
HDC hdc,
|
|
UINT giFirst,
|
|
UINT cgi,
|
|
LPWORD pgi,
|
|
LPINT piWidths
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// do parameter validation
|
|
|
|
if (!piWidths || (!pgi && (giFirst & 0xffff0000)))
|
|
{
|
|
WARNING("gdi! GetCharWidthI parameters \n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(bRet);
|
|
}
|
|
|
|
if (!cgi)
|
|
return TRUE; // quick exit
|
|
|
|
// kernel mode
|
|
|
|
bRet = NtGdiGetCharWidthW(
|
|
hdc,
|
|
giFirst,
|
|
cgi,
|
|
(PWCHAR)pgi,
|
|
(GCW_INT | GCW_GLYPH_INDEX),
|
|
(PVOID)piWidths);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetTextExtentPointW(HDC hdc,LPWSTR pwsz,DWORD cwc,LPSIZE psizl)
|
|
*
|
|
*
|
|
* History:
|
|
* 07-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define QUICK_BUFSIZE 0xFF
|
|
|
|
BOOL GetTextExtentPointWInternal(
|
|
HDC hdc,LPCWSTR pwsz,int cwc,LPSIZE psizl, FLONG fl
|
|
)
|
|
{
|
|
WCHAR *pwc;
|
|
CFONT *pcf;
|
|
INT bRet;
|
|
PDC_ATTR pDcAttr;
|
|
BOOL bCache;
|
|
INT i;
|
|
WCHAR wcTest = 0;
|
|
int ii = cwc;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (cwc <= 0)
|
|
{
|
|
|
|
// empty string, just return 0 for the extent
|
|
|
|
if (cwc == 0)
|
|
{
|
|
psizl->cx = 0;
|
|
psizl->cy = 0;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// Let's see if we can take advantage of the ANSI client side GetTextExtent
|
|
// code. If we can convert everything from Unicode to ANSI by ignoring the
|
|
// high byte and it fits into our quick buffer then we can. In the future
|
|
// we will probably want to do a quick Unicode to ANSI conversion using
|
|
// something other than sign extension so we don't mess up non 1252 CP locales
|
|
// by making them go through the slow code all the time.
|
|
|
|
// We need to use this performance optimization if an LPK is installed
|
|
// and some condiditions are met (LTR text alignment, ..etc)
|
|
|
|
pwc = (WCHAR *) pwsz;
|
|
|
|
unroll_here:
|
|
switch(ii)
|
|
{
|
|
default:
|
|
wcTest |= pwc[9];
|
|
case 9:
|
|
wcTest |= pwc[8];
|
|
case 8:
|
|
wcTest |= pwc[7];
|
|
case 7:
|
|
wcTest |= pwc[6];
|
|
case 6:
|
|
wcTest |= pwc[5];
|
|
case 5:
|
|
wcTest |= pwc[4];
|
|
case 4:
|
|
wcTest |= pwc[3];
|
|
case 3:
|
|
wcTest |= pwc[2];
|
|
case 2:
|
|
wcTest |= pwc[1];
|
|
case 1:
|
|
wcTest |= pwc[0];
|
|
}
|
|
|
|
if ((ii > 10) && !(wcTest & 0xFF80))
|
|
{
|
|
ii -= 10;
|
|
pwc += 10;
|
|
goto unroll_here;
|
|
}
|
|
|
|
if (!(wcTest & 0xFF80))
|
|
{
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
if (!pDcAttr)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
#ifdef LANGPACK
|
|
if (!gbLpk || (*fpLpkUseGDIWidthCache)(hdc, (LPCSTR) pwsz,cwc, pDcAttr->lTextAlign , TRUE)) {
|
|
#endif
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID)pwsz,cwc, FALSE);
|
|
|
|
if (pcf != NULL)
|
|
{
|
|
bRet = bComputeTextExtent(pDcAttr,pcf,(PVOID) pwsz,cwc,fl,psizl,FALSE);
|
|
|
|
DEC_CFONT_REF(pcf);
|
|
|
|
if(bRet)
|
|
{
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
return (bRet);
|
|
}
|
|
}
|
|
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
#ifdef LANGPACK
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef LANGPACK
|
|
if(gbLpk)
|
|
{
|
|
return(*fpLpkGetTextExtentExPoint)(hdc, pwsz, cwc, -1, NULL, NULL,
|
|
psizl, fl, -1);
|
|
}
|
|
#endif
|
|
|
|
return NtGdiGetTextExtent(hdc,
|
|
(LPWSTR)pwsz,
|
|
cwc,
|
|
psizl,
|
|
fl);
|
|
|
|
}
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentPointW(HDC hdc,LPCWSTR pwsz,int cwc,LPSIZE psizl)
|
|
{
|
|
return GetTextExtentPointWInternal(hdc, pwsz, cwc, psizl, GGTE_WIN3_EXTENT);
|
|
}
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentPoint32W(HDC hdc,LPCWSTR pwsz,int cwc,LPSIZE psizl)
|
|
{
|
|
return GetTextExtentPointWInternal(hdc, pwsz, cwc, psizl, 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetTextExtentPointI, index version
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentPointI(HDC hdc, LPWORD pgiIn, int cgi, LPSIZE psize)
|
|
{
|
|
return NtGdiGetTextExtent(hdc, (LPWSTR)pgiIn, cgi , psize, GGTE_GLYPH_INDEX);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetFontUnicodeRanges(HDC, LPGLYPHSET)
|
|
*
|
|
* return Unicode content of the font.
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#if 0
|
|
|
|
DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET pgs)
|
|
{
|
|
return NtGdiGetFontUnicodeRanges(hdc, pgs);
|
|
}
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetGlyphIndicesA(HDC, LPCSTR, int, LPWORD, DWORD mode);
|
|
*
|
|
* cmap based conversion, if (mode) indicate that glyph is not supported in the
|
|
* font by putting FFFF in the output array
|
|
*
|
|
* If successfull, the function returns the number of indicies in pgi buffer.
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD WINAPI GetGlyphIndicesA(
|
|
HDC hdc,
|
|
LPCSTR psz,
|
|
int c,
|
|
LPWORD pgi,
|
|
DWORD iMode)
|
|
{
|
|
DWORD dwRet = GDI_ERROR;
|
|
PWSZ pwszCapt;
|
|
PDC_ATTR pDcAttr;
|
|
DWORD dwCP;
|
|
WCHAR awcCaptureBuffer[CAPTURE_STRING_SIZE];
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (c <= 0)
|
|
{
|
|
// empty string, just return 0 for the extent
|
|
|
|
if (c == 0)
|
|
{
|
|
dwRet = 0;
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
dwRet = GDI_ERROR;
|
|
}
|
|
return(dwRet);
|
|
}
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
if (!pDcAttr)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
dwRet = GDI_ERROR;
|
|
return dwRet;
|
|
}
|
|
|
|
dwCP = GET_CODE_PAGE(hdc, pDcAttr);
|
|
|
|
if(guintDBCScp == dwCP)
|
|
{
|
|
QueryFontAssocStatus();
|
|
|
|
if(fFontAssocStatus &&
|
|
((c == 1) || ((c == 2 && *(psz) && *((LPCSTR)(psz + 1)) == '\0'))))
|
|
{
|
|
//
|
|
// If this function is called with only 1 char, and font association
|
|
// is enabled, we should forcely convert the chars to Unicode with
|
|
// codepage 1252.
|
|
// This is for enabling to output Latin-1 chars ( > 0x80 in Ansi codepage )
|
|
// Because, normally font association is enabled, we have no way to output
|
|
// those charactres, then we provide the way, if user call TextOutA() with
|
|
// A character and ansi font, we tempotary disable font association.
|
|
// This might be Windows 3.1 (Korean/Taiwanese) version compatibility..
|
|
//
|
|
dwCP = 1252;
|
|
}
|
|
}
|
|
|
|
// Allocate the string buffer
|
|
|
|
if (c <= CAPTURE_STRING_SIZE)
|
|
{
|
|
pwszCapt = awcCaptureBuffer;
|
|
}
|
|
else
|
|
{
|
|
pwszCapt = LOCALALLOC(c * sizeof(WCHAR));
|
|
}
|
|
|
|
if (pwszCapt)
|
|
{
|
|
|
|
c = MultiByteToWideChar(dwCP, 0, psz,c, pwszCapt, c*sizeof(WCHAR));
|
|
|
|
if (c)
|
|
{
|
|
dwRet = NtGdiGetGlyphIndicesW(hdc,
|
|
(LPWSTR)pwszCapt,
|
|
c,
|
|
pgi,
|
|
iMode);
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
dwRet = GDI_ERROR;
|
|
}
|
|
|
|
if (pwszCapt != awcCaptureBuffer)
|
|
LOCALFREE(pwszCapt);
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
dwRet = GDI_ERROR;
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetGlyphIndicesW(HDC, LPCSTR, int, LPWORD, DWORD);
|
|
*
|
|
* cmap based conversion, if (mode) indicate that glyph is not supported in the
|
|
* font by putting FFFF in the output array
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#if 0
|
|
|
|
DWORD WINAPI GetGlyphIndicesW(
|
|
HDC hdc,
|
|
LPCWSTR pwc,
|
|
int cwc,
|
|
LPWORD pgi,
|
|
DWORD iMode)
|
|
{
|
|
return NtGdiGetGlyphIndicesW(hdc, pwc, cwc, pgi, iMode);
|
|
}
|
|
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* int APIENTRY GetTextFaceA(HDC hdc,int c,LPSTR psz)
|
|
*
|
|
* History:
|
|
* 30-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetTextFaceA(HDC hdc,int c,LPSTR psz)
|
|
{
|
|
ULONG cRet = 0;
|
|
ULONG cbAnsi = 0;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ( (psz != (LPSTR) NULL) && (c <= 0) )
|
|
{
|
|
WARNING("gdi!GetTextFaceA(): invalid parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return cRet;
|
|
}
|
|
|
|
{
|
|
//
|
|
// Kernel mode, allocate a buffer for WCAHR return
|
|
//
|
|
// WINBUG #82833 2-7-2000 bhouse Possible cleanup work in GetTextFaceA
|
|
// Old Comment:
|
|
// - This allocates a temp buffer, then NtGdi does it again
|
|
//
|
|
|
|
PWCHAR pwch = (PWCHAR)NULL;
|
|
|
|
if (c > 0)
|
|
{
|
|
pwch = (WCHAR *)LOCALALLOC(c * sizeof(WCHAR));
|
|
if (pwch == (WCHAR *)NULL)
|
|
{
|
|
WARNING("gdi!GetTextFaceA(): Memory allocation error\n");
|
|
cRet = 0;
|
|
return(cRet);
|
|
}
|
|
}
|
|
|
|
cRet = NtGdiGetTextFaceW(hdc,c,(LPWSTR)pwch,FALSE);
|
|
|
|
if(cRet && (guintDBCScp != 0xFFFFFFFF) && !psz )
|
|
{
|
|
WCHAR *pwcTmp;
|
|
|
|
// now we need to actually need to get the string for DBCS code pages
|
|
// so that we can compute the proper multi-byte length
|
|
|
|
if(pwcTmp = (WCHAR*)LOCALALLOC(cRet*sizeof(WCHAR)))
|
|
{
|
|
UINT cwTmp;
|
|
|
|
cwTmp = NtGdiGetTextFaceW(hdc,cRet,pwcTmp, FALSE);
|
|
|
|
RtlUnicodeToMultiByteSize(&cbAnsi,pwcTmp,cwTmp*sizeof(WCHAR));
|
|
LOCALFREE(pwcTmp);
|
|
}
|
|
else
|
|
{
|
|
WARNING("gdi!GetTextFaceA(): UNICODE to ANSI conversion failed\n");
|
|
cRet = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cbAnsi = cRet;
|
|
}
|
|
|
|
//
|
|
// If successful and non-NULL buffer, convert back to ANSI.
|
|
//
|
|
|
|
if ( (cRet != 0) && (psz != (LPSTR) NULL) && (pwch != (WCHAR*)NULL))
|
|
{
|
|
|
|
if(!(cbAnsi = WideCharToMultiByte(CP_ACP,0,pwch,cRet,psz,c,NULL,NULL)))
|
|
{
|
|
WARNING("gdi!GetTextFaceA(): UNICODE to ANSI conversion failed\n");
|
|
cRet = 0;
|
|
}
|
|
}
|
|
|
|
if (pwch != (PWCHAR)NULL)
|
|
{
|
|
LOCALFREE(pwch);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// return for user and kernel mode
|
|
//
|
|
|
|
return( ((cRet == 0 ) || (psz == NULL) || psz[cbAnsi-1] != 0 ) ? cbAnsi : cbAnsi-1 );
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DWORD APIENTRY GetTextFaceAliasW(HDC hdc,DWORD c,LPWSTR pwsz)
|
|
*
|
|
* History:
|
|
* 24-Feb-1998 -by- Yung-Jen Tony Tsai [YungT]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetTextFaceAliasW(HDC hdc,int c,LPWSTR pwsz)
|
|
{
|
|
int cRet = 0;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ( (pwsz != (LPWSTR) NULL) && (c == 0) )
|
|
{
|
|
WARNING("gdi!GetTextFaceAliasW(): invalid parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return cRet;
|
|
}
|
|
|
|
cRet = NtGdiGetTextFaceW(hdc,c,pwsz,TRUE);
|
|
|
|
return(cRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DWORD APIENTRY GetTextFaceW(HDC hdc,DWORD c,LPWSTR pwsz)
|
|
*
|
|
* History:
|
|
* 13-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int APIENTRY GetTextFaceW(HDC hdc,int c,LPWSTR pwsz)
|
|
{
|
|
int cRet = 0;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ( (pwsz != (LPWSTR) NULL) && (c <= 0) )
|
|
{
|
|
WARNING("gdi!GetTextFaceW(): invalid parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return cRet;
|
|
}
|
|
|
|
cRet = NtGdiGetTextFaceW(hdc,c,pwsz,FALSE);
|
|
|
|
return(cRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vTextMetricWToTextMetricStrict (no char conversion)
|
|
*
|
|
* Effects: return FALSE if UNICODE chars have no ASCI equivalents
|
|
*
|
|
*
|
|
* History:
|
|
* 20-Aug-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL vTextMetricWToTextMetricStrict
|
|
(
|
|
LPTEXTMETRICA ptm,
|
|
LPTEXTMETRICW ptmw
|
|
)
|
|
{
|
|
|
|
ptm->tmHeight = ptmw->tmHeight ; // DWORD
|
|
ptm->tmAscent = ptmw->tmAscent ; // DWORD
|
|
ptm->tmDescent = ptmw->tmDescent ; // DWORD
|
|
ptm->tmInternalLeading = ptmw->tmInternalLeading ; // DWORD
|
|
ptm->tmExternalLeading = ptmw->tmExternalLeading ; // DWORD
|
|
ptm->tmAveCharWidth = ptmw->tmAveCharWidth ; // DWORD
|
|
ptm->tmMaxCharWidth = ptmw->tmMaxCharWidth ; // DWORD
|
|
ptm->tmWeight = ptmw->tmWeight ; // DWORD
|
|
ptm->tmOverhang = ptmw->tmOverhang ; // DWORD
|
|
ptm->tmDigitizedAspectX = ptmw->tmDigitizedAspectX ; // DWORD
|
|
ptm->tmDigitizedAspectY = ptmw->tmDigitizedAspectY ; // DWORD
|
|
ptm->tmItalic = ptmw->tmItalic ; // BYTE
|
|
ptm->tmUnderlined = ptmw->tmUnderlined ; // BYTE
|
|
ptm->tmStruckOut = ptmw->tmStruckOut ; // BYTE
|
|
|
|
ptm->tmPitchAndFamily = ptmw->tmPitchAndFamily ; // BYTE
|
|
ptm->tmCharSet = ptmw->tmCharSet ; // BYTE
|
|
|
|
}
|
|
|
|
|
|
VOID FASTCALL vTextMetricWToTextMetric
|
|
(
|
|
LPTEXTMETRICA ptma,
|
|
TMW_INTERNAL *ptmi
|
|
)
|
|
{
|
|
vTextMetricWToTextMetricStrict(ptma,&ptmi->tmw);
|
|
|
|
ptma->tmFirstChar = ptmi->tmdTmw.chFirst ;
|
|
ptma->tmLastChar = ptmi->tmdTmw.chLast ;
|
|
ptma->tmDefaultChar = ptmi->tmdTmw.chDefault;
|
|
ptma->tmBreakChar = ptmi->tmdTmw.chBreak ;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetTextExtentExPointA
|
|
*
|
|
* History:
|
|
* 06-Jan-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetTextExtentExPointA (
|
|
HDC hdc,
|
|
LPCSTR lpszString,
|
|
int cchString,
|
|
int nMaxExtent,
|
|
LPINT lpnFit,
|
|
LPINT lpnDx,
|
|
LPSIZE lpSize
|
|
)
|
|
{
|
|
WCHAR *pwsz = NULL;
|
|
WCHAR awc[GCP_GLYPHS];
|
|
INT aiDx[GCP_GLYPHS];
|
|
INT *pDx;
|
|
BOOL bRet = FALSE;
|
|
DWORD dwCP;
|
|
BOOL bZeroSize = FALSE;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// some parameter checking. In a single check we will both make sure that
|
|
// cchString is not negative and if positive, that it is not bigger than
|
|
// ULONG_MAX / (sizeof(ULONG) + sizeof(WCHAR)). This restriction is necessary
|
|
// for one of the memory allocations in ntgdi.c allocates
|
|
// cchString * (sizeof(ULONG) + sizeof(WCHAR)).
|
|
// Clearly, the result of this multiplication has to fit in ULONG for the
|
|
// alloc to make sense:
|
|
|
|
// also there is a validity check to be performed on nMaxExtent. -1 is the only
|
|
// legal negative value of nMaxExtent, this basically means
|
|
// that nMaxExtent can be ignored. All other negative values of nMaxExtent are
|
|
// not considered legal input.
|
|
|
|
|
|
if
|
|
(
|
|
((ULONG)cchString > (ULONG_MAX / (sizeof(ULONG)+sizeof(WCHAR))))
|
|
||
|
|
(nMaxExtent < -1)
|
|
)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return bRet;
|
|
}
|
|
|
|
if(cchString == 0)
|
|
bZeroSize = TRUE;
|
|
|
|
// now allocate memory (if needed) for the unicode string if needed
|
|
|
|
if (cchString <= GCP_GLYPHS)
|
|
{
|
|
pwsz = awc;
|
|
pDx = aiDx;
|
|
}
|
|
else
|
|
{
|
|
pwsz = LOCALALLOC((cchString+1) * (sizeof(WCHAR) + sizeof(INT)));
|
|
pDx = (INT*) &pwsz[(cchString+1)&~1];
|
|
}
|
|
|
|
|
|
if (pwsz)
|
|
{
|
|
UINT cwcWideChars;
|
|
|
|
// convert Ansi To Unicode based on the code page of the font selected in DC
|
|
|
|
dwCP = GetCodePage(hdc);
|
|
if( bZeroSize || ( cwcWideChars = MultiByteToWideChar(dwCP,
|
|
0,
|
|
lpszString, cchString,
|
|
pwsz, cchString*sizeof(WCHAR))) )
|
|
{
|
|
BOOL bDBCSFont = IS_ANY_DBCS_CODEPAGE(dwCP) ? TRUE : FALSE;
|
|
|
|
if(bZeroSize){
|
|
cwcWideChars = 0;
|
|
pwsz[0] = (WCHAR) 0x0;
|
|
}
|
|
|
|
#ifdef LANGPACK
|
|
if(gbLpk)
|
|
{
|
|
bRet = (*fpLpkGetTextExtentExPoint)(hdc, pwsz, cwcWideChars, nMaxExtent,
|
|
lpnFit, bDBCSFont ? pDx : lpnDx,
|
|
lpSize, 0, 0);
|
|
}
|
|
else
|
|
#endif
|
|
bRet = NtGdiGetTextExtentExW(hdc,
|
|
pwsz,
|
|
cwcWideChars,
|
|
nMaxExtent,
|
|
lpnFit,
|
|
bDBCSFont ? pDx : lpnDx,
|
|
lpSize,
|
|
0);
|
|
|
|
if (bDBCSFont && bRet)
|
|
{
|
|
// if this is a DBCS font then we need to make some adjustments
|
|
|
|
int i, j;
|
|
int cchFit, cwc;
|
|
|
|
// first compute return the proper fit in multi byte characters
|
|
|
|
if (lpnFit)
|
|
{
|
|
cwc = *lpnFit;
|
|
cchFit = WideCharToMultiByte(dwCP, 0, pwsz, cwc, NULL, 0, NULL, NULL);
|
|
*lpnFit = cchFit;
|
|
}
|
|
else
|
|
{
|
|
cwc = cwcWideChars;
|
|
cchFit = cchString;
|
|
}
|
|
|
|
// next copy the dx array. we duplicate the dx value for the high
|
|
// and low byte of DBCS characters.
|
|
|
|
if(lpnDx)
|
|
{
|
|
for(i = 0, j = 0; i < cchFit; j++)
|
|
{
|
|
if(IsDBCSLeadByteEx(dwCP,lpszString[i]))
|
|
{
|
|
lpnDx[i++] = pDx[j];
|
|
lpnDx[i++] = pDx[j];
|
|
}
|
|
else
|
|
{
|
|
lpnDx[i++] = pDx[j];
|
|
}
|
|
}
|
|
|
|
// I claim that we should be at exactly at the end of the Unicode
|
|
// string once we are here if not we need to examine the above loop
|
|
// to make sure it works properly [gerritv]
|
|
|
|
ASSERTGDI(j == cwc,
|
|
"GetTextExtentExPointA: problem converting DX array\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (pwsz != awc)
|
|
LOCALFREE(pwsz);
|
|
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetTextExtentExPointW
|
|
*
|
|
* History:
|
|
* 06-Jan-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentExPointW (
|
|
HDC hdc,
|
|
LPCWSTR lpwszString,
|
|
int cwchString,
|
|
int nMaxExtent,
|
|
LPINT lpnFit,
|
|
LPINT lpnDx,
|
|
LPSIZE lpSize
|
|
)
|
|
{
|
|
|
|
#ifdef LANGPACK
|
|
if(gbLpk)
|
|
{
|
|
return (*fpLpkGetTextExtentExPoint)(hdc, lpwszString, cwchString, nMaxExtent,
|
|
lpnFit, lpnDx, lpSize, 0, -1);
|
|
}
|
|
else
|
|
#endif
|
|
return NtGdiGetTextExtentExW(hdc,
|
|
(LPWSTR)lpwszString,
|
|
cwchString,
|
|
nMaxExtent,
|
|
lpnFit,
|
|
lpnDx,
|
|
lpSize,
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetTextExtentExPointWPri,
|
|
* The same as GetTextExtentExPointW, the only difference is that
|
|
* lpk is bypassed, whether installed or not. This routine is actually called
|
|
* by lpk when it is installed.
|
|
*
|
|
* History:
|
|
* 03-Jun-1997 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentExPointWPri (
|
|
HDC hdc,
|
|
LPCWSTR lpwszString,
|
|
int cwchString,
|
|
int nMaxExtent,
|
|
LPINT lpnFit,
|
|
LPINT lpnDx,
|
|
LPSIZE lpSize
|
|
)
|
|
{
|
|
|
|
return NtGdiGetTextExtentExW(hdc,
|
|
(LPWSTR)lpwszString,
|
|
cwchString,
|
|
nMaxExtent,
|
|
lpnFit,
|
|
lpnDx,
|
|
lpSize,
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL APIENTRY GetTextExtentExPointI
|
|
*
|
|
*
|
|
* History:
|
|
* 09-Sep-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL APIENTRY GetTextExtentExPointI (
|
|
HDC hdc,
|
|
LPWORD lpwszString,
|
|
int cwchString,
|
|
int nMaxExtent,
|
|
LPINT lpnFit,
|
|
LPINT lpnDx,
|
|
LPSIZE lpSize
|
|
)
|
|
{
|
|
return NtGdiGetTextExtentExW(hdc,
|
|
(LPWSTR)lpwszString,
|
|
cwchString,
|
|
nMaxExtent,
|
|
lpnFit,
|
|
lpnDx,
|
|
lpSize,
|
|
GTEEX_GLYPH_INDEX);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bGetCharABCWidthsA
|
|
*
|
|
* works for both floating point and integer version depending on bInt
|
|
*
|
|
* History:
|
|
* 24-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetCharABCWidthsA (
|
|
HDC hdc,
|
|
UINT wFirst,
|
|
UINT wLast,
|
|
FLONG fl,
|
|
PVOID pvBuf // if (fl & GCABCW_INT) pabc else pabcf,
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG cjData, cjWCHAR, cjABC;
|
|
ULONG cChar = wLast - wFirst + 1;
|
|
DWORD dwCP = GetCodePage(hdc);
|
|
BOOL bDBCSCodePage;
|
|
|
|
bDBCSCodePage = IS_ANY_DBCS_CODEPAGE(dwCP);
|
|
|
|
// Parameter checking.
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if((pvBuf == (PVOID) NULL) ||
|
|
(bDBCSCodePage && !IsValidDBCSRange(wFirst,wLast)) ||
|
|
(!bDBCSCodePage && ((wFirst > wLast) || (wLast > 255))))
|
|
{
|
|
WARNING("gdi!_GetCharABCWidthsA(): bad parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Compute buffer space needed in memory window.
|
|
// Buffer will be input array of WCHAR followed by output arrary of ABC.
|
|
// Because ABC need 32-bit alignment, cjWCHAR is rounded up to DWORD boundary.
|
|
|
|
cjABC = cChar * ((fl & GCABCW_INT) ? sizeof(ABC) : sizeof(ABCFLOAT));
|
|
cjWCHAR = ALIGN4(cChar * sizeof(WCHAR));
|
|
cjData = cjWCHAR + cjABC;
|
|
|
|
|
|
//
|
|
// WINBUG 82840 2-7-2000 bhouse Possible cleanup in bGetCharABCWidthsA
|
|
// Old Comment:
|
|
// - if vSetUpUnicodeString,x could be moved to ntgdi,
|
|
// we wouldn't need to allocated temp buffers twice
|
|
//
|
|
// Allocate memory for temp buffer, fill in with proper char values
|
|
//
|
|
// Write the unicode string [wFirst,wLast] at the top of the buffer.
|
|
// vSetUpUnicodeString requires a tmp CHAR buffer; we'll cheat a little
|
|
// and use the ABC return buffer (this assumes that ABC is bigger
|
|
// than a CHAR or USHORT in the case of DBCS). We can get away with this b
|
|
// because this memory is an output buffer for the server call.
|
|
//
|
|
|
|
{
|
|
PUCHAR pjTempBuffer = LOCALALLOC(cjData);
|
|
PUCHAR pwcABC = pjTempBuffer + cjWCHAR;
|
|
PWCHAR pwcCHAR = (PWCHAR)pjTempBuffer;
|
|
|
|
if (pjTempBuffer == (PUCHAR)NULL)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
|
|
if(bDBCSCodePage)
|
|
{
|
|
bRet = bSetUpUnicodeStringDBCS(wFirst,
|
|
wLast,
|
|
pwcABC,
|
|
pwcCHAR,
|
|
dwCP,
|
|
GetCurrentDefaultChar(hdc));
|
|
}
|
|
else
|
|
{
|
|
bRet = bSetUpUnicodeString(wFirst,
|
|
wLast,
|
|
pwcABC,
|
|
pwcCHAR, dwCP);
|
|
}
|
|
|
|
//
|
|
// call GDI
|
|
//
|
|
|
|
if(bRet)
|
|
{
|
|
bRet = NtGdiGetCharABCWidthsW(hdc,
|
|
wFirst,
|
|
cChar,
|
|
(PWCHAR)pwcCHAR,
|
|
(fl & GCABCW_INT),
|
|
(PVOID)pwcABC);
|
|
}
|
|
|
|
//
|
|
// If OK, then copy return data out of window.
|
|
//
|
|
|
|
if (bRet)
|
|
{
|
|
RtlCopyMemory((PBYTE) pvBuf,pwcABC, cjABC);
|
|
}
|
|
|
|
LOCALFREE(pjTempBuffer);
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY GetCharABCWidthsA (
|
|
*
|
|
* We want to get ABC spaces
|
|
* for a contiguous set of input codepoints (that range from wFirst to wLast).
|
|
* The set of corresponding UNICODE codepoints is not guaranteed to be
|
|
* contiguous. Therefore, we will translate the input codepoints here and
|
|
* pass the server a buffer of UNICODE codepoints.
|
|
*
|
|
* History:
|
|
* 20-Jan-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharABCWidthsA (
|
|
HDC hdc,
|
|
UINT wFirst,
|
|
UINT wLast,
|
|
LPABC lpABC
|
|
)
|
|
{
|
|
return bGetCharABCWidthsA(hdc,wFirst,wLast,GCABCW_INT,(PVOID)lpABC);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetCharABCWidthsFloatA
|
|
*
|
|
* History:
|
|
* 22-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharABCWidthsFloatA
|
|
(
|
|
IN HDC hdc,
|
|
IN UINT iFirst,
|
|
IN UINT iLast,
|
|
OUT LPABCFLOAT lpABCF
|
|
)
|
|
{
|
|
return bGetCharABCWidthsA(hdc,iFirst,iLast,0,(PVOID)lpABCF);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bGetCharABCWidthsW
|
|
*
|
|
* History:
|
|
* 22-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetCharABCWidthsW (
|
|
IN HDC hdc,
|
|
IN UINT wchFirst,
|
|
IN UINT wchLast,
|
|
IN FLONG fl,
|
|
OUT PVOID pvBuf
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG cwch = wchLast - wchFirst + 1;
|
|
|
|
// Parameter checking.
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ( (pvBuf == (PVOID)NULL) || (wchFirst > wchLast) )
|
|
{
|
|
WARNING("gdi!GetCharABCWidthsW(): bad parameter\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// kernel mode
|
|
//
|
|
|
|
bRet = NtGdiGetCharABCWidthsW(
|
|
hdc,
|
|
wchFirst,
|
|
cwch,
|
|
(PWCHAR)NULL,
|
|
fl,
|
|
(PVOID)pvBuf);
|
|
|
|
return(bRet);
|
|
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL APIENTRY GetCharABCWidthsW (
|
|
* IN HDC hdc,
|
|
* IN WORD wchFirst,
|
|
* IN WORD wchLast,
|
|
* OUT LPABC lpABC
|
|
* )
|
|
*
|
|
* For this case, we can truly assume that we want to get ABC character
|
|
* widths for a contiguous set of UNICODE codepoints from wchFirst to
|
|
* wchLast (inclusive). So we will call the server using wchFirst, but
|
|
* with an empty input buffer.
|
|
*
|
|
* History:
|
|
* 20-Jan-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharABCWidthsW (
|
|
HDC hdc,
|
|
UINT wchFirst,
|
|
UINT wchLast,
|
|
LPABC lpABC
|
|
)
|
|
{
|
|
return bGetCharABCWidthsW(hdc,wchFirst,wchLast,GCABCW_INT,(PVOID)lpABC);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetCharABCWidthsFloatW
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 22-Feb-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharABCWidthsFloatW
|
|
(
|
|
HDC hdc,
|
|
UINT iFirst,
|
|
UINT iLast,
|
|
LPABCFLOAT lpABCF
|
|
)
|
|
{
|
|
return bGetCharABCWidthsW(hdc,iFirst,iLast,0,(PVOID)lpABCF);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetCharABCWidthsI, index version
|
|
*
|
|
* if pgi == NULL use the consecutive range
|
|
* giFirst, giFirst + 1, ...., giFirst + cgi - 1
|
|
*
|
|
* if pgi != NULL ignore giFirst and use cgi indices pointed to by pgi
|
|
*
|
|
* History:
|
|
* 28-Aug-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharABCWidthsI(
|
|
HDC hdc,
|
|
UINT giFirst,
|
|
UINT cgi,
|
|
LPWORD pgi,
|
|
LPABC pabc
|
|
)
|
|
{
|
|
return NtGdiGetCharABCWidthsW(hdc,
|
|
giFirst,
|
|
cgi,
|
|
pgi,
|
|
GCABCW_INT | GCABCW_GLYPH_INDEX,
|
|
pabc
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetFontData
|
|
*
|
|
* Client side stub to GreGetFontData.
|
|
*
|
|
* History:
|
|
* 17-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD APIENTRY GetFontData (
|
|
HDC hdc,
|
|
DWORD dwTable,
|
|
DWORD dwOffset,
|
|
PVOID pvBuffer,
|
|
DWORD cjBuffer
|
|
)
|
|
{
|
|
DWORD dwRet = (DWORD) -1;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// if there is no buffer to copy data to, ignore possibly different
|
|
// from zero cjBuffer parameter. This is what win95 is doing.
|
|
|
|
if (cjBuffer && (pvBuffer == NULL))
|
|
cjBuffer = 0;
|
|
|
|
dwRet = NtGdiGetFontData(
|
|
hdc,
|
|
dwTable,
|
|
dwOffset,
|
|
pvBuffer,
|
|
cjBuffer);
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetGlyphOutline
|
|
*
|
|
* Client side stub to GreGetGlyphOutline.
|
|
*
|
|
* History:
|
|
* 17-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD GetGlyphOutlineInternalW (
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT fuFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cjBuffer,
|
|
LPVOID pvBuffer,
|
|
CONST MAT2 *lpmat2,
|
|
BOOL bIgnoreRotation
|
|
)
|
|
{
|
|
DWORD dwRet = (DWORD) -1;
|
|
|
|
// Parameter validation.
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ( (lpmat2 == (LPMAT2) NULL)
|
|
|| (lpgm == (LPGLYPHMETRICS) NULL)
|
|
)
|
|
{
|
|
WARNING("gdi!GetGlyphOutlineW(): bad parameter\n");
|
|
return (dwRet);
|
|
}
|
|
|
|
if (pvBuffer == NULL)
|
|
cjBuffer = 0;
|
|
|
|
// Compute buffer space needed in memory window.
|
|
|
|
dwRet = NtGdiGetGlyphOutline(
|
|
hdc,
|
|
(WCHAR)uChar,
|
|
fuFormat,
|
|
lpgm,
|
|
cjBuffer,
|
|
pvBuffer,
|
|
(LPMAT2)lpmat2,
|
|
bIgnoreRotation);
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
|
|
DWORD APIENTRY GetGlyphOutlineW (
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT fuFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cjBuffer,
|
|
LPVOID pvBuffer,
|
|
CONST MAT2 *lpmat2
|
|
)
|
|
{
|
|
|
|
return( GetGlyphOutlineInternalW( hdc,
|
|
uChar,
|
|
fuFormat,
|
|
lpgm,
|
|
cjBuffer,
|
|
pvBuffer,
|
|
lpmat2,
|
|
FALSE ) );
|
|
}
|
|
|
|
|
|
|
|
DWORD APIENTRY GetGlyphOutlineInternalA (
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT fuFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cjBuffer,
|
|
LPVOID pvBuffer,
|
|
CONST MAT2 *lpmat2,
|
|
BOOL bIgnoreRotation
|
|
)
|
|
{
|
|
WCHAR wc;
|
|
BOOL bRet;
|
|
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// The ANSI interface is compatible with Win 3.1 and is intended
|
|
// to take a 2 byte uChar. Since we are 32-bit, this 16-bit UINT
|
|
// is now 32-bit. So we are only interested in the least significant
|
|
// word of the uChar passed into the 32-bit interface.
|
|
|
|
if (!(fuFormat & GGO_GLYPH_INDEX))
|
|
{
|
|
// the conversion needs to be done based on
|
|
// the current code page of the font selected in the dc
|
|
UCHAR Mbcs[2];
|
|
UINT Convert;
|
|
DWORD dwCP = GetCodePage(hdc);
|
|
|
|
|
|
if(IS_ANY_DBCS_CODEPAGE(dwCP) &&
|
|
IsDBCSLeadByteEx(dwCP, (char) (uChar >> 8)))
|
|
{
|
|
Mbcs[0] = (uChar >> 8) & 0xFF;
|
|
Mbcs[1] = uChar & 0xFF;
|
|
Convert = 2;
|
|
}
|
|
else
|
|
{
|
|
Mbcs[0] = uChar & 0xFF;
|
|
Convert = 1;
|
|
}
|
|
|
|
if(!(bRet = MultiByteToWideChar(dwCP, 0,
|
|
(LPCSTR)Mbcs,Convert,
|
|
&wc, sizeof(WCHAR))))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// The uChar value is to be interpreted as glyph index and
|
|
// no conversion is necessary
|
|
|
|
wc = (WCHAR)uChar;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
|
|
if (bRet)
|
|
{
|
|
bRet = GetGlyphOutlineInternalW(
|
|
hdc,
|
|
(UINT) wc,
|
|
fuFormat,
|
|
lpgm,
|
|
cjBuffer,
|
|
pvBuffer,
|
|
lpmat2,
|
|
bIgnoreRotation);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
DWORD APIENTRY GetGlyphOutlineA (
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT fuFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cjBuffer,
|
|
LPVOID pvBuffer,
|
|
CONST MAT2 *lpmat2
|
|
)
|
|
{
|
|
|
|
return( GetGlyphOutlineInternalA( hdc,
|
|
uChar,
|
|
fuFormat,
|
|
lpgm,
|
|
cjBuffer,
|
|
pvBuffer,
|
|
lpmat2,
|
|
FALSE ) );
|
|
}
|
|
|
|
|
|
DWORD APIENTRY GetGlyphOutlineWow (
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT fuFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cjBuffer,
|
|
LPVOID pvBuffer,
|
|
CONST MAT2 *lpmat2
|
|
)
|
|
{
|
|
|
|
return( GetGlyphOutlineInternalA( hdc,
|
|
uChar,
|
|
fuFormat,
|
|
lpgm,
|
|
cjBuffer,
|
|
pvBuffer,
|
|
lpmat2,
|
|
TRUE ) );
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetOutlineTextMetricsW
|
|
*
|
|
* Client side stub to GreGetOutlineTextMetrics.
|
|
*
|
|
* History:
|
|
*
|
|
* Tue 20-Apr-1993 -by- Gerrit van Wingerden [gerritv]
|
|
* update: added bTTOnly stuff for Aldus escape in the WOW layer
|
|
*
|
|
* Thu 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* update: added TMDIFF * stuff
|
|
*
|
|
* 17-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
UINT APIENTRY GetOutlineTextMetricsWInternal (
|
|
HDC hdc,
|
|
UINT cjCopy, // refers to OTMW_INTERNAL, not to OUTLINETEXTMETRICSW
|
|
OUTLINETEXTMETRICW * potmw,
|
|
TMDIFF * ptmd
|
|
)
|
|
{
|
|
DWORD cjRet = (DWORD) 0;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (potmw == (OUTLINETEXTMETRICW *) NULL)
|
|
cjCopy = 0;
|
|
|
|
cjRet = NtGdiGetOutlineTextMetricsInternalW(
|
|
hdc,
|
|
cjCopy,
|
|
potmw,
|
|
ptmd);
|
|
|
|
return(cjRet);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* UINT APIENTRY GetOutlineTextMetricsW (
|
|
*
|
|
* wrote the wrapper to go around the corresponding internal routine
|
|
*
|
|
* History:
|
|
* 28-Jan-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
UINT APIENTRY GetOutlineTextMetricsW (
|
|
HDC hdc,
|
|
UINT cjCopy,
|
|
LPOUTLINETEXTMETRICW potmw
|
|
)
|
|
{
|
|
TMDIFF tmd;
|
|
|
|
return GetOutlineTextMetricsWInternal(hdc, cjCopy, potmw, &tmd);
|
|
}
|
|
|
|
|
|
#define bAnsiSize(a,b,c) (NT_SUCCESS(RtlUnicodeToMultiByteSize((a),(b),(c))))
|
|
|
|
// vAnsiSize macro should only be used within GetOTMA, where bAnsiSize
|
|
// is not supposed to fail [bodind]
|
|
|
|
#if DBG
|
|
|
|
#define vAnsiSize(a,b,c) \
|
|
{ \
|
|
BOOL bTmp = bAnsiSize(&cjString, pwszSrc, sizeof(WCHAR) * cwc); \
|
|
ASSERTGDI(bTmp, "gdi32!GetOTMA: bAnsiSize failed \n"); \
|
|
}
|
|
|
|
#else
|
|
|
|
#define vAnsiSize(a,b,c) bAnsiSize(a,b,c)
|
|
|
|
#endif //, non debug version
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetOutlineTextMetricsInternalA
|
|
*
|
|
* Client side stub to GreGetOutlineTextMetrics.
|
|
*
|
|
* History:
|
|
*
|
|
* 20-Apr-1993 -by- Gerrit van Wingerden [gerritv]
|
|
* Changed to GetOutlineTextMetricsInternalA from GetOutlineTextMetricsA
|
|
* to support all fonts mode for Aldus escape.
|
|
*
|
|
* 17-Feb-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
UINT APIENTRY GetOutlineTextMetricsInternalA (
|
|
HDC hdc,
|
|
UINT cjCopy,
|
|
LPOUTLINETEXTMETRICA potma
|
|
)
|
|
{
|
|
UINT cjRet = 0;
|
|
UINT cjotma, cjotmw;
|
|
|
|
TMDIFF tmd;
|
|
OUTLINETEXTMETRICW *potmwTmp;
|
|
OUTLINETEXTMETRICA otmaTmp; // tmp buffer on the stack
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// Because we need to be able to copy cjCopy bytes of data from the
|
|
// OUTLINETEXTMETRICA structure, we need to allocate a temporary buffer
|
|
// big enough for the entire structure. This is because the UNICODE and
|
|
// ANSI versions of OUTLINETEXTMETRIC have mismatched offsets to their
|
|
// corresponding fields.
|
|
|
|
// Determine size of the buffer.
|
|
|
|
if ((cjotmw = GetOutlineTextMetricsWInternal(hdc, 0, NULL,&tmd)) == 0 )
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): unable to determine size of buffer needed\n");
|
|
return (cjRet);
|
|
}
|
|
|
|
// get cjotma from tmd.
|
|
|
|
cjotma = (UINT)tmd.cjotma;
|
|
|
|
// if cjotma == 0, this is HONEST to God unicode font, can not convert
|
|
// strings to ansi
|
|
|
|
if (cjotma == 0)
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): unable to determine cjotma\n");
|
|
return (cjRet);
|
|
}
|
|
|
|
// Early out. If NULL buffer, then just return the size.
|
|
|
|
if (potma == (LPOUTLINETEXTMETRICA) NULL)
|
|
return (cjotma);
|
|
|
|
// Allocate temporary buffers.
|
|
|
|
if ((potmwTmp = (OUTLINETEXTMETRICW*) LOCALALLOC(cjotmw)) == (OUTLINETEXTMETRICW*)NULL)
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricA(): memory allocation error OUTLINETEXTMETRICW buffer\n");
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return (cjRet);
|
|
}
|
|
|
|
// Call the UNICODE version of the call.
|
|
|
|
if (GetOutlineTextMetricsWInternal(hdc, cjotmw, potmwTmp,&tmd) == 0 )
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): call to GetOutlineTextMetricsW() failed\n");
|
|
LOCALFREE(potmwTmp);
|
|
return (cjRet);
|
|
}
|
|
|
|
// Convert from OUTLINETEXTMETRICW to OUTLINETEXTMETRICA
|
|
|
|
vOutlineTextMetricWToOutlineTextMetricA(&otmaTmp, potmwTmp,&tmd);
|
|
|
|
// Copy data into return buffer. Do not copy strings.
|
|
|
|
cjRet = min(cjCopy, sizeof(OUTLINETEXTMETRICA));
|
|
RtlMoveMemory(potma,&otmaTmp,cjRet);
|
|
|
|
// Note that if
|
|
// offsetof(OUTLINETEXTMETRICA,otmpFamilyName) < cjCopy <= sizeof(OUTLINETEXTMETRICA)
|
|
// the offsets to strings have been set to zero [BodinD]
|
|
|
|
// If strings wanted, convert the strings to ANSI.
|
|
|
|
if (cjCopy > sizeof(OUTLINETEXTMETRICA))
|
|
{
|
|
ULONG cjString,cwc;
|
|
ULONG_PTR dpString;
|
|
ULONG_PTR dpStringEnd;
|
|
PWSZ pwszSrc;
|
|
|
|
// first have to make sure that we will not overwrite the end
|
|
// of the caller's buffer, if that is the case
|
|
|
|
if (cjCopy < cjotma)
|
|
{
|
|
// Win 31 spec is ambiguous about this case
|
|
// and by looking into the source code, it seems that
|
|
// they just overwrite the end of the buffer without
|
|
// even doing this check.
|
|
|
|
GdiSetLastError(ERROR_CAN_NOT_COMPLETE);
|
|
cjRet = 0;
|
|
goto GOTMA_clean_up;
|
|
}
|
|
|
|
// now we know that all the strings can fit, moreover we know that
|
|
// all string operations will succeed since we have called
|
|
// cjOTMA to do these same operations on the server side to give us
|
|
// cjotma [bodind]
|
|
|
|
// Note: have to do the backwards compatible casting below because Win 3.1 insists
|
|
// on using a PSTR as PTRDIFF (i.e., an offset).
|
|
|
|
// FAMILY NAME ------------------------------------------------------------
|
|
|
|
pwszSrc = (PWSZ) (((PBYTE) potmwTmp) + (ULONG_PTR) potmwTmp->otmpFamilyName);
|
|
cwc = wcslen(pwszSrc) + 1;
|
|
vAnsiSize(&cjString, pwszSrc, sizeof(WCHAR) * cwc);
|
|
|
|
// Convert from Unicode to ASCII.
|
|
|
|
dpString = sizeof(OUTLINETEXTMETRICA);
|
|
dpStringEnd = dpString + cjString;
|
|
|
|
ASSERTGDI(dpStringEnd <= cjCopy, "gdi32!GetOTMA: string can not fit1\n");
|
|
|
|
if (!bToASCII_N ((PBYTE)potma + dpString,cjString,pwszSrc,cwc))
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): UNICODE->ASCII conv error \n");
|
|
cjRet = 0;
|
|
goto GOTMA_clean_up;
|
|
}
|
|
|
|
// Store string offset in the return structure.
|
|
|
|
potma->otmpFamilyName = (PSTR) dpString;
|
|
|
|
// FACE NAME --------------------------------------------------------------
|
|
|
|
pwszSrc = (PWSZ) (((PBYTE) potmwTmp) + (ULONG_PTR) potmwTmp->otmpFaceName);
|
|
cwc = wcslen(pwszSrc) + 1;
|
|
vAnsiSize(&cjString, pwszSrc, sizeof(WCHAR) * cwc);
|
|
|
|
dpString = dpStringEnd;
|
|
dpStringEnd = dpString + cjString;
|
|
|
|
ASSERTGDI(dpStringEnd <= cjCopy, "gdi32!GetOTMA: string can not fit2\n");
|
|
|
|
// Convert from Unicode to ASCII.
|
|
|
|
if (!bToASCII_N ((PBYTE)potma + dpString,cjString,pwszSrc,cwc))
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): UNICODE->ASCII conv error \n");
|
|
cjRet = 0;
|
|
goto GOTMA_clean_up;
|
|
}
|
|
|
|
// Store string offset in return structure. Move pointers to next string.
|
|
|
|
potma->otmpFaceName = (PSTR) dpString;
|
|
|
|
// STYLE NAME -------------------------------------------------------------
|
|
|
|
pwszSrc = (PWSZ) (((PBYTE) potmwTmp) + (ULONG_PTR) potmwTmp->otmpStyleName);
|
|
cwc = wcslen(pwszSrc) + 1;
|
|
vAnsiSize(&cjString, pwszSrc, sizeof(WCHAR) * cwc);
|
|
|
|
dpString = dpStringEnd;
|
|
dpStringEnd = dpString + cjString;
|
|
|
|
ASSERTGDI(dpStringEnd <= cjCopy, "gdi32!GetOTMA: string can not fit3\n");
|
|
|
|
// Convert from Unicode to ASCII.
|
|
|
|
if (!bToASCII_N ((PBYTE)potma + dpString,cjString,pwszSrc,cwc))
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): UNICODE->ASCII conv error \n");
|
|
cjRet = 0;
|
|
goto GOTMA_clean_up;
|
|
}
|
|
|
|
// Store string offset in return structure. Move pointers to next string.
|
|
|
|
potma->otmpStyleName = (PSTR)dpString;
|
|
|
|
// FULL NAME --------------------------------------------------------------
|
|
|
|
pwszSrc = (PWSZ) (((PBYTE) potmwTmp) + (ULONG_PTR) potmwTmp->otmpFullName);
|
|
cwc = wcslen(pwszSrc) + 1;
|
|
vAnsiSize(&cjString, pwszSrc, sizeof(WCHAR) * cwc);
|
|
|
|
dpString = dpStringEnd;
|
|
dpStringEnd = dpString + cjString;
|
|
|
|
ASSERTGDI(dpStringEnd <= cjCopy, "gdi32!GetOTMA: string can not fit4\n");
|
|
|
|
// Convert from Unicode to ASCII.
|
|
|
|
if (!bToASCII_N ((PBYTE)potma + dpString,cjString,pwszSrc,cwc))
|
|
{
|
|
WARNING("gdi!GetOutlineTextMetricsInternalA(): UNICODE->ASCII conv error \n");
|
|
cjRet = 0;
|
|
goto GOTMA_clean_up;
|
|
}
|
|
|
|
// Store string offset in return structure.
|
|
|
|
potma->otmpFullName = (PSTR) dpString;
|
|
|
|
//Sundown: safe to truncate ULONG
|
|
cjRet = (ULONG)dpStringEnd;
|
|
ASSERTGDI(cjRet == cjotma, "gdi32!GetOTMA: cjRet != dpStringEnd\n");
|
|
|
|
}
|
|
|
|
GOTMA_clean_up:
|
|
|
|
// Free temporary buffer.
|
|
|
|
LOCALFREE(potmwTmp);
|
|
|
|
// Fixup size field.
|
|
|
|
if (cjCopy >= sizeof(UINT)) // if it is possible to store otmSize
|
|
potma->otmSize = cjRet;
|
|
|
|
// Successful, so return size.
|
|
|
|
return (cjRet);
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetOutlineTextMetricsA
|
|
*
|
|
* Client side stub to GreGetOutlineTextMetrics.
|
|
*
|
|
* History:
|
|
* Tue 02-Nov-1993 -by- Bodin Dresevic [BodinD]
|
|
\**************************************************************************/
|
|
|
|
|
|
UINT APIENTRY GetOutlineTextMetricsA (
|
|
HDC hdc,
|
|
UINT cjCopy,
|
|
LPOUTLINETEXTMETRICA potma
|
|
)
|
|
{
|
|
return GetOutlineTextMetricsInternalA(hdc, cjCopy, potma);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* *
|
|
* GetKerningPairs *
|
|
* *
|
|
* History: *
|
|
* Sun 23-Feb-1992 09:48:55 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
DWORD APIENTRY
|
|
GetKerningPairsW(
|
|
IN HDC hdc, // handle to application's DC
|
|
IN DWORD nPairs, // max no. KERNINGPAIR to be returned
|
|
OUT LPKERNINGPAIR lpKernPair // pointer to receiving buffer
|
|
)
|
|
{
|
|
ULONG sizeofMsg;
|
|
DWORD cRet = 0;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if (nPairs == 0 && lpKernPair != (KERNINGPAIR*) NULL)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(0);
|
|
}
|
|
|
|
cRet = NtGdiGetKerningPairs(
|
|
hdc,
|
|
nPairs,
|
|
lpKernPair);
|
|
|
|
return(cRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetKerningPairsA
|
|
*
|
|
* filters out pairs that are not contained in the code page of the font
|
|
* selected in DC
|
|
*
|
|
* History:
|
|
* 14-Mar-1996 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
DWORD APIENTRY GetKerningPairsA
|
|
(
|
|
HDC hdc, // handle to application's DC
|
|
DWORD nPairs, // max no. KERNINGPAIR to be returned
|
|
LPKERNINGPAIR lpKernPair // pointer to receiving buffer
|
|
)
|
|
{
|
|
#define MAXKERNPAIR 300
|
|
DWORD i;
|
|
DWORD dwCP;
|
|
KERNINGPAIR tmpKernPair[MAXKERNPAIR];
|
|
DWORD cRet, cRet1;
|
|
KERNINGPAIR *pkp, *pkrn;
|
|
KERNINGPAIR UNALIGNED *pkrnLast;
|
|
BOOL bDBCS;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
if ((nPairs == 0) && (lpKernPair != (KERNINGPAIR*) NULL))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return(0);
|
|
}
|
|
|
|
cRet = NtGdiGetKerningPairs(hdc, 0, NULL);
|
|
|
|
if (cRet == 0)
|
|
return(cRet);
|
|
|
|
if (cRet <= MAXKERNPAIR)
|
|
pkrn = tmpKernPair;
|
|
else
|
|
pkrn = LOCALALLOC(cRet * sizeof(KERNINGPAIR));
|
|
|
|
if (!pkrn)
|
|
{
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return 0;
|
|
}
|
|
|
|
cRet1 = NtGdiGetKerningPairs(hdc, cRet, pkrn);
|
|
|
|
if (cRet1 == 0 || cRet1 != cRet)
|
|
{
|
|
ASSERTGDI(FALSE, "NtGdiGetKerningPairs returns different values\n");
|
|
cRet = 0;
|
|
goto Cleanup;
|
|
}
|
|
|
|
pkp = pkrn;
|
|
pkrnLast = lpKernPair;
|
|
cRet = 0;
|
|
|
|
// GDI has returned iFirst and iSecond of the KERNINGPAIR structure in Unicode
|
|
// It is at this point that we translate them to the current code page
|
|
|
|
dwCP = GetCodePage(hdc);
|
|
|
|
bDBCS = IS_ANY_DBCS_CODEPAGE(dwCP);
|
|
|
|
for (i = 0; i < cRet1; i++,pkp++)
|
|
{
|
|
UCHAR ach[2], ach2[2];
|
|
BOOL bUsedDef[2];
|
|
|
|
ach[0] = ach[1] = 0; // insure zero extension
|
|
|
|
WideCharToMultiByte(dwCP,
|
|
0,
|
|
&(pkp->wFirst),
|
|
1,
|
|
ach,
|
|
sizeof(ach),
|
|
NULL,
|
|
&bUsedDef[0]);
|
|
if (!bUsedDef[0])
|
|
{
|
|
ach2[0] = ach2[1] = 0;
|
|
|
|
WideCharToMultiByte(dwCP,
|
|
0,
|
|
&(pkp->wSecond),
|
|
1,
|
|
ach2,
|
|
sizeof(ach2),
|
|
NULL,
|
|
&bUsedDef[1]);
|
|
|
|
if (!bUsedDef[1])
|
|
{
|
|
if (lpKernPair)
|
|
{
|
|
// do not overwrite the end of the buffer if it is provided
|
|
|
|
if (cRet >= nPairs)
|
|
break;
|
|
|
|
if (bDBCS)
|
|
{
|
|
if (IsDBCSLeadByteEx(dwCP,ach[0]))
|
|
{
|
|
pkrnLast->wFirst = (WORD)(ach[0] << 8 | ach[1]);
|
|
}
|
|
else
|
|
{
|
|
pkrnLast->wFirst = ach[0];
|
|
}
|
|
|
|
if (IsDBCSLeadByteEx(dwCP,ach2[0]))
|
|
{
|
|
pkrnLast->wSecond = (WORD)(ach2[0] << 8 | ach2[1]);
|
|
}
|
|
else
|
|
{
|
|
pkrnLast->wSecond = ach2[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pkrnLast->wFirst = ach[0];
|
|
pkrnLast->wSecond = ach2[0];
|
|
}
|
|
|
|
pkrnLast->iKernAmount = pkp->iKernAmount;
|
|
pkrnLast++;
|
|
|
|
}
|
|
cRet++;
|
|
}
|
|
}
|
|
}
|
|
Cleanup:
|
|
if (pkrn != tmpKernPair)
|
|
LOCALFREE(pkrn);
|
|
|
|
return cRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************Public*Routine******************************\
|
|
* FixBrushOrgEx
|
|
*
|
|
* for win32s
|
|
*
|
|
* History:
|
|
* 04-Jun-1992 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL FixBrushOrgEx(HDC hdc, int x, int y, LPPOINT ptl)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Function*****************************\
|
|
* GetColorAdjustment
|
|
*
|
|
* Get the color adjustment data for a given DC.
|
|
*
|
|
* History:
|
|
* 07-Aug-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT pclradj)
|
|
{
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
return(NtGdiGetColorAdjustment(hdc,pclradj));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetETM
|
|
*
|
|
* Aldus Escape support
|
|
*
|
|
* History:
|
|
* 20-Oct-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GetETM (HDC hdc, EXTTEXTMETRIC * petm)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
bRet = NtGdiGetETM(hdc,petm);
|
|
|
|
// path up the number of KerningPairs to match GetKerningPairsA
|
|
|
|
if (bRet && petm)
|
|
{
|
|
petm->etmNKernPairs = (WORD)GetKerningPairsA(hdc, 0, NULL);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
#if 0
|
|
/****************************Public*Routine********************************\
|
|
* GetCharWidthInfo
|
|
*
|
|
* Get the lMaxNegA lMaxNegC and lMinWidthD
|
|
*
|
|
* History:
|
|
* 09-Feb-1996 -by- Xudong Wu [tessiew]
|
|
* Wrote it
|
|
\***************************************************************************/
|
|
|
|
BOOL APIENTRY GetCharWidthInfo (HDC hdc, PCHWIDTHINFO pChWidthInfo)
|
|
{
|
|
return ( NtGdiGetCharWidthInfo(hdc, pChWidthInfo) );
|
|
}
|
|
#endif
|
|
|
|
#ifdef LANGPACK
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bGetRealizationInfoInternal
|
|
*
|
|
* Retreives the realization_info from kernel, if not cached in shared
|
|
* memory
|
|
*
|
|
* History:
|
|
* 18-Aug-1997 -by- Samer Arafeh [SamerA]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bGetRealizationInfoInternal(
|
|
HDC hdc,
|
|
REALIZATION_INFO *pri,
|
|
CFONT *pcf
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
if (pri)
|
|
{
|
|
// if no pcf or we havn't cached the metrics
|
|
|
|
if ((pcf == NULL) || !(pcf->fl & CFONT_CACHED_RI) || pcf->timeStamp != pGdiSharedMemory->timeStamp)
|
|
{
|
|
REALIZATION_INFO ri;
|
|
PDC_ATTR pDcAttr;
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if( pcf != NULL && (pcf->fl & CFONT_PUBLIC) )
|
|
bRet = NtGdiGetRealizationInfo(hdc,&ri, pcf->hf);
|
|
else
|
|
bRet = NtGdiGetRealizationInfo(hdc,&ri, 0);
|
|
|
|
if (bRet)
|
|
{
|
|
*pri = ri;
|
|
|
|
if (pcf && !(pcf->fl & CFONT_PUBLIC))
|
|
{
|
|
// we succeeded and we have a pcf so cache the data
|
|
|
|
pcf->ri = ri;
|
|
|
|
pcf->fl |= CFONT_CACHED_RI;
|
|
|
|
pcf->timeStamp = pGdiSharedMemory->timeStamp;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pri = pcf->ri;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GdiRealizationInfo
|
|
*
|
|
* Try retreive the RealizationInfo from shared memory
|
|
*
|
|
* History:
|
|
* 18-Aug-1997 -by- Samer Arafeh [SamerA]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY GdiRealizationInfo(HDC hdc,REALIZATION_INFO *pri)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PDC_ATTR pDcAttr;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
|
|
|
|
if (pDcAttr)
|
|
{
|
|
CFONT * pcf;
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
|
|
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID) NULL,0,TRUE);
|
|
|
|
bRet = bGetRealizationInfoInternal(hdc,pri,pcf);
|
|
|
|
// pcfLocateCFONT added a reference so now we need to remove it
|
|
|
|
if (pcf)
|
|
{
|
|
DEC_CFONT_REF(pcf);
|
|
}
|
|
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
}
|
|
else
|
|
{
|
|
// it could a public DC -OBJECT_OWNER_PUBLIC- (in which gpGdiShareMemory[hDC].pUser=NULL)
|
|
// so let's do it the expensive way by doing the kernel-transition...
|
|
|
|
bRet = NtGdiGetRealizationInfo(hdc,pri,0);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
#endif
|