/***************************************************************************** * Module Name: fontlink.cxx * * FontLink (EUDC) API's for NT graphics engine. * * History: * * 1-18-96 Gerrit van Wingerden Moved to kernel mode. * 1-14-96 Hideyuki Nagase Add Font Association emulation features. * 1-09-95 Hideyuki Nagase Rewrote it for new fontlink features. * 1-04-94 Hideyuki Nagase Update for Daytona fontlink. * 2-10-93 Gerrit van Wingerden Wrote it. * * Copyright (c) 1993-1999 Microsoft Corporation *****************************************************************************/ #include "precomp.hxx" #ifdef FE_SB LONG lNormAngle(LONG lAngle); VOID vInitializeFontAssocStatus(VOID); #define EUDC_USER_REGISTRY_KEY \ L"\\EUDC\\" #define EUDC_SYSTEM_REGISTRY_KEY \ L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink" #define FONT_ASSOC_REGISTRY_KEY \ L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc" #define DEFAULT_EUDC_FONT L"EUDC.TTE" extern PFONT_ASSOC_SUB pFontAssocSubs; HSEMAPHORE ghsemEUDC1; HSEMAPHORE ghsemEUDC2; // used to signal the EUDC API's that it is okay to change EUDC link data // used to protects gappfeSysEUDC[] and gawcEUDCPath // - This mutex should be locked during referring above two values without // holding ghsemEUDC1. and updating above two data anytime. // used to protects BaseFontListHead // - This mutex should be locked during referring above list without // holding ghsemEUDC1. and updating above list anytime. LONG gcEUDCCount = 0; BOOL gbAnyLinkedFonts = FALSE; // Global variables for System EUDC. // FontLink Configuration value. ULONG ulFontLinkControl = 0L; static ULONG ulFontLinkChange = 0L; // HPFE for system EUDC font. PFE *gappfeSysEUDC[2] = { PPFENULL , PPFENULL }; // Path of system EUDC font static WCHAR gawcEUDCPath[MAX_PATH+1]; // QUICKLOOKUP for system EUDC font && TT System Font QUICKLOOKUP gqlEUDC; QUICKLOOKUP gqlTTSystem; // System eudc uniq number static ULONG ulSystemEUDCTimeStamp = 0; // FaceName eudc uniq number static ULONG ulFaceNameEUDCTimeStamp = 0; // Global variables for FaceName EUDC. // Count of face name links in the system static UINT gcNumLinks = 0; // Pointer to list of base font list static LIST_ENTRY BaseFontListHead = { (PLIST_ENTRY)&BaseFontListHead , (PLIST_ENTRY)&BaseFontListHead }; LIST_ENTRY NullListHead = { (PLIST_ENTRY)&NullListHead , (PLIST_ENTRY)&NullListHead }; static WCHAR gawcSystemACP[10]; // Eudc Default Unicode codepoint WCHAR EudcDefaultChar = 0x30fb; RTL_QUERY_REGISTRY_TABLE SharedQueryTable[2]; extern BOOL bSetupDefaultFlEntry(VOID); extern WCHAR gawcSystemDBCSFontPath[MAX_PATH]; // // global EUDC debugging flags // #if DBG FLONG gflEUDCDebug = 0x0000; FLONG gflDumpDebug = 0x0000; #endif /***************************************************************************** * IsRegNameEqual (HANDLE hKey, HANDLE hKeyLink, BOOL *bIsEqual) * * Given two handles to registry keys, * return TRUE in bIsEqual if and only if the names of the paths are the same * (i.e., if the handles were created using ZwOpenKey (once without OBJ_OPENLINK * and once with), then the key is actually a symbolic link if this routine * returns FALSE in bIsEqual). * * If an error occurs (e.g., ZwQueryKey fails), this function returns the NTSTATUS. * If a memory allocation fails within this routine, this function returns 0. * * History: * 6-10-99 Donald Chinn * Wrote it. *****************************************************************************/ static NTSTATUS IsRegNameEqual (HANDLE hKey, HANDLE hKeyLink, BOOL *bIsEqual) { NTSTATUS rv; PKEY_NAME_INFORMATION Buffer = NULL; PKEY_NAME_INFORMATION BufferLink = NULL; ULONG BufferSize, BufferLinkSize; *bIsEqual = FALSE; // get the size of the return buffers so that we can allocate memory for them ZwQueryKey (hKey, KeyNameInformation, NULL, 0, &BufferSize); ZwQueryKey (hKeyLink, KeyNameInformation, NULL, 0, &BufferLinkSize); // Add space for a null character for each buffer BufferSize += sizeof(WCHAR); BufferLinkSize += sizeof(WCHAR); // Round BufferSize up to the nearest multiple of sizeof(DWORD) BufferSize = ((BufferSize + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD); if ((Buffer = (PKEY_NAME_INFORMATION) PALLOCMEM (BufferSize + BufferLinkSize, 'flnk')) == NULL) { rv = 0; goto done; } BufferLink = (PKEY_NAME_INFORMATION) ((PBYTE) Buffer + BufferSize); if (!NT_SUCCESS(rv = ZwQueryKey (hKey, KeyNameInformation, Buffer, BufferSize, &BufferSize))) { goto done; } Buffer->Name[Buffer->NameLength / sizeof(WCHAR)] = L'\0'; if (!NT_SUCCESS(rv = ZwQueryKey (hKeyLink, KeyNameInformation, BufferLink, BufferLinkSize, &BufferLinkSize))) { goto done; } BufferLink->Name[BufferLink->NameLength / sizeof(WCHAR)] = L'\0'; *bIsEqual = (wcscmp (Buffer->Name, BufferLink->Name) ? FALSE : TRUE); done: if (Buffer) VFREEMEM (Buffer); return rv; } /***************************************************************************** * BOOL bNotIsKeySymbolicLink (const WCHAR *RegistryPathBuffer, * HANDLE *phKey, * HANDLE *phKeyLink, * BOOL *pbIsEqual) * * Given an absolute path name in the registry, * return TRUE if the function completed successfully and * return FALSE otherwise. * * The function also returns two handles associated with the key * as parameters. One is the handle returned from ZwOpenKey and * the other handle is the handle returned from ZwOpenKey when asked * to open it as a link. * * If the function succeeds, then pbIsEqual will contain TRUE * if the registry paths associated with the two handles are equal * (and FALSE otherwise). pbIsEqual is TRUE exactly when the * registry key is not a symbolic link. * * History: * 6-10-99 Donald Chinn * Wrote it. *****************************************************************************/ static BOOL bNotIsKeySymbolicLink (const WCHAR *RegistryPathBuffer, HANDLE *phKey, HANDLE *phKeyLink, BOOL *pbIsEqual) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING EUDCSubKey; BOOL bIsEqual = FALSE; *phKey = NULL; *phKeyLink = NULL; // set up the pathname RtlInitUnicodeString(&EUDCSubKey, RegistryPathBuffer); InitializeObjectAttributes (&ObjectAttributes, &EUDCSubKey, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); if (!NT_SUCCESS(ZwOpenKey (phKey, KEY_ALL_ACCESS, &ObjectAttributes))) return FALSE; InitializeObjectAttributes (&ObjectAttributes, &EUDCSubKey, OBJ_CASE_INSENSITIVE | OBJ_OPENLINK | OBJ_KERNEL_HANDLE, NULL, NULL) if (!NT_SUCCESS(ZwOpenKey (phKeyLink, KEY_ALL_ACCESS, &ObjectAttributes))) return FALSE; // The key is a symbolic link exactly when the names of the keys are different if (!NT_SUCCESS(IsRegNameEqual (*phKey, *phKeyLink, pbIsEqual))) { return FALSE; } return TRUE; } /***************************************************************************** * VOID CleanUpEUDC() * * This function clean up EUDC when HYDRA shout down * * History * 8-26-98 Yung-Jen Tony Tsai * Wrote it. *****************************************************************************/ VOID CleanUpEUDC() { // disable/unload system wide/facename eudc for current user. // clean up eudc links // on Hydra system, when the user/client goes away so does the gre // but the flag ulFontLinkChange is only set for FLINK_UNLOAD_FACENAME_USER // at this point. We need to set bit FLINK_UNLOAD_FACENAME_SYSTEM. SEMOBJ so(ghsemPublicPFT); PUBLIC_PFTOBJ pfto; // access the public font table ulFontLinkChange |= FLINK_UNLOAD_FACENAME_SYSTEM; GreEnableEUDC(FALSE); if (gqlEUDC.puiBits) { VFREEMEM(gqlEUDC.puiBits); gqlEUDC.puiBits = NULL; } if (gqlTTSystem.puiBits) { VFREEMEM(gqlTTSystem.puiBits); gqlTTSystem.puiBits = NULL; } // Release Font Associate allocated memory if (bFinallyInitializeFontAssocDefault) { ULONG iIndex; for( iIndex = 0; iIndex < NUMBER_OF_FONTASSOC_DEFAULT; iIndex++ ) { if( (FontAssocDefaultTable[iIndex].ValidRegData) && (FontAssocDefaultTable[iIndex].DefaultFontPathName[0] != L'\0') && (FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] != PPFENULL) ) { QUICKLOOKUP * pql; { PFEOBJ pfeo( FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] ); pql = pfeo.pql(); if (pql->puiBits) { VFREEMEM(pql->puiBits); pql->puiBits = NULL; } FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_NORMAL] = PPFENULL; } if (FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_VERTICAL] != PPFENULL) { PFEOBJ pfeov(FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_VERTICAL]); pql = pfeov.pql(); if (pql->puiBits) { VFREEMEM(pql->puiBits); pql->puiBits = NULL; } FontAssocDefaultTable[iIndex].DefaultFontPFEs[PFE_VERTICAL] = PPFENULL; } } } for( iIndex = 0; iIndex < NUMBER_OF_FONTASSOC_DEFAULT; iIndex++ ) { if( (FontAssocDefaultTable[iIndex].ValidRegData) && (FontAssocDefaultTable[iIndex].DefaultFontPathName[0] != L'\0')) { pfto.bUnloadEUDCFont(FontAssocDefaultTable[iIndex].DefaultFontPathName); FontAssocDefaultTable[iIndex].DefaultFontPathName[0] = L'\0'; } } } if (pFontAssocSubs) { VFREEMEM( pFontAssocSubs ); pFontAssocSubs = NULL; } if (gbSystemDBCSFontEnabled) pfto.bUnloadEUDCFont(gawcSystemDBCSFontPath); } /***************************************************************************** * VOID PFFOBJ::vGetEUDC(PEUDCLOAD) * * This function finds requested facename PFEs * * History * 4-14-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ VOID PFFOBJ::vGetEUDC ( PEUDCLOAD pEudcLoadData ) { ASSERTGDI(pEudcLoadData != NULL,"PFFOBJ::vGetEUDC() pEudcLoadData == NULL\n"); // // Initialize return buffer with NULL. // pEudcLoadData->pppfeData[PFE_NORMAL] = NULL; pEudcLoadData->pppfeData[PFE_VERTICAL] = NULL; if( pEudcLoadData->LinkedFace == NULL ) { // // Linked face name is not specified. In this case if the font has 2 PFEs // we assume first entry is for Normal face, and 2nd is Verical face. // // // Fill it with normal face PFE. // pEudcLoadData->pppfeData[PFE_NORMAL] = ppfe(PFE_NORMAL); // // if this font has 2 PFEs, get 2nd PFE for vertical face. otherwise // use same PFE as normal face for Vertical face. // if( cFonts() == 2 ) pEudcLoadData->pppfeData[PFE_VERTICAL] = ppfe(PFE_VERTICAL); else pEudcLoadData->pppfeData[PFE_VERTICAL] = ppfe(PFE_NORMAL); } else { // // Linked face name is specified, try to find out its PFE. // COUNT cFont; for( cFont = 0; cFont < cFonts(); cFont++ ) { PFEOBJ pfeo(ppfe(cFont)); PWSTR pwszEudcFace = pfeo.pwszFamilyName(); ULONG iPfeOffset = PFE_NORMAL; // // Is this a vertical face ? // if( pwszEudcFace[0] == (WCHAR) L'@' ) { iPfeOffset = PFE_VERTICAL; } // // Is this a face that we want ? // if(pfeo.bCheckFamilyName(pEudcLoadData->LinkedFace,1)) { // // Yes....., keep it. // pEudcLoadData->pppfeData[iPfeOffset] = pfeo.ppfeGet(); // // if this is a PFE for Normal face, also keep it for Vertical face. // after this, this value might be over-written by CORRRCT vertical // face's PFE. // // NOTE : // This code assume Normal face come faster than Vertical face... // if( iPfeOffset == PFE_NORMAL ) { pEudcLoadData->pppfeData[PFE_VERTICAL] = pfeo.ppfeGet(); } } } } } /***************************************************************************** * BOOL bValidFontLinkParameter(PWSTR,PWSTR *) * * This function make sure the linked font parameter is valid or not. * * History * 3-29-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bValidFontLinkParameter ( PWSTR LinkedFontName, PWSTR *LinkedFaceName ) { PWSTR lp = LinkedFontName; BOOL bFound = FALSE; *LinkedFaceName = NULL; while( *lp ) { if( *lp == L',' ) { if(bFound) { *LinkedFaceName = NULL; return(FALSE); } else { *LinkedFaceName = lp + 1; *lp = (WCHAR)NULL; bFound = TRUE; } } lp++; } return(TRUE); } /****************************************************************************** * BOOL bComputeQuickLookup( QUICKLOOKUP *pql, FD_GLYPHSET *pfdg, BOOL bSystemEUDC ) * * This routine computes a quick lookup structure from an FD_GLYPHSET structure. * * History: * 7-7-93 Gerrit van Wingerden [gerritv] * Wrote it. *****************************************************************************/ #define uiMask2(X) (0xFFFFFFFF << (31-(X))) #define uiMask1(X) (0xFFFFFFFF >> (X)) BOOL bComputeQuickLookup( QUICKLOOKUP *pql, PFE * pPFE, BOOL bSystemEUDC ) { WCRUN *pwcrun; WCHAR wcHigh = 0x0000; WCHAR wcLow = 0xFFFF; UINT ui; // if this is not SystemEUDC and puiBits has pointer, the Lookup table // was already initialized. PFEOBJ pfeObj(pPFE); if (!pfeObj.bValid()) return FALSE; if (pql == NULL) pql = pfeObj.pql(); if ( !bSystemEUDC && pql->puiBits ) return (TRUE); PFD_GLYPHSET pfdg; if(!(pfdg = pfeObj.pfdg())) return FALSE; pwcrun = pfdg->awcrun; // first figure out the high and low glyphs for this font for( ui = 0; ui < pfdg->cRuns; ui++ ) { if( wcLow > pwcrun[ui].wcLow ) { wcLow = pwcrun[ui].wcLow; } if( wcHigh < pwcrun[ui].wcLow + pwcrun[ui].cGlyphs ) { wcHigh = ( pwcrun[ui].wcLow + pwcrun[ui].cGlyphs - 1 ); } } (*pql).wcLow = wcLow; (*pql).wcHigh = wcHigh; // Now we need to allocate puiBits. In the case of the system EUDC font will // do this only once even though the glyph set can change dynamically. This // means we will always allocate 0xFFFF bits. If *pql.puiBits != NULL then // we assume the glyphset has been allocated before and leave it alone if( bSystemEUDC ) { // see if already allocated before and if so don't allocate it again // we determine this by checking if *pql.auiBits is NULL or not // 8k * 8 = 64k, 64k glyphs // 8k == 8192 if( (*pql).puiBits == NULL ) { (*pql).puiBits = (UINT*)PALLOCMEM( 8192, 'flnk' ); } else { RtlZeroMemory( (*pql).puiBits, 8192); } wcLow = 0; } else { (*pql).puiBits = (UINT*)PALLOCMEM((((wcHigh - wcLow + 1) + 31) / 32) * 4,'flnk'); } if((*pql).puiBits == (UINT*) NULL) { WARNING("bComputeQuickLookup out of memory.\n"); pfeObj.vFreepfdg(); return(FALSE); } for( ui = 0; ui < pfdg->cRuns ; ui++ ) { UINT uiFirst = ( pwcrun[ui].wcLow - wcLow ) / 32 ; UINT uiLast = ( pwcrun[ui].wcLow - wcLow + pwcrun[ui].cGlyphs - 1 ) / 32; if( uiFirst == uiLast) { (*pql).puiBits[uiFirst] |= uiMask2(pwcrun[ui].cGlyphs-1) >> ( ( pwcrun[ui].wcLow - wcLow ) % 32 ); } else { (*pql).puiBits[uiFirst] |= uiMask1((pwcrun[ui].wcLow - wcLow)%32); for( UINT uiRun = uiFirst+1; uiRun < uiLast; uiRun++ ) { (*pql).puiBits[uiRun] = 0xFFFFFFFF; } (*pql).puiBits[uiLast] |= uiMask2((pwcrun[ui].wcLow - wcLow + pwcrun[ui].cGlyphs-1)%32); } } pfeObj.vFreepfdg(); return(TRUE); } /****************************************************************************** * BOOL bAppendSysDirectory( WCHAR *pwcTarget, const WCHAR *pwcSource, UINT cchBufferSize ) * * Given a file name in pwcSource, this function appends it to the * appropirate directory and returns it into the buffer pointed to * by pwcTarget. If the file already has a path it just copies * pwcSource to pwcTarget. * * History: * 8-30-93 Hideyuki Nagase [hideyukn] * Add code for searching path * * 3-23-93 Gerrit van Wingerden [gerritv] * Wrote it. *****************************************************************************/ BOOL bAppendSysDirectory( WCHAR *pwcTarget, const WCHAR *pwcSource, UINT cchBufferSize ) { WCHAR pwcTemp[MAX_PATH]; // Check it is file name only or full path name if( wcschr(pwcSource,L'\\') != NULL ) { WCHAR *pSystemRoot; // full path. // // Catitalize path name. // cCapString guarantees NULL termination of destination string cCapString(pwcTarget,pwcSource,cchBufferSize); // The path contains %SYSTEMROOT% ? if( (pSystemRoot = wcsstr(pwcTarget,L"%SYSTEMROOT%")) != NULL ) { // Yes, // // Replace %SystemRoot%\FileName with \SystemRoot\FileName. // 012345678901 pSystemRoot[0] = L'\\'; wcscpy(&(pSystemRoot[11]),&(pSystemRoot[12])); } else { // if the file format is "C:\....", we appen "\??\" to make NtPath. // 0123 // [note] // // for formal way... we need call RtlDosPathNameToNtPathName_U(). // the function could not be called from kernel mode.... // if((pwcTarget[1] == L':') && (pwcTarget[2] == L'\\')) { // keep a back up to pwcTemp. // Put "\??\" first. // Put original path. // if (FAILED(StringCchCopyW(pwcTemp, MAX_PATH, pwcTarget)) || FAILED(StringCchCopyW(pwcTarget, cchBufferSize, L"\\??\\")) || FAILED(StringCchCatW(pwcTarget, cchBufferSize, pwcTemp))) { WARNING("bAppendSysDirectory: target buffer too short.\n"); return FALSE; } } else { WARNING("bAppenSysDirectory():Need conversion (DosPath -> NtPath)\n"); } } #if DBG DbgPrint("bAppenSysDirectory():Path --> %ws\n",pwcTarget); #endif } else { // assume it is in the "fonts" directory if (FAILED(StringCchCopyW(pwcTemp, MAX_PATH, L"\\??\\")) || FAILED(StringCchCatW(pwcTemp, MAX_PATH, USER_SHARED_DATA->NtSystemRoot)) || FAILED(StringCchCatW(pwcTemp, MAX_PATH, L"\\fonts\\")) || FAILED(StringCchCatW(pwcTemp, MAX_PATH, pwcSource))) { WARNING("bAppendSysDirectory: target buffer too short.\n"); return FALSE; } cCapString(pwcTarget,pwcTemp,cchBufferSize); } return TRUE; } /**************************************************************************** * GetUserEUDCRegistryPath(LPWSTR,USHORT) * * Get EUDC registry path for current loggedon user. * * History: * 9-Feb-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. ***************************************************************************/ static NTSTATUS GetUserEUDCRegistryPath ( LPWSTR UserEUDCPathBuffer, USHORT UserEUDCPathLen ) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING UserEUDCPath; UNICODE_STRING UserRegistryPath; UserEUDCPath.Length = 0; UserEUDCPath.MaximumLength = UserEUDCPathLen; UserEUDCPath.Buffer = UserEUDCPathBuffer; // Get path of CurrentUser key. if(NT_SUCCESS(RtlFormatCurrentUserKeyPath(&UserRegistryPath))) { // Build path for EUDC data status = RtlAppendUnicodeStringToString(&UserEUDCPath,&UserRegistryPath); if (NT_SUCCESS(status)) status = RtlAppendUnicodeToString(&UserEUDCPath,EUDC_USER_REGISTRY_KEY); if (NT_SUCCESS(status)) status = RtlAppendUnicodeToString(&UserEUDCPath,gawcSystemACP); RtlFreeUnicodeString(&UserRegistryPath); } else { WARNING("GetUserEUDCRegistryPath():RtlFormatCurrentUserKeyPath\n"); // just retuen default path.. status = RtlAppendUnicodeToString(&UserEUDCPath,L"\\Registry\\User\\.DEFAULT"); if (NT_SUCCESS(status)) status = RtlAppendUnicodeToString(&UserEUDCPath,EUDC_USER_REGISTRY_KEY); if (NT_SUCCESS(status)) status = RtlAppendUnicodeToString(&UserEUDCPath,gawcSystemACP); } if (NT_SUCCESS(status)) { // check if RtlAppendXXX didn't null-terminate the output string if (UserEUDCPath.Length == UserEUDCPath.MaximumLength) { WARNING("GetUserEUDCRegistryPath(): the output string is not null-terminated\n"); status = STATUS_BUFFER_TOO_SMALL; } } return status; } /****************************************************************************** * bWriteUserSystemEUDCRegistry(LPWSTR) * * Write system wide eudc font file path for request user. * * History: * 9-Feb-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. *****************************************************************************/ static BOOL bWriteUserSystemEUDCRegistry ( LPWSTR DataBuffer, USHORT DataLen ) { WCHAR RegistryPathBuffer[MAX_PATH]; HANDLE hKey = NULL; HANDLE hKeyLink = NULL; BOOL bIsEqual = FALSE; // Get EUDC registry path for requested user NTSTATUS NtStatus = GetUserEUDCRegistryPath(RegistryPathBuffer,sizeof(RegistryPathBuffer)); if (NT_SUCCESS(NtStatus)) { // if the registry entry is a symbolic link, fail the call if (bNotIsKeySymbolicLink (RegistryPathBuffer, &hKey, &hKeyLink, &bIsEqual) && bIsEqual) { // Write registry. NtStatus = RtlWriteRegistryValue( RTL_REGISTRY_ABSOLUTE, RegistryPathBuffer, L"SystemDefaultEUDCFont", REG_SZ, DataBuffer, DataLen * sizeof(WCHAR) ); } else { NtStatus = (STATUS_SEVERITY_ERROR << 30); // any non-zero error is sufficient } } if (hKey) ZwClose (hKey); if (hKeyLink) ZwClose (hKeyLink); if(!NT_SUCCESS(NtStatus)) { WARNING("bWriteUserSystemEUDCRegistry():fail\n"); return(FALSE); } return(TRUE); } /****************************************************************************** * bReadUserSystemEUDCRegistry(LPWSTR,USHORT) * * Read system wide eudc font file path for request user. * * History: * 9-Feb-1995 -by- Hideyuki Nagase [hideyukn] * Wrote it. *****************************************************************************/ static BOOL bReadUserSystemEUDCRegistry ( LPWSTR FilePathBuffer, USHORT FilePathLen ) { WCHAR NoExpandFilePathBuffer[MAX_PATH]; WCHAR RegistryPathBuffer[MAX_PATH]; UNICODE_STRING FilePath; HANDLE hKey = NULL; HANDLE hKeyLink = NULL; BOOL bIsEqual = FALSE; RegistryPathBuffer[0] = NoExpandFilePathBuffer[0] = 0; FilePath.Length = 0; FilePath.MaximumLength = sizeof(NoExpandFilePathBuffer); FilePath.Buffer = NoExpandFilePathBuffer; // Get EUDC registry path for requested user NTSTATUS NtStatus = GetUserEUDCRegistryPath(RegistryPathBuffer,sizeof(RegistryPathBuffer)); if (NT_SUCCESS(NtStatus)) { // if the registry entry is a symbolic link, fail the call if (bNotIsKeySymbolicLink (RegistryPathBuffer, &hKey, &hKeyLink, &bIsEqual) && bIsEqual) { SharedQueryTable[0].QueryRoutine = NULL; SharedQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; SharedQueryTable[0].Name = (PWSTR) L"SystemDefaultEUDCFont"; SharedQueryTable[0].EntryContext = (PVOID) &FilePath; SharedQueryTable[0].DefaultType = REG_NONE; SharedQueryTable[0].DefaultData = NULL; SharedQueryTable[0].DefaultLength = 0; SharedQueryTable[1].QueryRoutine = NULL; SharedQueryTable[1].Flags = 0; SharedQueryTable[1].Name = NULL; // Read registry. NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPathBuffer, SharedQueryTable, NULL, NULL); } else { NtStatus = (STATUS_SEVERITY_ERROR << 30); // any non-zero error is sufficient } } if (hKey) ZwClose (hKey); if (hKeyLink) ZwClose (hKeyLink); if(!NT_SUCCESS(NtStatus) || FilePath.Length == 0) { if(NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) { WCHAR *LastBackslash = NULL; // // if the user does not have EUDC\ActiveCodePage\SystemDefaultEUDCFont // key\value, we create the key and set the default value here.. // // Create key. LastBackslash = wcsrchr(RegistryPathBuffer,L'\\'); if(LastBackslash != NULL && _wcsicmp(LastBackslash+1,gawcSystemACP) == 0) { // Create HKEY_CURRENT_USER\EUDC key. *LastBackslash = L'\0'; RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,RegistryPathBuffer); // Create HKEY_CURRENT_USER\EUDC\ActiveCodePage key. *LastBackslash = L'\\'; RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,RegistryPathBuffer); // Set value. if(bWriteUserSystemEUDCRegistry(DEFAULT_EUDC_FONT, wcslen(DEFAULT_EUDC_FONT)+1) ) { // // Initialize FilePath with default. // RtlInitUnicodeString(&FilePath,DEFAULT_EUDC_FONT); } else goto ErrorReturn; } else goto ErrorReturn; } else goto ErrorReturn; } else { if (FilePath.Length == FilePath.MaximumLength) { WARNING("bReadUserSystemEUDCRegistry(): SystemDefaultEUDCFont path too long.\n"); goto ErrorReturn; } } wcsncpy(FilePathBuffer,FilePath.Buffer,FilePathLen); return(TRUE); ErrorReturn: return(FALSE); } /***************************************************************************** * BOOL bKillEudcRFONTs( RFONT *prfntVictims ) * * Given a linked list of EUDC RFONT this routine kills them all. * * History * 6-30-93 Gerrit van Wingerden * Wrote it. *****************************************************************************/ static BOOL bKillEudcRFONTs( RFONT *prfntVictims ) { PRFONT prfnt; while( (prfnt = prfntVictims ) != (PRFONT) NULL ) { prfntVictims = prfntVictims->rflPDEV.prfntNext; { RFONTTMPOBJ rfloVictim(prfnt); // Need this so we can remove this from the PFF's RFONT list. PFFOBJ pffo(prfnt->pPFF); ASSERTGDI(pffo.bValid(), "gdisrv!vKillEudcRFONTs: bad HPFF"); // We pass in NULL for ppdo because we've already removed it from the // PDEV list. if( !rfloVictim.bDeleteRFONT((PDEVOBJ *) NULL, &pffo)) { WARNING("Unable vKillEudcRFONTs unable to delete RFONT.\n"); return(FALSE); } } } return(TRUE); } /***************************************************************************** * RFONT *prfntDeactivateEudcRFONTs(PFE **) * * Tracks down all the EUDC RFONTS in the system removes them from the active * and deactive lists and puts them on a list for deletion which it then * returns to the caller. * * The public font table semaphore must be held by the caller for this to work. * * History * 23-01-95 Hideyuki Nagase * Rewrote it. * * 2-10-93 Gerrit van Wingerden * Wrote it. *****************************************************************************/ static VOID vDeactivateEudcRFONTsWorker ( PPFE *appfe, PPFF pPFF, RFONT **pprfntToBeKilled ) { while(pPFF) { PFFOBJ pffo(pPFF); // Check if this font file is really loaded as EUDC font.. if(pffo.bEUDC()) { for( PRFONT prfnt = pffo.prfntList() ; prfnt != (PRFONT) NULL; ) { PRFONT prfntNext; { RFONTTMPOBJ rflo(prfnt); prfntNext = rflo.prflPFF()->prfntNext; } if( ( prfnt->ppfe == appfe[PFE_NORMAL] ) || ( prfnt->ppfe == appfe[PFE_VERTICAL] ) ) { FLINKMESSAGE2(DEBUG_FONTLINK_UNLOAD, "Removing EUDC font %x.\n", prfnt); RFONTTMPOBJ rfo(prfnt); PDEVOBJ pdo(prfnt->hdevConsumer); PRFONT prf; // remove it from the active or inactive list if( prfnt->cSelected != 0 ) { prf = pdo.prfntActive(); rfo.vRemove(&prf, PDEV_LIST); pdo.prfntActive(prf); } else { prf = pdo.prfntInactive(); rfo.vRemove(&prf, PDEV_LIST); pdo.prfntInactive(prf); pdo.cInactive( pdo.cInactive()-1 ); } // add it to the kill list rfo.vInsert( pprfntToBeKilled, PDEV_LIST ); } prfnt = prfntNext; } } pPFF = pPFF->pPFFNext; } } static RFONT *prfntDeactivateEudcRFONTs( PPFE *appfe ) { RFONT *prfntToBeKilled = PRFNTNULL; FLINKMESSAGE(DEBUG_FONTLINK_UNLOAD,"Deactivating EUDC RFONTs.\n"); SEMOBJ so1(ghsemPublicPFT); SEMOBJ so2(ghsemRFONTList); COUNT cBuckets; PPFF pPFF; PUBLIC_PFTOBJ pftoPublic; // access the public font table for( cBuckets = 0; cBuckets < pftoPublic.cBuckets(); cBuckets++ ) { if( (pPFF = pftoPublic.pPFF(cBuckets)) != NULL ) { vDeactivateEudcRFONTsWorker( appfe, pPFF, &prfntToBeKilled ); } } return(prfntToBeKilled); } /***************************************************************************** * BOOL bUnloadEudcFont( PFE ** ) * * This function delete RFONTs and unload fontfile for specified PFE * * History: * 24-01-1995 -by- Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bUnloadEudcFont( PFE **ppfe ) { WCHAR awcPathBuffer[MAX_PATH + 1]; PUBLIC_PFTOBJ pfto; // access the public font table PFEOBJ pfeo( ppfe[PFE_NORMAL] ); PFFOBJ pffo( pfeo.pPFF() ); // get font file path. if (FAILED(StringCchCopyW(awcPathBuffer, MAX_PATH + 1, pffo.pwszPathname()))) { WARNING("bUnloadEudcFont: temporary buffer too short\n"); return FALSE; } QUICKLOOKUP *pqlDelete; // Progress Normal face.. pqlDelete = pfeo.pql(); // if this is system wide eudc, won't need to free it. if( pqlDelete->puiBits != NULL ) { VFREEMEM(pqlDelete->puiBits); pqlDelete->puiBits = NULL; } PFEOBJ pfeoVert( ppfe[PFE_VERTICAL] ); if( pfeoVert.bValid() ) { pqlDelete = pfeoVert.pql(); // if this is system wide eudc, won't need to free it. if( pqlDelete->puiBits != NULL ) { VFREEMEM(pqlDelete->puiBits); pqlDelete->puiBits = NULL; } } // Deactivate all RFONT for this PFE PRFONT prfntToBeKilled = prfntDeactivateEudcRFONTs( ppfe ); // Kill all RFONT for this PFE if(!bKillEudcRFONTs( prfntToBeKilled )) { WARNING("bDeleteAllFlEntry():Can not kill Eudc RFONTs\n"); return(FALSE); } // // Unload this font file. // // if others link are using this font file, the font // is not unloaded here. At the last link that is using // this font, it will be really unloaded. // #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Unloading... %ws\n",awcPathBuffer); } #endif if(!pfto.bUnloadEUDCFont(awcPathBuffer)) { #if DBG DbgPrint("bDeleteAllFlEntry():Can not unload Eudc %ws\n",awcPathBuffer); #endif return(FALSE); } return(TRUE); } /***************************************************************************** * PFLENTRY FindBaseFontEntry(const WCHAR *) * * This function scan the base font list to find specified font is already * exist or not. * * Return. * Exist - Pointer to FLENTRY strucrure. * Not exist - NULL * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ PFLENTRY FindBaseFontEntry ( const WCHAR * BaseFontName ) { PLIST_ENTRY p; PFLENTRY pFlEntry; p = BaseFontListHead.Flink; pFlEntry = NULL; while( p != &BaseFontListHead ) { pFlEntry = CONTAINING_RECORD(p,FLENTRY,baseFontList); #if DBG if( gflEUDCDebug & (DEBUG_FONTLINK_INIT) ) { DbgPrint("%ws v.s. %ws\n",BaseFontName,pFlEntry->awcFaceName); } #endif // // if this is Vertical font name, compair without '@' // const WCHAR * pFaceName = ( (pFlEntry->awcFaceName[0] != L'@') ? &(pFlEntry->awcFaceName[0]) : &(pFlEntry->awcFaceName[1]) ); const WCHAR * pBaseFaceName = ( (BaseFontName[0] != L'@') ? &BaseFontName[0] : &BaseFontName[1] ); // // Compair font face name. // if( _wcsicmp(pBaseFaceName,pFaceName) == 0 ) { // // Find it. // break; } // // try next. // p = p->Flink; pFlEntry = NULL; } return(pFlEntry); } /***************************************************************************** * PPFEDATA FindLinkedFontEntry(PLIST_ENTRY,PWSTR,PWSTR) * * This function scan the linked font list to find specified font is already * exist or not. * * Return. * Exist - Pointer to PPFEDATA strucrure. * Not exist - NULL * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static PPFEDATA FindLinkedFontEntry ( PLIST_ENTRY LinkedFontList, const WCHAR * LinkedFontPath, const WCHAR * LinkedFontFace ) { PLIST_ENTRY p; PPFEDATA ppfeData; p = LinkedFontList->Flink; ppfeData = NULL; while( p != LinkedFontList ) { ppfeData = CONTAINING_RECORD(p,PFEDATA,linkedFontList); // // get PFE and PFF user object. // PFEOBJ pfeo( ppfeData->appfe[PFE_NORMAL] ); PFFOBJ pffo( pfeo.pPFF() ); #if DBG if( gflEUDCDebug & (DEBUG_FONTLINK_INIT) ) { DbgPrint("%ws v.s. %ws\n",pffo.pwszPathname(),LinkedFontPath); } #endif // // compair file path // if( _wcsicmp( pffo.pwszPathname() , LinkedFontPath ) == 0 ) { // // if facename of linked font is specified, check it also. // if( ((LinkedFontFace == NULL) && ((ppfeData->FontLinkFlag & FLINK_FACENAME_SPECIFIED) == 0)) || ((LinkedFontFace != NULL ) && ((ppfeData->FontLinkFlag & FLINK_FACENAME_SPECIFIED) != 0) && ((_wcsicmp(pfeo.pwszFamilyName() , LinkedFontFace))== 0) ) ) { // // Find it. // break; } } // // try next. // p = p->Flink; ppfeData = NULL; } return(ppfeData); } /*****************************************************************************\ * BOOL FindDefaultLinkedFontEntry * * This codepath check the passed facename is registered as Default link * facename in Default link table. if so, keep its facename for the facename. * * History * 1-14-96 Hideyuki Nagase * Wrote it. *****************************************************************************/ BOOL FindDefaultLinkedFontEntry ( const WCHAR * CandidateFaceName, const WCHAR * CandidatePathName ) { UINT iIndex; for( iIndex = 0; iIndex < NUMBER_OF_FONTASSOC_DEFAULT; iIndex++ ) { // // Check the data can be read from registry or not. // if( FontAssocDefaultTable[iIndex].ValidRegData ) { // // Check this path is not filled. // if( FontAssocDefaultTable[iIndex].DefaultFontPathName[0] == L'\0' ) { // // Check the candidate is matched with the facename from registry. // if( _wcsicmp(CandidateFaceName,FontAssocDefaultTable[iIndex].DefaultFontFaceName) == 0 ) { // // Mark the candidate path to default table. This font file will be RE-loaded // EUDC font file when GreEnableEUDC() was called next time. // if (FAILED(StringCchCopyW(FontAssocDefaultTable[iIndex].DefaultFontPathName, MAX_PATH+1, CandidatePathName))) { WARNING("FindDefaultLinkedFontEntry: temporary buffer too short\n"); return FALSE; } #if DBG DbgPrint("GDISRV:FONTASSOC DEFAULT:%ws -> %ws\n", FontAssocDefaultTable[iIndex].DefaultFontTypeID, FontAssocDefaultTable[iIndex].DefaultFontPathName); #endif } } } } return TRUE; } /***************************************************************************** * VOID vLinkEudcPFEs(PFLENTRY) * * This routine will find base font PFE from PFT, and set up Eudc data. * * History: * 24-Jan-1995 -by- Hideyuki Nagase * Wrote it. ****************************************************************************/ static VOID vLinkEudcPFEsWorker ( PFLENTRY pFlEntry, PPFF pPFF ) { while(pPFF) { // // get PFF user object // PFFOBJ pffo(pPFF); // // if this font is loaded as EUDC, it can not be a BaseFont. // if( !pffo.bEUDC() ) { for( COUNT c = 0 ; c < pffo.cFonts() ; c++ ) { PFEOBJ pfeo(pffo.ppfe(c)); if( pfeo.bValid() ) { BOOL bFound = FALSE; PFLENTRY pFlEntrySelected = pFlEntry; if( pFlEntrySelected ) { bFound = pfeo.bCheckFamilyName(pFlEntrySelected->awcFaceName, 0); } else { const WCHAR * pwszAlias = NULL; BOOL bIsFamilyNameAlias = FALSE; pwszAlias = pfeo.pwszFamilyNameAlias(&bIsFamilyNameAlias); bFound = ((pFlEntrySelected = FindBaseFontEntry(pwszAlias)) != NULL); if (!bFound && bIsFamilyNameAlias) { pwszAlias += (wcslen(pwszAlias) + 1); bFound = ((pFlEntrySelected = FindBaseFontEntry(pwszAlias)) != NULL); } } if( bFound ) { // // set eudc list.. // pfeo.vSetLinkedFontEntry( pFlEntrySelected ); #if DBG if( gflEUDCDebug & DEBUG_FACENAME_EUDC ) { PLIST_ENTRY p = pfeo.pGetLinkedFontList()->Flink; DbgPrint("Found FaceName EUDC for %ws (%ws) is ", pfeo.pwszFamilyName(),pffo.pwszPathname()); while( p != &(pFlEntrySelected->linkedFontListHead) ) { PPFEDATA ppfeData = CONTAINING_RECORD(p,PFEDATA,linkedFontList); PFEOBJ pfeoTemp( ppfeData->appfe[PFE_NORMAL] ); PFFOBJ pffoTemp( pfeoTemp.pPFF() ); DbgPrint(" %ws ",pffoTemp.pwszPathname()); p = p->Flink; } DbgPrint("\n"); } #endif } else { // mark the FaceNameEUDC pfe as NULL pfeo.vSetLinkedFontEntry( NULL ); } } } } pPFF = pPFF->pPFFNext; } } static VOID vLinkEudcPFEs ( PFLENTRY pFlEntry ) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_LOAD ) { DbgPrint( "vLinkEudcPFEs():Linking All EUDC PFEs.\n"); } #endif SEMOBJ so(ghsemPublicPFT); // // WE HAD BETTER USE FONTHASH TO SEARCH BASE FONT'S PFF. // COUNT cBuckets; PPFF pPFF; // // get PFT user object. // PUBLIC_PFTOBJ pftoPublic; // access the public font table for( cBuckets = 0; cBuckets < pftoPublic.cBuckets(); cBuckets++ ) { if( (pPFF = pftoPublic.pPFF(cBuckets)) != NULL ) { vLinkEudcPFEsWorker( pFlEntry, pPFF ); } } DEVICE_PFTOBJ pftoDevice; // access the public font table for( cBuckets = 0; cBuckets < pftoDevice.cBuckets(); cBuckets++ ) { if( (pPFF = pftoDevice.pPFF(cBuckets)) != NULL ) { vLinkEudcPFEsWorker( pFlEntry, pPFF ); } } } /***************************************************************************** * VOID vUnlinkEudcRFONTs( PPFE * ) * * This routine reset RFONT that has specified linked font. * * History: * 23-Jan-1995 -by- Hideyuki Nagase * Wrote it ****************************************************************************/ static VOID vUnlinkEudcRFONTsWorker ( PPFE *appfe, PPFF pPFF ) { while(pPFF) { PFFOBJ pffo(pPFF); // if this font is loaded as EUDC, it can not be a BaseFont. if( !pffo.bEUDC() ) { // Unlink Eudc from the RFONTs if it has specified Eudc.. for( PRFONT prfnt = pffo.prfntList() ; prfnt != (PRFONT) NULL; ) { PRFONT prfntNext; { RFONTTMPOBJ rflo(prfnt); prfntNext = rflo.prflPFF()->prfntNext; } // if this RFONT has Eudc font, search this Eudc.. for( UINT ii = 0 ; ii < prfnt->uiNumLinks ; ii++ ) { // Is this the Eudc RFONT that we want to remove? if((prfnt->paprfntFaceName[ii] != NULL ) && (((prfnt->paprfntFaceName[ii])->ppfe == appfe[PFE_NORMAL]) || ((prfnt->paprfntFaceName[ii])->ppfe == appfe[PFE_VERTICAL]))) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Removing face name EUDC pair %x -> %x\n", prfnt, prfnt->paprfntFaceName[ii]); } #endif prfnt->paprfntFaceName[ii] = NULL; } } // this RFONT's linked font array will be updated with new configuration // when this RFONT is used again (see vInitEUDC()). // and, if all Eudc font has been removed for this RFONT. // the array, its pointer and other information for Eudc will be // deleted/updated, vUnlinkEudcRFONTsAndPFEs() will be called instead // of this. prfnt->flEUDCState = 0; prfnt = prfntNext; } } pPFF = pPFF->pPFFNext; } } static VOID vUnlinkEudcRFONTs ( PPFE *appfe ) { FLINKMESSAGE(DEBUG_FONTLINK_UNLOAD,"vUnlinkEudcRFONTs():Unlinking EUDC RFONTs.\n"); SEMOBJ so1(ghsemPublicPFT); SEMOBJ so2(ghsemRFONTList); COUNT cBuckets; PPFF pPFF; PUBLIC_PFTOBJ pftoPublic; // access the public font table for( cBuckets = 0; cBuckets < pftoPublic.cBuckets(); cBuckets++ ) { if( (pPFF = pftoPublic.pPFF(cBuckets)) != NULL ) { vUnlinkEudcRFONTsWorker(appfe,pPFF); } } DEVICE_PFTOBJ pftoDevice; // access the public font table for( cBuckets = 0; cBuckets < pftoDevice.cBuckets(); cBuckets++ ) { if( (pPFF = pftoDevice.pPFF(cBuckets)) != NULL ) { vUnlinkEudcRFONTsWorker(appfe,pPFF); } } } /***************************************************************************** * VOID vUnlinkEudcRFONTsAndPFEs(PPFE *,PFLENTRY) * * This routine reset RFONT and PFE structure that has specified linked font. * * History: * 23-Jan-1995 -by- Hideyuki Nagase * Wrote it ****************************************************************************/ static VOID vUnlinkEudcRFONTsAndPFEsWorker ( PPFE *appfe, PFLENTRY pFlEntry, PPFF pPFF ) { while(pPFF) { PFFOBJ pffo(pPFF); // if this font is loaded as EUDC, it can not be a BaseFont. if( !pffo.bEUDC() ) { // Unlink Eudc from the RFONTs if it has specified Eudc.. for( PRFONT prfnt = pffo.prfntList() ; prfnt != (PRFONT) NULL; ) { PRFONT prfntNext; { RFONTTMPOBJ rflo(prfnt); prfntNext = rflo.prflPFF()->prfntNext; } // if this RFONT has Eudc font, search this Eudc.. BOOL bFound = FALSE; for( UINT ii = 0 ; ii < prfnt->uiNumLinks ; ii++ ) { // Is this the Eudc RFONT that we want to remove? if(((prfnt->paprfntFaceName[ii]) != NULL ) && (((prfnt->paprfntFaceName[ii])->ppfe == appfe[PFE_NORMAL]) || ((prfnt->paprfntFaceName[ii])->ppfe == appfe[PFE_VERTICAL]))) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Removing face name EUDC pair %x -> %x\n", prfnt, prfnt->paprfntFaceName[ii]); } // // Invalidate it for checking. // prfnt->paprfntFaceName[ii] = NULL; #endif bFound = TRUE; break; } } if( bFound ) { #if DBG // make sure the linked font array is really empty. for( UINT jj = 0; jj < prfnt->uiNumLinks ; jj++ ) { if( prfnt->paprfntFaceName[jj] != NULL ) { DbgPrint("vUnloadEudcRFONTsAndPFEs():*** Deleteing Eudc \ array that has valid data\n"); } } #endif // if the linked RFONT table was allocated, free it here if( prfnt->paprfntFaceName != prfnt->aprfntQuickBuff ) VFREEMEM( prfnt->paprfntFaceName ); // we have no facename eudc for this RFONT. prfnt->paprfntFaceName = NULL; prfnt->uiNumLinks = 0; prfnt->bFilledEudcArray = FALSE; prfnt->ulTimeStamp = 0L; } prfnt->flEUDCState = 0; prfnt = prfntNext; } // Unlink Eudcs from All PFEs that has Eudcs. for( COUNT c = 0 ; c < pffo.cFonts() ; c++ ) { PFEOBJ pfeo(pffo.ppfe(c)); if( pfeo.pGetLinkedFontEntry() == pFlEntry ) { FLINKMESSAGE2(DEBUG_FONTLINK_UNLOAD, "Removing face name PFE for %x (PFE)\n",pffo.ppfe(c)); pfeo.vSetLinkedFontEntry( NULL ); } } } pPFF = pPFF->pPFFNext; } } static VOID vUnlinkEudcRFONTsAndPFEs ( PPFE *appfe, PFLENTRY pFlEntry ) { FLINKMESSAGE(DEBUG_FONTLINK_UNLOAD, "vUnlinkEudcRFONTsAndPFEs():Unlinking EUDC RFONTs ans PFEs.\n"); SEMOBJ so1(ghsemPublicPFT); SEMOBJ so2(ghsemRFONTList); COUNT cBuckets; PPFF pPFF; // get PFT user object. PUBLIC_PFTOBJ pftoPublic; // access the public font table for( cBuckets = 0; cBuckets < pftoPublic.cBuckets(); cBuckets++ ) { if( (pPFF = pftoPublic.pPFF(cBuckets)) != NULL ) { vUnlinkEudcRFONTsAndPFEsWorker(appfe,pFlEntry,pPFF); } } DEVICE_PFTOBJ pftoDevice; // access the public font table for( cBuckets = 0; cBuckets < pftoDevice.cBuckets(); cBuckets++ ) { if( (pPFF = pftoDevice.pPFF(cBuckets)) != NULL ) { vUnlinkEudcRFONTsAndPFEsWorker(appfe,pFlEntry,pPFF); } } } /***************************************************************************** * VOID vUnlinkAllEudcRFONTsAndPFEs(BOOL,BOOL) * * This routine reset RFONT and PFE structure that has any linked font. * * History: * 23-Jan-1995 -by- Hideyuki Nagase * Wrote it ****************************************************************************/ static VOID vUnlinkAllEudcRFONTsAndPFEsWorker ( BOOL bUnlinkSystem, BOOL bUnlinkFaceName, PPFF pPFF ) { while(pPFF) { PFFOBJ pffo(pPFF); // if this font is loaded as EUDC, it can not be a BaseFont. if( !pffo.bEUDC() ) { // Unlink Eudc from All RFONTs that has Eudc.. for( PRFONT prfnt = pffo.prfntList() ; prfnt != (PRFONT) NULL; ) { PRFONT prfntNext; { RFONTTMPOBJ rflo(prfnt); prfntNext = rflo.prflPFF()->prfntNext; } // if this RFONT has system wide eudc, unlink it.. if( bUnlinkSystem ) { #if DBG if( prfnt->prfntSysEUDC != (PRFONT) NULL ) { if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Removing system wide EUDC pair %x -> %x\n", prfnt, prfnt->prfntSysEUDC); } prfnt->prfntSysEUDC = NULL; } #else prfnt->prfntSysEUDC = NULL; #endif } // if this RFONT has face name eudc, unlink it.. if( bUnlinkFaceName ) { // NOTE : // // We will unlink the pointer to Rfont, even some of // eudc link will valid (i.g. if we have on-bit of FONTLINK_SYSTEM in // FontLinkChange value. the type of EUDC may not need to unlink. // Because we should restructure the Rfonts array for following case, // when even we want to only USER attribute EUDC.... // // Before : // BaseFont->FaceNameEUDC(SYS)->FaceNameEUDC(USER)->FaceNameEUDC(SYS) // // After : // BaseFont -> FaceNameEUDC(SYS) -> FaceNameEUDC(SYS) // if( prfnt->paprfntFaceName != NULL ) { for( UINT ii = 0 ; ii < prfnt->uiNumLinks ; ii++ ) { #if DBG if( prfnt->paprfntFaceName[ii] != NULL ) { if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Removing face name EUDC pair %x -> %x\n", prfnt, prfnt->paprfntFaceName[ii]); } prfnt->paprfntFaceName[ii] = NULL; } #else prfnt->paprfntFaceName[ii] = NULL; #endif } if( prfnt->paprfntFaceName != prfnt->aprfntQuickBuff ) VFREEMEM( prfnt->paprfntFaceName ); prfnt->uiNumLinks = 0; prfnt->paprfntFaceName = NULL; prfnt->bFilledEudcArray = FALSE; prfnt->ulTimeStamp = 0; } } prfnt->flEUDCState = 0; prfnt = prfntNext; } if( bUnlinkFaceName ) { for( COUNT c = 0 ; c < pffo.cFonts() ; c++ ) { PFEOBJ pfeo(pffo.ppfe(c)); #if DBG if( pfeo.pGetLinkedFontEntry() != NULL ) { FLINKMESSAGE2(DEBUG_FONTLINK_UNLOAD, \ "Removing face name PFE for %x (PFE)\n", \ pffo.ppfe(c)); pfeo.vSetLinkedFontEntry( NULL ); } #else pfeo.vSetLinkedFontEntry( NULL ); #endif } } } pPFF = pPFF->pPFFNext; } } static VOID vUnlinkAllEudcRFONTsAndPFEs ( BOOL bUnlinkSystem, BOOL bUnlinkFaceName ) { FLINKMESSAGE(DEBUG_FONTLINK_UNLOAD, "vUnlinkAllEudcRFONTsAndPFEs():Unlinking All EUDC RFONTs and PFEs.\n"); SEMOBJ so1(ghsemPublicPFT); SEMOBJ so2(ghsemRFONTList); COUNT cBuckets; PPFF pPFF; // // get PFT user object. // PUBLIC_PFTOBJ pftoPublic; // access the public font table for( cBuckets = 0; cBuckets < pftoPublic.cBuckets(); cBuckets++ ) { if( (pPFF = pftoPublic.pPFF(cBuckets)) != NULL ) { vUnlinkAllEudcRFONTsAndPFEsWorker(bUnlinkSystem,bUnlinkFaceName,pPFF); } } DEVICE_PFTOBJ pftoDevice; // access the public font table for( cBuckets = 0; cBuckets < pftoDevice.cBuckets(); cBuckets++ ) { if( (pPFF = pftoDevice.pPFF(cBuckets)) != NULL ) { vUnlinkAllEudcRFONTsAndPFEsWorker(bUnlinkSystem,bUnlinkFaceName,pPFF); } } } /***************************************************************************** * BOOL bDeleteFlEntry(PWSTR,PWSTR,INT) * * This function delete base font and linked font pair from list. * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bDeleteFlEntry ( const WCHAR * BaseFontName, const WCHAR * LinkedFontPathAndName, INT iFontLinkType // FONTLINK_SYSTEM or FONTLINK_USER ) { PFLENTRY pFlEntry = NULL; PPFEDATA ppfeData = NULL; PWSTR LinkedFaceName = NULL; WCHAR awcPathBuffer[MAX_PATH]; WCHAR LinkedFontName[LF_FACESIZE+MAX_PATH+1]; // // Have a local copy... // if (FAILED(StringCchCopyW(LinkedFontName, LF_FACESIZE+MAX_PATH+1, LinkedFontPathAndName))) { WARNING("bDeleteFlEntry: temporary buffer too short\n"); return FALSE; } // // Find ',' char from LinkedFontName // // Registry format : // // Type 1: // // This format is for the specified Linked font contains only 1 font resource. // Except Vertical "@" face font, such as TrueType font (not TTC), and Vector font. // // BaseFontFaceName = REG_MULTI_SZ "FontPathFileName" , ... // // Type 2: // // This format is for the specified Linked font contains more than 1 font resource, // TTC TrueType font, and Bitmap font. // // BaseFontFaceName = REG_MULTI_SZ "FontPathFileName,FontFaceNameInTheFile" , ... // // After calling ValidLinkedRegistry(), the ',' character is replaced with NULL if // found. // if( !bValidFontLinkParameter(LinkedFontName,&LinkedFaceName) ) { #if DBG DbgPrint("Invalid Registry format - %ws\n",LinkedFontName); #endif return(FALSE); } // // Get full path name for this font file. // if (!bAppendSysDirectory(awcPathBuffer, LinkedFontName, MAX_PATH)) return FALSE; // If this file is being used as the system EUDC file then it can't be used // as a facename EUDC file. if( _wcsicmp(awcPathBuffer,gawcEUDCPath) == 0 ) { #if DBG DbgPrint("%ws can't be unload as a facename link because it is the system \ EUDC file.\n", LinkedFontName); #endif return(FALSE); } // // Check base font list, To remove, the base font should be listed.. // if( IsListEmpty( &BaseFontListHead ) || (pFlEntry = FindBaseFontEntry( BaseFontName )) == NULL ) { // // We can not find out this base font in current link list. // return(FALSE); } // // The Entry for this base font is already exist.... // #if DBG // // The FLENTRY should have one or more PFEDATA. // if( IsListEmpty( &(pFlEntry->linkedFontListHead) ) ) { DbgPrint("This FLENTRY has no PFEDATA (%ws)\n",pFlEntry->awcFaceName); } #endif // // Scan linked font list for this base font. // if this linked font is already listed, we do not add this. // if( (ppfeData = FindLinkedFontEntry( &(pFlEntry->linkedFontListHead) , awcPathBuffer, LinkedFaceName ) ) == NULL ) { #if DBG if( gflEUDCDebug & (DEBUG_FONTLINK_INIT|DEBUG_FONTLINK_LOAD|DEBUG_FACENAME_EUDC) ) { DbgPrint("Can not find linked font %ws -> %ws\n",BaseFontName,LinkedFontName); } #endif return(FALSE); } // // Check we can really unload this eudc font. // if( ppfeData->FontLinkType == iFontLinkType ) { // // Now we can find out target PFEDATA. // // // Remove the PFEDATA from current list. // RemoveEntryList( &(ppfeData->linkedFontList) ); // // Decrement number of linked list count. // pFlEntry->uiNumLinks--; // // if there is no PFEDATA for this FLENTRY... // if( pFlEntry->uiNumLinks == 0 ) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { DbgPrint("Deleting FLENTRY for %ws\n",pFlEntry->awcFaceName); } if(!IsListEmpty(&(pFlEntry->linkedFontListHead))) { DbgPrint("bDeleteFlEntry():Deleting FLENTRY that has PFEDATA \ (%ws -> %ws)\n", BaseFontName,LinkedFontName); } #endif // // disable the link of this facename. // vUnlinkEudcRFONTsAndPFEs(ppfeData->appfe,pFlEntry); // // Remove this FLENTRY from BaseFontList. // RemoveEntryList( &(pFlEntry->baseFontList) ); // // Free this FLENTRY. // VFREEMEM( pFlEntry ); // // Decrement global base font number // gcNumLinks--; // // BaseFontList has been change, update TimeStamp // ulFaceNameEUDCTimeStamp++; } else { // // disable the link of this facename Eudc. // vUnlinkEudcRFONTs(ppfeData->appfe); // // Update time stamp for this facename link. // pFlEntry->ulTimeStamp++; } // // Unload this Eudc font. // if( !bUnloadEudcFont( ppfeData->appfe ) ) { #if DBG DbgPrint("bDeleteFlEntry():bUnloadEudcFont() fail - %ws\n",LinkedFontName); #endif } #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_UNLOAD ) { PFEOBJ pfeo(ppfeData->appfe[PFE_NORMAL]); PFFOBJ pffo(pfeo.pPFF()); DbgPrint("Deleting PFEDATA for %ws\n",pffo.pwszPathname()); } #endif // // Free this PFEDATA. // VFREEMEM( ppfeData ); return(TRUE); } else { return(FALSE); } } /***************************************************************************** * BOOL bAddFlEntry(const WCHAR *,const WCHAR *,INT,PFLENTRY *) * * This function add new base font and linked font pair into list. * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bAddFlEntry ( const WCHAR * BaseFontName, const WCHAR * LinkedFontPathAndName, INT iFontLinkType, // FONTLINK_SYSTEM or FONTLINK_USER INT iPriority, PFLENTRY *ppFlEntry ) { PFLENTRY pFlEntry = (PFLENTRY) NULL; PFLENTRY tempEntry = (PFLENTRY) NULL; PPFEDATA ppfeData = (PPFEDATA) NULL; PWSTR LinkedFaceName = NULL; WCHAR awcBuf[MAX_PATH + (MAX_PATH+LF_FACESIZE)]; PWSTR TempPathBuffer = awcBuf; PWSTR LinkedFontName = &awcBuf[MAX_PATH]; BOOL bRet = FALSE; gbAnyLinkedFonts = TRUE; // // if ppFlEntry is presented, initialize with NULL. // if( ppFlEntry != NULL ) *ppFlEntry = NULL; // // Have a local copy... // if (FAILED(StringCchCopyW(LinkedFontName, MAX_PATH + LF_FACESIZE, LinkedFontPathAndName))) { WARNING("bAddFlEntry: temporary buffer too short\n"); return FALSE; } // // Find ',' char from LinkedFontName // // Registry format : // // Type 1: // // This format is for the specified Linked font contains only 1 font resource. // Except Vertical "@" face font, such as TrueType font (not TTC), and Vector font. // // BaseFontFaceName = REG_MULTI_SZ "FontPathFileName" , ... // // Type 2: // // This format is for the specified Linked font contains more than 1 font resource, // TTC TrueType font, and Bitmap font. // // BaseFontFaceName = REG_MULTI_SZ "FontPathFileName,FontFaceNameInTheFile" , ... // // After calling ValidLinkedRegistry(), the ',' character is replaced with NULL if // found. // if( !bValidFontLinkParameter(LinkedFontName,&LinkedFaceName) ) { #if DBG DbgPrint("Invalid Registry format - %ws\n",LinkedFontName); #endif return bRet; } #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_LOAD ) { if( LinkedFaceName ) { DbgPrint("FontFile - %ws : FontFace - %ws\n",LinkedFontName,LinkedFaceName); } } #endif // // Get full path name for this font file. // if (!bAppendSysDirectory(TempPathBuffer, LinkedFontName, MAX_PATH)) return FALSE; // // If this file is being used as the system EUDC file then it can't be used // as a facename EUDC file. // if( _wcsicmp(TempPathBuffer,gawcEUDCPath) == 0 ) { #if DBG DbgPrint( "%ws can't be load as a facename link because it is the system EUDC file.\n", LinkedFontName ); #endif return bRet; } // // Check base font list, it is a new one ? // if( !IsListEmpty( &BaseFontListHead ) && (pFlEntry = FindBaseFontEntry( BaseFontName )) != NULL ) { // // The Entry for this base font is already exist.... // if( !IsListEmpty( &(pFlEntry->linkedFontListHead) ) ) { // // Scan linked font list for this base font. // if this linked font is already listed, we do not add this. // if( FindLinkedFontEntry( &(pFlEntry->linkedFontListHead) , TempPathBuffer , LinkedFaceName ) != NULL ) { #if DBG DbgPrint("Dupulicate linked font - %ws\n",LinkedFontName); #endif return bRet; } } } { // // get and validate PFT user object // PUBLIC_PFTOBJ pfto; // access the public font table PPFE appfeLink[2]; // temporary buffer LONG cFonts; // count of fonts EUDCLOAD EudcLoadData; // eudc load data // // parameter for PFTOBJ::bLoadFonts() // FLONG flParam = PFF_STATE_EUDC_FONT; // // Fill up EudcLoadData structure // EudcLoadData.pppfeData = appfeLink; EudcLoadData.LinkedFace = LinkedFaceName; // // if the FontLinkType is system, it should be a Permanent font. // if( iFontLinkType == FONTLINK_SYSTEM ) { flParam |= PFF_STATE_PERMANENT_FONT; } if( pFlEntry == NULL ) { // Allocate new FLENTRY.. tempEntry = pFlEntry = (PFLENTRY) PALLOCNOZ( sizeof(FLENTRY), 'flnk' ); if (!pFlEntry) { goto FreeMemAndExit; } } // // Allocate new PFEDATA... // ppfeData = (PPFEDATA) PALLOCNOZ(sizeof(PFEDATA), 'flnk' ); if (!ppfeData) { goto FreeMemAndExit; } // // Load the linked font. // PFF *placeHolder; if( pfto.bLoadAFont( TempPathBuffer, (PULONG) &cFonts, flParam, &placeHolder, &EudcLoadData ) ) { // // Check we really succeed to load requested facename font. // if(!bComputeQuickLookup( NULL, appfeLink[PFE_NORMAL], FALSE )) { // // Compute table for normal face // WARNING("Unable to compute QuickLookUp for face name link\n"); pfto.bUnloadEUDCFont(TempPathBuffer); goto FreeMemAndExit; } // // Compute table for vertical face, if vertical face font is provided, // if( !bComputeQuickLookup( NULL, appfeLink[PFE_VERTICAL], FALSE )) { WARNING("Unable to compute QuickLookUp for face name link\n"); pfto.bUnloadEUDCFont(TempPathBuffer); goto FreeMemAndExit; } if (tempEntry) { // Initialize number of linked font count. pFlEntry->uiNumLinks = 0; // Initialize link time stamp pFlEntry->ulTimeStamp = 0; // Copy base font name to buffer. if (FAILED(StringCchCopyW(pFlEntry->awcFaceName, LF_FACESIZE+1, BaseFontName))) { WARNING("bAddFlEntry: target buffer too short.\n"); pfto.bUnloadEUDCFont(TempPathBuffer); goto FreeMemAndExit; } // Initialize linked font list for this base font. InitializeListHead( &(pFlEntry->linkedFontListHead) ); // Add this entry to BaseFontList. InsertTailList( &BaseFontListHead , &(pFlEntry->baseFontList) ); // Increment global base font number gcNumLinks++; // just notify new FLENTRY was allocated to caller if( ppFlEntry != NULL ) *(PFLENTRY *)ppFlEntry = pFlEntry; // BaseFontList has been change, update TimeStamp ulFaceNameEUDCTimeStamp++; } #if DBG if(gflEUDCDebug&(DEBUG_FONTLINK_LOAD|DEBUG_FONTLINK_INIT|DEBUG_FACENAME_EUDC)) { DbgPrint("Allocate PFEDATA for %ws - %ws\n",BaseFontName,LinkedFontName); } #endif // // Set PFE for linked font into the structure. // ppfeData->appfe[PFE_NORMAL] = appfeLink[PFE_NORMAL]; ppfeData->appfe[PFE_VERTICAL] = appfeLink[PFE_VERTICAL]; // // Set FontLinkType. // ppfeData->FontLinkType = iFontLinkType; // // Set FontLinkFlag. // ppfeData->FontLinkFlag = 0L; if( EudcLoadData.LinkedFace ) ppfeData->FontLinkFlag |= FLINK_FACENAME_SPECIFIED; // // Incremant number of linked font count for this base face name. // pFlEntry->uiNumLinks++; // // Update time stamp // pFlEntry->ulTimeStamp++; // // add pfe for this font our list of flinks // if( iPriority < 0 ) { // // Insert end of this list. // InsertTailList(&(pFlEntry->linkedFontListHead), &(ppfeData->linkedFontList) ); } else // later if( iPriority == 0 ) { // // Insert top of this list. // InsertHeadList(&(pFlEntry->linkedFontListHead), &(ppfeData->linkedFontList)); } bRet = TRUE; } else { #if DBG DbgPrint("Failed to load EUDC font - %ws\n",TempPathBuffer); #endif } } FreeMemAndExit: if (!bRet) { if(tempEntry) { VFREEMEM(tempEntry); } if (ppfeData) { VFREEMEM(ppfeData); } } return(bRet); } /***************************************************************************** * BOOL bDeleteAllFlEntry(BOOL,BOOL) * * This function delete all linked font information including system wide eudc. * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bDeleteAllFlEntry ( BOOL bDeleteSystem, BOOL bDeleteFaceName ) { BOOL bRet = TRUE; PFEDATA **UnloadBuffer; PFEDATA **UnloadBufferNew; ULONG NumUnload = 0; ULONG MaxUnload = 40; PFE *LocalppfeSysEUDC[2] = {NULL, NULL}; // // make sure we are the only ones changing the EUDC data // GreAcquireSemaphore( ghsemEUDC1 ); ASSERTGDI(gcEUDCCount >= 0, "gcEUDCCount < 0"); if (gcEUDCCount > 0) { // // another EUDC API is currently in progress // FLINKMESSAGE(DEBUG_FONTLINK_LOAD|DEBUG_FONTLINK_UNLOAD, " another EUDC API is currently in progress. bDeleteAllFlEntry() is failed.\n"); EngSetLastError(ERROR_LOCK_FAILED); GreReleaseSemaphore( ghsemEUDC1 ); return(FALSE); } UnloadBuffer = (PFEDATA **)PALLOCNOZ(sizeof(PFEDATA *) * MaxUnload, 'dueG'); if (!UnloadBuffer) { MaxUnload = 0; } // disable the link of all facename and system wide eudc. vUnlinkAllEudcRFONTsAndPFEs(bDeleteSystem,bDeleteFaceName); // if there is no system wife eudc font.. skip it. if( bDeleteSystem && IS_SYSTEM_EUDC_PRESENT() ) { // Unload system wide eudc font LocalppfeSysEUDC[PFE_NORMAL] = gappfeSysEUDC[PFE_NORMAL]; LocalppfeSysEUDC[PFE_VERTICAL] = gappfeSysEUDC[PFE_VERTICAL]; // Clear global data. gappfeSysEUDC[PFE_NORMAL] = NULL; gappfeSysEUDC[PFE_VERTICAL] = NULL; gawcEUDCPath[0] = 0; ulSystemEUDCTimeStamp++; } // if there is no facename eudc, just return here. if( bDeleteFaceName && !IsListEmpty(&BaseFontListHead) ) { COUNT NumberOfLinks = gcNumLinks; // start to scan facename link list. PLIST_ENTRY p = BaseFontListHead.Flink; while( p != &BaseFontListHead ) { PFLENTRY pFlEntry; PLIST_ENTRY pDelete = p; ULONG AlivePfeData = 0; pFlEntry = CONTAINING_RECORD(pDelete,FLENTRY,baseFontList); // if there is no linked font for this base face, try next base font. if(IsListEmpty(&(pFlEntry->linkedFontListHead))) { continue; } // get pointer to PFEDATA list. PLIST_ENTRY pp = pFlEntry->linkedFontListHead.Flink; FLINKMESSAGE2((DEBUG_FONTLINK_LOAD|DEBUG_FONTLINK_UNLOAD), "Delete %ws link\n",pFlEntry->awcFaceName); while( pp != &(pFlEntry->linkedFontListHead) ) { PPFEDATA ppfeData; PLIST_ENTRY ppDelete = pp; ppfeData = CONTAINING_RECORD(ppDelete,PFEDATA,linkedFontList); // Check Current FontLinkChange state to see if we can really unload // EUDC font. if( (ppfeData->FontLinkType == FONTLINK_SYSTEM && ulFontLinkChange & FLINK_UNLOAD_FACENAME_SYSTEM) || (ppfeData->FontLinkType == FONTLINK_USER && ulFontLinkChange & FLINK_UNLOAD_FACENAME_USER)) { // Remember PFE to unload font later. if (MaxUnload == NumUnload) { UnloadBufferNew = (PFEDATA **)PALLOCNOZ(sizeof(PFEDATA *) * MaxUnload + 10, 'dueG'); if (UnloadBufferNew) { MaxUnload += 10; memcpy(UnloadBufferNew, UnloadBuffer, sizeof(PFEDATA *) * NumUnload); if (UnloadBuffer) VFREEMEM(UnloadBuffer); UnloadBuffer = UnloadBufferNew; } } if (MaxUnload > NumUnload) { UnloadBuffer[NumUnload++] = ppfeData; pp = ppDelete->Flink; // Delete this PFEDATA from this link list RemoveEntryList(ppDelete); } else { // This PFEDATA is still valid... AlivePfeData++; pp = ppDelete->Flink; bRet = FALSE; } } else { // This PFEDATA is still valid... AlivePfeData++; pp = ppDelete->Flink; } } // next FLENTRY... p = pDelete->Flink; if( AlivePfeData == 0 ) { // Delete this FLENTRY from link list RemoveEntryList(pDelete); // Free FLENTRY VFREEMEM(pDelete); // Decrement number of facename links gcNumLinks--; } else { if( pFlEntry->uiNumLinks != AlivePfeData ) { // Update Timestamp for this pFlEntry->ulTimeStamp++; // Update number of linked font. pFlEntry->uiNumLinks = AlivePfeData; } } } if( NumberOfLinks != gcNumLinks ) { // BaseFontList has been changed, update TimeStamp ulFaceNameEUDCTimeStamp++; } if( gcNumLinks != 0 ) { // Connect to loaded PFEs for valid FLENTRY/PFEDATA. vLinkEudcPFEs(NULL); } } GreReleaseSemaphore( ghsemEUDC1 ); // if there is no system wide eudc font.. skip it. if( bDeleteSystem && ((LocalppfeSysEUDC[PFE_NORMAL] != NULL) || (LocalppfeSysEUDC[PFE_VERTICAL] != NULL))) { // Unload system wide eudc font if( !bUnloadEudcFont( LocalppfeSysEUDC ) ) { WARNING("bDeleteAllFlEntry():Can not unload system wide eudc\n"); } } for (ULONG i = 0; i < NumUnload; i++) { if( !bUnloadEudcFont(UnloadBuffer[i]->appfe)) { WARNING("bDeleteAllFlEntry():Can not unload eudc\n"); } VFREEMEM(UnloadBuffer[i]); } if (UnloadBuffer) VFREEMEM(UnloadBuffer); return(bRet); } /***************************************************************************** * NTSTATUS BuildAndLoadLinkedFontRoutine(PWSTR,ULONG,PVOID,ULONG,PVOID,PVOID) * * This is a callback function that is called by RtlQueryRegistryValues() * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ extern "C" NTSTATUS BuildAndLoadLinkedFontRoutine ( PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext ) { PWSTR FontPathName = (PWSTR) PALLOCNOZ((ValueLength + 1)*sizeof(WCHAR),'flnk'); if (FontPathName == NULL) { return (STATUS_NO_MEMORY); } #if DBG if( gflEUDCDebug & (DEBUG_FACENAME_EUDC|DEBUG_FONTLINK_INIT) ) { DbgPrint("BaseFontName - %ws : LinkedFont - %ws\n",ValueName,ValueData); } #endif // if this is a value for System EUDC, return here... if(_wcsicmp(ValueName,(PWSTR)L"SystemDefaultEUDCFont") == 0) { goto FreeMem; } // Copy it to local buffer and make sure its null-termination. RtlMoveMemory(FontPathName,ValueData,ValueLength); FontPathName[ValueLength/sizeof(WCHAR)] = L'\0'; // Add base font and linked font pair into global list.. // Sundown: the 3rd parameter to bAddFlEntry is iFontlinkType int if(!bAddFlEntry(ValueName,FontPathName,(INT)(ULONG_PTR)EntryContext,-1,NULL)) { WARNING("BuildAndLoadLinkedFontRoutine():lAddFlEntry() fail\n"); } FreeMem: VFREEMEM(FontPathName); // return STATUS_SUCCESS everytime,even we got error from above call, to // get next enumuration. return(STATUS_SUCCESS); } /***************************************************************************** * NTSTATUS bAddAllFlEntryWorker(LPWSTR,INT) * * This function load font and build link for eudc font according to registry. * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static NTSTATUS bAddAllFlEntryWorker ( const WCHAR * EUDCRegistryPath, INT FontLinkType // FONTLINK_SYSTEM or FONTLINK_USER ) { NTSTATUS NtStatus; // // initialize/load face name eudc // SharedQueryTable[0].QueryRoutine = BuildAndLoadLinkedFontRoutine; SharedQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; SharedQueryTable[0].Name = (PWSTR)NULL; SharedQueryTable[0].EntryContext = (PVOID)(ULONG_PTR)FontLinkType; 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; // // Enumurate registry values // NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, EUDCRegistryPath, SharedQueryTable, NULL, NULL); return(NtStatus); } /***************************************************************************** * BOOL bAddAllFlEntry(BOOL,BOOL,INT) * * This function load font and build link for eudc font according to registry. * * History * 1-09-95 Hideyuki Nagase * Wrote it. *****************************************************************************/ static BOOL bAddAllFlEntry ( BOOL bAddSystem, BOOL bAddFaceName ) { NTSTATUS NtStatus; BOOL bLoadSystem = FALSE; WCHAR TempPathBuffer1[MAX_PATH]; WCHAR TempPathBuffer2[MAX_PATH]; TempPathBuffer1[0] = TempPathBuffer2[0] = 0; FLINKMESSAGE(DEBUG_FONTLINK_INIT|DEBUG_FONTLINK_LOAD, "bAddAllFlEntry():Initializing EUDC data.\n"); // // make sure we are the only ones changing the EUDC data // GreAcquireSemaphore( ghsemEUDC1 ); ASSERTGDI(gcEUDCCount >= 0, "gcEUDCCount < 0"); if (gcEUDCCount > 0) { // // another EUDC API is currently in progress // FLINKMESSAGE(DEBUG_FONTLINK_LOAD|DEBUG_FONTLINK_UNLOAD, " another EUDC API is currently in progress. bAddAllFlEntry() is failed.\n"); EngSetLastError(ERROR_LOCK_FAILED); GreReleaseSemaphore( ghsemEUDC1 ); return(FALSE); } // initialize/load the system-wide ( all face-name EUDC font ) if( bAddSystem && !IS_SYSTEM_EUDC_PRESENT() ) { // // read registry data for System eudc // if(bReadUserSystemEUDCRegistry(TempPathBuffer1, MAX_PATH)) { PPFE appfeSysEUDC[2]; // // Search system-wide EUDC font. if the specified registry value does not // contain full path name. // // bAppendSysDirectory return TRUE, when we have to update registry data. // otherwise return FALSE. // // If the Eudc file is under Windows root directory (ex. WINNT) we want to // update registry data. because we might fail to load EUDC after user had // change System root with Disk Administrator. // if (!bAppendSysDirectory(TempPathBuffer2,TempPathBuffer1, MAX_PATH)) { WARNING("bAddAllFlEntry: buffer too short\n"); return FALSE; } // // NOTE : // // Currently Systen wide EUDC does not support Type 1 Registry format. // See description in bAddFlEntry(). // // // get and validate PFT user object // PUBLIC_PFTOBJ pfto; // access the public font table ASSERTGDI ( pfto.bValid(), "gdisrv!bAddAllFlEntry(): could not access the public font table\n" ); { SEMOBJ so(ghsemPublicPFT); // // Check this font is already loaded as Eudc font or not. // if( !pfto.pPFFGet(TempPathBuffer2, wcslen(TempPathBuffer2) + 1, // cwc 1, // cFiles NULL, // pdv 0, // cjDV NULL, // pppPFE TRUE) ) // bEudc { EUDCLOAD EudcLoadData; // // fill up EUDCLOAD structure // EudcLoadData.pppfeData = appfeSysEUDC; EudcLoadData.LinkedFace = NULL; // // load this font as eudc font. // LONG cFonts; // count of fonts PFF *placeHolder; bLoadSystem = pfto.bLoadAFont(TempPathBuffer2, (PULONG) &cFonts, PFF_STATE_EUDC_FONT, &placeHolder, &EudcLoadData ); } else { #if DBG DbgPrint("bAddAllElEntry():%ws is loaded as EUDC already\n", TempPathBuffer2); #endif bLoadSystem = FALSE; } } if( bLoadSystem ) { // // Compute table besed on normal face // if(!bComputeQuickLookup( &gqlEUDC, appfeSysEUDC[PFE_NORMAL], TRUE ) ) { WARNING("Unable to compute QuickLookUp for system EUDC\n"); // // Unload font.. // pfto.bUnloadEUDCFont(TempPathBuffer2); gappfeSysEUDC[PFE_NORMAL] = NULL; gappfeSysEUDC[PFE_VERTICAL] = NULL; gawcEUDCPath[0] = 0; } else { // // We believe that vertical face has same glyphset as normal face. // // // Update system wide Eudc global data.. // gappfeSysEUDC[PFE_NORMAL] = appfeSysEUDC[PFE_NORMAL]; gappfeSysEUDC[PFE_VERTICAL] = appfeSysEUDC[PFE_VERTICAL]; wcscpy(gawcEUDCPath,TempPathBuffer2); // // Update global eudc timestamp. // ulSystemEUDCTimeStamp++; } } else { //WARNING("Failed to load system wide EUDC font.\n"); gappfeSysEUDC[PFE_NORMAL] = PPFENULL; gappfeSysEUDC[PFE_VERTICAL] = PPFENULL; gawcEUDCPath[0] = 0; } #if DBG if( gflEUDCDebug & (DEBUG_SYSTEM_EUDC|DEBUG_FONTLINK_INIT) ) { DbgPrint("EUDC system wide %ws hpfe is %x vert hpfe is %x\n", gawcEUDCPath, gappfeSysEUDC[PFE_NORMAL], gappfeSysEUDC[PFE_VERTICAL]); } #endif } } if( bAddFaceName ) { if( ulFontLinkChange & FLINK_LOAD_FACENAME_SYSTEM ) { // // Call worker function. // NtStatus = bAddAllFlEntryWorker(EUDC_SYSTEM_REGISTRY_KEY,FONTLINK_SYSTEM); #if DBG if( !NT_SUCCESS(NtStatus) ) { WARNING1("Face name eudc is disabled (FONTLINK_SYSTEM)\n"); } #endif } if( ulFontLinkChange & FLINK_LOAD_FACENAME_USER ) { HANDLE hKey = NULL; HANDLE hKeyLink = NULL; BOOL bIsEqual = FALSE; // // Get Registry path for Eudc.. // NtStatus = GetUserEUDCRegistryPath(TempPathBuffer1, sizeof(TempPathBuffer1)); if (NT_SUCCESS(NtStatus)) { // if the registry entry is a symbolic link, fail the call if (bNotIsKeySymbolicLink (TempPathBuffer1, &hKey, &hKeyLink, &bIsEqual) && bIsEqual) { // // Call worker function. // NtStatus = bAddAllFlEntryWorker(TempPathBuffer1,FONTLINK_USER); } else { NtStatus = (STATUS_SEVERITY_ERROR << 30); // any non-zero error is sufficient } } if (hKey) ZwClose (hKey); if (hKeyLink) ZwClose (hKeyLink); #if DBG if( !NT_SUCCESS(NtStatus) ) { WARNING1("Face name eudc is disabled (FONTLINK_USER)\n"); } #endif } // // Connect to loaded PFEs. // vLinkEudcPFEs(NULL); } GreReleaseSemaphore( ghsemEUDC1 ); return(TRUE); } /***************************************************************************** * BOOL bInitializeEUDC(VOID) * * This is called once during win32k.sys initialization and initializes the * system EUDC information. First it creates a FLINKOBJ and set ghflEUDC to * it. Then it initializes the FLINKOBJ with information from the registry. * After that it loads all the EUDC fonts and sets up links between base * font PFE's and EUDC font pfe's. * * History * 1-09-95 Hideyuki Nagase * Rewrote it. * * 2-10-93 Gerrit van Wingerden * Wrote it. *****************************************************************************/ BOOL bInitializeEUDC(VOID) { NTSTATUS NtStatus; FLINKMESSAGE(DEBUG_FONTLINK_INIT, "bInitializeEUDC():Initializing EUDC data.\n"); gawcEUDCPath[0] = L'\0'; // Set up Global EUDC semaphores if ( !(ghsemEUDC1 = GreCreateSemaphore())) { return FALSE; } if ( !(ghsemEUDC2 = GreCreateSemaphore())) { return FALSE; } // KeInitializeEvent( &gfmEUDC2, SynchronizationEvent, FALSE ); // Set up EUDC QUICKLOOKUP Table gqlEUDC.puiBits = NULL; gqlEUDC.wcLow = 1; gqlEUDC.wcHigh = 0; // Get Current codepage to access registry.. USHORT usACP,usOEMCP; EngGetCurrentCodePage(&usOEMCP,&usACP); // Convert Integer to Unicode string.. UNICODE_STRING SystemACPString; SystemACPString.Length = 0; SystemACPString.MaximumLength = sizeof(gawcSystemACP); SystemACPString.Buffer = gawcSystemACP; RtlIntegerToUnicodeString( (int) usACP, 10, &SystemACPString ); FLINKMESSAGE2(DEBUG_FONTLINK_INIT,"GDISRV:System ACP is %ws\n",gawcSystemACP); // Read FontLink configuration value. SharedQueryTable[0].QueryRoutine = NULL; SharedQueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; SharedQueryTable[0].Name = (PWSTR)L"FontLinkControl"; SharedQueryTable[0].EntryContext = (PVOID) &ulFontLinkControl; SharedQueryTable[0].DefaultType = REG_DWORD; SharedQueryTable[0].DefaultData = 0; SharedQueryTable[0].DefaultLength = 0; SharedQueryTable[1].QueryRoutine = NULL; SharedQueryTable[1].Flags = 0; SharedQueryTable[1].Name = (PWSTR)NULL; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, L"FontLink", SharedQueryTable, NULL, NULL); if(!NT_SUCCESS(NtStatus)) { // WARNING("Error reading FontLinkControl\n"); ulFontLinkControl = 0L; } FLINKMESSAGE2(DEBUG_FONTLINK_CONTROL, "win32ksys:FontLinkControl = %x\n",ulFontLinkControl); // initialize Eudc default char code in Unicode. DWORD dwEudcDefaultChar; SharedQueryTable[0].Name = (PWSTR)L"FontLinkDefaultChar"; SharedQueryTable[0].EntryContext = (PVOID) &dwEudcDefaultChar; NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, L"FontLink", SharedQueryTable, NULL, NULL); if(!NT_SUCCESS(NtStatus)) { // WARNING("Error reading FontLinkDefaultChar\n"); EudcDefaultChar = 0x30fb; } else { EudcDefaultChar = (WCHAR)dwEudcDefaultChar; } // initialize base font list InitializeListHead(&BaseFontListHead); // if FontLink feature is disabled, nothing to do..... if( ulFontLinkControl & FLINK_DISABLE_FONTLINK ) { return TRUE; } // Load and setup SYSTEM Global facename EUDC data. ulFontLinkChange = FLINK_LOAD_FACENAME_SYSTEM | FLINK_UNLOAD_FACENAME_SYSTEM; // Enable only FaceName (system common) EUDC. bAddAllFlEntry(FALSE,TRUE); // After load system global EUDC, we will only allow to user to // load/unload per user eudc configuration. ulFontLinkChange = FLINK_LOAD_FACENAME_USER | FLINK_UNLOAD_FACENAME_USER; // Initialize font association scheme. vInitializeFontAssocStatus(); return TRUE; } /*****************************************************************************\ * GreEnableEUDC( BOOL bEnable ) * * This routine enable/disable system wide/face name specific EUDCs * * History: * 23-Jan-1995 Hideyuki Nagase * Wrote it. *****************************************************************************/ BOOL GreEnableEUDC ( BOOL bEnableEUDC ) { BOOL bRet = TRUE; // // This quick check for non-zero ghsemEUDC1 is a work around for hydra // cleanup assertions // if (!ghsemEUDC1 || !ghsemEUDC2) { return TRUE; } GreAcquireSemaphore( ghsemEUDC2 ); if( bEnableEUDC ) { // // if DefaultLink is ready to initalize and its is not initialized, // do the initialization. // if( (bReadyToInitializeFontAssocDefault == TRUE ) && (bFinallyInitializeFontAssocDefault == FALSE) ) { // // Load default linked font and fill up nessesary data fields. // if( bSetupDefaultFlEntry()) { // // Yes, we finally initialized default link font successfully. // bFinallyInitializeFontAssocDefault = TRUE; } } } if( bEnableEUDC ) { // // Enable EUDC link. // bRet = bAddAllFlEntry(TRUE,TRUE); } else { // Disable EUDC link. bRet = bDeleteAllFlEntry(TRUE,TRUE); } GreReleaseSemaphore( ghsemEUDC2 ); return(bRet); } /*****************************************************************************\ * GreEudcLoadLinkW(LPWSTR,COUNT,LPWSTR,COUNT,INT,INT) * * Establishes a font file as the source of EUDC glyphs for the system. Any * subsequent TextOut or GetTextMetrics related calls will reflect this * change immediately. * * History: * 13-01-95 Hideyuki Nagase * Rewrote it. * 02-10-93 Gerrit van Wingerden * Wrote it. *****************************************************************************/ static BOOL GreEudcLoadLinkW ( const WCHAR * lpBaseFaceName, // guaranteed to be NULL terminated COUNT cwcBaseFaceName, const WCHAR * lpEudcFontPath, // guaranteed to be NULL terminated COUNT cwcEudcFontPath, INT iPriority, INT iFontLinkType ) { BOOL bRet = TRUE; ASSERTGDI(lpEudcFontPath != NULL,"GreEudcLoadLinkW():lpEudcFontPath == NULL\n"); ASSERTGDI(cwcEudcFontPath != 0,"GreEudcLoadLinkW():cwcEudcFontPath == 0\n"); FLINKMESSAGE(DEBUG_FONTLINK_LOAD,"GreEudcLoadLinkW\n"); GreAcquireSemaphore( ghsemEUDC1 ); // // if text related API's using EUDC characters are in progess we must // wait // ASSERTGDI(gcEUDCCount >= 0, "gcEUDCCount < 0"); if (gcEUDCCount > 0) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_LOAD ) { DbgPrint("GreEudcLoadLinkW is waiting.\n"); } #endif // When the last text related API using EUDC characters finishes it will // release us. EngSetLastError(ERROR_LOCK_FAILED); GreReleaseSemaphore( ghsemEUDC1 ); return (FALSE); } // Is this a request to load system wide eudc ? if( lpBaseFaceName == NULL ) { WCHAR awcSystemEudcPath[MAX_PATH+1]; PPFE appfeNew[2]; // Get full path name of the requested font.. bRet = bAppendSysDirectory( awcSystemEudcPath , lpEudcFontPath, MAX_PATH ); if (bRet) { SEMOBJ so(ghsemPublicPFT); // Get and validate PFT user object PUBLIC_PFTOBJ pfto; ASSERTGDI(pfto.bValid(), "GreLoadLinkW():could not access the public font table\n"); // check this font file is loaded as eudc already. if( !pfto.pPFFGet(awcSystemEudcPath, wcslen(awcSystemEudcPath) + 1, // cwc 1, // cFiles NULL, // pdv 0, // cjDV NULL, // pppPFF TRUE) ) // bEudc { EUDCLOAD EudcLoadData; // fill up EUDCLOAD structure EudcLoadData.pppfeData = appfeNew; EudcLoadData.LinkedFace = NULL; // load font.. ULONG cFonts; PFF *placeHolder; bRet = pfto.bLoadAFont( awcSystemEudcPath, (PULONG) &cFonts, PFF_STATE_EUDC_FONT, &placeHolder, &EudcLoadData); } else { // // this font file is already loaded as EUDC.. // #if DBG DbgPrint("GreLoadLinkW():%ws is loaded as EUDC already\n", awcSystemEudcPath); #endif bRet = FALSE; } } if( bRet ) { // // now we can load new system wide eudc font.. // if we have system wide eudc font, deactivate and unload it.. // if( IS_SYSTEM_EUDC_PRESENT() ) { // // disable the link of all facename and system wide eudc. // vUnlinkAllEudcRFONTsAndPFEs(TRUE,FALSE); // // Unload system wide eudc font // bUnloadEudcFont( gappfeSysEUDC ); } // // set new system wide eudc data to global variable. // gappfeSysEUDC[PFE_NORMAL] = appfeNew[PFE_NORMAL]; gappfeSysEUDC[PFE_VERTICAL] = appfeNew[PFE_VERTICAL]; wcscpy(gawcEUDCPath,awcSystemEudcPath); // // Update global eudc timestamp. // ulSystemEUDCTimeStamp++; // // Finally compute the QuickLookup structure for the system EUDC font // if(!bComputeQuickLookup( &gqlEUDC, appfeNew[PFE_NORMAL], TRUE )) { WARNING("GreLoadLinkW:Unable to compute QuickLookUp for system EUDC\n"); } // // // Update registry data. // FLINKMESSAGE(DEBUG_FONTLINK_LOAD,"GreLoadLinkW():Eudc Path %ws is Saved\n"); if( !bWriteUserSystemEUDCRegistry(gawcEUDCPath, wcslen(gawcEUDCPath)+1) ) { WARNING("Unable to write new link to registry.\n"); } } else { // // Fail to load ... // #if DBG DbgPrint("GreLoadLinkW():%ws is could not be loaded\n",awcSystemEudcPath); #endif } } else { PFLENTRY pFlEntry; // // if we got invalid fontlink type, just force change to FONTLINK_USER // if( (iFontLinkType != FONTLINK_SYSTEM) && (iFontLinkType != FONTLINK_USER ) ) { iFontLinkType = FONTLINK_USER; } // // this is request for facename link. // bRet = bAddFlEntry(lpBaseFaceName,lpEudcFontPath,iFontLinkType,iPriority, &pFlEntry); if( bRet ) { // // check new FLENTRY is allocated or not. // if( pFlEntry != NULL ) { // // if new FLENTRY is allocated, Update base font's PFE. // Connect to loaded PFEs. // vLinkEudcPFEs( pFlEntry ); } } } GreReleaseSemaphore( ghsemEUDC1 ); return(bRet); } /***************************************************************************** * GreEudcUnloadLinkW() * * Unloads the current system wide EUDC link. Subsequent TextOut or * GetTextMetrics related calls will reflect this immediately. * * History * 26-01-95 Hideyuki Nagase * Rewrote it. * 4-01-93 Gerrit van Wingerden * Wrote it. *****************************************************************************/ static BOOL GreEudcUnloadLinkW ( const WCHAR * lpBaseFaceName, COUNT cwcBaseFaceName, const WCHAR * lpEudcFontPath, COUNT cwcEudcFontPath ) { BOOL bRet = TRUE; FLINKMESSAGE(DEBUG_FONTLINK_UNLOAD, "GreEudcUnloadLinkW()....\n"); GreAcquireSemaphore( ghsemEUDC1 ); // // if text related API's using EUDC characters are in progess we must // wait // ASSERTGDI(gcEUDCCount >= 0, "gcEUDCCount < 0"); if (gcEUDCCount > 0) { #if DBG if( gflEUDCDebug & DEBUG_FONTLINK_LOAD ) { DbgPrint("GreEudcLoadLinkW is waiting.\n"); } #endif // When the last text related API using EUDC characters finishes it will // release us. EngSetLastError(ERROR_LOCK_FAILED); GreReleaseSemaphore( ghsemEUDC1 ); return (FALSE); } // // Is this a request to load system wide eudc ? // if( lpBaseFaceName == NULL ) { // // if we have system wide eudc font, deactivate and unload it.. // if( IS_SYSTEM_EUDC_PRESENT() ) { // // disable the link of all facename and system wide eudc. // vUnlinkAllEudcRFONTsAndPFEs(TRUE,FALSE); // // Unload system wide eudc font // bUnloadEudcFont( gappfeSysEUDC ); // // set new system wide eudc data to global variable. // gappfeSysEUDC[PFE_NORMAL] = NULL; gappfeSysEUDC[PFE_VERTICAL] = NULL; gawcEUDCPath[0] = 0; // // Update global eudc timestamp. // ulSystemEUDCTimeStamp++; if( !bWriteUserSystemEUDCRegistry(L"\0",1) ) { WARNING("Unable to write new link to registry.\n"); } } } else { ASSERTGDI(lpBaseFaceName != NULL,"GreEudcLoadLinkW():lpBaseFaceName == NULL\n"); ASSERTGDI(cwcBaseFaceName != 0,"GreEudcLoadLinkW():cwcBaseFaceName == 0\n"); ASSERTGDI(lpEudcFontPath != NULL,"GreEudcLoadLinkW():lpEudcFontPath == NULL\n"); ASSERTGDI(cwcEudcFontPath != 0,"GreEudcLoadLinkW():cwcEudcFontPath == 0\n"); // // this is a request for facename link Eudc. // bRet = bDeleteFlEntry(lpBaseFaceName,lpEudcFontPath,FONTLINK_USER); // // if above call is failed, try FONTLINK_SYSTEM.... // if( !bRet ) bRet = bDeleteFlEntry(lpBaseFaceName,lpEudcFontPath,FONTLINK_SYSTEM); } // // Let others use EUDC characters again // GreReleaseSemaphore( ghsemEUDC1 ); return(bRet); } /***************************************************************************** * ULONG NtGdiGetEudcTimeStampEx * * Shared kernel mode entry point for GetEudcTimeStamp and GetEudcTimeStampEx * * History * 3-28-96 Gerrit van Wingerden [gerritv] * Wrote it. ****************************************************************************/ extern "C" ULONG NtGdiGetEudcTimeStampEx ( LPWSTR lpBaseFaceName, ULONG cwcBaseFaceName, BOOL bSystemTimeStamp ) { WCHAR awcBaseFaceName[LF_FACESIZE+1]; ULONG ulRet = 0; if(bSystemTimeStamp) { return(ulSystemEUDCTimeStamp); } else if((lpBaseFaceName == NULL) || (cwcBaseFaceName == 0)) { return(ulFaceNameEUDCTimeStamp); } if(cwcBaseFaceName <= LF_FACESIZE) { __try { ProbeForRead(lpBaseFaceName,cwcBaseFaceName*sizeof(WCHAR),sizeof(WCHAR)); RtlCopyMemory(awcBaseFaceName,lpBaseFaceName, cwcBaseFaceName * sizeof(WCHAR)); awcBaseFaceName[cwcBaseFaceName] = L'\0'; ulRet = 0; } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(3100); } if(ulRet) { GreAcquireSemaphore( ghsemEUDC1 ); PFLENTRY pFlEntry; if( (pFlEntry = FindBaseFontEntry(awcBaseFaceName)) != NULL ) { ulRet = pFlEntry->ulTimeStamp; } else { ulRet = 0; } GreReleaseSemaphore( ghsemEUDC1 ); } } else { WARNING("NtGdiGetEudcTimeStampEx: Facename too big\n"); EngSetLastError(ERROR_INVALID_PARAMETER); } return(ulRet); } /****************************************************************************** * VOID vDrawGlyph( BYTE, UINT, GLYPHPOS ) * * This routine draws a single glyph to a monochrome bitmap. It was stolen * from textblt.cxx and modified to be faster since clipping doesn't come in * to play in GetStringBitmapW. * * History: * 5-18-93 Gerrit van Wingerden [gerritv] * Wrote it. *****************************************************************************/ static const BYTE ajMask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE}; static VOID vDrawGlyph( BYTE *pjBits, // pointer to base of bitmap bits UINT cjScan, // size of a scan line GLYPHPOS *pgp // glyph bits and location. ) { GLYPHBITS *pgb = pgp->pgdf->pgb; ULONG cx = (ULONG) pgb->sizlBitmap.cx; ULONG cy = (ULONG) pgb->sizlBitmap.cy; if (cx == 0 || cy == 0) return; ULONG cjScanSrc = (cx + 7) >> 3; PBYTE pjSrcHolder = pgb->aj; ULONG xDst = pgp->ptl.x; ULONG yDst = pgp->ptl.y; PBYTE pjDstHolder = pjBits; pjDstHolder += (yDst * cjScan ); pjDstHolder += (xDst >> 3); // Set the source bits into the mono dib. // We can make use of the fact that either xSrcDib or xDstDib is 0. PBYTE pjDst; PBYTE pjSrc; if( !(xDst & 0x7) ) { // Handle the simple case where xDib is byte-alligned do { ULONG cBytes = cx >> 3; pjSrc = pjSrcHolder; pjDst = pjDstHolder; pjSrcHolder += cjScanSrc; pjDstHolder += cjScan; while (cBytes--) *pjDst++ |= *pjSrc++; // Do the last partial byte. if (cx & 0x7) *pjDst |= *pjSrc & ajMask[cx & 0x7]; } while (--cy); } else // if (xDstDib) { // Handle the case where xDstDib is not byte-aligned. int cShift = (int) xDst & 0x7; do { ULONG cBytes = ((xDst + cx) >> 3) - (xDst >> 3); pjSrc = pjSrcHolder; pjDst = pjDstHolder; pjSrcHolder += cjScanSrc; pjDstHolder += cjScan; WORD wSrc = (WORD) (*pjSrc++); while (cBytes--) { *pjDst++ |= (BYTE) (wSrc >> cShift); // don't read beyond src limit! if (pjSrc == pjSrcHolder) wSrc = (wSrc << 8); else wSrc = (wSrc << 8) | (WORD) (*pjSrc++); } // Do the last partial byte. if ((xDst + cx) & 0x7) *pjDst |= (BYTE) (wSrc >> cShift) & ajMask[(xDst+cx) & 0x7]; } while (--cy); } } /****************************************************************************** * VOID vStringBitmapTextOut( STROBJ, BYTE, UINT ) * * This routine draws a STROBJ to a monochrome bitmap. It is essentially * EngTextOut but much faster since it doesn't have to wory about opaqueing, * clipping, simulated rects, etc. * * History: * 9-19-95 Hideyuki Nagase [hideyukn] * Rewrote it. * * 5-18-93 Gerrit van Wingerden [gerritv] * Wrote it. *****************************************************************************/ static VOID vStringBitmapTextOut( STROBJ *pstro, // Pointer to STROBJ. BYTE *pjBits, // Pointer to buffer to store glyph image. UINT cjScan // Size of buffer. ) { BOOL bMoreGlyphs; GLYPHPOS *pgp = (GLYPHPOS*)NULL; LONG xAdjust = ( pstro->rclBkGround.left > 0 ) ? 0 : pstro->rclBkGround.left; LONG yAdjust = pstro->rclBkGround.top; ((ESTROBJ*)pstro)->vEnumStart(); if( pstro->pgp == (GLYPHPOS *) NULL ) { ULONG cGlyph; bMoreGlyphs = STROBJ_bEnum(pstro,&cGlyph,&pgp); } else { pgp = pstro->pgp; bMoreGlyphs = FALSE; } ASSERTGDI(bMoreGlyphs == FALSE,"vStringBitmapTextOut() bMoreGlyphs is TRUE.\n"); // Saw this on FE stress // ASSERTGDI(pgp, "vStringBitmapTextOut() STROBJ_bEnum returns NULL pgp.\n"); // fail textout if pgp == NULL if (pgp) { GLYPHBITS *pgb = pgp[0].pgdf->pgb; pgp[0].ptl.x += pgb->ptlOrigin.x - xAdjust; pgp[0].ptl.y += pgb->ptlOrigin.y - yAdjust; // // Blt the glyph into the bitmap // vDrawGlyph( pjBits, cjScan, &pgp[0] ); } } /****************************************************************************** * UINT GreGetStringBitmapW * * This routine does a kindof fast text out ( with restrictions ) to a monochrome * bitmap. * * History: * 9-19-95 Hideyuki Nagase [hideyukn] * Rewrote it. * * 5-18-93 Gerrit van Wingerden [gerritv] * Wrote it. *****************************************************************************/ UINT GreGetStringBitmapW( HDC hdc, LPWSTR pwsz, UINT cwc, // should be 1.... LPSTRINGBITMAP lpSB, UINT cj, UINT *puiOffset // not used... ) { // Parameter check, early out... if( cwc != 1 ) { WARNING("GreGetStringBitmap only works when char count is 1.\n"); return(0); } if( puiOffset != 0 && *puiOffset != 0 ) { WARNING("GreGetStringBitmap only works when offset is 0.\n"); return(0); } // Lock the DC and set the new attributes. DCOBJ dco(hdc); // Lock the DC. if (!dco.bValid()) // Check if it's good. { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(0); } // Get the transform from the DC. EXFORMOBJ xo(dco,WORLD_TO_DEVICE); // we only allow identity transforms for GetStringBitmap if( !xo.bIdentity() ) { WARNING("GreGetStringBitmap only works with identity WtoD xforms.\n"); return(0); } // Locate the font cache. RFONTOBJ rfo(dco,FALSE); if (!rfo.bValid()) { WARNING("gdisrv!GreGetStringBitmap(): could not lock RFONTOBJ\n"); return (0); } // GetStringBitmap doesn't support vector fonts. if( rfo.bPathFont() ) { WARNING("gdisrv!GetStringBitmap() : vector fonts aren't supported.\n"); return(0); } // GetStringBitmap doesn't support sny rotations. if((dco.pdc->lEscapement() | rfo.ulOrientation() ) != 0) { WARNING("gdisrv!GreGetStringBitmap(): Text isn't Horizontal.\n" ); return(0); } // Initialize ESTROBJ. Compute glyph layout positions. ESTROBJ to; to.vInitSimple(pwsz,cwc,dco,rfo,0L,0L,NULL); if (!to.bValid()) { WARNING("gdisrv!GetStringBitmap() : could not lock ESTROBJ.\n"); return(0); } // Compute the target string rectangle. UINT uiWidth = (UINT)( to.rclBkGround.right - to.rclBkGround.left ); UINT uiHeight = (UINT)( to.rclBkGround.bottom - to.rclBkGround.top ); // Offset the width by the C space of the last character and the A space of // the first character to get the true extent GLYPHDATA *pgd; EGLYPHPOS *pg = (EGLYPHPOS*)to.pgpGet(); pgd = pg->pgd(); uiWidth += FXTOL(pgd->fxA); pg = &pg[to.cGlyphsGet()-1]; pgd = pg->pgd(); uiWidth += FXTOL((pgd->fxD-pgd->fxAB)); // compute width of scanline in bytes ( must be byte alligned ) UINT cjScan = (uiWidth + 7) / 8; UINT cjSize = offsetof(STRINGBITMAP,ajBits) + (cjScan * uiHeight); PBYTE pjBits = lpSB->ajBits; // If the user only want the size return now. // And check the buffer is enough to store glyph image if( cj < cjSize ) return( cjSize ); // Clear the target buffer. RtlZeroMemory( pjBits, cjScan * uiHeight ); // Fill up its bitmap size... lpSB->uiHeight = uiHeight; lpSB->uiWidth = uiWidth; // adjust the baseline of the Sys EUDC for win 3.1 compatability POINTL ptlBaseLineAdjust = {0,0}; LONG lFontType = EUDCTYPE_BASEFONT; PRFONT pLinkedRfont = NULL; // Is the character linked one ? if( to.bLinkedGlyphs() ) { // Setup its font type... lFontType = *(LONG *)(to.plPartitionGet()); // Get corresponding RFONT with current linked font. switch (lFontType) { case EUDCTYPE_SYSTEM_WIDE: pLinkedRfont = rfo.prfntSysEUDC(); break; case EUDCTYPE_SYSTEM_TT_FONT: pLinkedRfont = rfo.prfntSystemTT(); break; case EUDCTYPE_DEFAULT: pLinkedRfont = rfo.prfntDefEUDC(); break; case EUDCTYPE_BASEFONT: // it's possible for this to be the case since the EUDC character // could have been a singular character or a blank character in which // case we will have already have set flags saying we have linked // glyphs but in actuality will grab the default glyph from the base font break; default: ASSERTGDI(lFontType >= EUDCTYPE_FACENAME, "GDISRV:GreGetStringBitmapW() Error lFontType\n"); pLinkedRfont = rfo.prfntFaceName(lFontType - EUDCTYPE_FACENAME); break; } // Is the RFONT is valid ? if( pLinkedRfont != NULL ) { RFONTTMPOBJ rfoLink(pLinkedRfont); // // Compute baseline diffs. // // *** Base font Height == Linked font Height *** // // Base font EUDC font Base font EUDC font // // ------- // ------- | | ------- ------- // | | | | -----> | | | | // | 15 | | 20 | | 15 | | 15 | // | | | | | | | | // -------------------- BaseLine --------------------- // | 5 | | 5 | | 5 | // ------- ------- ------- // // *** Base font Ascent >= Linked font Height **** // // Base font EUDC font Base font EUDC font // // ------- ------- // | | | | ------- // | | ------- -----> | | | | // | 20 | | 10 | | 20 | | 15 | // | | | | | | | | // -------------------- BaseLine --------------------- // | 5 | | 5 | | 5 | // ------- ------- ------- // // *** Others **** // // TBD. // if( rfo.fxMaxAscent() >= (rfoLink.fxMaxAscent() - rfoLink.fxMaxDescent()) ) { ptlBaseLineAdjust.y = (rfoLink.fxMaxDescent() >> 4); } else { ptlBaseLineAdjust.y = (rfoLink.fxMaxAscent() - rfo.fxMaxAscent()) >> 4; } // // if we need to adjust baseline, force emulation.... // if( ptlBaseLineAdjust.y ) to.pgpSet(NULL); } } // Set current font type. to.vFontSet(lFontType); RFONTTMPOBJ rfoLink(pLinkedRfont); if(pLinkedRfont) { to.prfntSet( &rfoLink ); } // Set base line adjustment delta. to.ptlBaseLineAdjustSet( ptlBaseLineAdjust ); // Draw the glyph vStringBitmapTextOut( (STROBJ*)&to, pjBits, cjScan ); return( cj ); } BOOL bAdjusBaseLine(RFONTOBJ &rfoBase, RFONTOBJ &rfoLink, POINTL *pptlAdjustBaseLine) { BOOL bRet = FALSE; // special case of the bitmap font, the heights are the same if ((rfoBase.fxMaxAscent() - rfoBase.fxMaxDescent()) == (rfoLink.fxMaxAscent() - rfoLink.fxMaxDescent())) { pptlAdjustBaseLine->x = FXTOLFLOOR((rfoBase.ptfxMaxAscent().x - rfoLink.ptfxMaxAscent().x)); pptlAdjustBaseLine->y = FXTOLFLOOR((rfoBase.ptfxMaxAscent().y - rfoLink.ptfxMaxAscent().y)); if (pptlAdjustBaseLine->y || pptlAdjustBaseLine->x) bRet = TRUE; } return bRet; } /******************************************************************************* * void AdjustBoundingBox(RFONTOBJ&, RFONTOBJ&, POINTFIX*, ERECTL*) * * This function adjusts the baseline of the EUDC font in a way that is * Win 3.1 compatible according to the following rules: * * * Base font Height == Linked font Height *** * * Base font EUDC font Base font EUDC font * ******************************************************************************/ static void AdjustBoundingBox( RFONTOBJ &rfoBase, RFONTOBJ &rfoLink, FIX *fxAdjustDeltaAsc, FIX *fxAdjustDeltaDsc, POINTFIX *ptfxDeltaAsc, POINTFIX *ptfxDeltaDsc ) { FIX fxDeltaDsc, fxDeltaAsc; fxDeltaDsc = rfoBase.fxMaxDescent() - rfoLink.fxMaxDescent(); fxDeltaAsc = -(rfoBase.fxMaxAscent() - rfoLink.fxMaxAscent()); // There is no internal leading in base font, most likely BMP case. // In this case we will adjust the baseline (the exact height match) // so that it will not be necessary to adjust the bounding box if ((fxDeltaDsc + fxDeltaAsc) == 0) return; if (fxDeltaDsc < 0) fxDeltaDsc = 0; if(fxDeltaAsc < 0) fxDeltaAsc = 0; if(!fxDeltaAsc && !fxDeltaDsc ) return; // eAu = (0, -1) // dA = eA * eAu = (x1, y1) // dD = -eD * eDu = (x2, y2) if (fxDeltaDsc > *fxAdjustDeltaDsc) { *fxAdjustDeltaDsc = fxDeltaDsc; ptfxDeltaDsc->x = -(rfoBase.ptfxMaxDescent().x - rfoLink.ptfxMaxDescent().x); ptfxDeltaDsc->y = -(rfoBase.ptfxMaxDescent().y - rfoLink.ptfxMaxDescent().y); } if (fxDeltaAsc > *fxAdjustDeltaAsc) { *fxAdjustDeltaAsc = fxDeltaAsc; ptfxDeltaAsc->x = -(rfoBase.ptfxMaxAscent().x - rfoLink.ptfxMaxAscent().x); ptfxDeltaAsc->y = -(rfoBase.ptfxMaxAscent().y - rfoLink.ptfxMaxAscent().y); } } VOID ESTROBJ::vEudcOpaqueArea(POINTFIX *aptfxBackground, BOOL bComplexBackground ) { FIX fxDeltaAsc = 0; FIX fxDeltaDsc = 0; POINTFIX ptfxDeltaAsc = {0, 0}; POINTFIX ptfxDeltaDsc = {0, 0}; for(LONG lFont = EUDCTYPE_BASEFONT ; lFont < (EUDCTYPE_FACENAME + (LONG) prfo->uiNumFaceNameLinks()) ; lFont++ ) { RFONTTMPOBJ rfoLink; switch( lFont ) { case EUDCTYPE_BASEFONT: break; case EUDCTYPE_SYSTEM_TT_FONT: if(cTTSysGlyphs) { rfoLink.vInit(prfo->prfntSystemTT()); AdjustBoundingBox(*prfo,rfoLink, &fxDeltaAsc, &fxDeltaDsc, &ptfxDeltaAsc, &ptfxDeltaDsc); } break; case EUDCTYPE_SYSTEM_WIDE: if( cSysGlyphs ) { rfoLink.vInit( prfo->prfntSysEUDC() ); AdjustBoundingBox(*prfo,rfoLink, &fxDeltaAsc, &fxDeltaDsc, &ptfxDeltaAsc, &ptfxDeltaDsc); } break; case EUDCTYPE_DEFAULT: if( cDefGlyphs) { rfoLink.vInit( prfo->prfntDefEUDC() ); AdjustBoundingBox(*prfo,rfoLink, &fxDeltaAsc, &fxDeltaDsc, &ptfxDeltaAsc, &ptfxDeltaDsc); } break; default: if( pacFaceNameGlyphs && pacFaceNameGlyphs[lFont-EUDCTYPE_FACENAME]) { rfoLink.vInit(prfo->prfntFaceName(lFont - EUDCTYPE_FACENAME)); AdjustBoundingBox(*prfo,rfoLink, &fxDeltaAsc, &fxDeltaDsc, &ptfxDeltaAsc, &ptfxDeltaDsc); } break; } } if (fxDeltaAsc || fxDeltaDsc) { LONG lDeltaL, lDeltaR, lDeltaT, lDeltaB; RECTL rclInflate = rclBkGround; // dLeft = min(x1, x2) // dRight = max(x1, x2) // dTop = min(y1, y2) // dBottom = max(y1, y2) lDeltaL = FXTOLFLOOR(min(ptfxDeltaAsc.x, ptfxDeltaDsc.x)); lDeltaR = FXTOLCEILING(max(ptfxDeltaAsc.x, ptfxDeltaDsc.x)); lDeltaT = FXTOLFLOOR(min(ptfxDeltaAsc.y, ptfxDeltaDsc.y)); lDeltaB = FXTOLCEILING(max(ptfxDeltaAsc.y, ptfxDeltaDsc.y)); rclInflate.left += lDeltaL; rclInflate.right += lDeltaR; rclInflate.top += lDeltaT; rclInflate.bottom += lDeltaB; if (rclInflate.top < rclBkGround.top) rclBkGround.top = rclInflate.top; if (rclInflate.bottom > rclBkGround.bottom) rclBkGround.bottom = rclInflate.bottom; if (rclInflate.left < rclBkGround.left) rclBkGround.left = rclInflate.left; if (rclInflate.right > rclBkGround.right) rclBkGround.right = rclInflate.right; // for the order of points in the bounding paralelogram look at textobj.cxx // we go around clockwise ie tl, tr, br, bl if (bComplexBackground) { if (fxDeltaAsc) { aptfxBackground[0].x += ptfxDeltaAsc.x; aptfxBackground[0].y += ptfxDeltaAsc.y; aptfxBackground[1].x += ptfxDeltaAsc.x; aptfxBackground[1].y += ptfxDeltaAsc.y; } if (fxDeltaDsc) { aptfxBackground[2].x += ptfxDeltaDsc.x; aptfxBackground[2].y += ptfxDeltaDsc.y; aptfxBackground[3].x += ptfxDeltaDsc.x; aptfxBackground[3].y += ptfxDeltaDsc.y; } } } } static BOOL bOutOfBounds(STROBJ *pstro, RFONTOBJ *prfo) { COUNT cGlyph; BOOL bMoreGlyphs; GLYPHPOS *pgp; BOOL bRet = FALSE; if((*((LONG*) &(prfo->pfdx()->eXY)) == 0 && *((LONG*)&(prfo->pfdx()->eYX)) == 0)) { // fast out for horizontal cases return(FALSE); } do { bMoreGlyphs = STROBJ_bEnum(pstro,&cGlyph,&pgp); if(cGlyph) { LONG xL, xR, yT, yB; ULONG ii; for (ii=0; iipgb) { xL = pgp[ii].ptl.x + pgp[ii].pgdf->pgb->ptlOrigin.x; xR = xL + pgp[ii].pgdf->pgb->sizlBitmap.cx; yT = pgp[ii].ptl.y + pgp[ii].pgdf->pgb->ptlOrigin.y; yB = yT + pgp[ii].pgdf->pgb->sizlBitmap.cy; if( (xL < pstro->rclBkGround.left) || (xR > pstro->rclBkGround.right) || (yT < pstro->rclBkGround.top) || (yB > pstro->rclBkGround.bottom) ) { bRet = TRUE; break; } } } } } while(bMoreGlyphs); // reset it for the text out call STROBJ_vEnumStart(pstro); return(bRet); } /****************************************************************************** * BOOL bProxyDrvTextOut() * * This routine takes the place of a DrvTextOut in the case when there are EUDC * characters in the ESTROBJ. It partitions the call into mutliple DrvTextOut * calls, one for each font int the string. * * Partitioning information is stored in an array of LONGS in the RFONTOBJ. * The i'th entry in the array tells what font the i'th glyph in the ESTROBJ * belongs to. * * History: * 7-14-93 Gerrit van Wingerden [gerritv] * Rewrote it to handle multiple face name links and just be better. * 2-10-93 Gerrit van Wingerden [gerritv] * Wrote it. * *****************************************************************************/ // This routine is used to partition calls to the driver if there are EUDC // characters in the string. BOOL bProxyDrvTextOut ( XDCOBJ& dco, SURFACE *pSurf, ESTROBJ& to, ECLIPOBJ& co, RECTL *prclExtra, RECTL *prclBackground, BRUSHOBJ *pboFore, BRUSHOBJ *pboOpaque, POINTL *pptlBrushOrg, RFONTOBJ& rfo, PDEVOBJ *pdo, FLONG flCaps, RECTL *prclExclude ) { RFONTOBJ *prfoSave; LONG *plPartition, *plPartitionEnd; COUNT cTotalGlyphs = 0; LONG lInflatedMax = 0; WCHAR *pwcPartition, *pwcTmp, *pwcSave, *pwcSource; ULONG cNumGlyphs = to.cGlyphsGet(); POINTL ptlAdjustBaseLine; BOOL bSkip = FALSE; prfoSave = to.prfo; BOOL bRet = TRUE; pwcPartition = to.pwcPartitionGet(); // now partition the EUDC glyphs by font pwcSave = to.pwszGet(); // set to NULL to force enumeration to.pgpSet( NULL ); // This code is only for NT bug #414953 // If the base font is stroke base then we would not allow to render the linked TT font if ((rfo.prfnt->flInfo & FM_INFO_TECH_STROKE) && rfo.iGraphicsMode() == GM_COMPATIBLE) { if ((dco.pdc->lEscapement() != (LONG) rfo.prfnt->ulOrientation)) bSkip = TRUE; } // Turn off acclerators since we'll seriously munge the properties of the string object. // also clear the ulCharInc value since the tga driver won't work properly if it's // set to.flAccelSet( 0 ); to.vClearCharInc(); for(LONG lFont = EUDCTYPE_BASEFONT ; lFont < (EUDCTYPE_FACENAME + (LONG) rfo.uiNumFaceNameLinks()) ; lFont++ ) { RFONTTMPOBJ rfoLink; RFONTOBJ *prfoLink; UINT ii; COUNT cLinkedGlyphs; switch( lFont ) { case EUDCTYPE_BASEFONT: // If there aren't any glyphs in the base font just draw the // opaque rectangle. We must draw the opaque rectangle here // because the linked glyphs don't neccesarily fit into the // the opaque rectangle. Passing such a rectangle to a driver // can cause unexpected results. cLinkedGlyphs = to.cSysGlyphsGet() + to.cDefGlyphsGet() + to.cTTSysGlyphsGet(); for( ii = 0; ii < rfo.uiNumFaceNameLinks(); ii++ ) { cLinkedGlyphs += to.cFaceNameGlyphsGet( ii ); } if( cLinkedGlyphs == cNumGlyphs ) { // Draw the opaque rectangle here if there is one ASSERTGDI(prclExclude, "bProxyDrvTextOut: prclExclude is NULL\n"); if(prclBackground != NULL) { co.erclExclude().left = max(prclExclude->left,prclBackground->left); co.erclExclude().right = min(prclExclude->right,prclBackground->right); co.erclExclude().top = max(prclExclude->top,prclBackground->top); co.erclExclude().bottom = min(prclExclude->bottom,prclBackground->bottom); } // if not clipped, Just paint the rectangle. if ((co.erclExclude().left < co.erclExclude().right) && (co.erclExclude().top < co.erclExclude().bottom) && prclBackground != NULL ) { INC_SURF_UNIQ(pSurf); TextOutBitBlt ( pSurf, rfo, (SURFOBJ *) NULL, // Source surface. (SURFOBJ *) NULL, // Mask surface. &co, // Clip object. (XLATEOBJ *) NULL, // Palette translation object. prclBackground, // Destination rectangle. (POINTL *) NULL, // Source origin. (POINTL *) NULL, // Mask origin. (BRUSHOBJ *) pboOpaque, // Realized opaque brush. pptlBrushOrg, // brush origin 0x0000f0f0 // PATCOPY ); } co.erclExclude() = *prclExclude; // set prclBackground to NULL since we have just drawn it prclBackground = NULL; continue; } prfoLink = &rfo; FLINKMESSAGE(DEBUG_FONTLINK_TEXTOUT,"Doing base font.\n"); break; case EUDCTYPE_SYSTEM_TT_FONT: if(bSkip || (to.cTTSysGlyphsGet() == 0)) { continue; } rfoLink.vInit(rfo.prfntSystemTT()); prfoLink = (RFONTOBJ *) &rfoLink; break; case EUDCTYPE_SYSTEM_WIDE: if(bSkip || (to.cSysGlyphsGet() == 0)) { continue; } rfoLink.vInit( rfo.prfntSysEUDC() ); prfoLink = (RFONTOBJ *) &rfoLink; break; case EUDCTYPE_DEFAULT: if(bSkip || (to.cDefGlyphsGet() == 0) ) { continue; } rfoLink.vInit( rfo.prfntDefEUDC() ); prfoLink = (RFONTOBJ *) &rfoLink; break; default: if( bSkip || (to.cFaceNameGlyphsGet( lFont-EUDCTYPE_FACENAME ) == 0) ) { continue; } rfoLink.vInit(rfo.prfntFaceName(lFont - EUDCTYPE_FACENAME)); prfoLink = (RFONTOBJ *) &rfoLink; break; } // Loop through all the glyphs in the TextObj using plPartition to // and construct a wchar array to match this textobj. for( plPartition = to.plPartitionGet(),plPartitionEnd = &plPartition[cNumGlyphs], pwcSource = pwcSave, pwcTmp = pwcPartition; plPartition < plPartitionEnd; plPartition += 1, pwcSource += 1 ) { if( *plPartition == lFont ) { *pwcTmp++ = *pwcSource; } } // Keep track of the total glyphs drawn so far so we know when we are doing // the last DrvTextOut. On the last DrvTextOut draw prclExtra. cTotalGlyphs += (COUNT) ( pwcTmp - pwcPartition ); to.cGlyphsSet( (LONG) ( pwcTmp - pwcPartition )); to.pwszSet( pwcPartition ); // set the font type and reset cGlyphPosCopied to 0 to.vFontSet( lFont ); if (lFont != EUDCTYPE_BASEFONT) { if (bAdjusBaseLine(rfo, rfoLink, &ptlAdjustBaseLine)) { to.ptlBaseLineAdjustSet(ptlAdjustBaseLine); } } // adjust the baseline of the Sys EUDC for win 3.1 compatability to.prfntSet( prfoLink ); // some drivers dink with the BkGround rectangle (like the Cirrus driver ) // so save a copy here and then restore it later to handle this situation to.vSaveBkGroundRect(); // check this is a path draw or not. if( prfoLink->bPathFont() ) { PATHMEMOBJ po; if( !po.bValid() ) { SAVE_ERROR_CODE( ERROR_NOT_ENOUGH_MEMORY ); bRet = FALSE; } else { if( !(prfoLink->bReturnsOutlines()) ) { // // VECTOR FONT CASE // if( !to.bTextToPathWorkhorse(po) || !po.bSimpleStroke1( flCaps, pdo, pSurf, &co, pboFore, pptlBrushOrg, ( R2_COPYPEN | ( R2_COPYPEN << 8 )) )) { #if DBG DbgPrint("ProxyDrvTextout:bTextToPath for vector font \ failed(%d).\n", lFont); #endif bRet = FALSE; } } else { // // OUTLINE FONT CASE // if( !to.bTextToPathWorkhorse(po) || (( po.cCurves > 1 ) && !po.bSimpleFill( flCaps, pdo, pSurf, &co, pboFore, pptlBrushOrg, ( R2_COPYPEN | ( R2_COPYPEN << 8 )), WINDING ) ) ) { #if DBG DbgPrint("ProxyDrvTextout:bTextToPath for outline font \ failed(%d).\n",lFont); #endif bRet = FALSE; } } } } else { // This is bad but we will peform a check to see if the linked glyphs // are out of bounds and if so fail the call. There are several reasons // why this may happen (some understood and some not yet understood). Since // we are so close to shipping it was better to do this rather than make // riskier fixes for the other problems. I should point out a few things: // // 1) We only do this check on rotations that are not multiples of 90. // These cases don't cause problem. This also means we are only // Slowing done non-common cases. bOutOfBounds returns TRUE // right away for horizontal text. // 2) It is always better to fail in this case since the alternative is // is system crash (of course fixing the underlying problems is ideal.) // 3) These cases are not real world (i.e. they won't affect text in // in real world scenarios) since they occur under extremely bizarre // transforms and only in our test apps. // 4) I am documenting what I have found about the failure cases so far // and fix these in 5.0 if(!bOutOfBounds((STROBJ*) &to, prfoLink)) { PFN_DrvTextOut pfnTextOut; pfnTextOut = pSurf->pfnTextOut(); // this code correspond to what is done in GreExtTextOutWLocked() // see MSPaint, ClearType bug under 16bits colors #106984 // If the pointer to the TextOut function points to SpTextOut then // we know that AntiAliased text can be handled and we can skip // the funny business in the else clause if (pfnTextOut == SpTextOut) { if (prfoLink->prfnt->fobj.flFontType & (FO_GRAY16 | FO_CLEARTYPE_X)) { pSurf->pdcoAA = &dco; } } else { if ( (prfoLink->prfnt->fobj.flFontType & FO_GRAY16) && (!(dco.flGraphicsCaps() & GCAPS_GRAY16) || (prfoLink->prfnt->fobj.flFontType & FO_CLEARTYPE_X)) ) { // Inform SpTextOut that this call came from GreExtTextOutW // for the purpose of rendering anti aliased text on a device // that does not support it. Remember to set this to zero // before releasing the surface to other users. if (pfnTextOut != EngTextOut) pSurf->pdcoAA = &dco; pfnTextOut = SpTextOut; } } // if (pfnTextOut == SpTextOut) else prfoLink->PreTextOut(dco); // // WINBUG #214225: re-visit the issue that RFONT cache semaphore // is held too long period of time. // Release/acquire the base rfont semaphore before/after // the DrvTextOut call. // { PDEVOBJ po(pSurf->hdev()); BOOL bAcquireSem = FALSE; if (prfoLink != (&rfo) && po.bPrinter() && po.bUMPD()) { if (rfo.prfnt->hsemCache != NULL && GreIsSemaphoreOwnedByCurrentThread(rfo.prfnt->hsemCache)) { GreReleaseSemaphore(rfo.prfnt->hsemCache); bAcquireSem = TRUE; } } if(!((*pfnTextOut)) ( pSurf->pSurfobj(), (STROBJ *) &to, prfoLink->pfo(), &co, (cTotalGlyphs == cNumGlyphs ) ? prclExtra : NULL, prclBackground, pboFore, pboOpaque, pptlBrushOrg, (R2_COPYPEN | (R2_COPYPEN << 8)) )) { #if DBG DbgPrint("ProxyDrvTextout:DrvTextOut for bitmap font failed(%d).\n", lFont); #endif bRet = FALSE; } if (bAcquireSem) { GreAcquireSemaphore(rfo.prfnt->hsemCache); } } prfoLink->PostTextOut(dco); pSurf->pdcoAA = 0; // clear AA state } // set this to NULL since we've already drawn it. prclBackground = NULL; } to.vRestoreBkGroundRect(); } // TextOut expects gpos and prfo to be correct so reset them to.pwszSet( pwcSave ); to.prfo = prfoSave; return(bRet); } /******************************Public*Routine*****************************\ * NtGdiEnableEudc * * Enable or disable system wide and per-user Eudc information. * * History: * 27-Mar-1996 by Gerrit van Wingerden [gerritv] * Wrote it. \*************************************************************************/ extern "C" BOOL APIENTRY NtGdiEnableEudc( BOOL bEnable ) { return(GreEnableEUDC(bEnable)); } /******************************Public*Routine*****************************\ * NtGdiEudcLoadUnloadLink * * Queries system link information * * History: * 27-Mar-1996 by Gerrit van Wingerden [gerritv] * Wrote it. \*************************************************************************/ extern "C" BOOL APIENTRY NtGdiEudcLoadUnloadLink( LPCWSTR pBaseFaceName, UINT cwcBaseFaceName, LPCWSTR pEudcFontPath, UINT cwcEudcFontPath, INT iPriority, INT iFontLinkType, BOOL bLoadLink) { WCHAR FaceNameBuffer[LF_FACESIZE+1]; WCHAR *pPathBuffer; BOOL bRet = FALSE; if(cwcBaseFaceName > LF_FACESIZE || pEudcFontPath == NULL || (cwcEudcFontPath == 0) || (cwcEudcFontPath > (MAX_PATH+LF_FACESIZE - 1))) { EngSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } pPathBuffer = (WCHAR*) AllocFreeTmpBuffer((cwcEudcFontPath+1) * sizeof(WCHAR)); if(pPathBuffer) { __try { if(pBaseFaceName) { ProbeForRead(pBaseFaceName,cwcBaseFaceName,sizeof(WCHAR)); RtlCopyMemory(FaceNameBuffer,pBaseFaceName, cwcBaseFaceName*sizeof(WCHAR)); FaceNameBuffer[cwcBaseFaceName] = (WCHAR) 0; pBaseFaceName = FaceNameBuffer; } ProbeForRead(pEudcFontPath,cwcEudcFontPath,sizeof(WCHAR)); RtlCopyMemory(pPathBuffer,pEudcFontPath, cwcEudcFontPath*sizeof(WCHAR)); pPathBuffer[cwcEudcFontPath] = (WCHAR) 0; bRet = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(3096); } if(bRet) { if(bLoadLink) { bRet = GreEudcLoadLinkW(pBaseFaceName, cwcBaseFaceName, pPathBuffer, cwcEudcFontPath, iPriority, iFontLinkType); } else { bRet = GreEudcUnloadLinkW(pBaseFaceName, cwcBaseFaceName, pPathBuffer, cwcEudcFontPath); } } FreeTmpBuffer(pPathBuffer); } return(bRet); } extern "C" UINT APIENTRY NtGdiGetStringBitmapW( HDC hdc, LPWSTR pwsz, UINT cwc, BYTE *lpSB, UINT cj ) { WCHAR Character; LPSTRINGBITMAP OutputBuffer = NULL; UINT Status = 1; if(cwc != 1) { return(FALSE); } if(cj) { if(!(OutputBuffer = (LPSTRINGBITMAP) AllocFreeTmpBuffer(cj))) { Status = 0; } } if(Status) { __try { ProbeForRead(pwsz,sizeof(WCHAR), sizeof(WCHAR)); Character = pwsz[0]; } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(3099); Status = 0; } if(Status) { Status = GreGetStringBitmapW(hdc, &Character, 1, (LPSTRINGBITMAP) OutputBuffer, cj, 0); } if(Status && OutputBuffer) { __try { ProbeForWrite(lpSB,cj,sizeof(BYTE)); RtlCopyMemory(lpSB,OutputBuffer,cj); } __except(EXCEPTION_EXECUTE_HANDLER) { WARNINGX(3100); Status = 0; } } } if(OutputBuffer) { FreeTmpBuffer(OutputBuffer); } return Status; } #endif