/*********************************************************************************** * Module Name: fntassoc.cxx * * Font association routines. * * History * * 4-8-96 Gerrit van Wingerden Moved code from flinkgdi.cxx * * Copyright (c) 1996-1999 Microsoft Corporation **********************************************************************************/ #include "precomp.hxx" #ifdef FE_SB #define FONT_ASSOCIATION_CHARSET_KEY \ L"FontAssoc\\Associated CharSet" #define FONT_ASSOCIATION_DEFAULT_KEY \ L"FontAssoc\\Associated DefaultFonts" #define FONT_ASSOCIATION_FONTS_KEY \ L"FontAssoc\\Associated Fonts" // Font Association configuration value UINT fFontAssocStatus = 0x0; // // Fontfile path for AssocSystemFont in // KEY : HKL\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc\\Associated DefaultFonts // VALUE : AssocSystemFont // // This font is loaded at system initialization stage. and will be used to provide // DBCS glyphs for System/Terminal/FixedSys/... This font should have all glyphs that // will be used on current system locale // // This hehavior is described in ... // "Font Association for Far East implementation for Windows 95" // Revision : 1.02 // Author : WJPark,ShusukeU. // // Holds the path of the font the font used to provide glyphs to system,terminal, // and fixedsys fonts. WCHAR gawcSystemDBCSFontPath[MAX_PATH]; // Identifies the facename to use for DBCS glyphs. This value comes out of the // "FontPackage" value in AssociatedDefaultFonts key static WCHAR gawcSystemDBCSFontFaceName[LF_FACESIZE+1]; // Holds the pfe's (vertical and non-vertical) for the system DBCS font face name PFE *gappfeSystemDBCS[2] = { PPFENULL , PPFENULL }; // set to TRUE if SystemDBCS font is enabled. BOOL gbSystemDBCSFontEnabled = FALSE; // // Font association default link initialization value. // // This value never be TRUE, if FontAssociation features are disabled. // And this value will be TRUE, if we suceed to read "Associated DefaultFonts" // key and fill up FontAssocDefaultTable. // BOOL bReadyToInitializeFontAssocDefault = FALSE; // // This value never be TRUE, if FontAssociation features are disabled. // And this value also never be TRUE, no-user logged-on this window station. // This value become TRUE at first time that GreEnableEUDC() is called. // and this value is turned off when user logout. // BOOL bFinallyInitializeFontAssocDefault = FALSE; // // Font Association default link configuration table // #define NUMBER_OF_FONTASSOC_DEFAULT 7 #define FF_DEFAULT 0xFF FONT_DEFAULTASSOC FontAssocDefaultTable[NUMBER_OF_FONTASSOC_DEFAULT] = { {FALSE, FF_DONTCARE, L"FontPackageDontCare", L"\0", L"\0", {PPFENULL,PPFENULL}}, {FALSE, FF_ROMAN, L"FontPackageRoman", L"\0", L"\0" , {PPFENULL,PPFENULL}}, {FALSE, FF_SWISS, L"FontPackageSwiss", L"\0", L"\0", {PPFENULL,PPFENULL}}, {FALSE, FF_MODERN, L"FontPackageModern", L"\0", L"\0", {PPFENULL,PPFENULL}}, {FALSE, FF_SCRIPT, L"FontPackageScript", L"\0", L"\0", {PPFENULL,PPFENULL}}, {FALSE, FF_DECORATIVE, L"FontPackageDecorative", L"\0", L"\0", {PPFENULL,PPFENULL}}, {FALSE, FF_DEFAULT, L"FontPackage", L"\0", L"\0", {PPFENULL,PPFENULL}} }; // Is font association substitition turned on? static BOOL bEnableFontAssocSubstitutes = FALSE; // Pointer to Substitution table for font association. static ULONG ulNumFontAssocSubs = 0L; PFONT_ASSOC_SUB pFontAssocSubs = (PFONT_ASSOC_SUB) NULL; // definition is in flinkgdi.cxx extern RTL_QUERY_REGISTRY_TABLE SharedQueryTable[2]; extern BOOL bAppendSysDirectory( WCHAR *pwcTarget, const WCHAR *pwcSource, UINT cchBufferSize ); extern BOOL bComputeQuickLookup(QUICKLOOKUP *pql, PFE *pPFE, BOOL bSystemEUDC); /******************************Public*Routine******************************\ * NTSTATUS CountRegistryEntryCoutine(PWSTR,ULONG,PVOID,ULONG,PVOID,PVOID) * * History: * 19-Jan-1996 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ extern "C" NTSTATUS CountRegistryEntryRoutine ( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext ) { (*(ULONG *)EntryContext) += 1L; return( STATUS_SUCCESS ); } /******************************Public*Routine******************************\ * NTSTATUS FontAssocCharsetRoutine(PWSTR,ULONG,PVOID,ULONG,PVOID,PVOID) * * History: * 28-Aug-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ extern "C" NTSTATUS FontAssocCharsetRoutine ( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext ) { // // Only process follows if the data value is "YES" // if( _wcsicmp((LPWSTR) ValueData, L"YES" ) == 0) { // // Check ANSI charset association is enabled // if( _wcsicmp(ValueName, L"ANSI(00)") == 0) { #if DBG DbgPrint("GDISRV:FONTASSOC CHARSET:Enable ANSI association\n"); #endif fFontAssocStatus |= ANSI_ASSOC; return(STATUS_SUCCESS); } // // Check SYMBOL charset association is enabled // else if( _wcsicmp(ValueName, L"SYMBOL(02)") == 0) { #if DBG DbgPrint("GDISRV:FONTASSOC CHARSET:Enable SYMBOL association\n"); #endif fFontAssocStatus |= SYMBOL_ASSOC; return(STATUS_SUCCESS); } // // Check OEM charset association is enabled // else if( _wcsicmp(ValueName, L"OEM(FF)") == 0) { #if DBG DbgPrint("GDISRV:FONTASSOC CHARSET:Enable OEM association\n"); #endif fFontAssocStatus |= OEM_ASSOC; return(STATUS_SUCCESS); } } // // return STATUS_SUCCESS everytime,even we got error from above call, to // get next enumuration. // return(STATUS_SUCCESS); } /******************************Public*Routine******************************\ * NTSTATUS FontAssocDefaultRoutine(PWSTR,ULONG,PVOID,ULONG,PVOID,PVOID) * * History: * 14-Jan-1996 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ extern "C" NTSTATUS FontAssocDefaultRoutine ( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext ) { UINT iIndex; if(_wcsicmp(ValueName,L"AssocSystemFont") == 0) { bAppendSysDirectory(gawcSystemDBCSFontPath,(const WCHAR *)ValueData, MAX_PATH); return(STATUS_SUCCESS); } else if(_wcsicmp(ValueName,L"FontPackage") == 0) { cCapString(gawcSystemDBCSFontFaceName,(const WCHAR*)ValueData,LF_FACESIZE); return(STATUS_SUCCESS); } for( iIndex = 0; iIndex < NUMBER_OF_FONTASSOC_DEFAULT; iIndex++ ) { if(_wcsicmp(ValueName, FontAssocDefaultTable[iIndex].DefaultFontTypeID) == 0) { // Check if the registry has some data. if( *(LPWSTR)ValueData != L'\0' ) { if (FAILED(StringCchCopyW(FontAssocDefaultTable[iIndex].DefaultFontFaceName, LF_FACESIZE+1, (const WCHAR *)ValueData))) { WARNING("FontAssocDefaultRoutine: not enough space in DefaultFontFaceName buffer\n"); return STATUS_SUCCESS; } FontAssocDefaultTable[iIndex].ValidRegData = TRUE; #if DBG DbgPrint("GDISRV:FONTASSOC DEFAULT:%ws -> %ws\n", FontAssocDefaultTable[iIndex].DefaultFontTypeID, FontAssocDefaultTable[iIndex].DefaultFontFaceName); #endif } return(STATUS_SUCCESS); } } #if DBG DbgPrint("GDISRV:FONTASSOC DEFAULT:%ws is invalid registry key\n",(LPWSTR)ValueName); #endif // // return STATUS_SUCCESS everytime,even we got error to do next enumuration. // return(STATUS_SUCCESS); } /******************************Public*Routine******************************\ * NTSTATUS FontAssocFontsRoutine(PWSTR,ULONG,PVOID,ULONG,PVOID,PVOID) * * History: * 19-Jan-1996 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ extern "C" NTSTATUS FontAssocFontsRoutine ( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext ) { UINT iIndex = (*(UINT *)EntryContext); PFONT_ASSOC_SUB pfas = pFontAssocSubs + iIndex; ASSERTGDI(iIndex < ulNumFontAssocSubs, "GDIOSRV:FONTASSOC iIndex >= ulNumFontAssocSubs\n"); // // Copy the registry data to local buffer.. // cCapString(pfas->AssociatedName,(const WCHAR*)ValueData,LF_FACESIZE+1); cCapString(pfas->OriginalName ,ValueName,LF_FACESIZE+1); #if DBG pfas->UniqNo = iIndex; DbgPrint("GDISRV:FONTASSOC FontSubs %d %ws -> %ws\n",iIndex, pfas->OriginalName, pfas->AssociatedName); #endif // // for Next entry.... // (*(UINT *)EntryContext) = ++iIndex; return (STATUS_SUCCESS); } /******************************Public*Routine******************************\ * VOID vInitializeFontAssocStatus() * * History: * 28-Aug-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. \**************************************************************************/ VOID vInitializeFontAssocStatus(VOID) { NTSTATUS NtStatus; // Read Font Association configuration value. // Initialize "FontAssoc\Association CharSet" related. SharedQueryTable[0].QueryRoutine = FontAssocCharsetRoutine; SharedQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; SharedQueryTable[0].Name = (PWSTR)NULL; SharedQueryTable[0].EntryContext = (PVOID)NULL; SharedQueryTable[0].DefaultType = REG_NONE; SharedQueryTable[0].DefaultData = NULL; SharedQueryTable[0].DefaultLength = 0; SharedQueryTable[1].QueryRoutine = NULL; SharedQueryTable[1].Flags = 0; SharedQueryTable[1].Name = (PWSTR)NULL; fFontAssocStatus = 0; gawcSystemDBCSFontPath[0] = L'\0'; // Enumurate registry values NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL|RTL_REGISTRY_OPTIONAL, FONT_ASSOCIATION_CHARSET_KEY, SharedQueryTable, NULL, NULL); if(!NT_SUCCESS(NtStatus)) { WARNING1("GDISRV:FontAssociation is disabled\n"); fFontAssocStatus = 0; } gawcSystemDBCSFontFaceName[0] = 0; // Initialize "FontAssoc\Association DefaultFonts" related. SharedQueryTable[0].QueryRoutine = FontAssocDefaultRoutine; // Enumurate registry values NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL|RTL_REGISTRY_OPTIONAL, FONT_ASSOCIATION_DEFAULT_KEY, SharedQueryTable, NULL, NULL); if( !NT_SUCCESS(NtStatus) ) { WARNING1("GDISRV:FontAssociation:Default table is not presented\n"); bReadyToInitializeFontAssocDefault = FALSE; } else { // We succeeded to read registry and fill up FontAssocDefaultTable. bReadyToInitializeFontAssocDefault = TRUE; // try to load the system DBCS font if we detected the appropriate registry // entries if(gawcSystemDBCSFontPath[0] && gawcSystemDBCSFontFaceName[0]) { PUBLIC_PFTOBJ pfto; LONG cFonts; EUDCLOAD EudcLoadData; PFF *placeHolder; EudcLoadData.pppfeData = gappfeSystemDBCS; EudcLoadData.LinkedFace = gawcSystemDBCSFontFaceName; if(pfto.bLoadAFont(gawcSystemDBCSFontPath, (PULONG) &cFonts, PFF_STATE_EUDC_FONT, &placeHolder, &EudcLoadData )) { // initialize quick lookup table if we successfully loaded the font // this must be NULL for bComputeQuickLookup gqlTTSystem.puiBits = NULL; if(bComputeQuickLookup(&gqlTTSystem, gappfeSystemDBCS[PFE_NORMAL], FALSE)) { // now try the vertical face if one is provided FLINKMESSAGE2(DEBUG_FONTLINK_INIT, "Loaded SystemDBCSFont %ws\n", gawcSystemDBCSFontPath); gbSystemDBCSFontEnabled = TRUE; gbAnyLinkedFonts = TRUE; } if(!gbSystemDBCSFontEnabled) { WARNING("vInitializeFontAssocStatus: error creating \ quick lookup tables for SystemDBCSFont\n"); pfto.bUnloadEUDCFont(gawcSystemDBCSFontPath); } } else { WARNING("vInitializeFontAssocStatus: error loading SystemDBCSFont\n"); } } } // Initialize "Font Association\Fonts" related. bEnableFontAssocSubstitutes = FALSE; SharedQueryTable[0].QueryRoutine = CountRegistryEntryRoutine; SharedQueryTable[0].EntryContext = (PVOID)(&ulNumFontAssocSubs); // Count the number of the registry entries. // NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL|RTL_REGISTRY_OPTIONAL, // FONT_ASSOCIATION_FONTS_KEY, // SharedQueryTable, // NULL, // NULL); ulNumFontAssocSubs = 0; if( NT_SUCCESS(NtStatus) && (ulNumFontAssocSubs != 0) ) { #if DBG DbgPrint("GDISRV:FONTASSOC %d FontAssoc Substitution is found\n", ulNumFontAssocSubs); #endif // Allocate lookaside table for fontassociation's substitution. pFontAssocSubs = (PFONT_ASSOC_SUB) PALLOCMEM(sizeof(FONT_ASSOC_SUB)*ulNumFontAssocSubs,'flnk'); if( pFontAssocSubs != NULL ) { UINT iCount = 0; // This will be used as Current Table Index. SharedQueryTable[0].QueryRoutine = FontAssocFontsRoutine; SharedQueryTable[0].EntryContext = (PVOID)(&iCount); NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL|RTL_REGISTRY_OPTIONAL, FONT_ASSOCIATION_FONTS_KEY, SharedQueryTable, NULL, NULL); if( !NT_SUCCESS(NtStatus) ) { VFREEMEM( pFontAssocSubs ); ulNumFontAssocSubs = 0L; } else { bEnableFontAssocSubstitutes = TRUE; gbAnyLinkedFonts = TRUE; } } else { ulNumFontAssocSubs = 0L; } } return; } /*****************************************************************************\ * GreGetFontAssocStatus( BOOL bEnable ) * * History: * 28-Aug-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. *****************************************************************************/ UINT GreGetFontAssocStatus(VOID) { return(fFontAssocStatus); } /***************************************************************************** * BOOL bSetupDefaultFlEntry(BOOL,BOOL,INT) * * This function load font and build link for eudc font according to * the default link table. * * History * 1-15-96 Hideyuki Nagase * Wrote it. *****************************************************************************/ BOOL bSetupDefaultFlEntry(VOID) { UINT iIndex; UINT bRet = FALSE; // // get and validate PFT user object // PUBLIC_PFTOBJ pfto; // access the public font table ASSERTGDI( pfto.bValid(), "gdisrv!bSetupDefaultFlEntry(): could not access the public font table\n" ); for( iIndex = 0; iIndex < NUMBER_OF_FONTASSOC_DEFAULT; iIndex++ ) { // // Check the registry data and fontpath is valid ,and // this font is not loaded, yet. // if( (FontAssocDefaultTable[iIndex].ValidRegData) && (FontAssocDefaultTable[iIndex].DefaultFontPathName[0] != L'\0') && (FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] == PPFENULL) ) { PPFE appfeLink[2]; // temporary buffer LONG cFonts; // count of fonts EUDCLOAD EudcLoadData; // eudc load data PFF *placeHolder; PWSZ FontPathName = FontAssocDefaultTable[iIndex].DefaultFontPathName; // // Fill up EudcLoadData structure // EudcLoadData.pppfeData = appfeLink; EudcLoadData.LinkedFace = FontAssocDefaultTable[iIndex].DefaultFontFaceName; // // Load the linked font. // if( pfto.bLoadAFont( FontPathName, (PULONG) &cFonts, (PFF_STATE_EUDC_FONT | PFF_STATE_PERMANENT_FONT), &placeHolder, &EudcLoadData ) ) { // // Check we really succeed to load requested facename font. // // // Compute table for normal face // if(!bComputeQuickLookup(NULL, appfeLink[PFE_NORMAL], FALSE )) { WARNING("Unable to compute QuickLookUp for default link\n"); // // Unload the fonts. // pfto.bUnloadEUDCFont(FontPathName); // // we got error during load, maybe font itself might be invalid, // just invalidate the pathname the default table. // FontAssocDefaultTable[iIndex].DefaultFontPathName[0] = L'\0'; // // Do next entry in default table. // continue; } // // Compute table for vertical face, if vertical face font is provided, // if( !bComputeQuickLookup(NULL, appfeLink[PFE_VERTICAL], FALSE )) { WARNING("Unable to compute QuickLookUp for default link\n"); // Unload the fonts. pfto.bUnloadEUDCFont(FontPathName); // we got error during load, maybe font itself might be invalid, // just invalidate the pathname the default table. FontAssocDefaultTable[iIndex].DefaultFontPathName[0] = L'\0'; // Do next entry in default table. continue; } // // Finally, we keeps the PFEs in default array. // FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] = appfeLink[PFE_NORMAL]; FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_VERTICAL] = appfeLink[PFE_VERTICAL]; #if DBG DbgPrint("GDISRV:FONTASSOC DEFAULT:Load %ws for %ws\n", FontAssocDefaultTable[iIndex].DefaultFontPathName, FontAssocDefaultTable[iIndex].DefaultFontTypeID); #endif // We can load Associated font. bRet = TRUE; } else { #if DBG DbgPrint("Failed to load default link font. (%ws)\n",FontPathName); #endif // // we got error during load, maybe font itself might be invalid, // just invalidate the pathname the default table. // FontAssocDefaultTable[iIndex].DefaultFontPathName[0] = L'\0'; // // Make sure the PFEs are invalid. // FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] = PPFENULL; FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_VERTICAL] = PPFENULL; } } } return(bRet); } /***************************************************************************** * ULONG NtGdiQueryFontAssocInfo * * Shared kernel mode entry point for QueryFontAssocStatus and * GetFontAssocStatus * * History * 6-12-96 Gerrit van Wingerden [gerritv] * Wrote it. ****************************************************************************/ #define GFA_NOT_SUPPORTED 0 #define GFA_SUPPORTED 1 #define GFA_DBCSFONT 2 extern "C" ULONG NtGdiQueryFontAssocInfo(HDC hdc) { // if hdc is NULL then just return fFontAssocStatus if(hdc == NULL) { return(fFontAssocStatus); } else { // for now eventually merge/share with NtGdiGetCharSet FLONG flSim; POINTL ptlSim; FLONG flAboutMatch; PFE *ppfe; DCOBJ dco (hdc); if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(GFA_NOT_SUPPORTED); } PDEVOBJ pdo(dco.hdev()); ASSERTGDI(pdo.bValid(), "gdisrv!GetCharSet: bad pdev in dc\n"); if (!pdo.bGotFonts()) pdo.bGetDeviceFonts(); LFONTOBJ lfo(dco.pdc->hlfntNew(), &pdo); if (dco.ulDirty() & DIRTY_CHARSET) { // force mapping if (!lfo.bValid()) { WARNING("gdisrv!RFONTOBJ(dco): bad LFONT handle\n"); return(GFA_NOT_SUPPORTED); } // Stabilize the public PFT for mapping. SEMOBJ so(ghsemPublicPFT); // LFONTOBJ::ppfeMapFont returns a pointer to the physical font face and // a simulation type (ist) // also store charset to the DC ppfe = lfo.ppfeMapFont(dco, &flSim, &ptlSim, &flAboutMatch); ASSERTGDI(!(dco.ulDirty() & DIRTY_CHARSET), "NtGdiGetCharSet, charset is dirty\n"); } UINT Charset = (dco.pdc->iCS_CP() >> 16) & 0xFF; if (IS_ANY_DBCS_CHARSET( Charset )) { return GFA_DBCSFONT; } if (((Charset == ANSI_CHARSET) && (fFontAssocStatus & ANSI_ASSOC)) || ((Charset == OEM_CHARSET) && (fFontAssocStatus & OEM_ASSOC)) || ((Charset == SYMBOL_CHARSET) && (fFontAssocStatus & SYMBOL_ASSOC)) ) { if(!(lfo.plfw()->lfClipPrecision & CLIP_DFA_DISABLE)) { return(GFA_SUPPORTED); } } return(GFA_NOT_SUPPORTED); } } #endif