/******************************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; iiwd.iBreak) fxExtra += fxBreakExtra; } } else { pwc = (WCHAR *) psz; for (ii=0; iiwd.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; iisWidth[((BYTE *)pch)[ii]] = psWidths[ii]; } else { for (ii=0; iisWidth[((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); }