Index: reactos/base/applications/fontview/display.c =================================================================== --- reactos/base/applications/fontview/display.c (revision 73479) +++ reactos/base/applications/fontview/display.c (working copy) @@ -162,7 +162,7 @@ } static LRESULT -Display_SetTypeFace(HWND hwnd, PEXTLOGFONTW pExtLogFont) +Display_SetTypeFace(HWND hwnd, PLOGFONTW pLogFont) { DISPLAYDATA* pData; TEXTMETRIC tm; @@ -174,13 +174,13 @@ /* Set the new type face name */ pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - _snwprintf(pData->szTypeFaceName, LF_FULLFACESIZE, pExtLogFont->elfFullName); + _snwprintf(pData->szTypeFaceName, LF_FULLFACESIZE, pLogFont->lfFaceName); /* Create the new fonts */ hDC = GetDC(hwnd); DeleteObject(pData->hCharSetFont); - logfont = pExtLogFont->elfLogFont; + logfont = *pLogFont; logfont.lfHeight = -MulDiv(16, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72); pData->hCharSetFont = CreateFontIndirectW(&logfont); @@ -252,11 +252,10 @@ DISPLAYDATA* pData; const int nSizes[MAX_SIZES] = {8, 12, 18, 24, 36, 48, 60, 72}; int i; - EXTLOGFONTW ExtLogFont = {{50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, - ANSI_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, PROOF_QUALITY, - DEFAULT_PITCH , L"Ms Shell Dlg"}, - L"Ms Shell Dlg"}; + LOGFONTW LogFont = {50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + ANSI_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, PROOF_QUALITY, + DEFAULT_PITCH , L"Ms Shell Dlg"}; /* Create data structure */ pData = malloc(sizeof(DISPLAYDATA)); @@ -270,13 +269,13 @@ pData->nSizes[i] = nSizes[i]; } - pData->hCaptionFont = CreateFontIndirectW(&ExtLogFont.elfLogFont); - ExtLogFont.elfLogFont.lfHeight = 12; - pData->hSizeFont = CreateFontIndirectW(&ExtLogFont.elfLogFont); + pData->hCaptionFont = CreateFontIndirectW(&LogFont); + LogFont.lfHeight = 12; + pData->hSizeFont = CreateFontIndirectW(&LogFont); Display_SetString(hwnd, (LPARAM)L"Jackdaws love my big sphinx of quartz. 1234567890"); - Display_SetTypeFace(hwnd, &ExtLogFont); + Display_SetTypeFace(hwnd, &LogFont); return 0; } @@ -520,7 +519,7 @@ return Display_OnVScroll(hwnd, wParam); case FVM_SETTYPEFACE: - return Display_SetTypeFace(hwnd, (PEXTLOGFONTW)lParam); + return Display_SetTypeFace(hwnd, (PLOGFONTW)lParam); case FVM_SETSTRING: return Display_SetString(hwnd, lParam); Index: reactos/base/applications/fontview/fontview.c =================================================================== --- reactos/base/applications/fontview/fontview.c (revision 73479) +++ reactos/base/applications/fontview/fontview.c (working copy) @@ -29,9 +29,12 @@ #include "fontview.h" #include "resource.h" -HINSTANCE g_hInstance; -EXTLOGFONTW g_ExtLogFontW; -LPCWSTR g_fileName; +HINSTANCE g_hInstance; +INT g_FontIndex = 0; +INT g_NumFonts; +LOGFONTW g_LogFonts[10]; +const INT g_MaxFonts = (INT)(sizeof(g_LogFonts) / sizeof(g_LogFonts[0])); +LPCWSTR g_fileName; static const WCHAR g_szFontViewClassName[] = L"FontViewWClass"; @@ -93,6 +96,7 @@ int nCmdShow) { int argc; + INT I; WCHAR** argv; WCHAR szFileName[MAX_PATH] = L""; DWORD dwSize; @@ -161,19 +165,21 @@ } /* Get the font name */ - dwSize = sizeof(g_ExtLogFontW.elfFullName); - if (!GetFontResourceInfoW(fileName, &dwSize, g_ExtLogFontW.elfFullName, 1)) + dwSize = sizeof(g_LogFonts); + ZeroMemory(g_LogFonts, dwSize); + if (!GetFontResourceInfoW(fileName, &dwSize, &g_LogFonts, 2)) { ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName); return -1; } + g_NumFonts = 0; + for (I = 0; I < g_MaxFonts; ++I) + { + if (g_LogFonts[I].lfFaceName[0] == 0) + break; - dwSize = sizeof(LOGFONTW); - if (!GetFontResourceInfoW(fileName, &dwSize, &g_ExtLogFontW.elfLogFont, 2)) - { - ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName); - return -1; - } + ++g_NumFonts; + } if (!Display_InitClass(hThisInstance)) { @@ -206,7 +212,7 @@ hMainWnd = CreateWindowExW( 0, /* Extended possibilities for variation */ g_szFontViewClassName, /* Classname */ - g_ExtLogFontW.elfFullName,/* Title Text */ + g_LogFonts[0].lfFaceName, /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ @@ -237,7 +243,9 @@ WCHAR szQuit[MAX_BUTTONNAME]; WCHAR szPrint[MAX_BUTTONNAME]; WCHAR szString[MAX_STRING]; - HWND hDisplay, hButtonInstall, hButtonPrint; + WCHAR szPrevious[MAX_STRING]; + WCHAR szNext[MAX_STRING]; + HWND hDisplay, hButtonInstall, hButtonPrint, hButtonPrev, hButtonNext; /* create the display window */ hDisplay = CreateWindowExW( @@ -258,10 +266,6 @@ LoadStringW(g_hInstance, IDS_STRING, szString, MAX_STRING); SendMessage(hDisplay, FVM_SETSTRING, 0, (LPARAM)szString); - /* Init the display window with the font name */ - SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_ExtLogFontW); - ShowWindow(hDisplay, SW_SHOWNORMAL); - /* Create the install button */ LoadStringW(g_hInstance, IDS_INSTALL, szQuit, MAX_BUTTONNAME); hButtonInstall = CreateWindowExW( @@ -298,6 +302,53 @@ ); SendMessage(hButtonPrint, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); + /* Create the previous button */ + LoadStringW(g_hInstance, IDS_PREVIOUS, szPrevious, MAX_BUTTONNAME); + hButtonPrev = CreateWindowExW( + 0, /* Extended style */ + L"button", /* Classname */ + szPrevious, /* Title text */ + WS_CHILD | WS_VISIBLE, /* Window style */ + 450, /* X-pos */ + BUTTON_POS_Y, /* Y-Pos */ + BUTTON_WIDTH, /* Width */ + BUTTON_HEIGHT, /* Height */ + hwnd, /* Parent */ + (HMENU)IDC_PREV, /* Identifier */ + g_hInstance, /* Program Instance handler */ + NULL /* Window Creation data */ + ); + SendMessage(hButtonPrev, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); + + /* Create the next button */ + LoadStringW(g_hInstance, IDS_NEXT, szNext, MAX_BUTTONNAME); + hButtonNext = CreateWindowExW( + 0, /* Extended style */ + L"button", /* Classname */ + szNext, /* Title text */ + WS_CHILD | WS_VISIBLE, /* Window style */ + 450, /* X-pos */ + BUTTON_POS_Y, /* Y-Pos */ + BUTTON_WIDTH, /* Width */ + BUTTON_HEIGHT, /* Height */ + hwnd, /* Parent */ + (HMENU)IDC_NEXT, /* Identifier */ + g_hInstance, /* Program Instance handler */ + NULL /* Window Creation data */ + ); + SendMessage(hButtonNext, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), (LPARAM)TRUE); + + if (g_NumFonts <= 1) + { + EnableWindow(hButtonPrev, FALSE); + EnableWindow(hButtonNext, FALSE); + } + + /* Init the display window with the font name */ + g_FontIndex = 0; + SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]); + ShowWindow(hDisplay, SW_SHOWNORMAL); + return 0; } @@ -304,12 +355,26 @@ static LRESULT MainWnd_OnSize(HWND hwnd) { - RECT rc; + RECT rc; + HWND hInstall, hPrint, hPrev, hNext, hDisplay; - GetClientRect(hwnd, &rc); - MoveWindow(GetDlgItem(hwnd, IDC_PRINT), rc.right - BUTTON_WIDTH - BUTTON_POS_X, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, TRUE); - MoveWindow(GetDlgItem(hwnd, IDC_DISPLAY), 0, HEADER_SIZE, rc.right, rc.bottom - HEADER_SIZE, TRUE); + GetClientRect(hwnd, &rc); + hInstall = GetDlgItem(hwnd, IDC_INSTALL); + MoveWindow(hInstall, BUTTON_POS_X, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, TRUE); + + hPrint = GetDlgItem(hwnd, IDC_PRINT); + MoveWindow(hPrint, BUTTON_POS_X + BUTTON_WIDTH + BUTTON_PADDING, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, TRUE); + + hPrev = GetDlgItem(hwnd, IDC_PREV); + MoveWindow(hPrev, rc.right - (BUTTON_WIDTH * 2 + BUTTON_PADDING + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, TRUE); + + hNext = GetDlgItem(hwnd, IDC_NEXT); + MoveWindow(hNext, rc.right - (BUTTON_WIDTH + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, TRUE); + + hDisplay = GetDlgItem(hwnd, IDC_DISPLAY); + MoveWindow(hDisplay, 0, HEADER_SIZE, rc.right, rc.bottom - HEADER_SIZE, TRUE); + return 0; } @@ -349,6 +414,42 @@ return 0; } +static LRESULT +MainWnd_OnPrev(HWND hwnd) +{ + HWND hDisplay; + if (g_FontIndex > 0) + { + --g_FontIndex; + EnableWindow(GetDlgItem(hwnd, IDC_NEXT), TRUE); + if (g_FontIndex == 0) + EnableWindow(GetDlgItem(hwnd, IDC_PREV), FALSE); + + hDisplay = GetDlgItem(hwnd, IDC_DISPLAY); + SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]); + InvalidateRect(hDisplay, NULL, TRUE); + } + return 0; +} + +static LRESULT +MainWnd_OnNext(HWND hwnd) +{ + HWND hDisplay; + if (g_FontIndex + 1 < g_NumFonts) + { + ++g_FontIndex; + EnableWindow(GetDlgItem(hwnd, IDC_PREV), TRUE); + if (g_FontIndex == g_NumFonts - 1) + EnableWindow(GetDlgItem(hwnd, IDC_NEXT), FALSE); + + hDisplay = GetDlgItem(hwnd, IDC_DISPLAY); + SendMessage(hDisplay, FVM_SETTYPEFACE, 0, (LPARAM)&g_LogFonts[g_FontIndex]); + InvalidateRect(hDisplay, NULL, TRUE); + } + return 0; +} + LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -368,11 +469,15 @@ { case IDC_INSTALL: return MainWnd_OnInstall(hwnd); - break; case IDC_PRINT: return Display_OnPrint(hwnd); - break; + + case IDC_PREV: + return MainWnd_OnPrev(hwnd); + + case IDC_NEXT: + return MainWnd_OnNext(hwnd); } break; Index: reactos/base/applications/fontview/fontview.h =================================================================== --- reactos/base/applications/fontview/fontview.h (revision 73479) +++ reactos/base/applications/fontview/fontview.h (working copy) @@ -8,11 +8,17 @@ #define BUTTON_POS_Y 8 #define BUTTON_WIDTH 72 #define BUTTON_HEIGHT 21 +#define BUTTON_PADDING 8 #define IDC_INSTALL 1001 #define IDC_PRINT 1002 #define IDC_DISPLAY 1003 +#define IDC_PREV 1004 +#define IDC_NEXT 1005 LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); BOOL LoadFont(LPWSTR lpCmdLine); + +extern INT g_FontIndex; +extern INT g_NumFonts; Index: reactos/base/applications/fontview/lang/bg-BG.rc =================================================================== --- reactos/base/applications/fontview/lang/bg-BG.rc (revision 73479) +++ reactos/base/applications/fontview/lang/bg-BG.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "Няма достатъчно място за завършване на действието." IDS_ERROR_NOFONT "%1 не е редовен шрифтов файл." IDS_ERROR_NOCLASS "Неуспешно изпълнение на класа на прозореца." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/cs-CZ.rc =================================================================== --- reactos/base/applications/fontview/lang/cs-CZ.rc (revision 73479) +++ reactos/base/applications/fontview/lang/cs-CZ.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "K dokončení operace není dostatek paměti." IDS_ERROR_NOFONT "Soubor %1 není platným souborem písma." IDS_ERROR_NOCLASS "Inicializace okna aplikace selhala." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/de-DE.rc =================================================================== --- reactos/base/applications/fontview/lang/de-DE.rc (revision 73479) +++ reactos/base/applications/fontview/lang/de-DE.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "Es steht nicht genügend Speicher zur Verfügung." IDS_ERROR_NOFONT "Die angegebene Datei %1 ist keine gültige Schriftartendatei." IDS_ERROR_NOCLASS "Fehler beim Initialisieren der Fensterklasse." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/en-US.rc =================================================================== --- reactos/base/applications/fontview/lang/en-US.rc (revision 73479) +++ reactos/base/applications/fontview/lang/en-US.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "There's not enough memory to complete the operation." IDS_ERROR_NOFONT "The file %1 is not a valid font file." IDS_ERROR_NOCLASS "Could not initialize window class." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/es-ES.rc =================================================================== --- reactos/base/applications/fontview/lang/es-ES.rc (revision 73479) +++ reactos/base/applications/fontview/lang/es-ES.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "No hay memoria suficiente para completar la operación." IDS_ERROR_NOFONT "El archivo %1 no es un archivo de fuente válido." IDS_ERROR_NOCLASS "No es posible iniciar la clase de ventana." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/fr-FR.rc =================================================================== --- reactos/base/applications/fontview/lang/fr-FR.rc (revision 73479) +++ reactos/base/applications/fontview/lang/fr-FR.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "Mémoire insuffisante pour terminer l'opération." IDS_ERROR_NOFONT "Le fichier %1 n'est pas un fichier police valide." IDS_ERROR_NOCLASS "Impossible d'initialiser la classe de fenêtre." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/he-IL.rc =================================================================== --- reactos/base/applications/fontview/lang/he-IL.rc (revision 73479) +++ reactos/base/applications/fontview/lang/he-IL.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "אין מספיק זיכרון כדי להשלים את הפעולה." IDS_ERROR_NOFONT "הקובץ %1 אינו קובץ גופנים חוקי." IDS_ERROR_NOCLASS "Could not initialize window class." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/it-IT.rc =================================================================== --- reactos/base/applications/fontview/lang/it-IT.rc (revision 73479) +++ reactos/base/applications/fontview/lang/it-IT.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "Memoria insufficiente per completare l'operazione." IDS_ERROR_NOFONT "Il file% 1 non è un file di origine valido." IDS_ERROR_NOCLASS "Impossibile avviare la classe." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/lt-LT.rc =================================================================== --- reactos/base/applications/fontview/lang/lt-LT.rc (revision 73479) +++ reactos/base/applications/fontview/lang/lt-LT.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "Užduočiai užbaigti, nepakanka atminties." IDS_ERROR_NOFONT "%1 nėra teisinga šrifto byla." IDS_ERROR_NOCLASS "Nepavyko inicijuoti lango klasės." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/ms-MY.rc =================================================================== --- reactos/base/applications/fontview/lang/ms-MY.rc (revision 73479) +++ reactos/base/applications/fontview/lang/ms-MY.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "Terdapat tidak cukup ingatan untuk melengkapkan operasi ini." IDS_ERROR_NOFONT "Fail %1 bukanlah fail fon yang sah." IDS_ERROR_NOCLASS "Tidak dapat mengawalkan kelas tetingkap." - IDS_FILTER_LIST "Semuanya disokong fon (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ -Fon TrueType (*.ttf)\0*.ttf\0\ -Fon OpenType (*.otf)\0*.otf\0\ -Fail fon (*.fon)\0*.fon\0\ -Semua fail (*.*)\0*.*\0" + IDS_FILTER_LIST "Semuanya disokong fon (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ +TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf)\0*.otf\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ +All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/no-NO.rc =================================================================== --- reactos/base/applications/fontview/lang/no-NO.rc (revision 73479) +++ reactos/base/applications/fontview/lang/no-NO.rc (working copy) @@ -10,9 +10,12 @@ IDS_ERROR_NOMEM "Det er ikke nok minne for å fullføre oppgaven." IDS_ERROR_NOFONT "Filen %1 er ikke et gyldig skriftfil." IDS_ERROR_NOCLASS "Kunne ikke initialise vindu klassen." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/pl-PL.rc =================================================================== --- reactos/base/applications/fontview/lang/pl-PL.rc (revision 73479) +++ reactos/base/applications/fontview/lang/pl-PL.rc (working copy) @@ -18,9 +18,12 @@ IDS_ERROR_NOMEM "Brakuje pamięci do ukończenia tej operacji." IDS_ERROR_NOFONT "Plik %1 nie jest poprawnym plikiem czcionki." IDS_ERROR_NOCLASS "Nie udało się zainicjować klasy window." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/pt-BR.rc =================================================================== --- reactos/base/applications/fontview/lang/pt-BR.rc (revision 73479) +++ reactos/base/applications/fontview/lang/pt-BR.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "Não há memória suficiente para completar a operação." IDS_ERROR_NOFONT "O arquivo %1 não é um arquivo de fonte válida." IDS_ERROR_NOCLASS "Não foi possível inicializar a janela." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/ro-RO.rc =================================================================== --- reactos/base/applications/fontview/lang/ro-RO.rc (revision 73479) +++ reactos/base/applications/fontview/lang/ro-RO.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "Nu e destulă memorie pentru a încheia operația." IDS_ERROR_NOFONT "Fișierul «%1» este un fișier font deteriorat." IDS_ERROR_NOCLASS "Clasa de ferestre nu a putut fi inițializată." - IDS_FILTER_LIST "Toate fonturile recunoscute (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "Toate fonturile recunoscute (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;.ttc;*.fon;*.otf\0\ Fonturi de tip TrueType (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ Fonturi de tip OpenType (*.otf)\0*.otf\0\ -Fișiere de tip Font (*.fon)\0*.fon\0\ +Fișiere de tip Font (*.fon;*.fnt)\0*.fon;*.fnt\0\ Orice fișier (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/ru-RU.rc =================================================================== --- reactos/base/applications/fontview/lang/ru-RU.rc (revision 73479) +++ reactos/base/applications/fontview/lang/ru-RU.rc (working copy) @@ -12,9 +12,12 @@ IDS_ERROR_NOMEM "Недостаточно памяти для выполнения операции." IDS_ERROR_NOFONT "%1 не является корректным файлом шрифта." IDS_ERROR_NOCLASS "Невозможно инициализировать класс окна." - IDS_FILTER_LIST "Все поддерживаемые шрифты (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "Все поддерживаемые шрифты (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType шрифты (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType шрифты (*.otf)\0*.otf\0\ -Файлы шрифтов (*.fon)\0*.fon\0\ +Файлы шрифтов (*.fon;*.fnt)\0*.fon;*.fnt\0\ Все файлы (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/sk-SK.rc =================================================================== --- reactos/base/applications/fontview/lang/sk-SK.rc (revision 73479) +++ reactos/base/applications/fontview/lang/sk-SK.rc (working copy) @@ -15,9 +15,12 @@ IDS_ERROR_NOMEM "Na vykonanie tejto operácie nie je dostatok voľnej pamäte." IDS_ERROR_NOFONT "Požadovaný súbor %1 nie je platným súborom písiem." IDS_ERROR_NOCLASS "Nepodarilo sa inicializovať triedu window." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/sq-AL.rc =================================================================== --- reactos/base/applications/fontview/lang/sq-AL.rc (revision 73479) +++ reactos/base/applications/fontview/lang/sq-AL.rc (working copy) @@ -14,9 +14,12 @@ IDS_ERROR_NOMEM "Nuk ka memorie të mjaftueshme për të përfunduar operacionin." IDS_ERROR_NOFONT "Dokumenti %1 nuk është një font i vlefshem." IDS_ERROR_NOCLASS "Nuk mund të fillojë dritaren e klases." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/sv-SE.rc =================================================================== --- reactos/base/applications/fontview/lang/sv-SE.rc (revision 73479) +++ reactos/base/applications/fontview/lang/sv-SE.rc (working copy) @@ -17,9 +17,12 @@ IDS_ERROR_NOMEM "Det er inte nog minne för att slutföre operationen." IDS_ERROR_NOFONT "Filen %1 är inte en giltig typsnittsfil." IDS_ERROR_NOCLASS "Kunde inte initialisera Windows klassen." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/tr-TR.rc =================================================================== --- reactos/base/applications/fontview/lang/tr-TR.rc (revision 73479) +++ reactos/base/applications/fontview/lang/tr-TR.rc (working copy) @@ -11,9 +11,12 @@ IDS_ERROR_NOMEM "Bu işlemi bitirmek için yeterli bellek yok." IDS_ERROR_NOFONT "%1 kütüğü, geçerli bir yazı tipi kütüğü değil." IDS_ERROR_NOCLASS "Pencere sınıfı başlatılamadı." - IDS_FILTER_LIST "Tüm Desteklenen Yazı Tipleri (*.ttf, *.fon, *.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "Tüm Desteklenen Yazı Tipleri (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Yazı Tipi (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Yazı Tipi (*.otf)\0*.otf\0\ -Yazı Tipi Kütüğü (*.fon)\0*.fon\0\ +Yazı Tipi Kütüğü (*.fon;*.fnt)\0*.fon;*.fnt\0\ Tüm Kütükler (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/uk-UA.rc =================================================================== --- reactos/base/applications/fontview/lang/uk-UA.rc (revision 73479) +++ reactos/base/applications/fontview/lang/uk-UA.rc (working copy) @@ -18,9 +18,12 @@ IDS_ERROR_NOMEM "Недостатньо пам'яті для завершення операції." IDS_ERROR_NOFONT "Файл %1 не є коректним файлом шрифту." IDS_ERROR_NOCLASS "Неможливо ініціалізувати віконний клас." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/zh-CN.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-CN.rc (revision 73479) +++ reactos/base/applications/fontview/lang/zh-CN.rc (working copy) @@ -18,9 +18,12 @@ IDS_ERROR_NOMEM "没有足够的内存来完成操作。" IDS_ERROR_NOFONT "%1不是一个有效的字体档案。" IDS_ERROR_NOCLASS "窗口无法初始化。" - IDS_FILTER_LIST "支持所有的字体 (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "支持所有的字体 (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType 字体 (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType 字体 (*.otf)\0*.otf\0\ -字体文件 (*.fon)\0*.fon\0\ +字体文件 (*.fon;*.fnt)\0*.fon;*.fnt\0\ 所有文件 (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/lang/zh-TW.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-TW.rc (revision 73479) +++ reactos/base/applications/fontview/lang/zh-TW.rc (working copy) @@ -18,9 +18,12 @@ IDS_ERROR_NOMEM "沒有足夠的記憶體來完成操作。" IDS_ERROR_NOFONT "%1 不是一個有效的字體檔案。" IDS_ERROR_NOCLASS "窗口無法初始化。" - IDS_FILTER_LIST "所有支援的字體 (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "所有支援的字體 (*.ttf;*.ttc;*.fon;*.fnt;*.otf)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf\0\ TrueType 字體 (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType 字體 (*.otf)\0*.otf\0\ -字體檔 (*.fon)\0*.fon\0\ +字體檔 (*.fon;*.fnt)\0*.fon;*.fnt\0\ 所有檔 (*.*)\0*.*\0" + IDS_PREVIOUS "< Previous" + IDS_NEXT "Next >" END Index: reactos/base/applications/fontview/resource.h =================================================================== --- reactos/base/applications/fontview/resource.h (revision 73479) +++ reactos/base/applications/fontview/resource.h (working copy) @@ -15,4 +15,7 @@ #define IDS_CHARSUPPER 701 #define IDS_SPECIALCHARS 702 +#define IDS_PREVIOUS 800 +#define IDS_NEXT 801 + #define IDI_TT 800 Index: reactos/boot/bootdata/hivecls.inf =================================================================== --- reactos/boot/bootdata/hivecls.inf (revision 73479) +++ reactos/boot/bootdata/hivecls.inf (working copy) @@ -121,19 +121,25 @@ HKCR,"fonfile","",0x00000000,"Font file" HKCR,"fonfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-209" HKCR,"fonfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-155" -HKCR,"fonfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"fonfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" HKCR,".ttf","",0x00000000,"ttffile" HKCR,"ttffile","",0x00000000,"TrueType Font file" HKCR,"ttffile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-210" HKCR,"ttffile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" -HKCR,"ttffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"ttffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" +HKCR,".ttc","",0x00000000,"ttcfile" +HKCR,"ttcfile","",0x00000000,"TrueType Font Collection file" +HKCR,"ttcfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-210" +HKCR,"ttcfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" +HKCR,"ttcfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" + HKCR,".otf","",0x00000000,"otffile" HKCR,"otffile","",0x00000000,"OpenType Font file" HKCR,"otffile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-211" HKCR,"otffile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" -HKCR,"otffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"otffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" ; Help Files HKCR,".hlp","",0x00000000,"hlpfile" Index: reactos/win32ss/gdi/eng/engobjects.h =================================================================== --- reactos/win32ss/gdi/eng/engobjects.h (revision 73479) +++ reactos/win32ss/gdi/eng/engobjects.h (working copy) @@ -107,15 +107,19 @@ ULONG Dummy; } FLOATGDI; +typedef struct _SHARED_FACE { + FT_Face Face; + LONG RefCount; +} SHARED_FACE, *PSHARED_FACE; + typedef struct _FONTGDI { FONTOBJ FontObj; ULONG iUnique; FLONG flType; - union{ - DHPDEV dhpdev; - FT_Face face; - }; + DHPDEV dhpdev; + PSHARED_FACE SharedFace; + LONG lMaxNegA; LONG lMaxNegC; LONG lMinWidthD; @@ -123,6 +127,9 @@ LPWSTR Filename; BYTE Underline; BYTE StrikeOut; + BYTE Italic; + LONG Weight; + BYTE CharSet; } FONTGDI, *PFONTGDI; typedef struct _PATHGDI { Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 73479) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -3,8 +3,9 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: win32ss/gdi/ntgdi/freetype.c * PURPOSE: FreeType font engine interface - * PROGRAMMER: Copyright 2001 Huw D M Davies for CodeWeavers. + * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers. * Copyright 2006 Dmitry Timoshkov for CodeWeavers. + * Copyright 2016 Katayama Hirofumi MZ. */ /** Includes ******************************************************************/ @@ -19,6 +20,12 @@ #include FT_OUTLINE_H #include FT_WINFONTS_H +#ifndef FT_INTERNAL_INTERNAL_H + #define FT_INTERNAL_INTERNAL_H + #include FT_INTERNAL_INTERNAL_H +#endif +#include FT_INTERNAL_TRUETYPE_TYPES_H + #include #define NDEBUG @@ -30,6 +37,11 @@ ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) ) #endif +/* TPMF_FIXED_PITCH is confusing; braindead api */ +#ifndef _TMPF_VARIABLE_PITCH + #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH +#endif + extern const MATRIX gmxWorldToDeviceDefault; extern const MATRIX gmxWorldToPageDefault; @@ -38,6 +50,40 @@ FT_Library library; +static PSHARED_FACE +SharedFace_Create(FT_Face Face) +{ + PSHARED_FACE Ptr; + Ptr = (PSHARED_FACE)ExAllocatePoolWithTag(PagedPool, + sizeof(SHARED_FACE), TAG_FONT); + if (Ptr) + { + Ptr->Face = Face; + Ptr->RefCount = 1; + } + return Ptr; +} + +static void +SharedFace_AddRef(PSHARED_FACE Ptr) +{ + ++Ptr->RefCount; +} + +static void +SharedFace_Release(PSHARED_FACE Ptr) +{ + if (Ptr->RefCount <= 0) + return; + + --Ptr->RefCount; + if (Ptr->RefCount == 0) + { + FT_Done_Face(Ptr->Face); + ExFreePoolWithTag(Ptr, TAG_FONT); + } +} + typedef struct _FONT_ENTRY { LIST_ENTRY ListEntry; @@ -223,7 +269,7 @@ IntLoadSystemFonts(VOID) { OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING Directory, SearchPattern, FileName, TempString; + UNICODE_STRING Directory, SearchPatterns[5], FileName, TempString; IO_STATUS_BLOCK Iosb; HANDLE hDirectory; BYTE *DirInfoBuffer; @@ -230,11 +276,17 @@ PFILE_DIRECTORY_INFORMATION DirInfo; BOOLEAN bRestartScan = TRUE; NTSTATUS Status; + INT I; + const INT NUM_PATTERNS = (INT)_countof(SearchPatterns); RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\"); - /* FIXME: Add support for other font types */ - RtlInitUnicodeString(&SearchPattern, L"*.ttf"); + RtlInitUnicodeString(&SearchPatterns[0], L"*.ttf"); + RtlInitUnicodeString(&SearchPatterns[1], L"*.ttc"); + RtlInitUnicodeString(&SearchPatterns[2], L"*.otf"); + RtlInitUnicodeString(&SearchPatterns[3], L"*.fon"); + RtlInitUnicodeString(&SearchPatterns[4], L"*.fnt"); + InitializeObjectAttributes( &ObjectAttributes, &Directory, @@ -252,198 +304,241 @@ if (NT_SUCCESS(Status)) { - DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); - if (DirInfoBuffer == NULL) + for (I = 0; I < NUM_PATTERNS; ++I) { - ZwClose(hDirectory); - return; - } + DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); + if (DirInfoBuffer == NULL) + { + ZwClose(hDirectory); + return; + } - FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); - if (FileName.Buffer == NULL) - { - ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); - ZwClose(hDirectory); - return; - } - FileName.Length = 0; - FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); - - while (1) - { - Status = ZwQueryDirectoryFile( - hDirectory, - NULL, - NULL, - NULL, - &Iosb, - DirInfoBuffer, - 0x4000, - FileDirectoryInformation, - FALSE, - &SearchPattern, - bRestartScan); - - if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) + FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); + if (FileName.Buffer == NULL) { - break; + ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); + ZwClose(hDirectory); + return; } + FileName.Length = 0; + FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); - DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; while (1) { - TempString.Buffer = DirInfo->FileName; - TempString.Length = - TempString.MaximumLength = DirInfo->FileNameLength; - RtlCopyUnicodeString(&FileName, &Directory); - RtlAppendUnicodeStringToString(&FileName, &TempString); - IntGdiAddFontResource(&FileName, 0); - if (DirInfo->NextEntryOffset == 0) + Status = ZwQueryDirectoryFile( + hDirectory, + NULL, + NULL, + NULL, + &Iosb, + DirInfoBuffer, + 0x4000, + FileDirectoryInformation, + FALSE, + &SearchPatterns[I], + bRestartScan); + + if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) + { break; - DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); + } + + DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; + while (1) + { + TempString.Buffer = DirInfo->FileName; + TempString.Length = + TempString.MaximumLength = DirInfo->FileNameLength; + RtlCopyUnicodeString(&FileName, &Directory); + RtlAppendUnicodeStringToString(&FileName, &TempString); + IntGdiAddFontResource(&FileName, 0); + if (DirInfo->NextEntryOffset == 0) + break; + DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); + } + + bRestartScan = FALSE; } - bRestartScan = FALSE; + ExFreePoolWithTag(FileName.Buffer, TAG_FONT); + ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); } - - ExFreePoolWithTag(FileName.Buffer, TAG_FONT); - ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); ZwClose(hDirectory); } } - -/* - * IntGdiAddFontResource - * - * Adds the font resource from the specified file to the system. - */ - -INT FASTCALL -IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) +static INT FASTCALL +IntGdiLoadFontsFromMemory(PUNICODE_STRING FileName, PVOID Buffer, ULONG BufferSize, + PVOID SectionObject, DWORD Characteristics, + PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex) { - FONTGDI *FontGDI; - NTSTATUS Status; - HANDLE FileHandle, KeyHandle; - OBJECT_ATTRIBUTES ObjectAttributes; - PVOID Buffer = NULL; - IO_STATUS_BLOCK Iosb; - INT Error; - FT_Face Face; - ANSI_STRING AnsiFaceName; - PFONT_ENTRY Entry; - PVOID SectionObject; - ULONG ViewSize = 0; - LARGE_INTEGER SectionSize; - UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); + FT_Error Error; + PFONT_ENTRY Entry; + FONTGDI * FontGDI; + NTSTATUS Status; + HANDLE KeyHandle; + FT_Face Face; + ANSI_STRING AnsiFaceName; + ANSI_STRING FaceNameA; + UNICODE_STRING FaceNameW; + OBJECT_ATTRIBUTES ObjectAttributes; + FT_WinFNT_HeaderRec WinFNT; + TT_OS2 * pOS2; + INT Count = 0, CharSetCount = 0; + static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett"); + static UNICODE_STRING FontRegPath = + RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); - /* Open the font file */ - - InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL); - Status = ZwOpenFile( - &FileHandle, - FILE_GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &Iosb, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - - if (!NT_SUCCESS(Status)) + if (SharedFace == NULL && CharSetIndex == -1) { - DPRINT("Could not load font file: %wZ\n", FileName); - return 0; - } + /* load a face from memory */ + IntLockFreeType; + Error = FT_New_Memory_Face( + library, + Buffer, + BufferSize, + ((FontIndex != -1) ? FontIndex : 0), + &Face); + IntUnLockFreeType; - SectionSize.QuadPart = 0LL; - Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS, - NULL, &SectionSize, PAGE_READONLY, - SEC_COMMIT, FileHandle, NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not map file: %wZ\n", FileName); - ZwClose(FileHandle); - return 0; + if (!Error) + SharedFace = SharedFace_Create(Face); + if (Error || SharedFace == NULL) + { + if (Error == FT_Err_Unknown_File_Format) + DPRINT("Unknown font file format\n"); + else + DPRINT("Error reading font file (error code: %d)\n", Error); + if (SectionObject) + ObDereferenceObject(SectionObject); + return 0; /* failure */ + } } - - ZwClose(FileHandle); - - Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize); - if (!NT_SUCCESS(Status)) + else { - DPRINT("Could not map file: %wZ\n", FileName); - ObDereferenceObject(SectionObject); - return 0; + Face = SharedFace->Face; + SharedFace_AddRef(SharedFace); } - IntLockFreeType; - Error = FT_New_Memory_Face( - library, - Buffer, - ViewSize, - 0, - &Face); - IntUnLockFreeType; - ObDereferenceObject(SectionObject); - - if (Error) - { - if (Error == FT_Err_Unknown_File_Format) - DPRINT("Unknown font file format\n"); - else - DPRINT("Error reading font file (error code: %d)\n", Error); - return 0; - } - + /* allocate a FONT_ENTRY */ Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT); if (!Entry) { - FT_Done_Face(Face); + SharedFace_Release(SharedFace); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + if (SectionObject) + ObDereferenceObject(SectionObject); + return 0; /* failure */ } + /* allocate a FONTGDI */ FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT); if (FontGDI == NULL) { - FT_Done_Face(Face); + SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + if (SectionObject) + ObDereferenceObject(SectionObject); + return 0; /* failure */ } - FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), GDITAG_PFF); + /* set file name */ + FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, + FileName->Length + sizeof(WCHAR), + GDITAG_PFF); if (FontGDI->Filename == NULL) { EngFreeMem(FontGDI); - FT_Done_Face(Face); + SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; + if (SectionObject) + ObDereferenceObject(SectionObject); + return 0; /* failure */ } RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length); FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0'; - FontGDI->face = Face; + /* set face */ + FontGDI->SharedFace = SharedFace; + FontGDI->CharSet = ANSI_CHARSET; + + /* check if Marlett */ + RtlInitAnsiString(&FaceNameA, Face->family_name); + Status = RtlAnsiStringToUnicodeString(&FaceNameW, &FaceNameA, TRUE); + if (NT_SUCCESS(Status)) + { + if (RtlCompareUnicodeString(&FaceNameW, &MarlettW, TRUE) == 0) + { + FontGDI->CharSet = SYMBOL_CHARSET; + } + RtlFreeUnicodeString(&FaceNameW); + } + + if (FontGDI->CharSet == ANSI_CHARSET) + { + /* get charset from OS/2 header */ + IntLockFreeType; + pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); + IntUnLockFreeType; + if (pOS2 && pOS2->version >= 1) + { + INT BitIndex; + for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex) + { + if (pOS2->ulCodePageRange1 & (1 << BitIndex)) + { + if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET) + continue; + + if ((CharSetIndex == -1 && CharSetCount == 0) || + CharSetIndex == CharSetCount) + { + FontGDI->CharSet = FontTci[BitIndex].ciCharset; + } + + ++CharSetCount; + } + } + } + else + { + /* get charset from WinFNT header */ + IntLockFreeType; + Error = FT_Get_WinFNT_Header(Face, &WinFNT); + IntUnLockFreeType; + if (!Error) + { + FontGDI->CharSet = WinFNT.charset; + } + } + } + + ++Count; DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name); DPRINT("Num glyphs: %d\n", Face->num_glyphs); + DPRINT("CharSet: %d\n", FontGDI->CharSet); /* Add this font resource to the font table */ - Entry->Font = FontGDI; Entry->NotEnum = (Characteristics & FR_NOT_ENUM); - RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name); + RtlInitAnsiString(&AnsiFaceName, Face->family_name); Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE); if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); EngFreeMem(FontGDI); - FT_Done_Face(Face); + SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); + if (SectionObject) + ObDereferenceObject(SectionObject); return 0; } if (Characteristics & FR_PRIVATE) { + /* private font */ PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); IntLockProcessPrivateFonts(Win32Process); InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry); @@ -451,25 +546,135 @@ } else { + /* global font */ IntLockGlobalFonts; InsertTailList(&FontListHead, &Entry->ListEntry); - InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + /* registry */ + /* FIXME: For *.ttc, please concatnate names by " & ". */ + /* FIXME: For TrueType, please add " (TrueType)" to the end of name. */ + /* NOTE: We can write registry later, not here */ + InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); if (NT_SUCCESS(Status)) { + ULONG DataSize; LPWSTR pName = wcsrchr(FileName->Buffer, L'\\'); if (pName) { pName++; - ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR)); + DataSize = (wcslen(pName) + 1) * sizeof(WCHAR); + ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, DataSize); } ZwClose(KeyHandle); } IntUnLockGlobalFonts; } - return 1; + + if (FontIndex == -1) + { + if (FT_IS_SFNT(Face)) + { + TT_Face TrueType = (TT_Face)Face; + if (TrueType->ttc_header.count > 1) + { + FT_Long I; + for (I = 1; I < TrueType->ttc_header.count; ++I) + { + Count += IntGdiLoadFontsFromMemory( + FileName, Buffer, BufferSize, NULL, Characteristics, + NULL, I, -1); + } + } + } + FontIndex = 0; + } + + if (CharSetIndex == -1) + { + INT I; + for (I = 1; I < CharSetCount; ++I) + { + Count += IntGdiLoadFontsFromMemory( + FileName, Buffer, BufferSize, NULL, Characteristics, + SharedFace, FontIndex, I); + } + } + + if (SectionObject) + { + /* now release the section */ + ObDereferenceObject(SectionObject); + } + + return Count; /* number of loaded fonts */ } +/* + * IntGdiAddFontResource + * + * Adds the font resource from the specified file to the system. + */ + +INT FASTCALL +IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) +{ + NTSTATUS Status; + HANDLE FileHandle; + PVOID Buffer = NULL; + IO_STATUS_BLOCK Iosb; + PVOID SectionObject; + ULONG ViewSize = 0; + LARGE_INTEGER SectionSize; + OBJECT_ATTRIBUTES ObjectAttributes; + + /* Open the font file */ + + InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL); + Status = ZwOpenFile( + &FileHandle, + FILE_GENERIC_READ | SYNCHRONIZE, + &ObjectAttributes, + &Iosb, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); + + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not load font file: %wZ\n", FileName); + return 0; + } + + SectionSize.QuadPart = 0LL; + Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS, + NULL, &SectionSize, PAGE_READONLY, + SEC_COMMIT, FileHandle, NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not map file: %wZ\n", FileName); + ZwClose(FileHandle); + return 0; + } + + ZwClose(FileHandle); + + Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize); + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not map file: %wZ\n", FileName); + ObDereferenceObject(SectionObject); + return 0; + } + + return IntGdiLoadFontsFromMemory(FileName, Buffer, ViewSize, + SectionObject, Characteristics, + NULL, -1, -1); +} + +// FIXME: Add RemoveFontResource + BOOL FASTCALL IntIsFontRenderingEnabled(VOID) { @@ -603,12 +808,13 @@ return FALSE; } + static void FASTCALL FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin) { FT_Fixed XScale, YScale; int Ascent, Descent; - FT_Face Face = FontGDI->face; + FT_Face Face = FontGDI->SharedFace->Face; XScale = Face->size->metrics.x_scale; YScale = Face->size->metrics.y_scale; @@ -622,7 +828,7 @@ TM->tmExternalLeading = pWin->external_leading; TM->tmAveCharWidth = pWin->avg_width; TM->tmMaxCharWidth = pWin->max_width; - TM->tmWeight = pWin->weight; + TM->tmWeight = FontGDI->Weight; TM->tmOverhang = 0; TM->tmDigitizedAspectX = pWin->horizontal_resolution; TM->tmDigitizedAspectY = pWin->vertical_resolution; @@ -630,11 +836,11 @@ TM->tmLastChar = pWin->last_char; TM->tmDefaultChar = pWin->default_char + pWin->first_char; TM->tmBreakChar = pWin->break_char + pWin->first_char; - TM->tmItalic = pWin->italic; + TM->tmItalic = FontGDI->Italic; TM->tmUnderlined = FontGDI->Underline; TM->tmStruckOut = FontGDI->StrikeOut; TM->tmPitchAndFamily = pWin->pitch_and_family; - TM->tmCharSet = pWin->charset; + TM->tmCharSet = FontGDI->CharSet; return; } @@ -677,7 +883,7 @@ /* Correct forumla to get the maxcharwidth from unicode and ansi font */ TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6; - TM->tmWeight = pOS2->usWeightClass; + TM->tmWeight = FontGDI->Weight; TM->tmOverhang = 0; TM->tmDigitizedAspectX = 96; TM->tmDigitizedAspectY = 96; @@ -711,14 +917,13 @@ TM->tmBreakChar = pOS2->usFirstCharIndex; TM->tmDefaultChar = TM->tmBreakChar - 1; } - TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0; + TM->tmItalic = FontGDI->Italic; TM->tmUnderlined = FontGDI->Underline; TM->tmStruckOut = FontGDI->StrikeOut; - /* Yes TPMF_FIXED_PITCH is correct; braindead api */ - if (! FT_IS_FIXED_WIDTH(Face)) + if (!FT_IS_FIXED_WIDTH(Face)) { - TM->tmPitchAndFamily = TMPF_FIXED_PITCH; + TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH; } else { @@ -788,7 +993,7 @@ TM->tmPitchAndFamily |= TMPF_TRUETYPE; } - TM->tmCharSet = DEFAULT_CHARSET; + TM->tmCharSet = FontGDI->CharSet; } /************************************************************* @@ -811,10 +1016,11 @@ FT_Error Error; char *Cp; NTSTATUS status; + FT_Face Face = FontGDI->SharedFace->Face; Needed = sizeof(OUTLINETEXTMETRICW); - RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name); + RtlInitAnsiString(&FamilyNameA, Face->family_name); status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -821,7 +1027,7 @@ return 0; } - RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name); + RtlInitAnsiString(&StyleNameA, Face->style_name); status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -858,11 +1064,11 @@ return Needed; } - XScale = FontGDI->face->size->metrics.x_scale; - YScale = FontGDI->face->size->metrics.y_scale; + XScale = Face->size->metrics.x_scale; + YScale = Face->size->metrics.y_scale; IntLockFreeType; - pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); + pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); if (NULL == pOS2) { IntUnLockFreeType; @@ -872,7 +1078,7 @@ return 0; } - pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea); + pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea); if (NULL == pHori) { IntUnLockFreeType; @@ -882,9 +1088,9 @@ return 0; } - pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* We can live with this failing */ + pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */ - Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); + Error = FT_Get_WinFNT_Header(Face , &Win); Otm->otmSize = Needed; @@ -897,16 +1103,16 @@ Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise; Otm->otmsCharSlopeRun = pHori->caret_Slope_Run; Otm->otmItalicAngle = 0; /* POST table */ - Otm->otmEMSquare = FontGDI->face->units_per_EM; + Otm->otmEMSquare = Face->units_per_EM; Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6; Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6; Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6; Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6; Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6; - Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6; - Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6; - Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6; - Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6; + Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6; + Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6; + Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6; + Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6; Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent; Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent; Otm->otmMacLineGap = Otm->otmLineGap; @@ -983,7 +1189,7 @@ FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); + RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name); status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -1048,6 +1254,7 @@ NEWTEXTMETRICW *Ntm; DWORD fs0; NTSTATUS status; + FT_Face Face = FontGDI->SharedFace->Face; RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); @@ -1116,7 +1323,7 @@ RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, sizeof(Info->EnumLogFontEx.elfFullName), FaceName); - RtlInitAnsiString(&StyleA, FontGDI->face->style_name); + RtlInitAnsiString(&StyleA, Face->style_name); StyleW.Buffer = Info->EnumLogFontEx.elfStyle; StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle); status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE); @@ -1128,7 +1335,7 @@ Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET; Info->EnumLogFontEx.elfScript[0] = L'\0'; IntLockFreeType; - pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); + pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); IntUnLockFreeType; if (NULL != pOS2) { @@ -1143,7 +1350,7 @@ { FT_UInt Dummy; - if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100) + if (FT_Get_First_Char(Face, &Dummy) < 0x100) fs.fsCsb[0] |= FS_LATIN1; else fs.fsCsb[0] |= FS_SYMBOL; @@ -1150,9 +1357,9 @@ } if (fs.fsCsb[0] == 0) { /* Let's see if we can find any interesting cmaps */ - for (i = 0; i < (UINT)FontGDI->face->num_charmaps; i++) + for (i = 0; i < (UINT)Face->num_charmaps; i++) { - switch (FontGDI->face->charmaps[i]->encoding) + switch (Face->charmaps[i]->encoding) { case FT_ENCODING_UNICODE: case FT_ENCODING_APPLE_ROMAN: @@ -1247,7 +1454,7 @@ FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); + RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name); status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -1802,7 +2009,7 @@ return GDI_ERROR; } FontGDI = ObjToGDI(TextObj->Font, FONT); - ft_face = FontGDI->face; + ft_face = FontGDI->SharedFace->Face; aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0; orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0; @@ -2271,7 +2478,7 @@ FontGDI = ObjToGDI(TextObj->Font, FONT); - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (NULL != Fit) { *Fit = 0; @@ -2424,7 +2631,7 @@ return Ret; } FontGdi = ObjToGDI(TextObj->Font, FONT); - Face = FontGdi->face; + Face = FontGdi->SharedFace->Face; TEXTOBJ_UnlockText(TextObj); IntLockFreeType; @@ -2512,7 +2719,7 @@ { DWORD size = 0; DWORD num_ranges = 0; - FT_Face face = Font->face; + FT_Face face = Font->SharedFace->Face; if (face->charmap->encoding == FT_ENCODING_UNICODE) { @@ -2608,7 +2815,7 @@ { FontGDI = ObjToGDI(TextObj->Font, FONT); - Face = FontGDI->face; + Face = FontGDI->SharedFace->Face; IntLockFreeType; Error = FT_Set_Pixel_Sizes(Face, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, @@ -2624,10 +2831,11 @@ } else { + FT_Face Face = FontGDI->SharedFace->Face; Status = STATUS_SUCCESS; IntLockFreeType; - pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); + pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); if (NULL == pOS2) { DPRINT1("Can't find OS/2 table - not TT font?\n"); @@ -2634,7 +2842,7 @@ Status = STATUS_INTERNAL_ERROR; } - pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea); + pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea); if (NULL == pHori) { DPRINT1("Can't find HHEA table - not TT font?\n"); @@ -2641,7 +2849,7 @@ Status = STATUS_INTERNAL_ERROR; } - Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); + Error = FT_Get_WinFNT_Header(Face, &Win); IntUnLockFreeType; @@ -2680,10 +2888,11 @@ DWORD Size) { DWORD Result = GDI_ERROR; + FT_Face Face = FontGdi->SharedFace->Face; IntLockFreeType; - if (FT_IS_SFNT(FontGdi->face)) + if (FT_IS_SFNT(Face)) { if (Table) Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) | @@ -2696,11 +2905,11 @@ FT_Error Error; FT_ULong Needed = 0; - Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed); + Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed); if ( !Error && Needed < Size) Size = Needed; } - if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size)) + if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size)) Result = Size; } @@ -2709,172 +2918,415 @@ return Result; } -static UINT FASTCALL -GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI) +static __inline BOOLEAN +SubstituteFontNameByKey(PUNICODE_STRING FaceName, + LPCWSTR Key) { - ANSI_STRING EntryFaceNameA; - UNICODE_STRING EntryFaceNameW; - unsigned Size; - OUTLINETEXTMETRICW *Otm; - LONG WeightDiff; + RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; NTSTATUS Status; - UINT Score = 1; + UNICODE_STRING Value; - RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); - Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); + RtlInitUnicodeString(&Value, NULL); + + QueryTable[0].QueryRoutine = NULL; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | + RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Name = FaceName->Buffer; + QueryTable[0].EntryContext = &Value; + QueryTable[0].DefaultType = REG_NONE; + QueryTable[0].DefaultData = NULL; + QueryTable[0].DefaultLength = 0; + + QueryTable[1].QueryRoutine = NULL; + QueryTable[1].Name = NULL; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, + Key, + QueryTable, + NULL, + NULL); if (NT_SUCCESS(Status)) { - static const UNICODE_STRING MarlettFaceNameW = RTL_CONSTANT_STRING(L"Marlett"); - static const UNICODE_STRING SymbolFaceNameW = RTL_CONSTANT_STRING(L"Symbol"); - static const UNICODE_STRING VGAFaceNameW = RTL_CONSTANT_STRING(L"VGA"); + RtlFreeUnicodeString(FaceName); + *FaceName = Value; - if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + /* truncate */ + if ((LF_FACESIZE - 1) * sizeof(WCHAR) < FaceName->Length) { - EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); - EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; + FaceName->Length = (LF_FACESIZE - 1) * sizeof(WCHAR); + FaceName->Buffer[LF_FACESIZE - 1] = L'\0'; } + } - if (!RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) + return NT_SUCCESS(Status); +} + +static __inline void +SubstituteFontName(PUNICODE_STRING FaceName) +{ + UINT Level; + const UINT MaxLevel = 10; + + if (FaceName->Buffer[0] == 0) + return; + + for (Level = 0; Level < MaxLevel; ++Level) + { + /* NOTE: SubstituteFontNameByKey changes FaceName. Be careful... */ + if (!SubstituteFontNameByKey(FaceName, L"FontSubstitutes")) + break; + } +} + +static BYTE +CharSetFromLangID(LANGID LangID) +{ + LangID = PRIMARYLANGID(LangID); + switch (LangID) + { + case LANG_ARABIC: return ARABIC_CHARSET; + case LANG_CHINESE: + switch (SUBLANGID(LangID)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + return GB2312_CHARSET; + case SUBLANG_CHINESE_TRADITIONAL: + return CHINESEBIG5_CHARSET; + } + break; + case LANG_ENGLISH: return ANSI_CHARSET; + case LANG_GREEK: return GREEK_CHARSET; + case LANG_HEBREW: return HEBREW_CHARSET; + case LANG_JAPANESE: return SHIFTJIS_CHARSET; + case LANG_KOREAN: return HANGUL_CHARSET; + case LANG_RUSSIAN: + case LANG_BULGARIAN: + case LANG_MACEDONIAN: + case LANG_SERBIAN: + case LANG_UKRAINIAN: + return RUSSIAN_CHARSET; + case LANG_CZECH: + case LANG_HUNGARIAN: + case LANG_POLISH: + case LANG_ROMANIAN: + case LANG_SLOVAK: + case LANG_SLOVENIAN: + return EASTEUROPE_CHARSET; + case LANG_THAI: return THAI_CHARSET; + case LANG_LATVIAN: return BALTIC_CHARSET; + case LANG_TURKISH: return TURKISH_CHARSET; + case LANG_VIETNAMESE: return VIETNAMESE_CHARSET; + /* FIXME: Add more and fix if wrong */ + default: break; + } + return ANSI_CHARSET; +} + +static UINT FASTCALL +GetFontPenalty(LOGFONTW * LogFont, + PUNICODE_STRING RequestedNameW, + PUNICODE_STRING ActualNameW, + PFONTGDI FontGDI, + OUTLINETEXTMETRICW * Otm, + TEXTMETRICW * TM) +{ + ULONG Penalty = 0; + BYTE Byte; + static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System"); + + // is request "System" font? + if (RtlCompareUnicodeString(RequestedNameW, &SystemW, TRUE) == 0) + { + /* Penalty += 65000: lfCharSet: not current charset */ + if (TM->tmCharSet != CharSetFromLangID(gusLanguageID)) + Penalty += 65000; + + /* Penalty += 10: system font should be fixed-pitch */ + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) + Penalty += 10; + } + else /* Request is non-"System" font */ + { + if (LogFont->lfCharSet != DEFAULT_CHARSET && + LogFont->lfCharSet != ANSI_CHARSET) { - Score += 49; + /* Penalty += 65000: lfCharSet: mismatched */ + if (LogFont->lfCharSet != TM->tmCharSet) + Penalty += 65000; } + } - /* FIXME: this is a work around to counter weird fonts on weird places. - A proper fix would be to score fonts on more attributes than - the ones in this function */ - if (!RtlCompareUnicodeString(&MarlettFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&MarlettFaceNameW, FaceName, TRUE)) + /* if face name is set */ + if (RequestedNameW->Buffer[0]) + { + if (RtlCompareUnicodeString(RequestedNameW, ActualNameW, TRUE) != 0) { - Score = 0; + /* Penalty += 10000: lfFaceName: mismatched */ + Penalty += 10000; } + } - if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE)) + /* Penalty += 19000: lfOutPrecision: mismatched */ + if (LogFont->lfOutPrecision != OUT_DEFAULT_PRECIS) + { + switch (LogFont->lfOutPrecision) { - Score = 0; + case OUT_DEVICE_PRECIS: + if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) + Penalty += 19000; + break; + case OUT_TT_ONLY_PRECIS: + if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) + Penalty += 19000; + break; + default: + break; } + } - if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE)) + /* get the pitch */ + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte != DEFAULT_PITCH) + { + if (Byte == FIXED_PITCH) { - Score = 0; + /* Penalty += 15000: lfPitchAndFamily: variable pitch was set on fixed-pitch specified */ + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) + { + Penalty += 15000; + } } - - RtlFreeUnicodeString(&EntryFaceNameW); + /* Penalty += 350: lfPitchAndFamily: non-variable pitch on variable pitch */ + if (Byte == VARIABLE_PITCH && !(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + Penalty += 350; + } } + else + { + /* Penalty += 1: pitch is not normal */ + if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + Penalty += 1; + } + } - Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); - Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); - if (NULL == Otm) + /* get family */ + Byte = (LogFont->lfPitchAndFamily & 0xF0); + if (Byte != FF_DONTCARE) { - return Score; + /* Penalty += 9000: lfPitchAndFamily: mismatched font family */ + if (Byte != (TM->tmPitchAndFamily & 0xF0)) + { + Penalty += 9000; + } + /* Penalty += 8000: lfPitchAndFamily: no family on family specified */ + if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) + { + Penalty += 8000; + } } - IntGetOutlineTextMetrics(FontGDI, Size, Otm); - if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) || - (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic)) + /* if the target is not scalable */ + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { - Score += 25; + if (LogFont->lfHeight != 0) + { + /* Penalty += 600: lfHeight: non-vector font and height was higher */ + if (labs(LogFont->lfHeight) < TM->tmHeight) + { + Penalty += 600; + } + /* Penalty += 600: lfHeight: non-vector font and height was higher */ + if (LogFont->lfHeight < 0 && labs(LogFont->lfHeight) < TM->tmHeight) + { + Penalty += 600; + } + /* Penalty += 150 * Diff * K: lfHeight: mismatched */ + if (labs(LogFont->lfHeight) != TM->tmHeight) + { + double K = 2; + /* lfHeight: avg. 16. */ + /* 16 * K = 32. */ + if (labs(LogFont->lfHeight) != TM->tmHeight) + { + LONG Diff = labs(labs(LogFont->lfHeight) - TM->tmHeight); + Penalty += (150 * Diff) * K; + } + } + } + + /* Penalty += 50: height or width scaling required */ + if ((LogFont->lfHeight != 0 && labs(LogFont->lfHeight) != TM->tmHeight) || + (LogFont->lfWidth != 0 && LogFont->lfWidth != TM->tmAveCharWidth)) + { + Penalty += 50; + } + + /* Penalty += 50 * Diff * K: mismatched width */ + if (LogFont->lfWidth != 0 && LogFont->lfWidth != TM->tmAveCharWidth) + { + double K = 0.2; + /* lfWidth: avg. 16. */ + /* 16 * K = 3.2. */ + if (LogFont->lfWidth != TM->tmAveCharWidth) + { + LONG Diff = labs(TM->tmAveCharWidth - LogFont->lfWidth); + Penalty += (50 * Diff) * K; + } + } + + /* Penalty += 1: it needs to be adjusted to italic */ + if (LogFont->lfItalic && !TM->tmItalic) + { + Penalty += 1; + } + /* Penalty += 1: it needs to be adjusted to underline */ + if (LogFont->lfUnderline && !TM->tmUnderlined) + { + Penalty += 1; + } + /* Penalty += 1: it needs to be adjusted to struke-out */ + if (LogFont->lfStrikeOut && !TM->tmStruckOut) + { + Penalty += 1; + } } + if (LogFont->lfWeight != FW_DONTCARE) { - if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight) + /* Penalty += 3 * Diff * K: lfWeight: weight mismatched */ + /* lfWeight: 100 to 900 */ + double K = 0.5; + /* K * 300 * 3 = 450 */ + if (LogFont->lfWeight != TM->tmWeight) { - WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight; + LONG Diff = labs(LogFont->lfWeight - TM->tmWeight); + Penalty += (3 * Diff) * K; } - else + } + else + { + /* Penalty += 100: lfWeight: weight is not normal */ + if (TM->tmWeight != FW_NORMAL) { - WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight; + Penalty += 100; } - Score += (1000 - WeightDiff) / (1000 / 25); } - else + + /* Penalty += 4: lfItalic: mismatched */ + if (!!LogFont->lfItalic != !!TM->tmItalic) { - Score += 25; + Penalty += 4; } + /* Penalty += 4: lfUnderline: mismatched */ + if (!!LogFont->lfUnderline != !!TM->tmUnderlined) + { + Penalty += 4; + } + /* Penalty += 4: lfStrikeOut: mismatched */ + if (!!LogFont->lfStrikeOut != !!TM->tmStruckOut) + { + Penalty += 4; + } - ExFreePoolWithTag(Otm, GDITAG_TEXT); + /* Penalty += 4: lfOutPrecision: non-TrueType on TrueType specified */ + if (LogFont->lfOutPrecision == OUT_TT_PRECIS) + { + if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) + Penalty += 4; + } - return Score; + /* Penalty += 2: not device font */ + if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) + { + Penalty += 2; + } + + if (Penalty < 500) + { + DPRINT("'%ls' -> '%ls' Penalty:%d, lfCharSet:%d, tmCharSet:%d, lfWeight:%d, tmWeight:%d\n", + RequestedNameW->Buffer, ActualNameW->Buffer, Penalty, + LogFont->lfCharSet, TM->tmCharSet, LogFont->lfWeight, TM->tmWeight); + } + + return Penalty; /* success */ } static __inline VOID -FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont, - PUNICODE_STRING FaceName, PLIST_ENTRY Head) +FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont, + PUNICODE_STRING pRequestedNameW, + PUNICODE_STRING pActualNameW, PLIST_ENTRY Head) { + ULONG Penalty; + NTSTATUS Status; PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; FONTGDI *FontGDI; - UINT Score; -ASSERT(FontObj && MatchScore && LogFont && FaceName && Head); + ANSI_STRING ActualNameA; + UNICODE_STRING ActualNameW; + OUTLINETEXTMETRICW *Otm = NULL; + UINT OtmSize, OldOtmSize = 0; + TEXTMETRICW *TM; + + ASSERT(FontObj && MatchPenalty && LogFont && pRequestedNameW && Head); + + /* get the FontObj of lowest penalty */ Entry = Head->Flink; while (Entry != Head) { CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); - FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - Score = GetFontScore(LogFont, FaceName, FontGDI); - if (*MatchScore == 0 || *MatchScore < Score) + /* create actual name */ + RtlInitAnsiString(&ActualNameA, FontGDI->SharedFace->Face->family_name); + Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE); + if (!NT_SUCCESS(Status)) { - *FontObj = GDIToObj(FontGDI, FONT); - *MatchScore = Score; + /* next entry */ + Entry = Entry->Flink; + continue; } - Entry = Entry->Flink; - } -} -static __inline BOOLEAN -SubstituteFontFamilyKey(PUNICODE_STRING FaceName, - LPCWSTR Key) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; - NTSTATUS Status; - UNICODE_STRING Value; + /* get text metrics */ + OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL); + if (OtmSize > OldOtmSize) + { + if (Otm) + ExFreePoolWithTag(Otm, GDITAG_TEXT); + Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT); + } - RtlInitUnicodeString(&Value, NULL); + /* update FontObj if lowest penalty */ + if (Otm) + { + IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm); + TM = &Otm->otmTextMetrics; + OldOtmSize = OtmSize; - QueryTable[0].QueryRoutine = NULL; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | - RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = FaceName->Buffer; - QueryTable[0].EntryContext = &Value; - QueryTable[0].DefaultType = REG_NONE; - QueryTable[0].DefaultData = NULL; - QueryTable[0].DefaultLength = 0; + Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW, + FontGDI, Otm, TM); + if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) + { + RtlFreeUnicodeString(pActualNameW); + RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer); + *FontObj = GDIToObj(FontGDI, FONT); + *MatchPenalty = Penalty; + } + } - QueryTable[1].QueryRoutine = NULL; - QueryTable[1].Name = NULL; + /* free strings */ + RtlFreeUnicodeString(&ActualNameW); - Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, - Key, - QueryTable, - NULL, - NULL); - if (NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(FaceName); - *FaceName = Value; + /* next entry */ + Entry = Entry->Flink; } - return NT_SUCCESS(Status); + if (Otm) + ExFreePoolWithTag(Otm, GDITAG_TEXT); } -static __inline void -SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level) -{ - if (10 < Level) /* Enough is enough */ - { - return; - } - - if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes")) - { - SubstituteFontFamily(FaceName, Level + 1); - } -} - static VOID FASTCALL @@ -2882,25 +3334,26 @@ { PS_FontInfoRec psfInfo; FT_ULong tmp_size = 0; + FT_Face Face = Font->SharedFace->Face; - if (FT_HAS_MULTIPLE_MASTERS(Font->face)) + if (FT_HAS_MULTIPLE_MASTERS(Face)) Font->FontObj.flFontType |= FO_MULTIPLEMASTER; - if (FT_HAS_VERTICAL( Font->face )) + if (FT_HAS_VERTICAL( Face )) Font->FontObj.flFontType |= FO_VERT_FACE; - if (FT_IS_SCALABLE( Font->face )) + if (FT_IS_SCALABLE( Face )) Font->FontObj.flFontType |= FO_TYPE_RASTER; - if (FT_IS_SFNT(Font->face)) + if (FT_IS_SFNT(Face)) { Font->FontObj.flFontType |= FO_TYPE_TRUETYPE; - if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post)) + if (FT_Get_Sfnt_Table(Face, ft_sfnt_post)) Font->FontObj.flFontType |= FO_POSTSCRIPT; } - if (!FT_Get_PS_Font_Info(Font->face, &psfInfo )) + if (!FT_Get_PS_Font_Info(Face, &psfInfo )) { Font->FontObj.flFontType |= FO_POSTSCRIPT; } /* Check for the presence of the 'CFF ' table to check if the font is Type1 */ - if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size)) + if (!FT_Load_Sfnt_Table(Face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size)) { Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT); } @@ -2912,9 +3365,10 @@ { NTSTATUS Status = STATUS_SUCCESS; PTEXTOBJ TextObj; - UNICODE_STRING FaceName; + UNICODE_STRING ActualNameW, RequestedNameW; PPROCESSINFO Win32Process; - UINT MatchScore; + ULONG MatchPenalty; + LOGFONTW *pLogFont; if (!pTextObj) { @@ -2931,35 +3385,46 @@ } } else + { TextObj = pTextObj; + } - if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName)) + RtlInitUnicodeString(&ActualNameW, NULL); + + pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; + if (! RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName)) { if (!pTextObj) TEXTOBJ_UnlockText(TextObj); return STATUS_NO_MEMORY; } - SubstituteFontFamily(&FaceName, 0); - MatchScore = 0; + + DPRINT("Font '%ls' is substituted by: ", RequestedNameW.Buffer); + SubstituteFontName(&RequestedNameW); + DPRINT("'%ls'.\n", RequestedNameW.Buffer); + + MatchPenalty = 0xFFFFFFFF; TextObj->Font = NULL; - /* First search private fonts */ Win32Process = PsGetCurrentProcessWin32Process(); + + /* Search private fonts */ IntLockProcessPrivateFonts(Win32Process); - FindBestFontFromList(&TextObj->Font, &MatchScore, - &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, + FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, + &RequestedNameW, &ActualNameW, &Win32Process->PrivateFontListHead); IntUnLockProcessPrivateFonts(Win32Process); /* Search system fonts */ IntLockGlobalFonts; - FindBestFontFromList(&TextObj->Font, &MatchScore, - &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, + FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, + &RequestedNameW, &ActualNameW, &FontListHead); IntUnLockGlobalFonts; + if (NULL == TextObj->Font) { DPRINT1("Requested font %S not found, no fonts loaded at all\n", - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName); + pLogFont->lfFaceName); Status = STATUS_NOT_FOUND; } else @@ -2970,13 +3435,25 @@ TextObj->Font->iUniq = 1; // Now it can be cached. IntFontType(FontGdi); FontGdi->flType = TextObj->Font->flFontType; - FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0; - FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0; + FontGdi->Underline = pLogFont->lfUnderline ? 0xff : 0; + FontGdi->StrikeOut = pLogFont->lfStrikeOut ? 0xff : 0; + FontGdi->Italic = pLogFont->lfItalic ? 0xff : 0; + if (pLogFont->lfWeight != FW_DONTCARE) + FontGdi->Weight = pLogFont->lfWeight; + else + FontGdi->Weight = FW_NORMAL; + RtlCopyMemory(pLogFont->lfFaceName, ActualNameW.Buffer, + ActualNameW.Length); TextObj->fl |= TEXTOBJECT_INIT; Status = STATUS_SUCCESS; + + DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n", + RequestedNameW.Buffer, pLogFont->lfCharSet, + ActualNameW.Buffer, FontGdi->CharSet); } - RtlFreeUnicodeString(&FaceName); + RtlFreeUnicodeString(&RequestedNameW); + RtlFreeUnicodeString(&ActualNameW); if (!pTextObj) TEXTOBJ_UnlockText(TextObj); ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0); @@ -3149,11 +3626,11 @@ FASTCALL ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info) { - if (FT_HAS_FIXED_SIZES(Font->face)) + if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face)) Info->iTechnology = RI_TECH_BITMAP; else { - if (FT_IS_SCALABLE(Font->face)) + if (FT_IS_SCALABLE(Font->SharedFace->Face)) Info->iTechnology = RI_TECH_SCALABLE; else Info->iTechnology = RI_TECH_FIXED; @@ -3172,7 +3649,7 @@ { DWORD Count = 0; INT i = 0; - FT_Face face = Font->face; + FT_Face face = Font->SharedFace->Face; if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE) { @@ -3492,7 +3969,7 @@ ASSERT(FontGDI); IntLockFreeType; - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { DPRINT("WARNING: No charmap selected!\n"); @@ -4120,7 +4597,7 @@ FontGDI = ObjToGDI(TextObj->Font, FONT); - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { for (i = 0; i < (UINT)face->num_charmaps; i++) @@ -4318,7 +4795,7 @@ FontGDI = ObjToGDI(TextObj->Font, FONT); - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { for (i = 0; i < (UINT)face->num_charmaps; i++) @@ -4456,10 +4933,11 @@ } else { - if (FT_IS_SFNT(FontGDI->face)) + FT_Face Face = FontGDI->SharedFace->Face; + if (FT_IS_SFNT(Face)) { - TT_OS2 *pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); - DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(FontGDI->face, pOS2->usDefaultChar) : 0); + TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); + DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0); } else { @@ -4502,7 +4980,7 @@ for (i = 0; i < cwc; i++) { - Buffer[i] = FT_Get_Char_Index(FontGDI->face, Safepwc[i]); + Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]); if (Buffer[i] == 0) { Buffer[i] = DefChar;