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[16]; +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,26 @@ } /* Get the font name */ - dwSize = sizeof(g_ExtLogFontW.elfFullName); - if (!GetFontResourceInfoW(fileName, &dwSize, g_ExtLogFontW.elfFullName, 1)) - { - ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName); - return -1; - } + dwSize = sizeof(g_LogFonts); + ZeroMemory(g_LogFonts, sizeof(g_LogFonts)); + 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 (g_NumFonts == 0) + { + MessageBoxA(NULL, "No fonts", NULL, MB_ICONERROR); + return -2; + } if (!Display_InitClass(hThisInstance)) { @@ -206,7 +217,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 +248,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 +271,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 +307,51 @@ ); 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); + + EnableWindow(hButtonPrev, FALSE); + if (g_NumFonts <= 1) + 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 +358,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 +417,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 +472,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/sdk/include/psdk/ntgdi.h =================================================================== --- reactos/sdk/include/psdk/ntgdi.h (revision 73479) +++ reactos/sdk/include/psdk/ntgdi.h (working copy) @@ -156,7 +156,7 @@ _In_ ULONG cFiles, _In_ UINT cjBuf, _Out_ LPDWORD pdwBytes, - _Out_writes_bytes_(cjBuf) LPVOID pvBuf, + _Inout_opt_ LPVOID pvBuf, _In_ DWORD iType); __kernel_entry Index: reactos/win32ss/gdi/eng/engobjects.h =================================================================== --- reactos/win32ss/gdi/eng/engobjects.h (revision 73479) +++ reactos/win32ss/gdi/eng/engobjects.h (working copy) @@ -107,22 +107,29 @@ 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; LPWSTR Filename; - BYTE Underline; - BYTE StrikeOut; + BYTE RequestUnderline; + BYTE RequestStrikeOut; + BYTE RequestItalic; + LONG RequestWeight; + BYTE CharSet; } FONTGDI, *PFONTGDI; typedef struct _PATHGDI { Index: reactos/win32ss/gdi/gdi32/objects/text.c =================================================================== --- reactos/win32ss/gdi/gdi32/objects/text.c (revision 73479) +++ reactos/win32ss/gdi/gdi32/objects/text.c (working copy) @@ -584,7 +584,7 @@ GetFontResourceInfoW( _In_z_ LPCWSTR lpFileName, _Inout_ DWORD *pdwBufSize, - _Out_writes_to_(*pdwBufSize, *pdwBufSize) PVOID lpBuffer, + _Inout_opt_ PVOID lpBuffer, _In_ DWORD dwType) { BOOL bRet; Index: reactos/win32ss/gdi/ntgdi/font.c =================================================================== --- reactos/win32ss/gdi/ntgdi/font.c (revision 73479) +++ reactos/win32ss/gdi/ntgdi/font.c (working copy) @@ -10,7 +10,7 @@ #include -#define NDEBUG +//#define NDEBUG #include HFONT APIENTRY HfontCreate( IN PENUMLOGFONTEXDVW pelfw,IN ULONG cjElfw,IN LFTYPE lft,IN FLONG fl,IN PVOID pvCliData ); @@ -865,13 +865,13 @@ BOOL APIENTRY NtGdiGetFontResourceInfoInternalW( - IN LPWSTR pwszFiles, - IN ULONG cwc, - IN ULONG cFiles, - IN UINT cjIn, - OUT LPDWORD pdwBytes, - OUT LPVOID pvBuf, - IN DWORD dwType) + IN LPWSTR pwszFiles, + IN ULONG cwc, + IN ULONG cFiles, + IN UINT cjIn, + IN OUT LPDWORD pdwBytes, + OUT LPVOID pvBuf, + IN DWORD dwType) { NTSTATUS Status = STATUS_SUCCESS; DWORD dwBytes; @@ -879,12 +879,6 @@ BOOL bRet = FALSE; ULONG cbStringSize; - union - { - LOGFONTW logfontw; - WCHAR FullName[LF_FULLFACESIZE]; - } Buffer; - /* FIXME: Handle cFiles > 0 */ /* Check for valid dwType values @@ -911,6 +905,7 @@ _SEH2_TRY { ProbeForRead(pwszFiles, cbStringSize, 1); + ProbeForRead(pdwBytes, sizeof(DWORD), 1); ProbeForWrite(pdwBytes, sizeof(DWORD), 1); ProbeForWrite(pvBuf, cjIn, 1); @@ -931,7 +926,7 @@ } /* Do the actual call */ - bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType); + bRet = IntGdiGetFontResourceInfo(&SafeFileNames, pvBuf, &dwBytes, dwType); /* Check if succeeded and the buffer is big enough */ if (bRet && cjIn >= dwBytes) @@ -939,8 +934,6 @@ /* Copy the data back to caller */ _SEH2_TRY { - /* Buffers are already probed */ - RtlCopyMemory(pvBuf, &Buffer, dwBytes); *pdwBytes = dwBytes; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 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,9 +20,15 @@ #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 +//#define NDEBUG #include #ifndef FT_MAKE_TAG @@ -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,45 @@ FT_Library library; +/* special font names */ +static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett"); +static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System"); +static const UNICODE_STRING SymbolW = RTL_CONSTANT_STRING(L"Symbol"); + +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 +274,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 +281,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 +309,244 @@ 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 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 or Symbol */ + RtlInitAnsiString(&FaceNameA, Face->family_name); + Status = RtlAnsiStringToUnicodeString(&FaceNameW, &FaceNameA, TRUE); + if (NT_SUCCESS(Status)) + { + if (RtlEqualUnicodeString(&FaceNameW, &MarlettW, TRUE)) + { + FontGDI->CharSet = SYMBOL_CHARSET; + } + if (RtlEqualUnicodeString(&FaceNameW, &SymbolW, TRUE)) + { + FontGDI->CharSet = GREEK_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 +554,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 +816,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; @@ -631,10 +845,10 @@ TM->tmDefaultChar = pWin->default_char + pWin->first_char; TM->tmBreakChar = pWin->break_char + pWin->first_char; TM->tmItalic = pWin->italic; - TM->tmUnderlined = FontGDI->Underline; - TM->tmStruckOut = FontGDI->StrikeOut; + TM->tmUnderlined = pWin->underline; + TM->tmStruckOut = pWin->strike_out; TM->tmPitchAndFamily = pWin->pitch_and_family; - TM->tmCharSet = pWin->charset; + TM->tmCharSet = FontGDI->CharSet; return; } @@ -711,14 +925,19 @@ TM->tmBreakChar = pOS2->usFirstCharIndex; TM->tmDefaultChar = TM->tmBreakChar - 1; } - TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0; - TM->tmUnderlined = FontGDI->Underline; - TM->tmStruckOut = FontGDI->StrikeOut; + if (Face->style_flags & FT_STYLE_FLAG_ITALIC) + TM->tmItalic = 0xFF; + else if (FontGDI->RequestItalic) + TM->tmItalic = 0xFF; /* should be simulated */ + else + TM->tmItalic = 0; - /* Yes TPMF_FIXED_PITCH is correct; braindead api */ - if (! FT_IS_FIXED_WIDTH(Face)) + TM->tmUnderlined = FontGDI->RequestUnderline; /* should be simulated */ + TM->tmStruckOut = FontGDI->RequestStrikeOut; /* should be simulated */ + + if (!FT_IS_FIXED_WIDTH(Face)) { - TM->tmPitchAndFamily = TMPF_FIXED_PITCH; + TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH; } else { @@ -788,7 +1007,7 @@ TM->tmPitchAndFamily |= TMPF_TRUETYPE; } - TM->tmCharSet = DEFAULT_CHARSET; + TM->tmCharSet = FontGDI->CharSet; } /************************************************************* @@ -811,10 +1030,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 +1041,7 @@ return 0; } - RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name); + RtlInitAnsiString(&StyleNameA, Face->style_name); status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -836,7 +1056,7 @@ RtlInitUnicodeString(&Regular, L"regular"); /* Length of otmpFaceName */ - if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) + if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE)) { Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */ } @@ -858,11 +1078,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 +1092,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 +1102,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 +1117,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; @@ -944,7 +1164,7 @@ Cp += StyleNameW.Length + sizeof(WCHAR); Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm); wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); - if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) + if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE)) { wcscat((WCHAR*) Cp, L" "); wcscat((WCHAR*) Cp, StyleNameW.Buffer); @@ -983,7 +1203,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)) { @@ -996,7 +1216,7 @@ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; } - if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) + if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE)) { RtlFreeUnicodeString(&EntryFaceNameW); return FontGDI; @@ -1048,6 +1268,7 @@ NEWTEXTMETRICW *Ntm; DWORD fs0; NTSTATUS status; + FT_Face Face = FontGDI->SharedFace->Face; RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); @@ -1116,7 +1337,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 +1349,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 +1364,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 +1371,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: @@ -1200,7 +1421,7 @@ for (i = 0; i < InfoEntries; i++) { RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); - if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE)) + if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE)) { return i; } @@ -1216,8 +1437,8 @@ UNICODE_STRING LogFontFaceName; RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); - if (0 != LogFontFaceName.Length - && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE)) + if (0 != LogFontFaceName.Length && + !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE)) { return FALSE; } @@ -1247,7 +1468,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 +2023,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 +2492,7 @@ FontGDI = ObjToGDI(TextObj->Font, FONT); - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (NULL != Fit) { *Fit = 0; @@ -2424,7 +2645,7 @@ return Ret; } FontGdi = ObjToGDI(TextObj->Font, FONT); - Face = FontGdi->face; + Face = FontGdi->SharedFace->Face; TEXTOBJ_UnlockText(TextObj); IntLockFreeType; @@ -2512,7 +2733,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 +2829,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 +2845,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 +2856,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 +2863,7 @@ Status = STATUS_INTERNAL_ERROR; } - Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); + Error = FT_Get_WinFNT_Header(Face, &Win); IntUnLockFreeType; @@ -2680,10 +2902,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 +2919,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 +2932,488 @@ 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; +} + +// NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx +static UINT FASTCALL +GetFontPenalty(LOGFONTW * LogFont, + PUNICODE_STRING RequestNameW, + PUNICODE_STRING ActualNameW, + PFONTGDI FontGDI, + OUTLINETEXTMETRICW * Otm, + TEXTMETRICW * TM) +{ + ULONG Penalty = 0; + BYTE Byte; + LONG Long; + BOOL fSystemFont = FALSE, fNeedScaling = FALSE; + /* FIXME: Aspect Penalty 30 */ + /* FIXME: FaceNameSubst Penalty 500 */ + /* FIXME: IntSizeSynth Penalty 20 */ + /* FIXME: ItalicSim Penalty 1 */ + /* FIXME: SmallPenalty Penalty 1 */ + + /* is request "System" font? */ + if (RtlEqualUnicodeString(RequestNameW, &SystemW, TRUE)) + { + if (TM->tmCharSet != CharSetFromLangID(gusLanguageID)) { - Score += 49; + /* CharSet Penalty 65000 */ + /* Requested charset does not match the candidate's. */ + Penalty += 65000; } + fSystemFont = TRUE; + } + else /* Request is non-"System" font */ + { + Byte = LogFont->lfCharSet; - /* 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)) + /* fixup */ + if (RtlEqualUnicodeString(RequestNameW, &MarlettW, TRUE)) { - Score = 0; + Byte = SYMBOL_CHARSET; } + else if (RtlEqualUnicodeString(RequestNameW, &SymbolW, TRUE)) + { + Byte = GREEK_CHARSET; + } - if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE)) + if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET) { - Score = 0; + if (Byte != TM->tmCharSet) + { + /* CharSet Penalty 65000 */ + /* Requested charset does not match the candidate's. */ + Penalty += 65000; + } } + } - if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE)) + Byte = LogFont->lfOutPrecision; + if (Byte == OUT_DEFAULT_PRECIS) + Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */ + switch (Byte) + { + case OUT_DEVICE_PRECIS: + if (!(TM->tmPitchAndFamily & TMPF_DEVICE) || + !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))) + { + /* OutputPrecision Penalty 19000 */ + /* Requested OUT_STROKE_PRECIS, but the device can't do it + or the candidate is not a vector font. */ + Penalty += 19000; + } + break; + default: + if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)) + { + /* OutputPrecision Penalty 19000 */ + /* Or OUT_STROKE_PRECIS not requested, and the candidate + is a vector font that requires GDI support. */ + Penalty += 19000; + } + break; + } + + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte == DEFAULT_PITCH) + Byte = VARIABLE_PITCH; + if (fSystemFont) + { + /* "System" font should be fixed-pitch */ + Byte = FIXED_PITCH; + } + if (Byte == FIXED_PITCH) + { + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) { - Score = 0; + /* FixedPitch Penalty 15000 */ + /* Requested a fixed pitch font, but the candidate is a + variable pitch font. */ + Penalty += 15000; } + } + if (Byte == VARIABLE_PITCH) + { + if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + /* PitchVariable Penalty 350 */ + /* Requested a variable pitch font, but the candidate is not a + variable pitch font. */ + Penalty += 350; + } + } - RtlFreeUnicodeString(&EntryFaceNameW); + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte == DEFAULT_PITCH) + { + if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + /* DefaultPitchFixed Penalty 1 */ + /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */ + Penalty += 1; + } } - Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); - Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); - if (NULL == Otm) + if (RequestNameW->Buffer[0]) { - return Score; + if (!RtlEqualUnicodeString(RequestNameW, ActualNameW, TRUE)) + { + /* FaceName Penalty 10000 */ + /* Requested a face name, but the candidate's face name + does not match. */ + Penalty += 10000; + } } - IntGetOutlineTextMetrics(FontGDI, Size, Otm); - if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) || - (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic)) + Byte = (LogFont->lfPitchAndFamily & 0xF0); + if (Byte == FF_DONTCARE) + Byte = FF_ROMAN; + if (Byte != (TM->tmPitchAndFamily & 0xF0)) { - Score += 25; + /* Family Penalty 9000 */ + /* Requested a family, but the candidate's family is different. */ + Penalty += 9000; } - if (LogFont->lfWeight != FW_DONTCARE) + if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) { - if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight) + /* FamilyUnknown Penalty 8000 */ + /* Requested a family, but the candidate has no family. */ + Penalty += 8000; + } + + /* Is the candidate a non-vector font? */ + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) + { + /* Is lfHeight specified? */ + if (LogFont->lfHeight != 0) { - WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight; + if (labs(LogFont->lfHeight) < TM->tmHeight) + { + /* HeightBigger Penalty 600 */ + /* The candidate is a nonvector font and is bigger than the + requested height. */ + Penalty += 600; + /* HeightBiggerDifference Penalty 150 */ + /* The candidate is a raster font and is larger than the + requested height. Penalty * height difference */ + Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)); + + fNeedScaling = TRUE; + } + if (TM->tmHeight < labs(LogFont->lfHeight)) + { + /* HeightSmaller Penalty 150 */ + /* The candidate is a raster font and is smaller than the + requested height. Penalty * height difference */ + Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)); + + fNeedScaling = TRUE; + } } - else + } + + switch (LogFont->lfPitchAndFamily & 0xF0) + { + case FF_ROMAN: case FF_MODERN: case FF_SWISS: + switch (TM->tmPitchAndFamily & 0xF0) + { + case FF_DECORATIVE: case FF_SCRIPT: + /* FamilyUnlikely Penalty 50 */ + /* Requested a roman/modern/swiss family, but the + candidate is decorative/script. */ + Penalty += 50; + break; + default: + break; + } + break; + case FF_DECORATIVE: case FF_SCRIPT: + switch (TM->tmPitchAndFamily & 0xF0) + { + case FF_ROMAN: case FF_MODERN: case FF_SWISS: + /* FamilyUnlikely Penalty 50 */ + /* Or requested decorative/script, and the candidate is + roman/modern/swiss. */ + Penalty += 50; + break; + default: + break; + } + default: + break; + } + + if (LogFont->lfWidth != 0) + { + if (LogFont->lfWidth != TM->tmAveCharWidth) { - WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight; + /* Width Penalty 50 */ + /* Requested a nonzero width, but the candidate's width + doesn't match. Penalty * width difference */ + Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth); + + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) + fNeedScaling = TRUE; } - Score += (1000 - WeightDiff) / (1000 / 25); } - else + + if (fNeedScaling) { - Score += 25; + /* SizeSynth Penalty 50 */ + /* The candidate is a raster font that needs scaling by GDI. */ + Penalty += 50; } - ExFreePoolWithTag(Otm, GDITAG_TEXT); + if (!!LogFont->lfItalic != !!TM->tmItalic) + { + /* Italic Penalty 4 */ + /* Requested font and candidate font do not agree on italic status, + and the desired result cannot be simulated. */ + /* FIXME: Simulate italic */ + Penalty += 4; + } - return Score; + if (LogFont->lfOutPrecision == OUT_TT_PRECIS) + { + if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) + { + /* NotTrueType Penalty 4 */ + /* Requested OUT_TT_PRECIS, but the candidate is not a + TrueType font. */ + Penalty += 4; + } + } + + Long = LogFont->lfWeight; + if (LogFont->lfWeight == FW_DONTCARE) + Long = FW_NORMAL; + if (Long != TM->tmWeight) + { + /* Weight Penalty 3 */ + /* The candidate's weight does not match the requested weight. + Penalty * (weight difference/10) */ + Penalty += 3 * labs(Long - TM->tmWeight); + } + + if (!!LogFont->lfUnderline != !!TM->tmUnderlined) + { + /* Underline Penalty 3 */ + Penalty += 3; + } + + if (!!LogFont->lfStrikeOut != !!TM->tmStruckOut) + { + /* StrikeOut Penalty 3 */ + Penalty += 3; + } + + + /* Is the candidate a vector font? */ + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) + { + if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight) + { + /* VectorHeightSmaller Penalty 2 */ + /* Candidate is a vector font that is smaller than the + requested height. Penalty * height difference */ + Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight); + } + if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight) + { + /* VectorHeightBigger Penalty 1 */ + /* Candidate is a vector font that is bigger than the + requested height. Penalty * height difference */ + Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight); + } + } + + if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) + { + /* DeviceFavor Penalty 2 */ + /* Extra penalty for all nondevice fonts. */ + Penalty += 2; + } + + 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 pRequestNameW, + 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 && pRequestNameW && 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, pRequestNameW, &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 +3421,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 +3452,10 @@ { NTSTATUS Status = STATUS_SUCCESS; PTEXTOBJ TextObj; - UNICODE_STRING FaceName; + UNICODE_STRING ActualNameW, RequestNameW; PPROCESSINFO Win32Process; - UINT MatchScore; + ULONG MatchPenalty; + LOGFONTW *pLogFont; if (!pTextObj) { @@ -2931,35 +3472,46 @@ } } else + { TextObj = pTextObj; + } - if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName)) + RtlInitUnicodeString(&ActualNameW, NULL); + + pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; + if (! RtlCreateUnicodeString(&RequestNameW, pLogFont->lfFaceName)) { if (!pTextObj) TEXTOBJ_UnlockText(TextObj); return STATUS_NO_MEMORY; } - SubstituteFontFamily(&FaceName, 0); - MatchScore = 0; + + DPRINT("Font '%ls' is substituted by: ", RequestNameW.Buffer); + SubstituteFontName(&RequestNameW); + DPRINT("'%ls'.\n", RequestNameW.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, + &RequestNameW, &ActualNameW, &Win32Process->PrivateFontListHead); IntUnLockProcessPrivateFonts(Win32Process); /* Search system fonts */ IntLockGlobalFonts; - FindBestFontFromList(&TextObj->Font, &MatchScore, - &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, + FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, + &RequestNameW, &ActualNameW, &FontListHead); IntUnLockGlobalFonts; + if (NULL == TextObj->Font) { - DPRINT1("Requested font %S not found, no fonts loaded at all\n", - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName); + DPRINT1("Request font %S not found, no fonts loaded at all\n", + pLogFont->lfFaceName); Status = STATUS_NOT_FOUND; } else @@ -2970,13 +3522,23 @@ 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->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0; + FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0; + FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0; + if (pLogFont->lfWeight != FW_DONTCARE) + FontGdi->RequestWeight = pLogFont->lfWeight; + else + FontGdi->RequestWeight = FW_NORMAL; TextObj->fl |= TEXTOBJECT_INIT; Status = STATUS_SUCCESS; + + DPRINT("RequestNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n", + RequestNameW.Buffer, pLogFont->lfCharSet, + ActualNameW.Buffer, FontGdi->CharSet); } - RtlFreeUnicodeString(&FaceName); + RtlFreeUnicodeString(&RequestNameW); + RtlFreeUnicodeString(&ActualNameW); if (!pTextObj) TEXTOBJ_UnlockText(TextObj); ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0); @@ -3030,6 +3592,19 @@ return TRUE; } +static BOOL +EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2) +{ + BOOL Ret; + UNICODE_STRING Str1, Str2; + RtlCreateUnicodeString(&Str1, pInfo1->EnumLogFontEx.elfLogFont.lfFaceName); + RtlCreateUnicodeString(&Str2, pInfo2->EnumLogFontEx.elfLogFont.lfFaceName); + Ret = RtlEqualUnicodeString(&Str1, &Str2, TRUE); + RtlFreeUnicodeString(&Str2); + RtlFreeUnicodeString(&Str1); + return Ret; +} + BOOL FASTCALL IntGdiGetFontResourceInfo( @@ -3042,9 +3617,9 @@ POBJECT_NAME_INFORMATION NameInfo1, NameInfo2; PLIST_ENTRY ListEntry; PFONT_ENTRY FontEntry; - FONTFAMILYINFO Info; - ULONG Size; - BOOL bFound = FALSE; + FONTFAMILYINFO Info[10]; + ULONG Size, I, Count, Count2; + LPBYTE pbBuffer; /* Create buffer for full path name */ Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); @@ -3072,6 +3647,7 @@ } /* Try to find the pathname in the global font list */ + Count = 0; IntLockGlobalFonts; for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead; @@ -3085,10 +3661,23 @@ { if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) { - /* Found */ - FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font); - bFound = TRUE; - break; + BOOL IsEqual = FALSE; + FontFamilyFillInfo(&Info[Count], FontEntry->FaceName.Buffer, FontEntry->Font); + for (I = 0; I < Count; ++I) + { + if (EqualFamilyInfo(&Info[I], &Info[Count])) + { + IsEqual = TRUE; + break; + } + } + if (!IsEqual) + { + /* Found */ + ++Count; + if (Count >= _countof(Info)) + break; + } } } } @@ -3099,7 +3688,7 @@ ExFreePoolWithTag(NameInfo1, TAG_FINF); ExFreePool(NameInfo2); - if (!bFound && dwType != 5) + if (Count == 0 && dwType != 5) { /* Font could not be found in system table dwType == 5 will still handle this */ @@ -3114,17 +3703,26 @@ break; case 1: /* Copy the full font name */ - Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1; + Size = wcslen(Info[0].EnumLogFontEx.elfFullName) + 1; Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR); - RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size); + RtlCopyMemory(pBuffer, Info[0].EnumLogFontEx.elfFullName, Size); // FIXME: Do we have to zeroterminate? *pdwBytes = Size; break; case 2: /* Copy a LOGFONTW structure */ - Info.EnumLogFontEx.elfLogFont.lfWidth = 0; - RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); - *pdwBytes = sizeof(LOGFONTW); + if (*pdwBytes < Count * sizeof(LOGFONTW)) + Count2 = *pdwBytes / sizeof(LOGFONTW); + else + Count2 = Count; + pbBuffer = (LPBYTE)pBuffer; + for (I = 0; I < Count2; ++I) + { + Info[I].EnumLogFontEx.elfLogFont.lfWidth = 0; + RtlCopyMemory(pbBuffer, &Info[I].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); + pbBuffer += sizeof(LOGFONTW); + } + *pdwBytes = Count * sizeof(LOGFONTW); break; case 3: /* FIXME: What exactly is copied here? */ @@ -3133,7 +3731,7 @@ break; case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */ - *(BOOL*)pBuffer = !bFound; + *(BOOL*)pBuffer = Count == 0; *pdwBytes = sizeof(BOOL); break; @@ -3149,11 +3747,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 +3770,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 +4090,7 @@ ASSERT(FontGDI); IntLockFreeType; - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { DPRINT("WARNING: No charmap selected!\n"); @@ -4120,7 +4718,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 +4916,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 +5054,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 +5101,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;