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

5259 lines
150 KiB

/*****************************************************************************
* 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; ii<cGlyph; ii++)
{
// for device font pgb will be NULL so don't do the check
if(pgp[ii].pgdf->pgb)
{
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