|
|
/****************************************************************************
TIPCAND.CPP : CKorIMX's Candidate UI member functions implementation History: 16-DEC-1999 CSLim Created ****************************************************************************/
#include "private.h"
#include <initguid.h> // For DEFINE_GUID IID_ITfCandidateUIEx and CLSID_TFCandidateUIEx
#include "mscandui.h"
#include "korimx.h"
#include "immxutil.h"
#include "dispattr.h"
#include "helpers.h"
#include "funcprv.h"
#include "kes.h"
#include "editcb.h"
#include "osver.h"
#include "ucutil.h"
#include "hanja.h"
#include "canduies.h"
#include "candkey.h"
#include "tsattrs.h"
//
// candidate list related functions
//
typedef struct _ENUMFONTFAMPARAM { LPCWSTR szFontFace; BYTE chs; BOOL fVertical;
BOOL fFound; // output
BOOL fTrueType; // output
LOGFONTW LogFont; // output
} ENUMFONTFAMPARAM;
static BOOL FFontExist(LPCWSTR szFontFace, LOGFONTW *pLogFont); static BOOL CALLBACK FEnumFontFamProcA(const ENUMLOGFONTA *lpELF, const NEWTEXTMETRICA *lpNTM, DWORD dwFontType, LPARAM lParam); static BOOL CALLBACK FEnumFontFamProcW(const ENUMLOGFONTW *lpELF, const NEWTEXTMETRICW *lpNTM, DWORD dwFontType, LPARAM lParam); static BOOL FEnumFontFamProcMain(const LOGFONTW *pLogFont, DWORD dwFontType, ENUMFONTFAMPARAM *pParam); static BOOL FFindFont(BYTE chs, BOOL fVertical, LOGFONTW *pLogFont);
/*---------------------------------------------------------------------------
CKorIMX::CreateCandidateList
Create a candidate list from input Hangul char ---------------------------------------------------------------------------*/ CCandidateListEx *CKorIMX::CreateCandidateList(ITfContext *pic, ITfRange *pRange, LPWSTR pwzRead) { CCandidateListEx *pCandList; HANJA_CAND_STRING_LIST CandStrList;
Assert(pic != NULL); Assert(pRange != NULL);
if (pic == NULL || pwzRead == NULL) return NULL;
ZeroMemory(&CandStrList, sizeof(HANJA_CAND_STRING_LIST)); // Get Conversion list
if (GetConversionList(*pwzRead, &CandStrList)) { // Create ITfCandidateList object and add cadn string to it.
pCandList = new CCandidateListEx(CandidateUICallBack, pic, pRange); for (UINT i=0; i<CandStrList.csz; i++) { CCandidateStringEx *pCandStr; WCHAR szCand[2];
// Add candidate Hanja
szCand[0] = CandStrList.pHanjaString[i].wchHanja; szCand[1] = L'\0';
pCandList->AddString(szCand, GetLangID(), this, NULL, &pCandStr); pCandStr->SetInlineComment(CandStrList.pHanjaString[i].wzMeaning); pCandStr->m_bHanjaCat = CandStrList.pHanjaString[i].bHanjaCat; // Set read Hangul char
pCandStr->SetReadingString(pwzRead); pCandStr->Release(); }
// Free temp result buffer and return
cicMemFree(CandStrList.pwsz); cicMemFree(CandStrList.pHanjaString);
return pCandList; } else MessageBeep(MB_ICONEXCLAMATION);
return NULL; }
#define FONTNAME_MSSANSSERIF L"Microsoft Sans Serif"
#define FONTNAME_GULIM_KOR L"\xAD74\xB9BC" // Gulim
#define FONTNAME_GULIM_KOR_VERT L"@\xAD74\xB9BC" // Gulim
#define FONTNAME_GULIM_ENG L"Gulim" // Gulim
#define FONTNAME_GULIM_ENG_VERT L"@Gulim" // Gulim
static const LPCWSTR rgszCandFontList9xHoriz[] = { FONTNAME_GULIM_KOR, FONTNAME_GULIM_ENG, NULL };
static const LPCWSTR rgszCandFontList9xVert[] = { FONTNAME_GULIM_KOR_VERT, FONTNAME_GULIM_ENG_VERT, NULL };
static const LPCWSTR rgszCandFontListNT5Horiz[] = { FONTNAME_MSSANSSERIF, FONTNAME_GULIM_KOR, FONTNAME_GULIM_ENG, NULL };
static const LPCWSTR rgszCandFontListNT5Vert[] = { FONTNAME_GULIM_KOR_VERT, FONTNAME_GULIM_ENG_VERT, NULL };
/*---------------------------------------------------------------------------
CKorIMX::GetCandidateFontInternal ---------------------------------------------------------------------------*/ void CKorIMX::GetCandidateFontInternal(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, LOGFONTW *plf, LONG lFontPoint, BOOL fCandList) { HDC hDC; LOGFONTW lfMenu; LOGFONTW lfFont; LONG lfHeightMin; BOOL fVertFont = fFalse; const LPCWSTR *ppFontFace = rgszCandFontList9xHoriz; BOOL fFound;
//
// get menu font
//
if (!IsOnNT()) { NONCLIENTMETRICSA ncmA = {0};
ncmA.cbSize = sizeof(ncmA); SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncmA), &ncmA, 0);
ConvertLogFontAtoW( &ncmA.lfMenuFont, &lfMenu ); } else { NONCLIENTMETRICSW ncmW = {0};
ncmW.cbSize = sizeof(ncmW); SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncmW), &ncmW, 0);
lfMenu = ncmW.lfMenuFont; }
// check font direction of main doc
if (fCandList) { ITfReadOnlyProperty *pProp = NULL; VARIANT var;
if ((pic != NULL) && (pic->GetAppProperty(TSATTRID_Text_VerticalWriting, &pProp) == S_OK)) { QuickVariantInit(&var);
if (pProp->GetValue(ec, pRange, &var) == S_OK) { Assert( var.vt == VT_BOOL ); fVertFont = var.boolVal; VariantClear( &var ); }
SafeRelease( pProp ); } } // set face name
if (IsOnNT5()) ppFontFace = fVertFont ? rgszCandFontListNT5Vert : rgszCandFontListNT5Horiz; else ppFontFace = fVertFont ? rgszCandFontList9xVert : rgszCandFontList9xHoriz;
// find font from font list (expected font)
fFound = FFontExist(*(ppFontFace++), &lfFont); while (!fFound && (*ppFontFace != NULL)) fFound = FFontExist(*(ppFontFace++), &lfFont);
// find another Korean font if no expected font is found
if (!fFound) fFound = FFindFont(HANGEUL_CHARSET, fVertFont, &lfFont);
// use menu font when no Korean font found
if (!fFound) lfFont = lfMenu;
//
// store font
//
*plf = lfMenu;
plf->lfCharSet = lfFont.lfCharSet; plf->lfOutPrecision = lfFont.lfOutPrecision; plf->lfQuality = lfFont.lfQuality; plf->lfPitchAndFamily = lfFont.lfPitchAndFamily; wcscpy(plf->lfFaceName, lfFont.lfFaceName);
//
// font size
//
// check minimum size
hDC = GetDC(NULL); // Cand font size 12pt
lfHeightMin = -MulDiv(lFontPoint, GetDeviceCaps(hDC, LOGPIXELSY), 72); // minimum size
ReleaseDC(NULL, hDC);
plf->lfHeight = min(lfHeightMin, plf->lfHeight); }
/* G E T T E X T D I R E C T I O N */ /*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/ TEXTDIRECTION CKorIMX::GetTextDirection(TfEditCookie ec, ITfContext *pic, ITfRange *pRange) { TEXTDIRECTION dir = TEXTDIRECTION_LEFTTORIGHT; ITfReadOnlyProperty *pProp = NULL; VARIANT var; LONG lOrientation;
QuickVariantInit(&var);
if (pic == NULL) goto LError;
if (pic->GetAppProperty(TSATTRID_Text_Orientation, &pProp) != S_OK) goto LError;
if (pProp->GetValue(ec, pRange, &var) != S_OK) goto LError;
Assert(var.vt == VT_I4);
lOrientation = var.lVal; Assert((0 <= lOrientation) && (lOrientation < 3600));
if (lOrientation < 450) dir = TEXTDIRECTION_LEFTTORIGHT; else if (lOrientation < 900 + 450) dir = TEXTDIRECTION_BOTTOMTOTOP; else if (lOrientation < 1800 + 450) dir = TEXTDIRECTION_RIGHTTOLEFT; else if (lOrientation < 2700 + 450) dir = TEXTDIRECTION_TOPTOBOTTOM; else dir = TEXTDIRECTION_LEFTTORIGHT;
LError: SafeRelease(pProp); VariantClear(&var);
return dir; }
/* G E T C A N D U I D I R E C T I O N */ /*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/ CANDUIUIDIRECTION CKorIMX::GetCandUIDirection(TfEditCookie ec, ITfContext *pic, ITfRange *pRange) { TEXTDIRECTION DirText = GetTextDirection(ec, pic, pRange); CANDUIUIDIRECTION DirCand = CANDUIDIR_LEFTTORIGHT; switch(DirText) { case TEXTDIRECTION_TOPTOBOTTOM: DirCand = CANDUIDIR_RIGHTTOLEFT; break; case TEXTDIRECTION_RIGHTTOLEFT: DirCand = CANDUIDIR_BOTTOMTOTOP; break; case TEXTDIRECTION_BOTTOMTOTOP: DirCand = CANDUIDIR_LEFTTORIGHT; break; case TEXTDIRECTION_LEFTTORIGHT: DirCand = CANDUIDIR_TOPTOBOTTOM; break; }
return DirCand; }
/*---------------------------------------------------------------------------
CKorIMX::OpenCandidateUI
Open candidate UI - Open candidate UI window at the specified range - This function never release the range nor candidate list object. They must be released in caller side. ---------------------------------------------------------------------------*/ void CKorIMX::OpenCandidateUI(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, CCandidateListEx *pCandList ) { ITfDocumentMgr *pdim;
Assert(pic != NULL); Assert(pRange != NULL); Assert(pCandList != NULL);
if (pic == NULL || pRange == NULL || pCandList == NULL) return;
// Create and initialize candidate UI
if (m_pCandUI == NULL) { if (SUCCEEDED(CoCreateInstance(CLSID_TFCandidateUI, NULL, CLSCTX_INPROC_SERVER, IID_ITfCandidateUI, (LPVOID*)&m_pCandUI))) { // Set client ID
m_pCandUI->SetClientId(GetTID()); } } Assert(m_pCandUI != NULL);
if (m_pCandUI != NULL && SUCCEEDED(GetFocusDIM(&pdim))) { LOGFONTW lf; ULONG iSelection; ITfCandUICandString *pCandString; ITfCandUICandIndex *pCandIndex; ITfCandUIInlineComment *pCandInlineComment; CANDUIUIDIRECTION dir; ITfCandUICandWindow *pCandWindow;
// Set Cand string and Cand index font
GetCandidateFontInternal(ec, pic, pRange, &lf, 12, fTrue); if (SUCCEEDED(m_pCandUI->GetUIObject(IID_ITfCandUICandString, (IUnknown**)&pCandString))) { pCandString->SetFont(&lf); pCandString->Release(); }
// Set Inline Comment font
// GetCandidateFontInternal(ec, pic, pRange, plf, 9, fTrue);
lf.lfHeight = (lf.lfHeight * 3) / 4; if (SUCCEEDED(m_pCandUI->GetUIObject(IID_ITfCandUIInlineComment, (IUnknown**)&pCandInlineComment))) { pCandInlineComment->SetFont(&lf); pCandInlineComment->Release(); }
GetCandidateFontInternal(ec, pic, pRange, &lf, 12, fFalse); if (SUCCEEDED(m_pCandUI->GetUIObject(IID_ITfCandUICandIndex, (IUnknown**)&pCandIndex))) { pCandIndex->SetFont(&lf); pCandIndex->Release(); }
// Set UI direction
dir = GetCandUIDirection(ec, pic, pRange); if (SUCCEEDED(m_pCandUI->GetUIObject(IID_ITfCandUICandWindow, (IUnknown**)&pCandWindow))) { pCandWindow->SetUIDirection(dir); pCandWindow->Release(); }
// set key table
SetCandidateKeyTable(pic, dir);
// set and open candidate list
if (m_pCandUI->SetCandidateList(pCandList) == S_OK) {
m_fCandUIOpen = fTrue; pCandList->GetInitialSelection(&iSelection); m_pCandUI->SetSelection(iSelection);
m_pCandUI->OpenCandidateUI(GetForegroundWindow(), pdim, ec, pRange); } } }
/* C L O S E C A N D I D A T E U I P R O C */ /*------------------------------------------------------------------------------
Main procedure of closing CandidateUI
------------------------------------------------------------------------------*/ void CKorIMX::CloseCandidateUIProc() { if (m_pCandUI != NULL) { m_pCandUI->CloseCandidateUI();
// BUGBUG: Candidate UI module never free candidatelist until
// set next candidate list. set NULL candidate list then
// it frees the previous one.
m_pCandUI->SetCandidateList(NULL);
m_fCandUIOpen = fFalse; } }
/*---------------------------------------------------------------------------
CKorIMX::CloseCandidateUI
Close CandidateUI in EditSession ---------------------------------------------------------------------------*/ void CKorIMX::CloseCandidateUI(ITfContext *pic) { CEditSession2 *pes; ESSTRUCT ess; HRESULT hr; ESStructInit(&ess, ESCB_CANDUI_CLOSECANDUI);
if ((pes = new CEditSession2(pic, this, &ess, _EditSessionCallback2 ))) { pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr); pes->Release(); } }
// REVIEW : NOT USED
void CKorIMX::SelectCandidate( TfEditCookie ec, ITfContext *pic, INT idxCand, BOOL fFinalize ) { // IImeIPoint* pIp = GetIPoint( pic );
// CIImeIPointCallBackCIC* pIPCB = GetIPCB( pic );
// if (( pIp == NULL ) || (pIPCB == NULL)) {
// return;
// }
// UINT uiType = pIPCB->GetCandidateInfo();
/*
CONTROLIDS* pControl = NULL; INT nControl = 0;
INT idx; idx = idxCand; if (uiType == CANDINFO_RECOMMEND) { idx |= MAKE_PCACATEGLY(IMEPCA_CATEGLY_RECOMMEND); }
HRESULT hRes = pIp->GetCandidateInfo( idx, &nControl, (VOID**)&pControl ); if( pControl == NULL || hRes == S_FALSE ) { return; }
INT i;
CONTROLIDS* pCtrl = NULL; // generate control IDs
for( i=0; i<nControl; i++ ) { pCtrl = pControl + i; pIp->Control( (WORD)pCtrl->dwControl, (LPARAM)pCtrl->lpVoid ); }
if (fFinalize) { // select with candidate close
pIp->Control( (WORD)JCONV_C_CANDCURRENT, (LPARAM)CTRLID_DEFAULT ); } else { if (uiType == CANDINFO_RECOMMEND) { pIp->Control( (WORD)JCONV_C_RECOMMENDCAND, (LPARAM)CTRLID_DEFAULT ); } }
pIp->UpdateContext( FALSE ); // generate composition string message
_UpdateContext( ec, GetDIM(), pic, NULL); */ }
void CKorIMX::CancelCandidate(TfEditCookie ec, ITfContext *pic) { /*
IImeIPoint* pIp = GetIPoint( pic );
if( pIp == NULL ) { return; }
// close candidate
pIp->Control( (WORD)JCONV_C_CANDCURRENT, (LPARAM)CTRLID_DEFAULT ); _UpdateContext( ec, GetDIM(), pic, NULL); // REVIEW: KOJIW: unneeded???
*/ CloseCandidateUIProc(); }
//////////////////////////////////////////////////////////////////////////////
// Candlist key code behavior definition tables
CANDUIKEYDATA rgCandKeyDef[] = { /*
{ flag, keydata, command, paramater } */ { CANDUIKEY_CHAR, L'1', CANDUICMD_SELECTLINE, 1 }, { CANDUIKEY_CHAR, L'2', CANDUICMD_SELECTLINE, 2 }, { CANDUIKEY_CHAR, L'3', CANDUICMD_SELECTLINE, 3 }, { CANDUIKEY_CHAR, L'4', CANDUICMD_SELECTLINE, 4 }, { CANDUIKEY_CHAR, L'5', CANDUICMD_SELECTLINE, 5 }, { CANDUIKEY_CHAR, L'6', CANDUICMD_SELECTLINE, 6 }, { CANDUIKEY_CHAR, L'7', CANDUICMD_SELECTLINE, 7 }, { CANDUIKEY_CHAR, L'8', CANDUICMD_SELECTLINE, 8 }, { CANDUIKEY_CHAR, L'9', CANDUICMD_SELECTLINE, 9 }, { CANDUIKEY_CHAR, L'0', CANDUICMD_SELECTEXTRACAND, 0 }, { CANDUIKEY_VKEY, VK_HANJA, CANDUICMD_CANCEL, 0 }, { CANDUIKEY_VKEY, VK_RETURN, CANDUICMD_COMPLETE, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_SPACE, CANDUICMD_MOVESELNEXT, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_DOWN, CANDUICMD_MOVESELNEXT, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_UP, CANDUICMD_MOVESELPREV, 0 }, { CANDUIKEY_VKEY, VK_HOME, CANDUICMD_MOVESELFIRST, 0 }, { CANDUIKEY_VKEY, VK_END, CANDUICMD_MOVESELLAST, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_PRIOR, CANDUICMD_MOVESELPREVPG, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_NEXT, CANDUICMD_MOVESELNEXTPG, 0 }, { CANDUIKEY_VKEY, VK_ESCAPE, CANDUICMD_CANCEL, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_RIGHT, CANDUICMD_MOVESELNEXT, 0 }, { CANDUIKEY_VKEY|CANDUIKEY_RELATIVEDIR, VK_LEFT, CANDUICMD_MOVESELPREV, 0 }, { CANDUIKEY_VKEY, VK_LWIN, CANDUICMD_CANCEL, 0 }, { CANDUIKEY_VKEY, VK_RWIN, CANDUICMD_CANCEL, 0 }, { CANDUIKEY_VKEY, VK_APPS, CANDUICMD_CANCEL, 0 } };
#define irgCandKeyDefMax (sizeof(rgCandKeyDef) / sizeof(rgCandKeyDef[0]))
/*---------------------------------------------------------------------------
CKorIMX::SetCandidateKeyTable ---------------------------------------------------------------------------*/ void CKorIMX::SetCandidateKeyTable(ITfContext *pic, CANDUIUIDIRECTION dir) { CCandUIKeyTable *pCandUIKeyTable; ITfCandUIFnKeyConfig *pCandUIFnKeyConfig; if (m_pCandUI == NULL) return;
if (FAILED(m_pCandUI->GetFunction(IID_ITfCandUIFnKeyConfig, (IUnknown**)&pCandUIFnKeyConfig))) return;
if ((pCandUIKeyTable = new CCandUIKeyTable(irgCandKeyDefMax)) == NULL) return;
for (int i = 0; i < irgCandKeyDefMax; i++) pCandUIKeyTable->AddKeyData(&rgCandKeyDef[i]);
pCandUIFnKeyConfig->SetKeyTable(pic, pCandUIKeyTable); pCandUIKeyTable->Release(); pCandUIFnKeyConfig->Release(); }
/*---------------------------------------------------------------------------
CKorIMX::CandidateUICallBack ---------------------------------------------------------------------------*/ HRESULT CKorIMX::CandidateUICallBack(ITfContext *pic, ITfRange *pRange, CCandidateListEx *pCandList, CCandidateStringEx *pCand, TfCandidateResult imcr) { CKorIMX *pSIMX = (CKorIMX *)(pCand->m_pv); CEditSession2 *pes; ESSTRUCT ess; HRESULT hr;
Assert(pic != NULL); Assert(pRange != NULL); // Only handle CAND_FINALIZED and CAND_CANCELED
if (imcr == CAND_FINALIZED) { ESStructInit(&ess, ESCB_FINALIZECONVERSION);
ess.pRange = pRange; ess.pCandList = pCandList; ess.pCandStr = pCand;
if (pes = new CEditSession2(pic, pSIMX, &ess, CKorIMX::_EditSessionCallback2)) { pCandList->AddRef(); ; // be released in edit session callback
pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr); pes->Release(); } }
// If user hit ESC or arrow keys..
if (imcr == CAND_CANCELED) { // Complete current comp char if exist
// This will reset Automata also.
ESStructInit(&ess, ESCB_COMPLETE); ess.pRange = pRange; if ((pes = new CEditSession2(pic, pSIMX, &ess, CKorIMX::_EditSessionCallback2)) == NULL) return fFalse;
pes->Invoke(ES2_READWRITE | ES2_ASYNC, &hr); pes->Release(); }
return S_OK; }
/*---------------------------------------------------------------------------
CKorIMX::IsCandKey ---------------------------------------------------------------------------*/ BOOL CKorIMX::IsCandKey(WPARAM wParam, const BYTE abKeyState[256]) { if (IsShiftKeyPushed(abKeyState) || IsControlKeyPushed(abKeyState)) return fFalse;
if (wParam == VK_HANGUL || wParam == VK_HANJA || wParam == VK_JUNJA) return fTrue; for (int i=0; i<irgCandKeyDefMax; i++) { if (rgCandKeyDef[i].uiKey == wParam) return fTrue; } if (wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) return fTrue; else return fFalse; }
/////////////////////////////////////////////////////////////////////////////
// Private Functions
/* F F O N T E X I S T */ /*------------------------------------------------------------------------------
Check if the font is installed
------------------------------------------------------------------------------*/ BOOL FFontExist(LPCWSTR szFontFace, LOGFONTW *pLogFont) { ENUMFONTFAMPARAM param = {0}; HDC hDC;
param.szFontFace = szFontFace; param.fFound = FALSE;
hDC = GetDC(NULL); if (!IsOnNT5()) { CHAR szFontFaceA[LF_FACESIZE];
ConvertStrWtoA(szFontFace, -1, szFontFaceA, LF_FACESIZE); EnumFontFamiliesA(hDC, szFontFaceA, (FONTENUMPROCA)FEnumFontFamProcA, (LPARAM)¶m); } else EnumFontFamiliesW(hDC, szFontFace, (FONTENUMPROCW)FEnumFontFamProcW, (LPARAM)¶m); ReleaseDC(NULL, hDC);
if (param.fFound) *pLogFont = param.LogFont;
return param.fFound; }
/* F E N U M F O N T F A M P R O C A */ /*------------------------------------------------------------------------------
Callback funtion in enumeration font (ANSI version)
------------------------------------------------------------------------------*/ BOOL CALLBACK FEnumFontFamProcA(const ENUMLOGFONTA *lpELF, const NEWTEXTMETRICA *lpNTM, DWORD dwFontType, LPARAM lParam) { LOGFONTW lfW;
UNREFERENCED_PARAMETER(lpNTM); UNREFERENCED_PARAMETER(dwFontType);
ConvertLogFontAtoW(&lpELF->elfLogFont, &lfW);
return FEnumFontFamProcMain(&lfW, dwFontType, (ENUMFONTFAMPARAM *)lParam); }
/* F E N U M F O N T F A M P R O C W */ /*------------------------------------------------------------------------------
Callback funtion in enumeration font (Unicode version)
------------------------------------------------------------------------------*/ BOOL CALLBACK FEnumFontFamProcW(const ENUMLOGFONTW *lpELF, const NEWTEXTMETRICW *lpNTM, DWORD dwFontType, LPARAM lParam) { UNREFERENCED_PARAMETER(lpNTM);
return FEnumFontFamProcMain(&lpELF->elfLogFont, dwFontType, (ENUMFONTFAMPARAM *)lParam); }
/* F E N U M F O N T F A M P R O C M A I N */ /*------------------------------------------------------------------------------
Main procedure of enumeration font (find fonts)
------------------------------------------------------------------------------*/ BOOL FEnumFontFamProcMain( const LOGFONTW *pLogFont, DWORD dwFontType, ENUMFONTFAMPARAM *pParam ) { if (pParam->szFontFace != NULL) { if (pParam->fFound) goto Exit;
// check font face
if (wcscmp( pParam->szFontFace, pLogFont->lfFaceName ) == 0) { pParam->fFound = TRUE; pParam->fTrueType = (dwFontType == TRUETYPE_FONTTYPE); pParam->LogFont = *pLogFont; } } else { // check character set
if (pLogFont->lfCharSet != pParam->chs) goto Exit;
// check font direction
if (pParam->fVertical && (pLogFont->lfFaceName[0] != L'@')) goto Exit; else if (!pParam->fVertical && (pLogFont->lfFaceName[0] == L'@')) goto Exit;
// store first found font anyway
if (!pParam->fFound) { pParam->fFound = TRUE; pParam->fTrueType = (dwFontType == TRUETYPE_FONTTYPE); pParam->LogFont = *pLogFont; goto Exit; }
// check if the font is better than previous
// font type (truetype font has priority)
if (pParam->fTrueType && (dwFontType != TRUETYPE_FONTTYPE)) goto Exit; else if (!pParam->fTrueType && (dwFontType == TRUETYPE_FONTTYPE)) { pParam->fTrueType = (dwFontType == TRUETYPE_FONTTYPE); pParam->LogFont = *pLogFont; goto Exit; }
// font family (swiss font has priority)
if (((pParam->LogFont.lfPitchAndFamily & (0x0f<<4)) == FF_SWISS) && ((pLogFont->lfPitchAndFamily & (0x0f<<4)) != FF_SWISS)) goto Exit; else if (((pParam->LogFont.lfPitchAndFamily & (0x0f<<4)) != FF_SWISS) && ((pLogFont->lfPitchAndFamily & (0x0f<<4)) == FF_SWISS)) { pParam->fTrueType = (dwFontType == TRUETYPE_FONTTYPE); pParam->LogFont = *pLogFont; goto Exit; }
// pitch (variable pitch font has priority)
if (((pParam->LogFont.lfPitchAndFamily & (0x03)) == VARIABLE_PITCH) && ((pLogFont->lfPitchAndFamily & (0x03)) != VARIABLE_PITCH)) goto Exit; else if (((pParam->LogFont.lfPitchAndFamily & (0x03)) != VARIABLE_PITCH) && ((pLogFont->lfPitchAndFamily & (0x03)) == VARIABLE_PITCH)) { pParam->fTrueType = (dwFontType == TRUETYPE_FONTTYPE); pParam->LogFont = *pLogFont; goto Exit; } }
Exit: return TRUE; }
/* F F I N D F O N T */ /*------------------------------------------------------------------------------
Find the font that matches about following specified in the parameter * character set * font direction (vertical/horizontal)
The priorities of finding are as belloow * TrueType font * Swiss (w/o serif) font * variable pitch font
------------------------------------------------------------------------------*/ BOOL FFindFont(BYTE chs, BOOL fVertical, LOGFONTW *pLogFont) { ENUMFONTFAMPARAM param = {0}; HDC hDC;
param.szFontFace = NULL; param.chs = chs; param.fVertical = fVertical; param.fFound = FALSE;
hDC = GetDC(NULL); if (!IsOnNT5()) EnumFontFamiliesA(hDC, NULL, (FONTENUMPROCA)FEnumFontFamProcA, (LPARAM)¶m); else EnumFontFamiliesW(hDC, NULL, (FONTENUMPROCW)FEnumFontFamProcW, (LPARAM)¶m);
ReleaseDC(NULL, hDC);
if (param.fFound) *pLogFont = param.LogFont;
return param.fFound; }
|