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
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);
|
|
}
|