Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1272 lines
38 KiB

/******************************Module*Header*******************************\
* Module Name: cfont.c
*
* Created: 28-May-1991 13:01:27
* Author: Gilman Wong [gilmanw]
*
* Copyright (c) 1990-1999 Microsoft Corporation
*
*
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
CFONT *pcfCreateCFONT(HDC hdc,PDC_ATTR pDcAttr,UINT iFirst,PVOID pch,UINT c,BOOL bAnsi);
BOOL bFillWidthTableForGTE( HDC, CFONT *, PVOID, UINT, BOOL);
BOOL bFillWidthTableForGCW( HDC, CFONT *, UINT, UINT);
VOID vFreeCFONTCrit(CFONT *pcf);
// If the app deletes a LOCALFONT but one or more of the CFONTs hanging
// of the local font are in use then they will be added to this list.
// anytime we try to allocate a new CFONT we will check the list and
// if there entries on that list we will free them up.
CFONT *pcfDeleteList = (CFONT*) NULL;
/******************************Public*Routine******************************\
* pcfAllocCFONT () *
* *
* Allocates a CFONT. Tries to get one off the free list first. Does not *
* do any initialization. *
* *
* Sun 10-Jan-1993 01:16:04 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
#ifdef DBGCFONT
int cCfontAlloc = 0;
int cCfontMax = 0;
#endif
int cCfontFree = 0;
CFONT *pcfFreeListCFONT = (CFONT *) NULL;
CFONT *pcfAllocCFONT()
{
CFONT *pcf;
CFONT **ppcf;
// first lets walk the list of deleted fonts and delete any that
ppcf = &pcfDeleteList;
while (*ppcf)
{
if ((*ppcf)->cRef == 0)
{
pcf = (*ppcf);
*ppcf = pcf->pcfNext;
vFreeCFONTCrit(pcf);
}
else
{
ppcf = &(*ppcf)->pcfNext;
}
}
// Try to get one off the free list.
pcf = pcfFreeListCFONT;
if (pcf != (CFONT *) NULL)
{
pcfFreeListCFONT = *((CFONT **) pcf);
--cCfontFree;
}
// Otherwise allocate new memory.
if (pcf == (CFONT *) NULL)
{
pcf = (CFONT *) LOCALALLOC(sizeof(CFONT));
if (pcf == (CFONT *) NULL)
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
#ifdef DBGCFONT
cCfontAlloc++;
if (cCfontAlloc > cCfontMax)
{
cCfontMax = cCfontAlloc;
DbgPrint("\n\n******************* cCfontMax = %ld\n\n",cCfontMax);
}
#endif
}
return(pcf);
}
/******************************Public*Routine******************************\
* vFreeCFONTCrit (pcf) *
* *
* Frees a CFONT. Actually just puts it on the free list. We assume that *
* we are already in a critical section. *
* *
* Sun 10-Jan-1993 01:20:36 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
#define MAX_FREE_CFONT 10
VOID vFreeCFONTCrit(CFONT *pcf)
{
ASSERTGDI(pcf != (CFONT *) NULL,"Trying to free NULL CFONT.\n");
if(cCfontFree > MAX_FREE_CFONT)
{
LOCALFREE(pcf);
#ifdef DBGCFONT
cCfontAlloc--;
#endif
}
else
{
*((CFONT **) pcf) = pcfFreeListCFONT;
pcfFreeListCFONT = pcf;
++cCfontFree;
}
}
/******************************Public*Routine******************************\
* bComputeCharWidths *
* *
* Client side version of GetCharWidth. *
* *
* Sat 16-Jan-1993 04:27:19 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL bComputeCharWidths
(
CFONT *pcf,
UINT iFirst,
UINT iLast,
ULONG fl,
PVOID pv
)
{
USHORT *ps;
UINT ii;
switch (fl & (GCW_INT | GCW_16BIT))
{
case GCW_INT: // Get LONG widths.
{
LONG *pl = (LONG *) pv;
LONG fxOverhang = 0;
// Check for Win 3.1 compatibility.
if (fl & GCW_WIN3)
fxOverhang = pcf->wd.sOverhang;
// Do the trivial no-transform case.
if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline))
{
fxOverhang += 8; // To round the final result.
// for (ii=iFirst; ii<=iLast; ii++)
// *pl++ = (pcf->sWidth[ii] + fxOverhang) >> 4;
ps = &pcf->sWidth[iFirst];
ii = iLast - iFirst;
unroll_1:
switch(ii)
{
default:
pl[4] = (ps[4] + fxOverhang) >> 4;
case 3:
pl[3] = (ps[3] + fxOverhang) >> 4;
case 2:
pl[2] = (ps[2] + fxOverhang) >> 4;
case 1:
pl[1] = (ps[1] + fxOverhang) >> 4;
case 0:
pl[0] = (ps[0] + fxOverhang) >> 4;
}
if (ii > 4)
{
ii -= 5;
pl += 5;
ps += 5;
goto unroll_1;
}
return(TRUE);
}
// Otherwise use the back transform.
else
{
for (ii=iFirst; ii<=iLast; ii++)
*pl++ = lCvt(pcf->efDtoWBaseline,pcf->sWidth[ii] + fxOverhang);
return(TRUE);
}
}
case GCW_INT+GCW_16BIT: // Get SHORT widths.
{
USHORT *psDst = (USHORT *) pv;
USHORT fsOverhang = 0;
// Check for Win 3.1 compatibility.
if (fl & GCW_WIN3)
fsOverhang = pcf->wd.sOverhang;
// Do the trivial no-transform case.
if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline))
{
fsOverhang += 8; // To round the final result.
// for (ii=iFirst; ii<=iLast; ii++)
// *psDst++ = (pcf->sWidth[ii] + fsOverhang) >> 4;
ps = &pcf->sWidth[iFirst];
ii = iLast - iFirst;
unroll_2:
switch(ii)
{
default:
psDst[4] = (ps[4] + fsOverhang) >> 4;
case 3:
psDst[3] = (ps[3] + fsOverhang) >> 4;
case 2:
psDst[2] = (ps[2] + fsOverhang) >> 4;
case 1:
psDst[1] = (ps[1] + fsOverhang) >> 4;
case 0:
psDst[0] = (ps[0] + fsOverhang) >> 4;
}
if (ii > 4)
{
ii -= 5;
psDst += 5;
ps += 5;
goto unroll_2;
}
return(TRUE);
}
// Otherwise use the back transform.
else
{
for (ii=iFirst; ii<=iLast; ii++)
{
*psDst++ = (USHORT)
lCvt
(
pcf->efDtoWBaseline,
(LONG) (pcf->sWidth[ii] + fsOverhang)
);
}
return(TRUE);
}
}
case 0: // Get FLOAT widths.
{
LONG *pe = (LONG *) pv; // Cheat to avoid expensive copies.
EFLOAT_S efWidth,efWidthLogical;
for (ii=iFirst; ii<=iLast; ii++)
{
vFxToEf((LONG) pcf->sWidth[ii],efWidth);
vMulEFLOAT(efWidthLogical,efWidth,pcf->efDtoWBaseline);
*pe++ = lEfToF(efWidthLogical);
}
return(TRUE);
}
}
RIP("bComputeCharWidths: Don't come here!\n");
return(FALSE);
}
/******************************Public*Routine******************************\
* bComputeTextExtent (pldc,pcf,psz,cc,fl,psizl,btype) *
* *
* A quick function to compute text extents on the client side. *
* *
* Thu 14-Jan-1993 04:00:57 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL bComputeTextExtent
(
PDC_ATTR pDcAttr,
CFONT *pcf,
LPVOID psz,
int cc,
UINT fl,
SIZE *psizl,
BOOL bAnsi // TRUE is for ANSI, FALSE is for Unicode
)
{
LONG fxBasicExtent;
INT lTextExtra,lBreakExtra,cBreak;
int ii;
BYTE * pc;
LONG fxCharExtra = 0;
LONG fxBreakExtra;
LONG fxExtra = 0;
BOOL bRet = TRUE;
WCHAR * pwc;
lTextExtra = pDcAttr->lTextExtra;
lBreakExtra = pDcAttr->lBreakExtra;
cBreak = pDcAttr->cBreak;
// Compute the basic extent.
if (pcf->wd.sCharInc == 0)
{
fxBasicExtent = 0;
if(bAnsi)
pc = (BYTE *) psz;
else
pwc = (WCHAR *) psz;
ii = cc;
unroll_here:
if(bAnsi)
{
switch (ii)
{
default:
fxBasicExtent += pcf->sWidth[pc[9]];
case 9:
fxBasicExtent += pcf->sWidth[pc[8]];
case 8:
fxBasicExtent += pcf->sWidth[pc[7]];
case 7:
fxBasicExtent += pcf->sWidth[pc[6]];
case 6:
fxBasicExtent += pcf->sWidth[pc[5]];
case 5:
fxBasicExtent += pcf->sWidth[pc[4]];
case 4:
fxBasicExtent += pcf->sWidth[pc[3]];
case 3:
fxBasicExtent += pcf->sWidth[pc[2]];
case 2:
fxBasicExtent += pcf->sWidth[pc[1]];
case 1:
fxBasicExtent += pcf->sWidth[pc[0]];
}
}
else
{
switch (ii)
{
default:
fxBasicExtent += pcf->sWidth[pwc[9]];
case 9:
fxBasicExtent += pcf->sWidth[pwc[8]];
case 8:
fxBasicExtent += pcf->sWidth[pwc[7]];
case 7:
fxBasicExtent += pcf->sWidth[pwc[6]];
case 6:
fxBasicExtent += pcf->sWidth[pwc[5]];
case 5:
fxBasicExtent += pcf->sWidth[pwc[4]];
case 4:
fxBasicExtent += pcf->sWidth[pwc[3]];
case 3:
fxBasicExtent += pcf->sWidth[pwc[2]];
case 2:
fxBasicExtent += pcf->sWidth[pwc[1]];
case 1:
fxBasicExtent += pcf->sWidth[pwc[0]];
}
}
ii -= 10;
if (ii > 0)
{
if(bAnsi)
pc += 10;
else
pwc += 10;
goto unroll_here;
}
}
else
{
// Fixed pitch case.
fxBasicExtent = cc * (LONG) pcf->wd.sCharInc;
}
// Adjust for CharExtra.
if (lTextExtra)
{
int cNoBackup = 0;
fxCharExtra = lCvt(pcf->efM11,lTextExtra);
if (fxCharExtra < 0)
{
// the layout code won't backup a characters past it's origin regardless
// of the value of iTextCharExtra so figure out for how many values
// we will need to ignore fxCharExtra
if (pcf->wd.sCharInc == 0)
{
if(bAnsi)
{
pc = (BYTE *) psz;
for (ii = 0; ii < cc; ii++)
{
if (pcf->sWidth[pc[ii]] + fxCharExtra <= 0)
{
cNoBackup += 1;
}
}
}
else
{
pwc = (WCHAR *) psz;
for (ii = 0; ii < cc; ii++)
{
if (pcf->sWidth[pwc[ii]] + fxCharExtra <= 0)
{
cNoBackup += 1;
}
}
}
}
else if (pcf->wd.sCharInc + fxCharExtra <= 0)
{
cNoBackup = cc;
}
}
if ( (fl & GGTE_WIN3_EXTENT) && (pcf->hdc == 0) // hdc of zero is display DC
&& (!(pcf->flInfo & FM_INFO_TECH_STROKE)) )
fxExtra = fxCharExtra * ((lTextExtra > 0) ? cc : (cc - 1));
else
fxExtra = fxCharExtra * (cc - cNoBackup);
}
// Adjust for lBreakExtra.
if (lBreakExtra && cBreak)
{
fxBreakExtra = lCvt(pcf->efM11,lBreakExtra) / cBreak;
// Windows won't let us back up over a break. Set up the BreakExtra
// to just cancel out what we've already got.
if (fxBreakExtra + pcf->wd.sBreak + fxCharExtra < 0)
fxBreakExtra = -(pcf->wd.sBreak + fxCharExtra);
// Add it up for all breaks.
if(bAnsi)
{
pc = (BYTE *) psz;
for (ii=0; ii<cc; ii++)
{
if (*pc++ == pcf->wd.iBreak)
fxExtra += fxBreakExtra;
}
}
else
{
pwc = (WCHAR *) psz;
for (ii=0; ii<cc; ii++)
{
if (*pwc++ == pcf->wd.iBreak)
fxExtra += fxBreakExtra;
}
}
}
// Add in the extra stuff.
fxBasicExtent += fxExtra;
// Add in the overhang for font simulations.
if (fl & GGTE_WIN3_EXTENT)
fxBasicExtent += pcf->wd.sOverhang;
// Transform the result to logical coordinates.
if (bIsOneSixteenthEFLOAT(pcf->efDtoWBaseline))
psizl->cx = (fxBasicExtent + 8) >> 4;
else
psizl->cx = lCvt(pcf->efDtoWBaseline,fxBasicExtent);
psizl->cy = pcf->lHeight;
return bRet;
}
/******************************Public*Routine******************************\
* pcfLocateCFONT (hdc,pDcAttr,iFirst,pch,c)
*
* Locates a CFONT for the given LDC. First we try the CFONT last used by
* the LDC. Then we try to do a mapping ourselves through the LOCALFONT.
* If that fails we create a new one.
*
* Mon 11-Jan-1993 16:18:43 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
CFONT *pcfLocateCFONT(
HDC hdc,
PDC_ATTR pDcAttr,
UINT iFirst,
PVOID pch,
UINT c,
BOOL bAnsi)
{
CFONT *pcf = NULL;
LOCALFONT *plf;
ULONG fl;
HANDLE hf;
int i;
WCHAR *pwc;
BYTE *pchar;
if (fFontAssocStatus)
return(pcf);
fl = pDcAttr->ulDirty_;
hf = pDcAttr->hlfntNew;
// Check to make sure that the XFORM is okay. If not return FALSE and
// mark this DC as having slow widths.
if ((fl & SLOW_WIDTHS) || USER_XFORM_DIRTY(pDcAttr) ||
!(pDcAttr->mxWtoD.flAccel & XFORM_SCALE))
{
if (!(fl & SLOW_WIDTHS))
{
if (!NtGdiComputeXformCoefficients(hdc))
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
}
if (pDcAttr->ulDirty_ & SLOW_WIDTHS)
return(pcf);
}
if(guintDBCScp != 0xFFFFFFFF)
{
DWORD dwCodePage = GetCodePage(hdc);
//If this is a DBCS charset but not our native one then we can not
//compute widths and extent quickly, because gpwcDBCSCharSet[]
//array is computed based on our NATIVE_CODEPAGE using IsDBCSLeadByte()
//function.
if ((guintDBCScp != dwCodePage) && IS_ANY_DBCS_CODEPAGE(dwCodePage))
{
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
return pcf;
}
}
// now find the font
PSHARED_GET_VALIDATE(plf,hf,LFONT_TYPE);
if (plf == NULL)
{
// If there is no local font then this must be a public font or one
// that's been deleted while still being selected into a DC. If it's a
// stockfont let's try to find it.
if ((hf != NULL) &&
!(pGdiSharedHandleTable[HANDLE_TO_INDEX(hf)].Flags & HMGR_ENTRY_LAZY_DEL) &&
(pDcAttr->iMapMode == MM_TEXT) &&
(fl & DC_PRIMARY_DISPLAY))
{
for (i = 0; i < MAX_PUBLIC_CFONT; ++i)
if (pGdiSharedMemory->acfPublic[i].hf == hf)
break;
// if we didn't find one, try to set one up
if (i == MAX_PUBLIC_CFONT)
{
// this will fill in both the text metrics and widths
i = NtGdiSetupPublicCFONT(hdc,NULL,0);
}
// have we found one yet
if ((i >= 0) && (i < MAX_PUBLIC_CFONT))
{
// make sure mapping table is initialized before we give out a
// public CFONT
if ((gpwcANSICharSet == (WCHAR *) NULL) && !bGetANSISetMap())
{
return((CFONT *) NULL);
}
pcf = &pGdiSharedMemory->acfPublic[i];
}
}
else
{
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
}
}
else if (plf->fl & LF_HARDWAY)
{
// If the logfont has non-zero escapement or orientation then bail out.
// Stock fonts will never have non-zero escapments or orientation so we can do
// this now.
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
}
else
{
BOOL bRet = FALSE;
// next loop through all the CFONTs associated with this LOGFONT to see if
// we can find a match.
for (pcf = plf->pcf; pcf ; pcf = pcf->pcfNext)
{
// if the DC's are both display DC's or the same printer DC and the
// transform's coefficients match then we've got a winner.
if ((((pcf->hdc == 0) && (fl & DC_PRIMARY_DISPLAY)) || (pcf->hdc == hdc)) &&
bEqualEFLOAT(pcf->efM11, pDcAttr->mxWtoD.efM11) &&
bEqualEFLOAT(pcf->efM22, pDcAttr->mxWtoD.efM22))
{
// update the refcount so we don't accidentally delete this CFONT while
// we are using it.
INC_CFONT_REF(pcf);
break;
}
}
if (pcf == NULL)
{
// don't do this under semaphore because pcfCreateCFONT will call off to
// font drivers which in turn could access a file on the net and take a
// very long time
pcf = pcfCreateCFONT(hdc,pDcAttr,iFirst,pch,c,bAnsi);
if (pcf)
{
// next update the REFCOUNT of the CFONT
pcf->hf = hf;
pcf->hdc = (fl & DC_PRIMARY_DISPLAY) ? (HDC) 0 : (HDC) hdc;
// now that we have a CFONT link it in to the chain off of this
// LOCALFONT
pcf->pcfNext = plf->pcf;
plf->pcf = pcf;
}
}
else
{
// At this point we have a non-NULL pcf which is referenced by the LDC.
// We must check it to see if it contains the widths we need.
if (pcf->fl & CFONT_COMPLETE)
return(pcf);
if (pch != NULL)
{
// Make sure we have widths for all the chars in the string.
if (pcf->fl & CFONT_CACHED_WIDTHS)
{
if(bAnsi)
{
INT ic = (INT)c;
pchar = (BYTE *) pch;
if (pcf->fl & CFONT_DBCS)
{
// we won't have local width cache for DBCS chars in sWidth[] array.
for (;ic > 0; ic--,pchar++)
{
if (gpwcDBCSCharSet[*pchar] == 0xffff)
{
// skip DBCS chars
if (ic > 0)
{
ic--;
pchar++;
}
}
else if (pcf->sWidth[*pchar] == NO_WIDTH)
{
break;
}
}
if (ic < 0)
c = 0;
else
c = (UINT)ic;
}
else
{
for (; c && (pcf->sWidth[*pchar] != NO_WIDTH); c--,pchar++)
{}
}
pch = (PVOID) pchar;
}
else
{
pwc = (WCHAR *) pch;
for (; c && (pcf->sWidth[*pwc] != NO_WIDTH); c--,pwc++)
{}
pch = (PVOID) pwc;
}
}
if (c)
{
bRet = bFillWidthTableForGTE(hdc, pcf, pch, c, bAnsi);
}
}
else
{
// Make sure we have widths for the array requested.
if (pcf->fl & CFONT_CACHED_WIDTHS)
{
if (!(iFirst & 0xffffff00) && !((iFirst + c) & 0xffffff00))
{
for (; c && (pcf->sWidth[iFirst] != NO_WIDTH); c--,iFirst++)
{}
}
}
if (c)
{
bRet = bFillWidthTableForGCW(hdc, pcf, iFirst, c);
}
}
if (bRet == GDI_ERROR)
{
// Something bad happened while trying to fill. To avoid hitting this
// problem again on the next call, we mark the LDC as slow.
DEC_CFONT_REF(pcf);
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
pcf = NULL;
}
}
}
return(pcf);
}
/******************************Public*Routine******************************\
* pcfCreateCFONT (pldc,iFirst,pch,c) *
* *
* Allocate and initialize a new CFONT. *
* *
* History: *
* Tue 19-Jan-1993 16:16:03 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
EFLOAT_S ef_1 = EFLOAT_1;
CFONT *pcfCreateCFONT(
HDC hdc,
PDC_ATTR pDcAttr,
UINT iFirst,
PVOID pch,
UINT c,
BOOL bAnsi)
{
CFONT *pcfNew;
BOOL bRet;
// Make sure we have the UNICODE translation of the ANSI character set.
// We'll create this once and keep it around to avoid lots of conversion.
if ((gpwcANSICharSet == (WCHAR *) NULL) && !bGetANSISetMap())
return((CFONT *) NULL);
// Allocate a new CFONT to hold the results.
pcfNew = pcfAllocCFONT();
if (pcfNew != (CFONT *) NULL)
{
pcfNew->timeStamp = pGdiSharedMemory->timeStamp;
pcfNew->fl = 0;
// if the default code page is a DBCS code page then we may need to mark this
// as a DBCS font
if(guintDBCScp != 0xFFFFFFFF)
{
DWORD dwCodePage = GetCodePage(hdc);
//If this is a DBCS charset but not our native one then we can not
//compute widths and extent quickly, because gpwcDBCSCharSet[]
//array is computed based on our NATIVE_CODEPAGE using IsDBCSLeadByte()
//function. We should never get here because we will be doing a check
//higher up to make sure the codepage of the font in the DC is matches
//the current DBCS code page
if(guintDBCScp == dwCodePage)
{
pcfNew->fl = CFONT_DBCS;
}
ASSERTGDI(guintDBCScp == dwCodePage || !IS_ANY_DBCS_CODEPAGE(dwCodePage),
"pcfLocateCFONT called on non-native DBCS font\n");
}
pcfNew->cRef = 1;
// Compute the back transforms.
pcfNew->efM11 = pDcAttr->mxWtoD.efM11;
pcfNew->efM22 = pDcAttr->mxWtoD.efM22;
efDivEFLOAT(pcfNew->efDtoWBaseline,ef_1,pcfNew->efM11);
vAbsEFLOAT(pcfNew->efDtoWBaseline);
efDivEFLOAT(pcfNew->efDtoWAscent,ef_1,pcfNew->efM22);
vAbsEFLOAT(pcfNew->efDtoWAscent);
// Send over a request.
if (pch != NULL)
{
bRet = bFillWidthTableForGTE(hdc,pcfNew,pch,c,bAnsi);
}
else if (c)
{
bRet = bFillWidthTableForGCW(hdc,pcfNew,iFirst,c);
}
else
{
// probably just creating a cache entry for text metrics.
// FALSE just means haven't gotten all the widths. Note
// that GDI_ERROR is actualy -1
bRet = FALSE;
}
// Clean up failed requests.
if (bRet == GDI_ERROR)
{
// we will not attempt to create cfont if this failed once in the
// past, because the chances are it will fail again with this logfont.
// It turns out it is costly to figure out that cfont creation is going to fail
// so we record this by setting LF_NO_CFONT flag to avoid another attempt at
// creating cfont.
pDcAttr->ulDirty_ |= SLOW_WIDTHS;
vFreeCFONTCrit(pcfNew);
pcfNew = NULL;
}
}
return(pcfNew);
}
/******************************Public*Routine******************************\
* bFillWidthTableForGCW *
* *
* Requests ANSI character widths from the server for a call to *
* GetCharWidthA. iFirst and c specify the characters needed by the API *
* call, the server must return these. In addition, it may be prudent to *
* fill in a whole table of 256 widths at psWidthCFONT. We will fill in *
* the whole table and a WIDTHDATA structure if the pointer pwd is non-NULL.*
* *
* History: *
* Tue 19-Jan-1993 14:29:31 -by- Charles Whitmer [chuckwh] *
* Wrote it. *
\**************************************************************************/
BOOL bFillWidthTableForGCW
(
HDC hdc,
CFONT *pcf,
UINT iFirst,
UINT c
)
{
BOOL bRet = GDI_ERROR;
BOOL bDBCS = pcf->fl & CFONT_DBCS;
WCHAR *pwcBuf;
UINT c1,c2;
WIDTHDATA *pwd;
if(iFirst > 256)
{
// this is possible for DBCS fonts, just get all the widths
iFirst = 0;
c = 256;
}
if (pcf->fl & CFONT_CACHED_WIDTHS)
{
// Not the first time. Just get the important widths.
c1 = c;
c2 = 0;
pwd = NULL;
}
else
{
// Get the whole table, but put the important widths at the start.
c2 = iFirst;
c1 = 256 - c2; // only c of those are "important"
pwd = &pcf->wd;
}
pwcBuf = (WCHAR *)LocalAlloc(LMEM_FIXED,
(c1+c2) * (sizeof(WCHAR)+sizeof(USHORT)));
if (pwcBuf)
{
USHORT *psWidths = pwcBuf + c1+c2;
RtlCopyMemory(pwcBuf,
(bDBCS) ? (PBYTE) &gpwcDBCSCharSet[iFirst] :
(PBYTE) &gpwcANSICharSet[iFirst],
c1*sizeof(WCHAR));
if (c2)
{
RtlCopyMemory(&pwcBuf[c1],
(bDBCS) ? (PBYTE) &gpwcDBCSCharSet[0] :
(PBYTE) &gpwcANSICharSet[0],
c2*sizeof(WCHAR));
}
LEAVECRITICALSECTION(&semLocal);
bRet = NtGdiGetWidthTable( hdc, // The DC
c, // Number of special characters
pwcBuf, // Unicode characters requested
c1+c2, // Number of non-special chars
psWidths, // Buffer to get widths returned
pwd, // Width data
&pcf->flInfo); // Font info flags
ENTERCRITICALSECTION(&semLocal);
if (bRet != GDI_ERROR)
{
if (!(pcf->fl & CFONT_CACHED_WIDTHS))
{
// mark this cfont as having some widths
pcf->fl |= CFONT_CACHED_WIDTHS;
// Precompute the height.
pcf->lHeight = lCvt(pcf->efDtoWAscent,(LONG) pcf->wd.sHeight);
}
if (bRet && ((c1+c2) >= 256))
pcf->fl |= CFONT_COMPLETE;
// Copy the widths into the CFONT table.
RtlCopyMemory(
&pcf->sWidth[iFirst], psWidths, c1 * sizeof(USHORT));
if (c2)
{
RtlCopyMemory (
pcf->sWidth, &psWidths[c1], c2 * sizeof(USHORT));
}
}
LocalFree(pwcBuf);
}
return(bRet);
}
/******************************Public*Routine******************************\
* bFillWidthTableForGTE
*
* Requests ANSI character widths from the server for a call to
* GetTextExtentA. pch specifies the string from the API call. The
* server must return widths for these characters. In addition, it may be
* prudent to fill in a whole table of 256 widths at psWidthCFONT. We will
* fill in the whole table and a WIDTHDATA structure if the pointer pwd is
* non-NULL.
*
* History:
* Tue 13-Jun-1995 14:29:31 -by- Gerrit van Wingerden [gerritv]
* Converted for kernel mode.
* Tue 19-Jan-1993 14:29:31 -by- Charles Whitmer [chuckwh]
* Wrote it.
\**************************************************************************/
BOOL bFillWidthTableForGTE
(
HDC hdc,
CFONT *pcf,
PVOID pch,
UINT c,
BOOL bAnsi
)
{
BOOL bRet = GDI_ERROR;
BOOL bDBCS = pcf->fl & CFONT_DBCS;
UINT ii;
UINT c1;
WCHAR *pwcBuf;
WCHAR *pwcXlat = (bDBCS) ? gpwcDBCSCharSet : gpwcANSICharSet;
WIDTHDATA *pwd;
if (pcf->fl & CFONT_CACHED_WIDTHS)
{
c1 = c;
pwd = NULL;
}
else
{
c1 = c+256;
pwd = &pcf->wd;
}
pwcBuf = LocalAlloc(LMEM_FIXED,c1*(sizeof(WCHAR)+sizeof(USHORT)));
if( pwcBuf )
{
WCHAR *pwc = pwcBuf;
USHORT *psWidths = pwcBuf + c1;
if(bAnsi)
{
for( ii = 0; ii < c; ii++ )
{
*pwc++ = pwcXlat[((BYTE *)pch)[ii]];
}
}
else
{
RtlCopyMemory((PBYTE)pwc, (PBYTE) pch, c * sizeof(WCHAR));
pwc += c;
}
if (pwd != (WIDTHDATA *) NULL)
{
// Request the whole table, too.
RtlCopyMemory((PBYTE)pwc,
(bDBCS) ? (PBYTE) &gpwcDBCSCharSet[0] :
(PBYTE) &gpwcANSICharSet[0],
256*sizeof(WCHAR));
}
LEAVECRITICALSECTION(&semLocal);
bRet = NtGdiGetWidthTable( hdc, // the DC
c, // number of special characters
pwcBuf, // the requested chars in Unicode
c1, // total number of characters
psWidths, // the actual width
pwd, // useful width data
&pcf->flInfo);// font info flags
ENTERCRITICALSECTION(&semLocal);
if (bRet != GDI_ERROR)
{
if (!(pcf->fl & CFONT_CACHED_WIDTHS))
{
// mark this cfont as having some widths
pcf->fl |= CFONT_CACHED_WIDTHS;
// Precompute the height.
pcf->lHeight = lCvt(pcf->efDtoWAscent,(LONG) pcf->wd.sHeight);
if (bRet) // bFillWidthTableForGTE() tries to get width for all 0x00 to 0xff only at the first time
pcf->fl |= CFONT_COMPLETE;
}
if( pwd != (WIDTHDATA *) NULL )
RtlCopyMemory( pcf->sWidth,&psWidths[c],256 * sizeof(USHORT));
// Write the hard widths into the table too.
if (bAnsi)
{
for (ii=0; ii<c; ii++)
pcf->sWidth[((BYTE *)pch)[ii]] = psWidths[ii];
}
else
{
for (ii=0; ii<c; ii++)
pcf->sWidth[((WCHAR *)pch)[ii]] = psWidths[ii];
}
}
LocalFree( pwcBuf );
}
return(bRet);
}
/***************************************************************************\
* GetCharDimensions
*
* This function loads the Textmetrics of the font currently selected into
* the hDC and returns the Average char width of the font; Pl Note that the
* AveCharWidth value returned by the Text metrics call is wrong for
* proportional fonts. So, we compute them On return, lpTextMetrics contains
* the text metrics of the currently selected font.
*
* Legacy code imported from USER.
*
* History:
* 10-Nov-1993 mikeke Created
\***************************************************************************/
int GdiGetCharDimensions(
HDC hdc,
TEXTMETRICW *lptm,
LPINT lpcy)
{
TEXTMETRICW tm;
PLDC pldc;
PDC_ATTR pDcAttr;
CFONT *pcf;
int iAve;
PSHARED_GET_VALIDATE(pDcAttr,hdc,DC_TYPE);
if (!pDcAttr)
{
WARNING("GdiGetCharDimensions: invalid DC");
return(0);
}
// find the local font or create one
if (lptm == NULL)
lptm = &tm;
// now find the metrics
ENTERCRITICALSECTION(&semLocal);
pcf = pcfLocateCFONT(hdc,pDcAttr,0,(PVOID)NULL,0, TRUE);
if (!bGetTextMetricsWInternal(hdc, (TMW_INTERNAL *)lptm,sizeof(*lptm), pcf))
{
LEAVECRITICALSECTION(&semLocal);
return(0);
}
LEAVECRITICALSECTION(&semLocal);
if (lpcy != NULL)
*lpcy = lptm->tmHeight;
// If fixed width font
if (lptm->tmPitchAndFamily & TMPF_FIXED_PITCH)
{
if (pcf && (pcf->fl & CFONT_CACHED_AVE))
{
iAve = (int)pcf->ulAveWidth;
}
else
{
SIZE size;
static WCHAR wszAvgChars[] =
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Change from tmAveCharWidth. We will calculate a true average
// as opposed to the one returned by tmAveCharWidth. This works
// better when dealing with proportional spaced fonts.
// legacy from USER so can't change this.
if(!GetTextExtentPointW(hdc, wszAvgChars,
(sizeof(wszAvgChars) / sizeof(WCHAR)) - 1,
&size))
{
WARNING("GetCharDimension: GetTextExtentPointW failed\n");
return(0);
}
ASSERTGDI(size.cx,
"GetCharDimension: GetTextExtentPointW return 0 width string\n");
iAve = ((size.cx / 26) + 1) / 2; // round up
// if we have a pcf, let's cache it
if (pcf)
{
// if it is a public font, we need to go to the kernel because
// the pcf is read only here.
if (pcf->fl & CFONT_PUBLIC)
{
NtGdiSetupPublicCFONT(NULL,(HFONT)pcf->hf,(ULONG)iAve);
}
else
{
pcf->ulAveWidth = (ULONG)iAve;
pcf->fl |= CFONT_CACHED_AVE;
}
}
}
}
else
{
iAve = lptm->tmAveCharWidth;
}
// pcfLocateCFONT added a reference so now we need to remove it
if (pcf)
{
DEC_CFONT_REF(pcf);
}
return(iAve);
}