Index: reactos/base/applications/fontview/display.c =================================================================== --- reactos/base/applications/fontview/display.c (revision 73640) +++ reactos/base/applications/fontview/display.c (working copy) @@ -28,6 +28,9 @@ #define SPACING1 8 #define SPACING2 5 +extern INT g_NumFonts; +extern WCHAR g_FontTitle[]; + const WCHAR g_szFontDisplayClassName[] = L"FontDisplayClass"; LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM); @@ -90,7 +93,10 @@ hOldFont = SelectObject(hDC, pData->hCaptionFont); GetTextMetrics(hDC, &tm); - swprintf(szCaption, L"%s%s", pData->szTypeFaceName, pData->szFormat); + if (g_NumFonts == 1) + lstrcpyW(szCaption, g_FontTitle); + else + swprintf(szCaption, L"%s%s", pData->szTypeFaceName, pData->szFormat); TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption)); y += tm.tmHeight + SPACING1; @@ -162,7 +168,7 @@ } static LRESULT -Display_SetTypeFace(HWND hwnd, PEXTLOGFONTW pExtLogFont) +Display_SetTypeFace(HWND hwnd, PLOGFONTW pLogFont) { DISPLAYDATA* pData; TEXTMETRIC tm; @@ -171,16 +177,21 @@ SCROLLINFO si; int i; LOGFONTW logfont; + BOOL fOpenType; + BYTE Buffer[512]; + LPOUTLINETEXTMETRICW pOTM = (LPOUTLINETEXTMETRICW)Buffer; + LPWSTR pch; /* Set the new type face name */ pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - _snwprintf(pData->szTypeFaceName, LF_FULLFACESIZE, pExtLogFont->elfFullName); + lstrcpynW(pData->szTypeFaceName, pLogFont->lfFaceName, + ARRAYSIZE(pData->szTypeFaceName)); /* 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); @@ -189,8 +200,19 @@ GetTextMetrics(hDC, &tm); if (tm.tmPitchAndFamily & TMPF_TRUETYPE) { - BOOL fOpenType = FALSE; + if (GetOutlineTextMetricsW(hDC, sizeof(Buffer), pOTM)) + { + LPBYTE pb = Buffer; + pb += (WORD)(DWORD_PTR)pOTM->otmpStyleName; + pch = (LPWSTR)pb; + if (*pch) + { + lstrcatW(pData->szTypeFaceName, L" "); + lstrcatW(pData->szTypeFaceName, pch); + } + } + fOpenType = FALSE; EnumFontFamiliesExW(hDC, &logfont, EnumFontFamProcW, (LPARAM)&fOpenType, 0); @@ -234,12 +256,12 @@ } static LRESULT -Display_SetString(HWND hwnd, LPARAM lParam) +Display_SetString(HWND hwnd, LPCWSTR pszString) { DISPLAYDATA* pData; pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - _snwprintf(pData->szString, MAX_STRING, (WCHAR*)lParam); + lstrcpynW(pData->szString, pszString, ARRAYSIZE(pData->szString)); InvalidateRect(hwnd, NULL, TRUE); @@ -252,11 +274,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 +291,14 @@ 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_SetString(hwnd, + L"Jackdaws love my big sphinx of quartz. 1234567890"); - Display_SetTypeFace(hwnd, &ExtLogFont); + Display_SetTypeFace(hwnd, &LogFont); return 0; } @@ -520,10 +542,10 @@ 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); + return Display_SetString(hwnd, (WCHAR *)lParam); case WM_DESTROY: return Display_OnDestroy(hwnd); Index: reactos/base/applications/fontview/fontview.c =================================================================== --- reactos/base/applications/fontview/fontview.c (revision 73640) +++ reactos/base/applications/fontview/fontview.c (working copy) @@ -4,6 +4,7 @@ * fontview.c * * Copyright (C) 2007 Timo Kreuzer kreuzer reactos org> + * Copyright (C) 2016-2017 Katayama Hirofumi MZ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,9 +30,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 = 0; +LOGFONTW g_LogFonts[64]; +LPCWSTR g_fileName; +WCHAR g_FontTitle[1024] = L""; static const WCHAR g_szFontViewClassName[] = L"FontViewWClass"; @@ -93,6 +97,7 @@ int nCmdShow) { int argc; + INT i; WCHAR** argv; WCHAR szFileName[MAX_PATH] = L""; DWORD dwSize; @@ -160,21 +165,33 @@ return -1; } - /* 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; - } + /* Get the font name */ + 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 < ARRAYSIZE(g_LogFonts); ++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) + { + ErrorMsgBox(0, IDS_ERROR_NOFONT, fileName); + return -1; + } + /* get font title */ + dwSize = sizeof(g_FontTitle); + ZeroMemory(g_FontTitle, sizeof(g_FontTitle)); + GetFontResourceInfoW(fileName, &dwSize, g_FontTitle, 1); + if (!Display_InitClass(hThisInstance)) { ErrorMsgBox(0, IDS_ERROR_NOCLASS); @@ -206,7 +223,7 @@ hMainWnd = CreateWindowExW( 0, /* Extended possibilities for variation */ g_szFontViewClassName, /* Classname */ - g_ExtLogFontW.elfFullName,/* Title Text */ + g_FontTitle, /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ @@ -220,8 +237,10 @@ ShowWindow(hMainWnd, nCmdShow); /* Main message loop */ - while (GetMessage (&msg, NULL, 0, 0)) + while (GetMessage(&msg, NULL, 0, 0)) { + if (IsDialogMessage(hMainWnd, &msg)) + continue; TranslateMessage(&msg); DispatchMessage(&msg); } @@ -237,7 +256,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 +279,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 +315,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 +366,38 @@ static LRESULT MainWnd_OnSize(HWND hwnd) { - RECT rc; + RECT rc; + HWND hInstall, hPrint, hPrev, hNext, hDisplay; + HDWP hDWP; - 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); + hDWP = BeginDeferWindowPos(5); + + hInstall = GetDlgItem(hwnd, IDC_INSTALL); + if (hDWP) + hDWP = DeferWindowPos(hDWP, hInstall, NULL, BUTTON_POS_X, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER); + + hPrint = GetDlgItem(hwnd, IDC_PRINT); + if (hDWP) + hDWP = DeferWindowPos(hDWP, hPrint, NULL, BUTTON_POS_X + BUTTON_WIDTH + BUTTON_PADDING, BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER); + + hPrev = GetDlgItem(hwnd, IDC_PREV); + if (hDWP) + hDWP = DeferWindowPos(hDWP, hPrev, NULL, rc.right - (BUTTON_WIDTH * 2 + BUTTON_PADDING + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER); + + hNext = GetDlgItem(hwnd, IDC_NEXT); + if (hDWP) + hDWP = DeferWindowPos(hDWP, hNext, NULL, rc.right - (BUTTON_WIDTH + BUTTON_POS_X), BUTTON_POS_Y, BUTTON_WIDTH, BUTTON_HEIGHT, SWP_NOZORDER); + + hDisplay = GetDlgItem(hwnd, IDC_DISPLAY); + if (hDWP) + hDWP = DeferWindowPos(hDWP, hDisplay, NULL, 0, HEADER_SIZE, rc.right, rc.bottom - HEADER_SIZE, SWP_NOZORDER); + + EndDeferWindowPos(hDWP); + + InvalidateRect(hwnd, NULL, TRUE); + return 0; } @@ -349,6 +437,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 +492,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 73640) +++ reactos/base/applications/fontview/fontview.h (working copy) @@ -8,11 +8,16 @@ #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; Index: reactos/base/applications/fontview/lang/bg-BG.rc =================================================================== --- reactos/base/applications/fontview/lang/bg-BG.rc (revision 73640) +++ reactos/base/applications/fontview/lang/bg-BG.rc (working copy) @@ -2,7 +2,7 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" + IDS_INSTALL "&Install" IDS_PRINT "Печат" IDS_STRING "Абвгд ежзий клмно прсту фхцчш щъьюя. 1234567890" IDS_OPEN "Open Font..." @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/cs-CZ.rc =================================================================== --- reactos/base/applications/fontview/lang/cs-CZ.rc (revision 73640) +++ reactos/base/applications/fontview/lang/cs-CZ.rc (working copy) @@ -2,8 +2,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Nainstalovat" - IDS_PRINT "Tisk" + IDS_INSTALL "&Nainstalovat" + IDS_PRINT "&Tisk" IDS_STRING "Příliš žluťoučký kůň úpěl ďábelské ódy. 1234567890" IDS_OPEN "Otevřít soubor písma..." IDS_ERROR "Chyba" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\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 73640) +++ reactos/base/applications/fontview/lang/de-DE.rc (working copy) @@ -2,8 +2,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Installieren" - IDS_PRINT "Drucken" + IDS_INSTALL "&Installieren" + IDS_PRINT "&Drucken" IDS_STRING "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. 1234567890" IDS_OPEN "Schriftartendatei öffnen..." IDS_ERROR "Fehler" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/en-US.rc =================================================================== --- reactos/base/applications/fontview/lang/en-US.rc (revision 73640) +++ reactos/base/applications/fontview/lang/en-US.rc (working copy) @@ -2,8 +2,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" - IDS_PRINT "Print" + IDS_INSTALL "&Install" + IDS_PRINT "&Print" IDS_STRING "Jackdaws love my big sphinx of quartz. 1234567890" IDS_OPEN "Open Font..." IDS_ERROR "Error" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/es-ES.rc =================================================================== --- reactos/base/applications/fontview/lang/es-ES.rc (revision 73640) +++ reactos/base/applications/fontview/lang/es-ES.rc (working copy) @@ -4,8 +4,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Instalar" - IDS_PRINT "Imprimir" + IDS_INSTALL "&Instalar" + IDS_PRINT "Im&primir" IDS_STRING "Jovencillo emponzoñado de whisky: ¡qué figurota exhibe! 1234567890" IDS_OPEN "Abrir fuente..." IDS_ERROR "Error" @@ -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\ -TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ -All Files (*.*)\0*.*\0" + IDS_FILTER_LIST "Todas las tipografías (*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ +Tipografía TrueType (*.ttf)\0*.ttf\0\ +Colección de tipografías TrueType (*.ttc)\0*.ttc\0\ +Tipografía OpenType (*.otf;*.otc)\0*.otf;*.otc\0\ +Tipografía de mapa de bits (*.fon;*.fnt)\0*.fon;*.fnt\0\ +Todos los archivos (*.*)\0*.*\0" + IDS_PREVIOUS "< Ante&rior" + IDS_NEXT "Siguie&nte >" END Index: reactos/base/applications/fontview/lang/fr-FR.rc =================================================================== --- reactos/base/applications/fontview/lang/fr-FR.rc (revision 73640) +++ reactos/base/applications/fontview/lang/fr-FR.rc (working copy) @@ -2,17 +2,20 @@ STRINGTABLE BEGIN - IDS_INSTALL "Installer" - IDS_PRINT "Imprimer" + IDS_INSTALL "&Installer" + IDS_PRINT "Im&primer" IDS_STRING "Voix ambiguë d'un cœur qui au zéphyr préfère les jattes de kiwis. 1234567890" IDS_OPEN "Ouvrir un fichier police..." IDS_ERROR "Erreur" 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_NOFONT "Le fichier %1 n'est pas un fichier de polices 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 "Toutes polices supportées (*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Fichier de polices (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&récédent" + IDS_NEXT "Suiva&nt >" END Index: reactos/base/applications/fontview/lang/he-IL.rc =================================================================== --- reactos/base/applications/fontview/lang/he-IL.rc (revision 73640) +++ 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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/it-IT.rc =================================================================== --- reactos/base/applications/fontview/lang/it-IT.rc (revision 73640) +++ reactos/base/applications/fontview/lang/it-IT.rc (working copy) @@ -2,8 +2,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Installa" - IDS_PRINT "Stampa" + IDS_INSTALL "&Installa" + IDS_PRINT "Stam&pa" IDS_STRING "Jackdaws love my big sphinx of quartz. 1234567890" IDS_OPEN "Apri Font..." IDS_ERROR "Errore" @@ -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\ -TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ + IDS_FILTER_LIST "Tutti i font supportati (*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ +Font TrueType (*.ttf)\0*.ttf\0\ +Collezione Font TrueType (*.ttc)\0*.ttc\0\ +Font OpenType (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&recedente" + IDS_NEXT "Ava&nti >" END Index: reactos/base/applications/fontview/lang/lt-LT.rc =================================================================== --- reactos/base/applications/fontview/lang/lt-LT.rc (revision 73640) +++ reactos/base/applications/fontview/lang/lt-LT.rc (working copy) @@ -4,8 +4,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" - IDS_PRINT "Spausdinti" + IDS_INSTALL "&Install" + IDS_PRINT "&Spausdinti" IDS_STRING "ABCDEFGHIYJKLMNOPQRSTUVWXZ ąčęėįšųūž 1234567890" IDS_OPEN "Aatvira šriftas..." IDS_ERROR "Klaida" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/ms-MY.rc =================================================================== --- reactos/base/applications/fontview/lang/ms-MY.rc (revision 73640) +++ reactos/base/applications/fontview/lang/ms-MY.rc (working copy) @@ -4,8 +4,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Memasang" - IDS_PRINT "Mencetak" + IDS_INSTALL "&Memasang" + IDS_PRINT "M&encetak" IDS_STRING "Jackdaws love my big sphinx of quartz. 1234567890" IDS_OPEN "Buka fon..." IDS_ERROR "Ralat" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ +TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ +All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/no-NO.rc =================================================================== --- reactos/base/applications/fontview/lang/no-NO.rc (revision 73640) +++ reactos/base/applications/fontview/lang/no-NO.rc (working copy) @@ -2,8 +2,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" - IDS_PRINT "Skriv" + IDS_INSTALL "&Install" + IDS_PRINT "&Skriv" IDS_STRING "Jackdaws love my big sphinx of quartz. 1234567890" IDS_OPEN "Open Font..." IDS_ERROR "Feil" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/pl-PL.rc =================================================================== --- reactos/base/applications/fontview/lang/pl-PL.rc (revision 73640) +++ reactos/base/applications/fontview/lang/pl-PL.rc (working copy) @@ -10,8 +10,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Instaluj" - IDS_PRINT "Drukuj" + IDS_INSTALL "&Instaluj" + IDS_PRINT "&Drukuj" IDS_STRING "Zażółć gęślą Jaźń żółwiątkiem. 1234567890. !@#$%^&*()_+=-/?" IDS_OPEN "Otwórz czcionkę..." IDS_ERROR "Błąd" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/pt-BR.rc =================================================================== --- reactos/base/applications/fontview/lang/pt-BR.rc (revision 73640) +++ reactos/base/applications/fontview/lang/pt-BR.rc (working copy) @@ -4,8 +4,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" - IDS_PRINT "Imprimir" + IDS_INSTALL "&Install" + IDS_PRINT "Im&primir" IDS_STRING "Jackdaws ama minha grande esfinge de quartzo. 1234567890" IDS_OPEN "Open Font..." IDS_ERROR "Erro" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/ro-RO.rc =================================================================== --- reactos/base/applications/fontview/lang/ro-RO.rc (revision 73640) +++ 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;*.otc)\0*.ttf;.ttc;*.fon;*.otf;*.otc\0\ Fonturi de tip TrueType (*.ttf)\0*.ttf\0\ -Fonturi de tip OpenType (*.otf)\0*.otf\0\ -Fișiere de tip Font (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +Fonturi de tip OpenType (*.otf;*.otc)\0*.otf;*.otc\0\ +Fișiere de tip Font (*.fon;*.fnt)\0*.fon;*.fnt\0\ Orice fișier (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/ru-RU.rc =================================================================== --- reactos/base/applications/fontview/lang/ru-RU.rc (revision 73640) +++ 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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType шрифты (*.ttf)\0*.ttf\0\ -OpenType шрифты (*.otf)\0*.otf\0\ -Файлы шрифтов (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType шрифты (*.otf;*.otc)\0*.otf;*.otc\0\ +Файлы шрифтов (*.fon;*.fnt)\0*.fon;*.fnt\0\ Все файлы (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/sk-SK.rc =================================================================== --- reactos/base/applications/fontview/lang/sk-SK.rc (revision 73640) +++ 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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/sq-AL.rc =================================================================== --- reactos/base/applications/fontview/lang/sq-AL.rc (revision 73640) +++ reactos/base/applications/fontview/lang/sq-AL.rc (working copy) @@ -6,8 +6,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Instalo" - IDS_PRINT "Printo" + IDS_INSTALL "&Instalo" + IDS_PRINT "&Printo" IDS_STRING "Jackdaws dashuron sphinxin tim të madh prej kuartzi. 1234567890" IDS_OPEN "Hap fontin..." IDS_ERROR "Error" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/sv-SE.rc =================================================================== --- reactos/base/applications/fontview/lang/sv-SE.rc (revision 73640) +++ reactos/base/applications/fontview/lang/sv-SE.rc (working copy) @@ -9,8 +9,8 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" - IDS_PRINT "Skriv ut" + IDS_INSTALL "&Install" + IDS_PRINT "&Skriv ut" IDS_STRING "Jackdaws love my big sphinx of quartz. 1234567890" IDS_OPEN "Open Font..." IDS_ERROR "Fel" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/tr-TR.rc =================================================================== --- reactos/base/applications/fontview/lang/tr-TR.rc (revision 73640) +++ reactos/base/applications/fontview/lang/tr-TR.rc (working copy) @@ -3,8 +3,8 @@ LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT STRINGTABLE BEGIN - IDS_INSTALL "Kur..." - IDS_PRINT "Yazdır..." + IDS_INSTALL "&Kur..." + IDS_PRINT "&Yazdır..." IDS_STRING "Küçük karga, benim büyük kuvars sfenksimi seviyor. 1234567890" IDS_OPEN "Yazı Tipi Aç..." IDS_ERROR "Yanlışlık" @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Yazı Tipi (*.ttf)\0*.ttf\0\ -OpenType Yazı Tipi (*.otf)\0*.otf\0\ -Yazı Tipi Kütüğü (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Yazı Tipi (*.otf;*.otc)\0*.otf;*.otc\0\ +Yazı Tipi Kütüğü (*.fon;*.fnt)\0*.fon;*.fnt\0\ Tüm Kütükler (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/uk-UA.rc =================================================================== --- reactos/base/applications/fontview/lang/uk-UA.rc (revision 73640) +++ reactos/base/applications/fontview/lang/uk-UA.rc (working copy) @@ -10,7 +10,7 @@ STRINGTABLE BEGIN - IDS_INSTALL "Install" + IDS_INSTALL "&Install" IDS_PRINT "Друк" IDS_STRING "Чуєш їх, доцю, га? Кумедна ж ти, прощайся без ґольфів! 1234567890" IDS_OPEN "Open Font..." @@ -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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType Font (*.ttf)\0*.ttf\0\ -OpenType Font (*.otf)\0*.otf\0\ -Font File (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf;*.otc)\0*.otf;*.otc\0\ +Font File (*.fon;*.fnt)\0*.fon;*.fnt\0\ All Files (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/zh-CN.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-CN.rc (revision 73640) +++ 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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType 字体 (*.ttf)\0*.ttf\0\ -OpenType 字体 (*.otf)\0*.otf\0\ -字体文件 (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType 字体 (*.otf;*.otc)\0*.otf;*.otc\0\ +字体文件 (*.fon;*.fnt)\0*.fon;*.fnt\0\ 所有文件 (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/lang/zh-TW.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-TW.rc (revision 73640) +++ 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;*.otc)\0*.ttf;*.ttc;*.fon;*.fnt;*.otf;*.otc\0\ TrueType 字體 (*.ttf)\0*.ttf\0\ -OpenType 字體 (*.otf)\0*.otf\0\ -字體檔 (*.fon)\0*.fon\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType 字體 (*.otf;*.otc)\0*.otf;*.otc\0\ +字體檔 (*.fon;*.fnt)\0*.fon;*.fnt\0\ 所有檔 (*.*)\0*.*\0" + IDS_PREVIOUS "< P&revious" + IDS_NEXT "&Next >" END Index: reactos/base/applications/fontview/resource.h =================================================================== --- reactos/base/applications/fontview/resource.h (revision 73640) +++ 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 73640) +++ reactos/boot/bootdata/hivecls.inf (working copy) @@ -121,20 +121,38 @@ 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,".fnt","",0x00000000,"fntfile" +HKCR,"fntfile","",0x00000000,"Font file" +HKCR,"fntfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-209" +HKCR,"fntfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-155" +HKCR,"fntfile\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""" +HKCR,".otc","",0x00000000,"otcfile" +HKCR,"otcfile","",0x00000000,"OpenType Font file" +HKCR,"otcfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-211" +HKCR,"otcfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" +HKCR,"otcfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" + ; Help Files HKCR,".hlp","",0x00000000,"hlpfile" HKCR,"hlpfile","",0x00000000,"Help File" Index: reactos/win32ss/gdi/eng/engobjects.h =================================================================== --- reactos/win32ss/gdi/eng/engobjects.h (revision 73640) +++ reactos/win32ss/gdi/eng/engobjects.h (working copy) @@ -107,22 +107,31 @@ 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 OriginalItalic; + LONG OriginalWeight; + BYTE CharSet; } FONTGDI, *PFONTGDI; typedef struct _PATHGDI { Index: reactos/win32ss/gdi/gdi32/objects/text.c =================================================================== --- reactos/win32ss/gdi/gdi32/objects/text.c (revision 73640) +++ reactos/win32ss/gdi/gdi32/objects/text.c (working copy) @@ -584,13 +584,13 @@ GetFontResourceInfoW( _In_z_ LPCWSTR lpFileName, _Inout_ DWORD *pdwBufSize, - _Out_writes_to_(*pdwBufSize, *pdwBufSize) PVOID lpBuffer, + _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer, _In_ DWORD dwType) { BOOL bRet; UNICODE_STRING NtFileName; - if (!lpFileName || !pdwBufSize || !lpBuffer) + if (!lpFileName || !pdwBufSize) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; Index: reactos/win32ss/gdi/ntgdi/font.c =================================================================== --- reactos/win32ss/gdi/ntgdi/font.c (revision 73640) +++ reactos/win32ss/gdi/ntgdi/font.c (working copy) @@ -3,7 +3,8 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: win32ss/gdi/ntgdi/font.c * PURPOSE: Font - * PROGRAMMER: + * PROGRAMMERS: Hermes Belusca-Maito + * Katayama Hirofumi MZ */ /** Includes ******************************************************************/ @@ -865,13 +866,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; @@ -878,13 +879,8 @@ UNICODE_STRING SafeFileNames; BOOL bRet = FALSE; ULONG cbStringSize; + LPVOID Buffer; - union - { - LOGFONTW logfontw; - WCHAR FullName[LF_FULLFACESIZE]; - } Buffer; - /* FIXME: Handle cFiles > 0 */ /* Check for valid dwType values @@ -912,9 +908,12 @@ { ProbeForRead(pwszFiles, cbStringSize, 1); ProbeForWrite(pdwBytes, sizeof(DWORD), 1); - ProbeForWrite(pvBuf, cjIn, 1); + if (pvBuf) + ProbeForWrite(pvBuf, cjIn, 1); RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize); + Buffer = ExAllocatePoolWithTag(PagedPool, *pdwBytes, TAG_FINF); + dwBytes = *pdwBytes; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { @@ -930,8 +929,15 @@ return FALSE; } + if (Buffer == NULL) + { + ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR); + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + /* Do the actual call */ - bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType); + bRet = IntGdiGetFontResourceInfo(&SafeFileNames, Buffer, &dwBytes, dwType); /* Check if succeeded and the buffer is big enough */ if (bRet && cjIn >= dwBytes) @@ -940,7 +946,8 @@ _SEH2_TRY { /* Buffers are already probed */ - RtlCopyMemory(pvBuf, &Buffer, dwBytes); + if (pvBuf) + RtlCopyMemory(pvBuf, Buffer, dwBytes); *pdwBytes = dwBytes; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) @@ -956,6 +963,7 @@ } } + ExFreePoolWithTag(Buffer, TAG_FINF); /* Free the string for the safe filenames */ ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR); Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 73640) +++ 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-2017 Katayama Hirofumi MZ. */ /** Includes ******************************************************************/ @@ -14,20 +15,28 @@ #include FT_GLYPH_H #include FT_TYPE1_TABLES_H #include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H #include FT_TRIGONOMETRY_H #include FT_BITMAP_H #include FT_OUTLINE_H #include FT_WINFONTS_H +#include FT_SFNT_NAMES_H +#include FT_SYNTHESIS_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 #include -#ifndef FT_MAKE_TAG -#define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \ - ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \ - ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) ) +/* TPMF_FIXED_PITCH is confusing; brain-dead api */ +#ifndef _TMPF_VARIABLE_PITCH + #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH #endif extern const MATRIX gmxWorldToDeviceDefault; @@ -38,6 +47,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 FixedSysW = RTL_CONSTANT_STRING(L"FixedSys"); +static const UNICODE_STRING SymbolW = RTL_CONSTANT_STRING(L"Symbol"); + +static PSHARED_FACE +SharedFace_Create(FT_Face Face) +{ + PSHARED_FACE Ptr; + Ptr = 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 +271,7 @@ IntLoadSystemFonts(VOID) { OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING Directory, SearchPattern, FileName, TempString; + UNICODE_STRING Directory, FileName, TempString; IO_STATUS_BLOCK Iosb; HANDLE hDirectory; BYTE *DirInfoBuffer; @@ -230,10 +278,18 @@ PFILE_DIRECTORY_INFORMATION DirInfo; BOOLEAN bRestartScan = TRUE; NTSTATUS Status; + INT i; + static UNICODE_STRING SearchPatterns[] = + { + RTL_CONSTANT_STRING(L"*.ttf"), + RTL_CONSTANT_STRING(L"*.ttc"), + RTL_CONSTANT_STRING(L"*.otf"), + RTL_CONSTANT_STRING(L"*.otc"), + RTL_CONSTANT_STRING(L"*.fon"), + RTL_CONSTANT_STRING(L"*.fnt") + }; RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\"); - /* FIXME: Add support for other font types */ - RtlInitUnicodeString(&SearchPattern, L"*.ttf"); InitializeObjectAttributes( &ObjectAttributes, @@ -252,198 +308,306 @@ if (NT_SUCCESS(Status)) { - DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); - if (DirInfoBuffer == NULL) + for (i = 0; i < _countof(SearchPatterns); ++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); } } +static BYTE +ItalicFromStyle(const char *style_name) +{ + if (style_name == NULL || style_name[0] == 0) + return FALSE; + if (strstr(style_name, "Italic") != NULL) + return TRUE; + if (strstr(style_name, "Oblique") != NULL) + return TRUE; + return FALSE; +} -/* - * IntGdiAddFontResource - * - * Adds the font resource from the specified file to the system. - */ +static LONG +WeightFromStyle(const char *style_name) +{ + if (style_name == NULL || style_name[0] == 0) + return FW_NORMAL; + if (strstr(style_name, "Regular") != NULL) + return FW_REGULAR; + if (strstr(style_name, "Normal") != NULL) + return FW_NORMAL; + if (strstr(style_name, "SemiBold") != NULL) + return FW_SEMIBOLD; + if (strstr(style_name, "UltraBold") != NULL) + return FW_ULTRABOLD; + if (strstr(style_name, "DemiBold") != NULL) + return FW_DEMIBOLD; + if (strstr(style_name, "ExtraBold") != NULL) + return FW_EXTRABOLD; + if (strstr(style_name, "Bold") != NULL) + return FW_BOLD; + if (strstr(style_name, "UltraLight") != NULL) + return FW_ULTRALIGHT; + if (strstr(style_name, "ExtraLight") != NULL) + return FW_EXTRALIGHT; + if (strstr(style_name, "Light") != NULL) + return FW_LIGHT; + if (strstr(style_name, "Hairline") != NULL) + return 50; + if (strstr(style_name, "Book") != NULL) + return 350; + if (strstr(style_name, "ExtraBlack") != NULL) + return 950; + if (strstr(style_name, "UltraBlack") != NULL) + return 1000; + if (strstr(style_name, "Black") != NULL) + return FW_BLACK; + if (strstr(style_name, "Medium") != NULL) + return FW_MEDIUM; + if (strstr(style_name, "Thin") != NULL) + return FW_THIN; + if (strstr(style_name, "Heavy") != NULL) + return FW_HEAVY; + return FW_NORMAL; +} -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; + FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name); + FontGDI->RequestItalic = FALSE; + FontGDI->OriginalWeight = WeightFromStyle(Face->style_name); + FontGDI->RequestWeight = FW_NORMAL; + + RtlInitAnsiString(&FaceNameA, Face->family_name); + Status = RtlAnsiStringToUnicodeString(&FaceNameW, &FaceNameA, TRUE); + if (NT_SUCCESS(Status)) + { + /* FIXME: CharSet is invalid on Marlett */ + if (RtlEqualUnicodeString(&FaceNameW, &MarlettW, TRUE)) + { + FontGDI->CharSet = SYMBOL_CHARSET; + } + RtlFreeUnicodeString(&FaceNameW); + } + + if (FontGDI->CharSet == ANSI_CHARSET) + { + IntLockFreeType; + pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); + IntUnLockFreeType; + if (pOS2 && pOS2->version >= 1) + { + /* get charset from OS/2 header */ + 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; + } + } + /* set actual weight */ + if (FontGDI->OriginalWeight == FW_DONTCARE || + FontGDI->OriginalWeight == FW_NORMAL) + { + FontGDI->OriginalWeight = pOS2->usWeightClass; + } + } + 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 +615,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) { @@ -510,6 +784,7 @@ TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont) { PLFONT plfont; + LOGFONTW *plf; plfont = LFONT_AllocFontWithHandle(); if (!plfont) @@ -519,12 +794,12 @@ ExInitializePushLock(&plfont->lock); *NewFont = plfont->BaseObject.hHmgr; - RtlCopyMemory(&plfont->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW)); + plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont; + RtlCopyMemory(plf, lf, sizeof(LOGFONTW)); if (lf->lfEscapement != lf->lfOrientation) { /* This should really depend on whether GM_ADVANCED is set */ - plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation = - plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement; + plf->lfOrientation = plf->lfEscapement; } LFONT_UnlockFont(plfont); @@ -603,38 +878,52 @@ return FALSE; } + static void FASTCALL -FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin) +FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI, + TT_OS2 *pOS2, TT_HoriHeader *pHori, + FT_WinFNT_HeaderRec *pFNT, BOOL RealFont) { 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; - if (pWin) + if (pFNT) { - TM->tmHeight = pWin->pixel_height; - TM->tmAscent = pWin->ascent; + TM->tmHeight = pFNT->pixel_height; + TM->tmAscent = pFNT->ascent; TM->tmDescent = TM->tmHeight - TM->tmAscent; - TM->tmInternalLeading = pWin->internal_leading; - TM->tmExternalLeading = pWin->external_leading; - TM->tmAveCharWidth = pWin->avg_width; - TM->tmMaxCharWidth = pWin->max_width; - TM->tmWeight = pWin->weight; + TM->tmInternalLeading = pFNT->internal_leading; + TM->tmExternalLeading = pFNT->external_leading; + TM->tmAveCharWidth = pFNT->avg_width; + TM->tmMaxCharWidth = pFNT->max_width; TM->tmOverhang = 0; - TM->tmDigitizedAspectX = pWin->horizontal_resolution; - TM->tmDigitizedAspectY = pWin->vertical_resolution; - TM->tmFirstChar = pWin->first_char; - 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->tmUnderlined = FontGDI->Underline; - TM->tmStruckOut = FontGDI->StrikeOut; - TM->tmPitchAndFamily = pWin->pitch_and_family; - TM->tmCharSet = pWin->charset; + TM->tmDigitizedAspectX = pFNT->horizontal_resolution; + TM->tmDigitizedAspectY = pFNT->vertical_resolution; + TM->tmFirstChar = pFNT->first_char; + TM->tmLastChar = pFNT->last_char; + TM->tmDefaultChar = pFNT->default_char + pFNT->first_char; + TM->tmBreakChar = pFNT->break_char + pFNT->first_char; + TM->tmPitchAndFamily = pFNT->pitch_and_family; + if (RealFont) + { + TM->tmWeight = FontGDI->OriginalWeight; + TM->tmItalic = FontGDI->OriginalItalic; + TM->tmUnderlined = pFNT->underline; + TM->tmStruckOut = pFNT->strike_out; + TM->tmCharSet = pFNT->charset; + } + else + { + TM->tmWeight = FontGDI->RequestWeight; + TM->tmItalic = FontGDI->RequestItalic; + TM->tmUnderlined = FontGDI->RequestUnderline; + TM->tmStruckOut = FontGDI->RequestStrikeOut; + TM->tmCharSet = FontGDI->CharSet; + } return; } @@ -677,11 +966,28 @@ /* 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; + if (RealFont) + { + TM->tmWeight = FontGDI->OriginalWeight; + } + else + { + if (FontGDI->OriginalWeight != FW_DONTCARE && + FontGDI->OriginalWeight != FW_NORMAL) + { + TM->tmWeight = FontGDI->OriginalWeight; + } + else + { + TM->tmWeight = FontGDI->RequestWeight; + } + } + TM->tmOverhang = 0; TM->tmDigitizedAspectX = 96; TM->tmDigitizedAspectY = 96; - if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100)) + if (face_has_symbol_charmap(Face) || + (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100)) { USHORT cpOEM, cpAnsi; @@ -711,17 +1017,33 @@ 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; - /* Yes TPMF_FIXED_PITCH is correct; braindead api */ - if (! FT_IS_FIXED_WIDTH(Face)) + if (RealFont) { - TM->tmPitchAndFamily = TMPF_FIXED_PITCH; + TM->tmItalic = FontGDI->OriginalItalic; + TM->tmUnderlined = FALSE; + TM->tmStruckOut = FALSE; } else { + if (FontGDI->OriginalItalic || FontGDI->RequestItalic) + { + TM->tmItalic = 0xFF; + } + else + { + TM->tmItalic = 0; + } + TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0); + TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0); + } + + if (!FT_IS_FIXED_WIDTH(Face)) + { + TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH; + } + else + { TM->tmPitchAndFamily = 0; } @@ -788,9 +1110,17 @@ TM->tmPitchAndFamily |= TMPF_TRUETYPE; } - TM->tmCharSet = DEFAULT_CHARSET; + TM->tmCharSet = FontGDI->CharSet; } +static void FASTCALL +FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, + TT_OS2 *pOS2, TT_HoriHeader *pHori, + FT_WinFNT_HeaderRec *pFNT) +{ + FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE); +} + /************************************************************* * IntGetOutlineTextMetrics * @@ -811,10 +1141,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 +1152,7 @@ return 0; } - RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name); + RtlInitAnsiString(&StyleNameA, Face->style_name); status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); if (!NT_SUCCESS(status)) { @@ -834,9 +1165,9 @@ /* Length of otmpFamilyName */ Needed += FamilyNameW.Length + sizeof(WCHAR); - RtlInitUnicodeString(&Regular, L"regular"); + 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 +1189,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 +1203,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 +1213,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 +1228,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 +1275,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 +1314,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 +1327,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 +1379,7 @@ NEWTEXTMETRICW *Ntm; DWORD fs0; NTSTATUS status; + FT_Face Face = FontGDI->SharedFace->Face; RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); @@ -1110,6 +1442,7 @@ ExFreePoolWithTag(Otm, GDITAG_TEXT); + /* FIXME: support localized names */ RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName, sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName), FaceName); @@ -1116,7 +1449,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); @@ -1124,11 +1457,21 @@ { return; } + if (StyleW.Length) + { + if (wcslen(Info->EnumLogFontEx.elfFullName) + + StyleW.Length / sizeof(WCHAR) + 1 <= + sizeof(Info->EnumLogFontEx.elfFullName)) + { + wcscat(Info->EnumLogFontEx.elfFullName, L" "); + wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer); + } + } 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 +1486,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 +1493,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 +1543,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 +1559,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 +1590,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)) { @@ -1444,7 +1787,49 @@ return FontEntry->BitmapGlyph; } +/* no cache */ FT_BitmapGlyph APIENTRY +ftGdiGlyphSet( + FT_Face Face, + FT_GlyphSlot GlyphSlot, + FT_Render_Mode RenderMode) +{ + FT_Glyph Glyph; + INT error; + FT_Bitmap AlignedBitmap; + FT_BitmapGlyph BitmapGlyph; + + error = FT_Get_Glyph(GlyphSlot, &Glyph); + if (error) + { + DPRINT1("Failure getting glyph.\n"); + return NULL; + } + + error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1); + if (error) + { + FT_Done_Glyph(Glyph); + DPRINT1("Failure rendering glyph.\n"); + return NULL; + } + + BitmapGlyph = (FT_BitmapGlyph)Glyph; + FT_Bitmap_New(&AlignedBitmap); + if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) + { + DPRINT1("Conversion failed\n"); + FT_Done_Glyph((FT_Glyph)BitmapGlyph); + return NULL; + } + + FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); + BitmapGlyph->bitmap = AlignedBitmap; + + return BitmapGlyph; +} + +FT_BitmapGlyph APIENTRY ftGdiGlyphCacheSet( FT_Face Face, INT GlyphIndex, @@ -1784,6 +2169,7 @@ int n = 0; FT_CharMap found = 0, charmap; XFORM xForm; + LOGFONTW *plf; DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm, cjBuf, pvBuf, pmat2); @@ -1802,10 +2188,11 @@ 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; + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; + aveWidth = FT_IS_SCALABLE(ft_face) ? plf->lfWidth : 0; + orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0; Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); @@ -1847,10 +2234,11 @@ } FT_Set_Pixel_Sizes(ft_face, - abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth), + abs(plf->lfWidth), /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc)); TEXTOBJ_UnlockText(TextObj); @@ -1929,19 +2317,6 @@ needsTransform = TRUE; } - /* Slant transform */ - if (potm->otmTextMetrics.tmItalic) - { - FT_Matrix slantMat; - DPRINT("Slant Trans!\n"); - slantMat.xx = (1 << 16); - slantMat.xy = ((1 << 16) >> 2); - slantMat.yx = 0; - slantMat.yy = (1 << 16); - FT_Matrix_Multiply(&slantMat, &transMat); - needsTransform = TRUE; - } - /* Rotation transform */ if (orientation) { @@ -2081,7 +2456,7 @@ ft_bitmap.width = width; ft_bitmap.rows = height; ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_mono; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO; ft_bitmap.buffer = pvBuf; IntLockFreeType; @@ -2145,7 +2520,7 @@ ft_bitmap.width = width; ft_bitmap.rows = height; ft_bitmap.pitch = pitch; - ft_bitmap.pixel_mode = ft_pixel_mode_grays; + ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY; ft_bitmap.buffer = pvBuf; IntLockFreeType; @@ -2268,10 +2643,12 @@ FT_Render_Mode RenderMode; BOOLEAN Render; PMATRIX pmxWorldToDevice; + LOGFONTW *plf; + BOOL EmuBold, EmuItalic; FontGDI = ObjToGDI(TextObj->Font, FONT); - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (NULL != Fit) { *Fit = 0; @@ -2306,17 +2683,19 @@ } } + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; Render = IntIsFontRenderingEnabled(); if (Render) - RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont); + RenderMode = IntGetFontRenderMode(plf); else RenderMode = FT_RENDER_MODE_MONO; error = FT_Set_Pixel_Sizes(face, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, + plf->lfWidth, /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); if (error) { DPRINT1("Error in setting pixel sizes: %d\n", error); @@ -2336,9 +2715,16 @@ else glyph_index = FT_Get_Char_Index(face, *String); - if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice))) + EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); + EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); + + if (EmuBold || EmuItalic) + realglyph = NULL; + else + realglyph = ftGdiGlyphCacheGet(face, glyph_index, + plf->lfHeight, pmxWorldToDevice); + + if (EmuBold || EmuItalic || !realglyph) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -2348,12 +2734,24 @@ } glyph = face->glyph; - realglyph = ftGdiGlyphCacheSet(face, - glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice, - glyph, - RenderMode); + if (EmuBold || EmuItalic) + { + if (EmuBold) + FT_GlyphSlot_Embolden(glyph); + if (EmuItalic) + FT_GlyphSlot_Oblique(glyph); + realglyph = ftGdiGlyphSet(face, glyph, RenderMode); + } + else + { + realglyph = ftGdiGlyphCacheSet(face, + glyph_index, + plf->lfHeight, + pmxWorldToDevice, + glyph, + RenderMode); + } + if (!realglyph) { DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); @@ -2380,6 +2778,12 @@ Dx[i] = (TotalWidth + 32) >> 6; } + if (EmuBold || EmuItalic) + { + FT_Done_Glyph((FT_Glyph)realglyph); + realglyph = NULL; + } + previous = glyph_index; String++; } @@ -2386,8 +2790,9 @@ IntUnLockFreeType; Size->cx = (TotalWidth + 32) >> 6; - Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)); + Size->cy = (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight)); Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72); return TRUE; @@ -2424,7 +2829,7 @@ return Ret; } FontGdi = ObjToGDI(TextObj->Font, FONT); - Face = FontGdi->face; + Face = FontGdi->SharedFace->Face; TEXTOBJ_UnlockText(TextObj); IntLockFreeType; @@ -2512,7 +2917,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) { @@ -2590,6 +2995,7 @@ FT_WinFNT_HeaderRec Win; ULONG Error; NTSTATUS Status = STATUS_SUCCESS; + LOGFONTW *plf; if (!ptmwi) { @@ -2606,15 +3012,17 @@ TextObj = RealizeFontInit(pdcattr->hlfntNew); if (NULL != TextObj) { + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; FontGDI = ObjToGDI(TextObj->Font, FONT); - Face = FontGDI->face; + Face = FontGDI->SharedFace->Face; IntLockFreeType; Error = FT_Set_Pixel_Sizes(Face, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, + plf->lfWidth, /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc)); IntUnLockFreeType; if (0 != Error) @@ -2624,10 +3032,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 +3043,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 +3050,7 @@ Status = STATUS_INTERNAL_ERROR; } - Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); + Error = FT_Get_WinFNT_Header(Face, &Win); IntUnLockFreeType; @@ -2680,10 +3089,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 +3106,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,170 +3119,622 @@ 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 BOOL +SubstituteFontName(PUNICODE_STRING FaceName) +{ + UINT Level; + const UINT MaxLevel = 10; + + if (FaceName->Buffer[0] == 0) + return FALSE; + + for (Level = 0; Level < MaxLevel; ++Level) + { + /* NOTE: SubstituteFontNameByKey changes FaceName. Be careful... */ + if (!SubstituteFontNameByKey(FaceName, L"FontSubstitutes")) + break; + } + return (Level > 0); +} + +/* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */ +static BYTE +CharSetFromLangID(LANGID LangID) +{ + switch (PRIMARYLANGID(LangID)) + { + case LANG_ARABIC: return ARABIC_CHARSET; + case LANG_BASQUE: return ANSI_CHARSET; + case LANG_CATALAN: return ANSI_CHARSET; + case LANG_CHINESE: + switch (SUBLANGID(LangID)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + return GB2312_CHARSET; + case SUBLANG_CHINESE_TRADITIONAL: + return CHINESEBIG5_CHARSET; + } + break; + case LANG_CZECH: return EASTEUROPE_CHARSET; + case LANG_DANISH: return ANSI_CHARSET; + case LANG_DUTCH: return ANSI_CHARSET; + case LANG_ENGLISH: return ANSI_CHARSET; + case LANG_FINNISH: return ANSI_CHARSET; + case LANG_FRENCH: return ANSI_CHARSET; + case LANG_GERMAN: return ANSI_CHARSET; + case LANG_GREEK: return GREEK_CHARSET; + case LANG_HEBREW: return HEBREW_CHARSET; + case LANG_HUNGARIAN: return EASTEUROPE_CHARSET; + case LANG_ITALIAN: return ANSI_CHARSET; + case LANG_JAPANESE: return SHIFTJIS_CHARSET; + case LANG_KOREAN: return JOHAB_CHARSET; + case LANG_NORWEGIAN: return ANSI_CHARSET; + case LANG_POLISH: return EASTEUROPE_CHARSET; + case LANG_PORTUGUESE: return ANSI_CHARSET; + case LANG_RUSSIAN: return RUSSIAN_CHARSET; + case LANG_SLOVAK: return EASTEUROPE_CHARSET; + case LANG_SLOVENIAN: return EASTEUROPE_CHARSET; + case LANG_SPANISH: return ANSI_CHARSET; + case LANG_SWEDISH: return ANSI_CHARSET; + case LANG_TURKISH: return TURKISH_CHARSET; + /**/ + case LANG_BULGARIAN: return RUSSIAN_CHARSET; + case LANG_MACEDONIAN: return RUSSIAN_CHARSET; + case LANG_SERBIAN: return RUSSIAN_CHARSET; + case LANG_UKRAINIAN: return RUSSIAN_CHARSET; + case LANG_ROMANIAN: return EASTEUROPE_CHARSET; + case LANG_THAI: return THAI_CHARSET; + case LANG_LATVIAN: return BALTIC_CHARSET; + case LANG_VIETNAMESE: return VIETNAMESE_CHARSET; + /* FIXME: Add more and fix if wrong */ + default: break; + } + return ANSI_CHARSET; +} + +static NTSTATUS +IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face) +{ + FT_SfntName Name; + INT i, Count; + WCHAR Buf[LF_FACESIZE]; + NTSTATUS Status = STATUS_NOT_FOUND; + + RtlInitUnicodeString(pLocalNameW, NULL); + + Count = FT_Get_Sfnt_Name_Count(Face); + for (i = 0; i < Count; ++i) + { + FT_Get_Sfnt_Name(Face, i, &Name); + if (Name.platform_id == 3 && Name.encoding_id == 1) { - Score += 49; + /* Microsoft Unicode name */ + if (Name.name_id != 1 || Name.string == NULL || + Name.string[0] == 0 || Name.string_len == 0) + { + continue; /* not family_name */ + } + + if (sizeof(Buf) >= Name.string_len + 2) + { + /* NOTE: Name.string is not null-terminated */ + RtlCopyMemory(Buf, Name.string, Name.string_len); + ((char *)Buf)[Name.string_len + 0] = 0; + ((char *)Buf)[Name.string_len + 1] = 0; + DPRINT("IntGetFontLocalizedName: %ls\n", Buf); + Status = RtlCreateUnicodeString(pLocalNameW, Buf); + break; + } } + } - /* 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)) + return Status; +} + +// NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx +static UINT FASTCALL +GetFontPenalty(LOGFONTW * LogFont, + PUNICODE_STRING RequestedNameW, + PUNICODE_STRING ActualNameW, + PUNICODE_STRING FullFaceNameW, + PFONTGDI FontGDI, + OUTLINETEXTMETRICW * Otm, + TEXTMETRICW * TM, + const char * style_name) +{ + ULONG Penalty = 0; + BYTE Byte; + LONG Long; + BOOL fFixedSys = FALSE, fNeedScaling = FALSE; + /* FIXME: Aspect Penalty 30 */ + /* FIXME: IntSizeSynth Penalty 20 */ + /* FIXME: SmallPenalty Penalty 1 */ + /* FIXME: FaceNameSubst Penalty 500 */ + + if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE)) + { + /* "System" font */ + if (TM->tmCharSet != CharSetFromLangID(gusLanguageID)) { - Score = 0; + /* CharSet Penalty 65000 */ + /* Requested charset does not match the candidate's. */ + Penalty += 65000; } + } + else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE)) + { + /* "FixedSys" font */ + if (TM->tmCharSet != CharSetFromLangID(gusLanguageID)) + { + /* CharSet Penalty 65000 */ + /* Requested charset does not match the candidate's. */ + Penalty += 65000; + } + fFixedSys = TRUE; + } + else /* Request is non-"System" font */ + { + Byte = LogFont->lfCharSet; - if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE)) + if (Byte == DEFAULT_CHARSET) { - Score = 0; + if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE)) + { + /* We assume SYMBOL_CHARSET for "Marlett" font */ + Byte = SYMBOL_CHARSET; + } + else + { + Byte = CharSetFromLangID(gusLanguageID); + } } - if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE)) + if (Byte != TM->tmCharSet) { - Score = 0; + if (Byte != ANSI_CHARSET) + { + /* CharSet Penalty 65000 */ + /* Requested charset does not match the candidate's. */ + Penalty += 65000; + } } + } - RtlFreeUnicodeString(&EntryFaceNameW); + 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; } - Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); - Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); - if (NULL == Otm) + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte == DEFAULT_PITCH) + Byte = VARIABLE_PITCH; + if (fFixedSys) { - return Score; + /* "FixedSys" font should be fixed-pitch */ + Byte = FIXED_PITCH; } - IntGetOutlineTextMetrics(FontGDI, Size, Otm); + if (Byte == FIXED_PITCH) + { + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) + { + /* 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; + } + } - if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) || - (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic)) + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte == DEFAULT_PITCH) { - Score += 25; + if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + /* DefaultPitchFixed Penalty 1 */ + /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */ + Penalty += 1; + } } - if (LogFont->lfWeight != FW_DONTCARE) + + if (RequestedNameW->Buffer[0]) { - if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight) + if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE)) { - WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight; + /* matched with full face name */ } + else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE)) + { + /* matched with actual name */ + } else { - WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight; + /* try the localized name */ + UNICODE_STRING LocalNameW; + FT_Face Face = FontGDI->SharedFace->Face; + IntGetFontLocalizedName(&LocalNameW, Face); + if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE)) + { + /* matched with localizied name */ + } + else + { + /* FaceName Penalty 10000 */ + /* Requested a face name, but the candidate's face name + does not match. */ + Penalty += 10000; + } + RtlFreeUnicodeString(&LocalNameW); } - Score += (1000 - WeightDiff) / (1000 / 25); } - else + + Byte = (LogFont->lfPitchAndFamily & 0xF0); + if (Byte != FF_DONTCARE) { - Score += 25; + if (Byte != (TM->tmPitchAndFamily & 0xF0)) + { + /* Family Penalty 9000 */ + /* Requested a family, but the candidate's family is different. */ + Penalty += 9000; + } + if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) + { + /* FamilyUnknown Penalty 8000 */ + /* Requested a family, but the candidate has no family. */ + Penalty += 8000; + } } - ExFreePoolWithTag(Otm, GDITAG_TEXT); + /* Is the candidate a non-vector font? */ + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) + { + /* Is lfHeight specified? */ + if (LogFont->lfHeight != 0) + { + 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)); - return Score; + 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; + } + } + } + + 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) + { + /* 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; + } + } + + if (fNeedScaling) + { + /* SizeSynth Penalty 50 */ + /* The candidate is a raster font that needs scaling by GDI. */ + Penalty += 50; + } + + if (!!LogFont->lfItalic != !!TM->tmItalic) + { + if (!LogFont->lfItalic && ItalicFromStyle(style_name)) + { + /* Italic Penalty 4 */ + /* Requested font and candidate font do not agree on italic status, + and the desired result cannot be simulated. */ + /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */ + Penalty += 40; + } + else if (LogFont->lfItalic && !ItalicFromStyle(style_name)) + { + /* ItalicSim Penalty 1 */ + /* Requested italic font but the candidate is not italic, + although italics can be simulated. */ + Penalty += 1; + } + } + + 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) + { + if (Long != WeightFromStyle(style_name)) + { + /* Weight Penalty 3 */ + /* The candidate's weight does not match the requested weight. + Penalty * (weight difference/10) */ + Penalty += 3 * (labs(Long - TM->tmWeight) / 10); + } + } + + if (!LogFont->lfUnderline && TM->tmUnderlined) + { + /* Underline Penalty 3 */ + /* Requested font has no underline, but the candidate is + underlined. */ + Penalty += 3; + } + + if (!LogFont->lfStrikeOut && TM->tmStruckOut) + { + /* StrikeOut Penalty 3 */ + /* Requested font has no strike-out, but the candidate is + struck out. */ + Penalty += 3; + } + + /* Is the candidate a non-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; + } + + if (Penalty < 200) + { + DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, " + "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, " + "tmCharSet:%d, tmWeight:%ld\n", + Penalty, RequestedNameW->Buffer, ActualNameW->Buffer, + LogFont->lfCharSet, LogFont->lfWeight, + TM->tmCharSet, 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, FullFaceNameW; + OUTLINETEXTMETRICW *Otm = NULL; + UINT OtmSize, OldOtmSize = 0; + TEXTMETRICW *TM; + FT_Face Face; + LPBYTE pb; + + ASSERT(FontObj); + ASSERT(MatchPenalty); + ASSERT(LogFont); + ASSERT(pRequestedNameW); + ASSERT(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); + Face = FontGDI->SharedFace->Face; - Score = GetFontScore(LogFont, FaceName, FontGDI); - if (*MatchScore == 0 || *MatchScore < Score) + /* create actual name */ + RtlInitAnsiString(&ActualNameA, 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; + /* create full name */ + pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName; + Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb); + if (!NT_SUCCESS(Status)) + { + RtlFreeUnicodeString(&ActualNameW); + RtlFreeUnicodeString(&FullFaceNameW); + /* next entry */ + Entry = Entry->Flink; + continue; + } - QueryTable[1].QueryRoutine = NULL; - QueryTable[1].Name = NULL; + Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW, + &FullFaceNameW, FontGDI, Otm, TM, + Face->style_name); + if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) + { + DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty); + RtlFreeUnicodeString(pActualNameW); + RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer); - Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, - Key, - QueryTable, - NULL, - NULL); - if (NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(FaceName); - *FaceName = Value; - } + *FontObj = GDIToObj(FontGDI, FONT); + *MatchPenalty = Penalty; + } - return NT_SUCCESS(Status); -} + RtlFreeUnicodeString(&FullFaceNameW); + } -static __inline void -SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level) -{ - if (10 < Level) /* Enough is enough */ - { - return; + /* free strings */ + RtlFreeUnicodeString(&ActualNameW); + + /* next entry */ + Entry = Entry->Flink; } - if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes")) - { - SubstituteFontFamily(FaceName, Level + 1); - } + if (Otm) + ExFreePoolWithTag(Otm, GDITAG_TEXT); } static @@ -2882,25 +3744,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, TTAG_CFF, 0, NULL, &tmp_size)) { Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT); } @@ -2912,9 +3775,11 @@ { NTSTATUS Status = STATUS_SUCCESS; PTEXTOBJ TextObj; - UNICODE_STRING FaceName; + UNICODE_STRING ActualNameW, RequestedNameW; PPROCESSINFO Win32Process; - UINT MatchScore; + ULONG MatchPenalty; + LOGFONTW *pLogFont; + FT_Face Face; if (!pTextObj) { @@ -2931,35 +3796,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); + DPRINT1("Request font %S not found, no fonts loaded at all\n", + pLogFont->lfFaceName); Status = STATUS_NOT_FOUND; } else @@ -2970,13 +3846,35 @@ 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; + + Face = FontGdi->SharedFace->Face; + + if (FontGdi->OriginalWeight == FW_DONTCARE || + FontGdi->OriginalWeight == FW_NORMAL) + { + FontGdi->OriginalWeight = WeightFromStyle(Face->style_name); + } + + if (!FontGdi->OriginalItalic) + FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name); + 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); @@ -3030,6 +3928,44 @@ return TRUE; } +static BOOL +EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2) +{ + UNICODE_STRING Str1, Str2; + ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx; + ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx; + RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName); + RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName); + if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE)) + { + return FALSE; + } + if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL)) + return FALSE; + if (pLog1->elfStyle != NULL) + { + RtlInitUnicodeString(&Str1, pLog1->elfStyle); + RtlInitUnicodeString(&Str2, pLog2->elfStyle); + if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE)) + { + return FALSE; + } + } + return TRUE; +} + +static VOID +IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo) +{ + wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName); + if (FamInfo->EnumLogFontEx.elfStyle[0] && + _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0) + { + wcscat(psz, L" "); + wcscat(psz, FamInfo->EnumLogFontEx.elfStyle); + } +} + BOOL FASTCALL IntGdiGetFontResourceInfo( @@ -3042,9 +3978,11 @@ POBJECT_NAME_INFORMATION NameInfo1, NameInfo2; PLIST_ENTRY ListEntry; PFONT_ENTRY FontEntry; - FONTFAMILYINFO Info; - ULONG Size; - BOOL bFound = FALSE; + ULONG Size, i, Count, CountToRead; + LPBYTE pbBuffer; + BOOL IsEqual; + FONTFAMILYINFO *FamInfo; + const ULONG MaxFamInfo = 64; /* Create buffer for full path name */ Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); @@ -3071,7 +4009,18 @@ return FALSE; } + FamInfo = ExAllocatePoolWithTag(PagedPool, + sizeof(FONTFAMILYINFO) * MaxFamInfo, + TAG_FINF); + if (!FamInfo) + { + ExFreePoolWithTag(NameInfo2, TAG_FINF); + ExFreePoolWithTag(NameInfo1, TAG_FINF); + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } /* Try to find the pathname in the global font list */ + Count = 0; IntLockGlobalFonts; for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead; @@ -3078,20 +4027,34 @@ ListEntry = ListEntry->Flink) { FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry); - if (FontEntry->Font->Filename != NULL) + if (FontEntry->Font->Filename == NULL) + continue; + + RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename); + if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName)) + continue; + + if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) + continue; + + IsEqual = FALSE; + FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer, + FontEntry->Font); + for (i = 0; i < Count; ++i) { - RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename); - if (IntGetFullFileName(NameInfo2, Size, &EntryFileName)) + if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count])) { - if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) - { - /* Found */ - FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font); - bFound = TRUE; - break; - } + IsEqual = TRUE; + break; } } + if (!IsEqual) + { + /* Found */ + ++Count; + if (Count >= MaxFamInfo) + break; + } } IntUnLockGlobalFonts; @@ -3099,10 +4062,11 @@ 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 */ + ExFreePoolWithTag(FamInfo, TAG_FINF); return FALSE; } @@ -3113,18 +4077,68 @@ *pdwBytes = sizeof(DWORD); break; - case 1: /* Copy the full font name */ - Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1; - Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR); - RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size); - // FIXME: Do we have to zeroterminate? + case 1: /* copy the font title */ + /* calculate the required size */ + Size = 0; + Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName); + if (FamInfo[0].EnumLogFontEx.elfStyle[0] && + _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0) + { + Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle); + } + for (i = 1; i < Count; ++i) + { + Size += 3; /* " & " */ + Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName); + if (FamInfo[i].EnumLogFontEx.elfStyle[0] && + _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0) + { + Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle); + } + } + if (FamInfo[0].FontType & TRUETYPE_FONTTYPE) + { + Size += wcslen(L" (TrueType)"); + } + Size += 1; /* '\0' */ + Size *= sizeof(WCHAR); + + if (Size <= *pdwBytes) + { + /* store font title to buffer */ + WCHAR *psz = pBuffer; + *psz = 0; + IntAddNameFromFamInfo(psz, &FamInfo[0]); + for (i = 1; i < Count; ++i) + { + wcscat(psz, L" & "); + IntAddNameFromFamInfo(psz, &FamInfo[i]); + } + if (FamInfo[0].FontType & TRUETYPE_FONTTYPE) + { + wcscat(psz, L" (TrueType)"); + } + } + else + { + RtlZeroMemory(pBuffer, *pdwBytes); + } *pdwBytes = Size; break; - case 2: /* Copy a LOGFONTW structure */ - Info.EnumLogFontEx.elfLogFont.lfWidth = 0; - RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); - *pdwBytes = sizeof(LOGFONTW); + case 2: /* Copy an array of LOGFONTW */ + if (*pdwBytes < Count * sizeof(LOGFONTW)) + CountToRead = *pdwBytes / sizeof(LOGFONTW); + else + CountToRead = Count; + pbBuffer = (LPBYTE)pBuffer; + for (i = 0; i < CountToRead; ++i) + { + FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0; + RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); + pbBuffer += sizeof(LOGFONTW); + } + *pdwBytes = Count * sizeof(LOGFONTW); break; case 3: /* FIXME: What exactly is copied here? */ @@ -3133,13 +4147,15 @@ 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; default: + ExFreePoolWithTag(FamInfo, TAG_FINF); return FALSE; } + ExFreePoolWithTag(FamInfo, TAG_FINF); return TRUE; } @@ -3149,11 +4165,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 +4188,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) { @@ -3358,6 +4374,8 @@ PMATRIX pmxWorldToDevice; LONG fixAscender, fixDescender; FLOATOBJ Scale; + LOGFONTW *plf; + int thickness; // TODO: Write test-cases to exactly match real Windows in different // bad parameters (e.g. does Windows check the DC or the RECT first?). @@ -3492,7 +4510,7 @@ ASSERT(FontGDI); IntLockFreeType; - face = FontGDI->face; + face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { DPRINT("WARNING: No charmap selected!\n"); @@ -3519,18 +4537,20 @@ } } + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; Render = IntIsFontRenderingEnabled(); if (Render) - RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont); + RenderMode = IntGetFontRenderMode(plf); else RenderMode = FT_RENDER_MODE_MONO; error = FT_Set_Pixel_Sizes( face, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, + plf->lfWidth, /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); if (error) { DPRINT1("Error in setting pixel sizes: %d\n", error); @@ -3596,14 +4616,21 @@ for (i = iStart; i < Count; i++) { + BOOL EmuBold = + (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); + BOOL EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); + if (fuOptions & ETO_GLYPH_INDEX) glyph_index = *TempText; else glyph_index = FT_Get_Char_Index(face, *TempText); - if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice))) + if (EmuBold || EmuItalic) + realglyph = NULL; + else + realglyph = ftGdiGlyphCacheGet(face, glyph_index, + plf->lfHeight, pmxWorldToDevice); + if (!realglyph) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -3612,12 +4639,23 @@ } glyph = face->glyph; - realglyph = ftGdiGlyphCacheSet(face, - glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice, - glyph, - RenderMode); + if (EmuBold || EmuItalic) + { + if (EmuBold) + FT_GlyphSlot_Embolden(glyph); + if (EmuItalic) + FT_GlyphSlot_Oblique(glyph); + realglyph = ftGdiGlyphSet(face, glyph, RenderMode); + } + else + { + realglyph = ftGdiGlyphCacheSet(face, + glyph_index, + plf->lfHeight, + pmxWorldToDevice, + glyph, + RenderMode); + } if (!realglyph) { DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); @@ -3636,6 +4674,12 @@ TextWidth += realglyph->root.advance.x >> 10; + if (EmuBold || EmuItalic) + { + FT_Done_Glyph((FT_Glyph)realglyph); + realglyph = NULL; + } + previous = glyph_index; TempText++; } @@ -3671,19 +4715,29 @@ if(dc->pdcattr->ulDirty_ & DIRTY_TEXT) DC_vUpdateTextBrush(dc) ; + thickness = face->underline_thickness * + face->size->metrics.y_ppem / face->units_per_EM; + /* * The main rendering loop. */ for (i = 0; i < Count; i++) { + BOOL EmuBold = + (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL); + BOOL EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic); + if (fuOptions & ETO_GLYPH_INDEX) glyph_index = *String; else glyph_index = FT_Get_Char_Index(face, *String); - if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice))) + if (EmuBold || EmuItalic) + realglyph = NULL; + else + realglyph = ftGdiGlyphCacheGet(face, glyph_index, + plf->lfHeight, pmxWorldToDevice); + if (!realglyph) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -3693,13 +4747,25 @@ DC_vFinishBlit(dc, NULL); goto fail2; } + glyph = face->glyph; - realglyph = ftGdiGlyphCacheSet(face, - glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, - pmxWorldToDevice, - glyph, - RenderMode); + if (EmuBold || EmuItalic) + { + if (EmuBold) + FT_GlyphSlot_Embolden(glyph); + if (EmuItalic) + FT_GlyphSlot_Oblique(glyph); + realglyph = ftGdiGlyphSet(face, glyph, RenderMode); + } + else + { + realglyph = ftGdiGlyphCacheSet(face, + glyph_index, + plf->lfHeight, + pmxWorldToDevice, + glyph, + RenderMode); + } if (!realglyph) { DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index); @@ -3832,10 +4898,44 @@ break; } + if (plf->lfUnderline) + { + int i, position = face->underline_position * + face->size->metrics.y_ppem / face->units_per_EM; + for (i = -thickness / 2; i <= thickness / 2; ++i) + { + EngLineTo(SurfObj, + &dc->co.ClipObj, + &dc->eboText.BrushObject, + (TextLeft >> 6), + TextTop + yoff - position + i, + ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), + TextTop + yoff - position + i, + NULL, + ROP2_TO_MIX(R2_COPYPEN)); + } + } + if (plf->lfStrikeOut) + { + int i; + for (i = -thickness / 2; i <= thickness / 2; ++i) + { + EngLineTo(SurfObj, + &dc->co.ClipObj, + &dc->eboText.BrushObject, + (TextLeft >> 6), + TextTop + yoff - (fixAscender >> 6) / 3 + i, + ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6), + TextTop + yoff - (fixAscender >> 6) / 3 + i, + NULL, + ROP2_TO_MIX(R2_COPYPEN)); + } + } + if (NULL == Dx) { TextLeft += realglyph->root.advance.x >> 10; - DPRINT("New TextLeft: %I64d\n", TextLeft); + DPRINT("New TextLeft: %I64d\n", TextLeft); } else { @@ -3856,6 +4956,12 @@ previous = glyph_index; + if (EmuBold || EmuItalic) + { + FT_Done_Glyph((FT_Glyph)realglyph); + realglyph = NULL; + } + String++; } @@ -3866,6 +4972,7 @@ IntUnLockFreeType; DC_vFinishBlit(dc, NULL) ; + EXLATEOBJ_vCleanup(&exloRGB2Dst); EXLATEOBJ_vCleanup(&exloDst2RGB); if (TextObj != NULL) @@ -4036,6 +5143,7 @@ NTSTATUS Status = STATUS_SUCCESS; PMATRIX pmxWorldToDevice; PWCHAR Safepwch = NULL; + LOGFONTW *plf; if (!Buffer) { @@ -4120,7 +5228,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++) @@ -4150,12 +5258,14 @@ IntUnLockFreeType; } + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; IntLockFreeType; FT_Set_Pixel_Sizes(face, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, + plf->lfWidth, /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); FtSetCoordinateTransform(face, pmxWorldToDevice); for (i = FirstChar; i < FirstChar+Count; i++) @@ -4248,6 +5358,7 @@ HFONT hFont = 0; PMATRIX pmxWorldToDevice; PWCHAR Safepwc = NULL; + LOGFONTW *plf; if (UnSafepwc) { @@ -4318,7 +5429,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++) @@ -4348,12 +5459,14 @@ IntUnLockFreeType; } + plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; IntLockFreeType; FT_Set_Pixel_Sizes(face, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, + plf->lfWidth, /* FIXME: Should set character height if neg */ - (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? - dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); + (plf->lfHeight == 0 ? + dc->ppdev->devinfo.lfDefaultFont.lfHeight : + abs(plf->lfHeight))); FtSetCoordinateTransform(face, pmxWorldToDevice); for (i = FirstChar; i < FirstChar+Count; i++) @@ -4456,10 +5569,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 +5616,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;