Index: reactos/base/applications/fontview/lang/bg-BG.rc =================================================================== --- reactos/base/applications/fontview/lang/bg-BG.rc (revision 73465) +++ reactos/base/applications/fontview/lang/bg-BG.rc (working copy) @@ -10,8 +10,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/cs-CZ.rc =================================================================== --- reactos/base/applications/fontview/lang/cs-CZ.rc (revision 73465) +++ reactos/base/applications/fontview/lang/cs-CZ.rc (working copy) @@ -10,8 +10,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/de-DE.rc =================================================================== --- reactos/base/applications/fontview/lang/de-DE.rc (revision 73465) +++ reactos/base/applications/fontview/lang/de-DE.rc (working copy) @@ -10,8 +10,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/en-US.rc =================================================================== --- reactos/base/applications/fontview/lang/en-US.rc (revision 73465) +++ reactos/base/applications/fontview/lang/en-US.rc (working copy) @@ -10,8 +10,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/es-ES.rc =================================================================== --- reactos/base/applications/fontview/lang/es-ES.rc (revision 73465) +++ reactos/base/applications/fontview/lang/es-ES.rc (working copy) @@ -12,8 +12,9 @@ IDS_ERROR_NOMEM "No hay memoria suficiente para completar la operación." IDS_ERROR_NOFONT "El archivo %1 no es un archivo de fuente válido." IDS_ERROR_NOCLASS "No es posible iniciar la clase de ventana." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/fr-FR.rc =================================================================== --- reactos/base/applications/fontview/lang/fr-FR.rc (revision 73465) +++ reactos/base/applications/fontview/lang/fr-FR.rc (working copy) @@ -10,8 +10,9 @@ IDS_ERROR_NOMEM "Mémoire insuffisante pour terminer l'opération." IDS_ERROR_NOFONT "Le fichier %1 n'est pas un fichier police valide." IDS_ERROR_NOCLASS "Impossible d'initialiser la classe de fenêtre." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/he-IL.rc =================================================================== --- reactos/base/applications/fontview/lang/he-IL.rc (revision 73465) +++ reactos/base/applications/fontview/lang/he-IL.rc (working copy) @@ -12,8 +12,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/it-IT.rc =================================================================== --- reactos/base/applications/fontview/lang/it-IT.rc (revision 73465) +++ reactos/base/applications/fontview/lang/it-IT.rc (working copy) @@ -10,8 +10,9 @@ IDS_ERROR_NOMEM "Memoria insufficiente per completare l'operazione." IDS_ERROR_NOFONT "Il file% 1 non è un file di origine valido." IDS_ERROR_NOCLASS "Impossibile avviare la classe." - IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.fon;*.otf)\0*.ttf;*.fon;*.otf\0\ + IDS_FILTER_LIST "All Supported Fonts (*.ttf;*.ttc;*.fon;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/lt-LT.rc =================================================================== --- reactos/base/applications/fontview/lang/lt-LT.rc (revision 73465) +++ reactos/base/applications/fontview/lang/lt-LT.rc (working copy) @@ -12,8 +12,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/ms-MY.rc =================================================================== --- reactos/base/applications/fontview/lang/ms-MY.rc (revision 73465) +++ reactos/base/applications/fontview/lang/ms-MY.rc (working copy) @@ -12,9 +12,10 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ +TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ +OpenType Font (*.otf)\0*.otf\0\ +Font File (*.fon)\0*.fon\0\ +All Files (*.*)\0*.*\0" END Index: reactos/base/applications/fontview/lang/no-NO.rc =================================================================== --- reactos/base/applications/fontview/lang/no-NO.rc (revision 73465) +++ reactos/base/applications/fontview/lang/no-NO.rc (working copy) @@ -10,8 +10,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/pl-PL.rc =================================================================== --- reactos/base/applications/fontview/lang/pl-PL.rc (revision 73465) +++ reactos/base/applications/fontview/lang/pl-PL.rc (working copy) @@ -18,8 +18,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/pt-BR.rc =================================================================== --- reactos/base/applications/fontview/lang/pt-BR.rc (revision 73465) +++ reactos/base/applications/fontview/lang/pt-BR.rc (working copy) @@ -12,8 +12,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/ro-RO.rc =================================================================== --- reactos/base/applications/fontview/lang/ro-RO.rc (revision 73465) +++ reactos/base/applications/fontview/lang/ro-RO.rc (working copy) @@ -12,8 +12,9 @@ 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;*.otf)\0*.ttf;.ttc;*.fon;*.otf\0\ Fonturi de tip TrueType (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ Fonturi de tip OpenType (*.otf)\0*.otf\0\ Fișiere de tip Font (*.fon)\0*.fon\0\ Orice fișier (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/ru-RU.rc =================================================================== --- reactos/base/applications/fontview/lang/ru-RU.rc (revision 73465) +++ reactos/base/applications/fontview/lang/ru-RU.rc (working copy) @@ -12,8 +12,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType шрифты (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType шрифты (*.otf)\0*.otf\0\ Файлы шрифтов (*.fon)\0*.fon\0\ Все файлы (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/sk-SK.rc =================================================================== --- reactos/base/applications/fontview/lang/sk-SK.rc (revision 73465) +++ reactos/base/applications/fontview/lang/sk-SK.rc (working copy) @@ -15,8 +15,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/sq-AL.rc =================================================================== --- reactos/base/applications/fontview/lang/sq-AL.rc (revision 73465) +++ reactos/base/applications/fontview/lang/sq-AL.rc (working copy) @@ -14,8 +14,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/sv-SE.rc =================================================================== --- reactos/base/applications/fontview/lang/sv-SE.rc (revision 73465) +++ reactos/base/applications/fontview/lang/sv-SE.rc (working copy) @@ -17,8 +17,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/tr-TR.rc =================================================================== --- reactos/base/applications/fontview/lang/tr-TR.rc (revision 73465) +++ reactos/base/applications/fontview/lang/tr-TR.rc (working copy) @@ -11,8 +11,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Yazı Tipi (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Yazı Tipi (*.otf)\0*.otf\0\ Yazı Tipi Kütüğü (*.fon)\0*.fon\0\ Tüm Kütükler (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/uk-UA.rc =================================================================== --- reactos/base/applications/fontview/lang/uk-UA.rc (revision 73465) +++ reactos/base/applications/fontview/lang/uk-UA.rc (working copy) @@ -18,8 +18,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType Font (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType Font (*.otf)\0*.otf\0\ Font File (*.fon)\0*.fon\0\ All Files (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/zh-CN.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-CN.rc (revision 73465) +++ reactos/base/applications/fontview/lang/zh-CN.rc (working copy) @@ -18,8 +18,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType 字体 (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType 字体 (*.otf)\0*.otf\0\ 字体文件 (*.fon)\0*.fon\0\ 所有文件 (*.*)\0*.*\0" Index: reactos/base/applications/fontview/lang/zh-TW.rc =================================================================== --- reactos/base/applications/fontview/lang/zh-TW.rc (revision 73465) +++ reactos/base/applications/fontview/lang/zh-TW.rc (working copy) @@ -18,8 +18,9 @@ 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;*.otf)\0*.ttf;*.ttc;*.fon;*.otf\0\ TrueType 字體 (*.ttf)\0*.ttf\0\ +TrueType Font Collection (*.ttc)\0*.ttc\0\ OpenType 字體 (*.otf)\0*.otf\0\ 字體檔 (*.fon)\0*.fon\0\ 所有檔 (*.*)\0*.*\0" Index: reactos/boot/bootdata/hivecls.inf =================================================================== --- reactos/boot/bootdata/hivecls.inf (revision 73465) +++ reactos/boot/bootdata/hivecls.inf (working copy) @@ -121,19 +121,25 @@ HKCR,"fonfile","",0x00000000,"Font file" HKCR,"fonfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-209" HKCR,"fonfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-155" -HKCR,"fonfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"fonfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" HKCR,".ttf","",0x00000000,"ttffile" HKCR,"ttffile","",0x00000000,"TrueType Font file" HKCR,"ttffile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-210" HKCR,"ttffile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" -HKCR,"ttffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"ttffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" +HKCR,".ttc","",0x00000000,"ttcfile" +HKCR,"ttcfile","",0x00000000,"TrueType Font Collection file" +HKCR,"ttcfile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-210" +HKCR,"ttcfile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" +HKCR,"ttcfile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" + HKCR,".otf","",0x00000000,"otffile" HKCR,"otffile","",0x00000000,"OpenType Font file" HKCR,"otffile","FriendlyTypeName",0x00020000,"@%SystemRoot%\system32\shell32.dll,-211" HKCR,"otffile\DefaultIcon","",0x00020000,"%SystemRoot%\system32\shell32.dll,-156" -HKCR,"otffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe %1" +HKCR,"otffile\shell\open\command","",0x00020000,"%SystemRoot%\system32\fontview.exe ""%1""" ; Help Files HKCR,".hlp","",0x00000000,"hlpfile" Index: reactos/win32ss/gdi/eng/engobjects.h =================================================================== --- reactos/win32ss/gdi/eng/engobjects.h (revision 73465) +++ reactos/win32ss/gdi/eng/engobjects.h (working copy) @@ -123,6 +123,9 @@ LPWSTR Filename; BYTE Underline; BYTE StrikeOut; + BYTE Italic; + LONG Weight; + BYTE CharSet; } FONTGDI, *PFONTGDI; typedef struct _PATHGDI { Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 73465) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -3,8 +3,9 @@ * LICENSE: GPL - See COPYING in the top level directory * FILE: win32ss/gdi/ntgdi/freetype.c * PURPOSE: FreeType font engine interface - * PROGRAMMER: Copyright 2001 Huw D M Davies for CodeWeavers. + * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers. * Copyright 2006 Dmitry Timoshkov for CodeWeavers. + * Copyright 2016 Katayama Hirofumi MZ. */ /** Includes ******************************************************************/ @@ -19,6 +20,12 @@ #include FT_OUTLINE_H #include FT_WINFONTS_H +#ifndef FT_INTERNAL_INTERNAL_H + #define FT_INTERNAL_INTERNAL_H + #include FT_INTERNAL_INTERNAL_H +#endif +#include FT_INTERNAL_TRUETYPE_TYPES_H + #include #define NDEBUG @@ -30,6 +37,11 @@ ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) ) #endif +/* TPMF_FIXED_PITCH is confusing; braindead api */ +#ifndef _TMPF_VARIABLE_PITCH + #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH +#endif + extern const MATRIX gmxWorldToDeviceDefault; extern const MATRIX gmxWorldToPageDefault; @@ -38,6 +50,85 @@ FT_Library library; +/*--------------------------------------------------------------------------*/ +/* face stock */ + +typedef struct FACE_STOCK +{ + struct FACE_STOCK * Next; + FT_Face Face; + LONG RefCount; +} FACE_STOCK, *PFACE_STOCK; + +static FACE_STOCK FaceStock = { NULL, NULL, 0 }; + +FACE_STOCK *FindPrevFontRef(FT_Face Face) +{ + FACE_STOCK *Entry = &FaceStock; + + for (;;) + { + if (Entry->Next == NULL) + return NULL; + if (Entry->Next->Face == Face) + return Entry; + Entry = Entry->Next; + } +} + +static FACE_STOCK * +AddFaceRef(FT_Face Face) +{ + FACE_STOCK *Entry; + + Entry = FindPrevFontRef(Face); + if (Entry) + { + Entry = Entry->Next; + ++Entry->RefCount; + return Entry; + } + + Entry = (FACE_STOCK *)ExAllocatePoolWithTag(PagedPool, + sizeof(FACE_STOCK), TAG_FONT); + if (Entry) + { + Entry->Next = FaceStock.Next; + Entry->Face = Face; + Entry->RefCount = 1; + FaceStock.Next = Entry; + } + + return Entry; +} + +static void +ReleaseFaceRef(FT_Face Face) +{ + FACE_STOCK *Removed; + FACE_STOCK *Entry; + + Entry = FindPrevFontRef(Face); + if (Entry == NULL) + { + return; + } + + if (Entry->RefCount > 0) + { + --Entry->RefCount; + } + if (Entry->RefCount == 0) + { + Removed = Entry->Next; + FT_Done_Face(Removed->Face); + Entry->Next = Removed->Next; + ExFreePoolWithTag(Removed, TAG_FONT); + } +} + +/*--------------------------------------------------------------------------*/ + typedef struct _FONT_ENTRY { LIST_ENTRY ListEntry; @@ -223,7 +314,7 @@ IntLoadSystemFonts(VOID) { OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING Directory, SearchPattern, FileName, TempString; + UNICODE_STRING Directory, SearchPatterns[2], FileName, TempString; IO_STATUS_BLOCK Iosb; HANDLE hDirectory; BYTE *DirInfoBuffer; @@ -230,10 +321,12 @@ PFILE_DIRECTORY_INFORMATION DirInfo; BOOLEAN bRestartScan = TRUE; NTSTATUS Status; + INT I, NumSearchPatterns = (INT)_countof(SearchPatterns); RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\"); /* FIXME: Add support for other font types */ - RtlInitUnicodeString(&SearchPattern, L"*.ttf"); + RtlInitUnicodeString(&SearchPatterns[0], L"*.ttf"); + RtlInitUnicodeString(&SearchPatterns[1], L"*.ttc"); InitializeObjectAttributes( &ObjectAttributes, @@ -252,198 +345,240 @@ if (NT_SUCCESS(Status)) { - DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); - if (DirInfoBuffer == NULL) + for (I = 0; I < NumSearchPatterns; ++I) { - ZwClose(hDirectory); - return; - } + DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); + if (DirInfoBuffer == NULL) + { + ZwClose(hDirectory); + return; + } - FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); - if (FileName.Buffer == NULL) - { - ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); - ZwClose(hDirectory); - return; - } - FileName.Length = 0; - FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); - - while (1) - { - Status = ZwQueryDirectoryFile( - hDirectory, - NULL, - NULL, - NULL, - &Iosb, - DirInfoBuffer, - 0x4000, - FileDirectoryInformation, - FALSE, - &SearchPattern, - bRestartScan); - - if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) + FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); + if (FileName.Buffer == NULL) { - break; + ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); + ZwClose(hDirectory); + return; } + FileName.Length = 0; + FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); - DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; while (1) { - TempString.Buffer = DirInfo->FileName; - TempString.Length = - TempString.MaximumLength = DirInfo->FileNameLength; - RtlCopyUnicodeString(&FileName, &Directory); - RtlAppendUnicodeStringToString(&FileName, &TempString); - IntGdiAddFontResource(&FileName, 0); - if (DirInfo->NextEntryOffset == 0) + Status = ZwQueryDirectoryFile( + hDirectory, + NULL, + NULL, + NULL, + &Iosb, + DirInfoBuffer, + 0x4000, + FileDirectoryInformation, + FALSE, + &SearchPatterns[I], + bRestartScan); + + if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) + { break; - DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); + } + + DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; + while (1) + { + TempString.Buffer = DirInfo->FileName; + TempString.Length = + TempString.MaximumLength = DirInfo->FileNameLength; + RtlCopyUnicodeString(&FileName, &Directory); + RtlAppendUnicodeStringToString(&FileName, &TempString); + IntGdiAddFontResource(&FileName, 0); + if (DirInfo->NextEntryOffset == 0) + break; + DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); + } + + bRestartScan = FALSE; } - bRestartScan = FALSE; + ExFreePoolWithTag(FileName.Buffer, TAG_FONT); + ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); } - - ExFreePoolWithTag(FileName.Buffer, TAG_FONT); - ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); ZwClose(hDirectory); } } - -/* - * IntGdiAddFontResource - * - * Adds the font resource from the specified file to the system. - */ - -INT FASTCALL -IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) +static INT FASTCALL +IntGdiLoadFontsFromMemory(PUNICODE_STRING FileName, PVOID Buffer, ULONG BufferSize, + PVOID SectionObject, DWORD Characteristics, + FT_Face Face, 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; + ANSI_STRING AnsiFaceName; + ANSI_STRING FaceNameA; + UNICODE_STRING FaceNameW; + OBJECT_ATTRIBUTES ObjectAttributes; + FT_WinFNT_HeaderRec WinFNT; + TT_OS2 * pOS2; + INT Count = 0, CharSetCount = 0; + static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett"); + static UNICODE_STRING FontRegPath = + RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); - /* Open the font file */ - - InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL); - Status = ZwOpenFile( - &FileHandle, - FILE_GENERIC_READ | SYNCHRONIZE, - &ObjectAttributes, - &Iosb, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - - if (!NT_SUCCESS(Status)) + if (Face == 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) + { + 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)) - { - DPRINT("Could not map file: %wZ\n", FileName); - ObDereferenceObject(SectionObject); - return 0; - } - - 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); + if (CharSetIndex == -1) + FT_Done_Face(Face); 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); + if (CharSetIndex == -1) + FT_Done_Face(Face); 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); + if (CharSetIndex == -1) + FT_Done_Face(Face); 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'; + + /* set face */ FontGDI->face = Face; + IntLockGlobalFonts; + AddFaceRef(Face); + IntUnLockGlobalFonts; + FontGDI->CharSet = ANSI_CHARSET; + + /* check if Marlett */ + RtlInitAnsiString(&FaceNameA, Face->family_name); + Status = RtlAnsiStringToUnicodeString(&FaceNameW, &FaceNameA, TRUE); + if (NT_SUCCESS(Status)) + { + if (RtlCompareUnicodeString(&FaceNameW, &MarlettW, TRUE) == 0) + { + FontGDI->CharSet = SYMBOL_CHARSET; + } + RtlFreeUnicodeString(&FaceNameW); + } + + if (FontGDI->CharSet == ANSI_CHARSET) + { + /* get charset from OS/2 header */ + IntLockFreeType; + pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); + IntUnLockFreeType; + if (pOS2 && pOS2->version >= 1) + { + INT BitIndex; + for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex) + { + if (pOS2->ulCodePageRange1 & (1 << BitIndex)) + { + if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET) + continue; + + if ((CharSetIndex == -1 && CharSetCount == 0) || + CharSetIndex == CharSetCount) + { + FontGDI->CharSet = FontTci[BitIndex].ciCharset; + } + + ++CharSetCount; + } + } + } + else + { + /* get charset from WinFNT header */ + IntLockFreeType; + Error = FT_Get_WinFNT_Header(Face, &WinFNT); + IntUnLockFreeType; + if (!Error) + { + FontGDI->CharSet = WinFNT.charset; + } + } + } + + ++Count; DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name); DPRINT("Num glyphs: %d\n", Face->num_glyphs); + DPRINT("CharSet: %d\n", FontGDI->CharSet); /* Add this font resource to the font table */ - Entry->Font = FontGDI; Entry->NotEnum = (Characteristics & FR_NOT_ENUM); - RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name); + RtlInitAnsiString(&AnsiFaceName, Face->family_name); Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE); if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); EngFreeMem(FontGDI); - FT_Done_Face(Face); + ReleaseFaceRef(Face); 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,8 +586,11 @@ } else { + /* global font */ IntLockGlobalFonts; InsertTailList(&FontListHead, &Entry->ListEntry); + + /* registry */ InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); if (NT_SUCCESS(Status)) @@ -467,9 +605,106 @@ } 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, + Face, FontIndex, I); + } + } + + if (SectionObject) + 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) { @@ -602,6 +837,7 @@ return FALSE; } + static void FASTCALL FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin) { @@ -621,7 +857,7 @@ TM->tmExternalLeading = pWin->external_leading; TM->tmAveCharWidth = pWin->avg_width; TM->tmMaxCharWidth = pWin->max_width; - TM->tmWeight = pWin->weight; + TM->tmWeight = FontGDI->Weight; TM->tmOverhang = 0; TM->tmDigitizedAspectX = pWin->horizontal_resolution; TM->tmDigitizedAspectY = pWin->vertical_resolution; @@ -629,11 +865,11 @@ TM->tmLastChar = pWin->last_char; TM->tmDefaultChar = pWin->default_char + pWin->first_char; TM->tmBreakChar = pWin->break_char + pWin->first_char; - TM->tmItalic = pWin->italic; + TM->tmItalic = FontGDI->Italic; TM->tmUnderlined = FontGDI->Underline; TM->tmStruckOut = FontGDI->StrikeOut; TM->tmPitchAndFamily = pWin->pitch_and_family; - TM->tmCharSet = pWin->charset; + TM->tmCharSet = FontGDI->CharSet; return; } @@ -676,7 +912,7 @@ /* Correct forumla to get the maxcharwidth from unicode and ansi font */ TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6; - TM->tmWeight = pOS2->usWeightClass; + TM->tmWeight = FontGDI->Weight; TM->tmOverhang = 0; TM->tmDigitizedAspectX = 96; TM->tmDigitizedAspectY = 96; @@ -710,14 +946,13 @@ TM->tmBreakChar = pOS2->usFirstCharIndex; TM->tmDefaultChar = TM->tmBreakChar - 1; } - TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0; + TM->tmItalic = FontGDI->Italic; TM->tmUnderlined = FontGDI->Underline; TM->tmStruckOut = FontGDI->StrikeOut; - /* Yes TPMF_FIXED_PITCH is correct; braindead api */ - if (! FT_IS_FIXED_WIDTH(Face)) + if (!FT_IS_FIXED_WIDTH(Face)) { - TM->tmPitchAndFamily = TMPF_FIXED_PITCH; + TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH; } else { @@ -787,7 +1022,7 @@ TM->tmPitchAndFamily |= TMPF_TRUETYPE; } - TM->tmCharSet = DEFAULT_CHARSET; + TM->tmCharSet = FontGDI->CharSet; } /************************************************************* @@ -2708,172 +2943,393 @@ return Result; } -static UINT FASTCALL -GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI) +static __inline BOOLEAN +SubstituteFontNameByKey(PUNICODE_STRING FaceName, + LPCWSTR Key) { - ANSI_STRING EntryFaceNameA; - UNICODE_STRING EntryFaceNameW; - unsigned Size; - OUTLINETEXTMETRICW *Otm; - LONG WeightDiff; + RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; NTSTATUS Status; - UINT Score = 1; + UNICODE_STRING Value; - RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); - Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); + RtlInitUnicodeString(&Value, NULL); + + QueryTable[0].QueryRoutine = NULL; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | + RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Name = FaceName->Buffer; + QueryTable[0].EntryContext = &Value; + QueryTable[0].DefaultType = REG_NONE; + QueryTable[0].DefaultData = NULL; + QueryTable[0].DefaultLength = 0; + + QueryTable[1].QueryRoutine = NULL; + QueryTable[1].Name = NULL; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, + Key, + QueryTable, + NULL, + NULL); if (NT_SUCCESS(Status)) { - static const UNICODE_STRING MarlettFaceNameW = RTL_CONSTANT_STRING(L"Marlett"); - static const UNICODE_STRING SymbolFaceNameW = RTL_CONSTANT_STRING(L"Symbol"); - static const UNICODE_STRING VGAFaceNameW = RTL_CONSTANT_STRING(L"VGA"); + RtlFreeUnicodeString(FaceName); + *FaceName = Value; - if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + /* truncate */ + if ((LF_FACESIZE - 1) * sizeof(WCHAR) < FaceName->Length) { - EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); - EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; + FaceName->Length = (LF_FACESIZE - 1) * sizeof(WCHAR); + FaceName->Buffer[LF_FACESIZE - 1] = L'\0'; } + } - if (!RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) + return NT_SUCCESS(Status); +} + +static __inline void +SubstituteFontName(PUNICODE_STRING FaceName) +{ + UINT Level; + const UINT MaxLevel = 10; + + if (FaceName->Buffer[0] == 0) + return; + + for (Level = 0; Level < MaxLevel; ++Level) + { + /* NOTE: SubstituteFontNameByKey changes FaceName. Be careful... */ + if (!SubstituteFontNameByKey(FaceName, L"FontSubstitutes")) + break; + } +} + +static BYTE +CharSetFromLangID(WORD LangID) +{ + LangID = PRIMARYLANGID(LangID); + switch (LangID) + { + case LANG_ARABIC: return ARABIC_CHARSET; + case LANG_CHINESE: return CHINESEBIG5_CHARSET; + case LANG_ENGLISH: return ANSI_CHARSET; + case LANG_GREEK: return GREEK_CHARSET; + case LANG_HEBREW: return HEBREW_CHARSET; + case LANG_JAPANESE: return SHIFTJIS_CHARSET; + case LANG_KOREAN: return HANGUL_CHARSET; + case LANG_RUSSIAN: return RUSSIAN_CHARSET; + case LANG_THAI: return THAI_CHARSET; + case LANG_TURKISH: return TURKISH_CHARSET; + case LANG_VIETNAMESE: return VIETNAMESE_CHARSET; + /* FIXME: Add more */ + default: return DEFAULT_CHARSET; + } +} + +static UINT FASTCALL +GetFontPenalty(LOGFONTW * LogFont, + PUNICODE_STRING RequestedNameW, + PUNICODE_STRING ActualNameW, + PFONTGDI FontGDI, + OUTLINETEXTMETRICW * Otm, + TEXTMETRICW * TM) +{ + ULONG Penalty = 0; + BYTE Byte; + static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System"); + + // is request "System" font? + if (RtlCompareUnicodeString(RequestedNameW, &SystemW, TRUE) == 0) + { + /* Penalty += 65000: lfCharSet: not current charset */ + if (TM->tmCharSet != CharSetFromLangID(gusLanguageID)) + Penalty += 65000; + + /* Penalty += 10: system font should be fixed-pitch */ + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) + Penalty += 10; + } + else /* Request is non-"System" font */ + { + if (LogFont->lfCharSet != DEFAULT_CHARSET && + LogFont->lfCharSet != ANSI_CHARSET) { - Score += 49; + /* Penalty += 65000: lfCharSet: mismatched */ + if (LogFont->lfCharSet != TM->tmCharSet) + Penalty += 65000; } + } - /* FIXME: this is a work around to counter weird fonts on weird places. - A proper fix would be to score fonts on more attributes than - the ones in this function */ - if (!RtlCompareUnicodeString(&MarlettFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&MarlettFaceNameW, FaceName, TRUE)) + /* if face name is set */ + if (RequestedNameW->Buffer[0]) + { + if (RtlCompareUnicodeString(RequestedNameW, ActualNameW, TRUE) != 0) { - Score = 0; + /* Penalty += 10000: lfFaceName: mismatched */ + Penalty += 10000; } + } - if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE)) + /* Penalty += 19000: lfOutPrecision: mismatched */ + if (LogFont->lfOutPrecision != OUT_DEFAULT_PRECIS) + { + switch (LogFont->lfOutPrecision) { - Score = 0; + case OUT_DEVICE_PRECIS: + if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) + Penalty += 19000; + break; + case OUT_TT_ONLY_PRECIS: + if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) + Penalty += 19000; + break; + default: + break; } + } - if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) && - RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE)) + /* get the pitch */ + Byte = (LogFont->lfPitchAndFamily & 0x0F); + if (Byte != DEFAULT_PITCH) + { + if (Byte == FIXED_PITCH) { - Score = 0; + /* Penalty += 15000: lfPitchAndFamily: variable pitch was set on fixed-pitch specified */ + if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH) + { + Penalty += 15000; + } } - - RtlFreeUnicodeString(&EntryFaceNameW); + /* Penalty += 350: lfPitchAndFamily: non-variable pitch on variable pitch */ + if (Byte == VARIABLE_PITCH && !(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + Penalty += 350; + } } + else + { + /* Penalty += 1: pitch is not normal */ + if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)) + { + Penalty += 1; + } + } - Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); - Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); - if (NULL == Otm) + /* get family */ + Byte = (LogFont->lfPitchAndFamily & 0xF0); + if (Byte != FF_DONTCARE) { - return Score; + /* Penalty += 9000: lfPitchAndFamily: mismatched font family */ + if (Byte != (TM->tmPitchAndFamily & 0xF0)) + { + Penalty += 9000; + } + /* Penalty += 8000: lfPitchAndFamily: no family on family specified */ + if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE) + { + Penalty += 8000; + } } - IntGetOutlineTextMetrics(FontGDI, Size, Otm); - if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) || - (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic)) + /* if the target is not scalable */ + if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))) { - Score += 25; + if (LogFont->lfHeight != 0) + { + /* Penalty += 600: lfHeight: non-vector font and height was higher */ + if (labs(LogFont->lfHeight) < TM->tmHeight) + { + Penalty += 600; + } + /* Penalty += 600: lfHeight: non-vector font and height was higher */ + if (LogFont->lfHeight < 0 && labs(LogFont->lfHeight) < TM->tmHeight) + { + Penalty += 600; + } + /* Penalty += 150 * Diff * K: lfHeight: mismatched */ + if (labs(LogFont->lfHeight) != TM->tmHeight) + { + double K = 2; + /* lfHeight: avg. 16. */ + /* 16 * K = 32. */ + if (labs(LogFont->lfHeight) != TM->tmHeight) + { + LONG Diff = labs(labs(LogFont->lfHeight) - TM->tmHeight); + Penalty += (150 * Diff) * K; + } + } + } + + /* Penalty += 50: height or width scaling required */ + if ((LogFont->lfHeight != 0 && labs(LogFont->lfHeight) != TM->tmHeight) || + (LogFont->lfWidth != 0 && LogFont->lfWidth != TM->tmAveCharWidth)) + { + Penalty += 50; + } + + /* Penalty += 50 * Diff * K: mismatched width */ + if (LogFont->lfWidth != 0 && LogFont->lfWidth != TM->tmAveCharWidth) + { + double K = 0.2; + /* lfWidth: avg. 16. */ + /* 16 * K = 3.2. */ + if (LogFont->lfWidth != TM->tmAveCharWidth) + { + LONG Diff = labs(TM->tmAveCharWidth - LogFont->lfWidth); + Penalty += (50 * Diff) * K; + } + } + + /* Penalty += 1: it needs to be adjusted to italic */ + if (LogFont->lfItalic && !TM->tmItalic) + { + Penalty += 1; + } + /* Penalty += 1: it needs to be adjusted to underline */ + if (LogFont->lfUnderline && !TM->tmUnderlined) + { + Penalty += 1; + } + /* Penalty += 1: it needs to be adjusted to struke-out */ + if (LogFont->lfStrikeOut && !TM->tmStruckOut) + { + Penalty += 1; + } } + if (LogFont->lfWeight != FW_DONTCARE) { - if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight) + /* Penalty += 3 * Diff * K: lfWeight: weight mismatched */ + /* lfWeight: 100 to 900 */ + double K = 0.5; + /* K * 300 * 3 = 450 */ + if (LogFont->lfWeight != TM->tmWeight) { - WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight; + LONG Diff = labs(LogFont->lfWeight - TM->tmWeight); + Penalty += (3 * Diff) * K; } - else + } + else + { + /* Penalty += 100: lfWeight: weight is not normal */ + if (TM->tmWeight != FW_NORMAL) { - WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight; + Penalty += 100; } - Score += (1000 - WeightDiff) / (1000 / 25); } - else + + /* Penalty += 4: lfItalic: mismatched */ + if (!!LogFont->lfItalic != !!TM->tmItalic) { - Score += 25; + Penalty += 4; } + /* Penalty += 4: lfUnderline: mismatched */ + if (!!LogFont->lfUnderline != !!TM->tmUnderlined) + { + Penalty += 4; + } + /* Penalty += 4: lfStrikeOut: mismatched */ + if (!!LogFont->lfStrikeOut != !!TM->tmStruckOut) + { + Penalty += 4; + } - ExFreePoolWithTag(Otm, GDITAG_TEXT); + /* Penalty += 4: lfOutPrecision: non-TrueType on TrueType specified */ + if (LogFont->lfOutPrecision == OUT_TT_PRECIS) + { + if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE)) + Penalty += 4; + } - return Score; + /* Penalty += 2: not device font */ + if (!(TM->tmPitchAndFamily & TMPF_DEVICE)) + { + Penalty += 2; + } + + if (Penalty < 500) + { + DPRINT("'%ls' -> '%ls' Penalty:%d, lfCharSet:%d, tmCharSet:%d, lfWeight:%d, tmWeight:%d\n", + RequestedNameW->Buffer, ActualNameW->Buffer, Penalty, + LogFont->lfCharSet, TM->tmCharSet, LogFont->lfWeight, TM->tmWeight); + } + + return Penalty; /* success */ } static __inline VOID -FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont, - PUNICODE_STRING FaceName, PLIST_ENTRY Head) +FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont, + PUNICODE_STRING pRequestedNameW, + PUNICODE_STRING pActualNameW, PLIST_ENTRY Head) { + ULONG Penalty; + NTSTATUS Status; PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; FONTGDI *FontGDI; - UINT Score; -ASSERT(FontObj && MatchScore && LogFont && FaceName && Head); + ANSI_STRING ActualNameA; + UNICODE_STRING ActualNameW; + OUTLINETEXTMETRICW *Otm = NULL; + UINT OtmSize, OldOtmSize = 0; + TEXTMETRICW *TM; + + ASSERT(FontObj && MatchPenalty && LogFont && pRequestedNameW && Head); + + /* get the FontObj of lowest penalty */ Entry = Head->Flink; while (Entry != Head) { CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); - FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - Score = GetFontScore(LogFont, FaceName, FontGDI); - if (*MatchScore == 0 || *MatchScore < Score) + /* create actual name */ + RtlInitAnsiString(&ActualNameA, FontGDI->face->family_name); + Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE); + if (!NT_SUCCESS(Status)) { - *FontObj = GDIToObj(FontGDI, FONT); - *MatchScore = Score; + /* next entry */ + Entry = Entry->Flink; + continue; } - Entry = Entry->Flink; - } -} -static __inline BOOLEAN -SubstituteFontFamilyKey(PUNICODE_STRING FaceName, - LPCWSTR Key) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; - NTSTATUS Status; - UNICODE_STRING Value; + /* get text metrics */ + OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL); + if (OtmSize > OldOtmSize) + { + if (Otm) + ExFreePoolWithTag(Otm, GDITAG_TEXT); + Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT); + } - RtlInitUnicodeString(&Value, NULL); + /* update FontObj if lowest penalty */ + if (Otm) + { + IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm); + TM = &Otm->otmTextMetrics; + OldOtmSize = OtmSize; - QueryTable[0].QueryRoutine = NULL; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | - RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = FaceName->Buffer; - QueryTable[0].EntryContext = &Value; - QueryTable[0].DefaultType = REG_NONE; - QueryTable[0].DefaultData = NULL; - QueryTable[0].DefaultLength = 0; + Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW, + FontGDI, Otm, TM); + if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) + { + RtlFreeUnicodeString(pActualNameW); + RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer); + *FontObj = GDIToObj(FontGDI, FONT); + *MatchPenalty = Penalty; + } + } - QueryTable[1].QueryRoutine = NULL; - QueryTable[1].Name = NULL; + /* free strings */ + RtlFreeUnicodeString(&ActualNameW); - Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, - Key, - QueryTable, - NULL, - NULL); - if (NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(FaceName); - *FaceName = Value; + /* next entry */ + Entry = Entry->Flink; } - return NT_SUCCESS(Status); + if (Otm) + ExFreePoolWithTag(Otm, GDITAG_TEXT); } -static __inline void -SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level) -{ - if (10 < Level) /* Enough is enough */ - { - return; - } - - if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes")) - { - SubstituteFontFamily(FaceName, Level + 1); - } -} - static VOID FASTCALL @@ -2911,9 +3367,10 @@ { NTSTATUS Status = STATUS_SUCCESS; PTEXTOBJ TextObj; - UNICODE_STRING FaceName; + UNICODE_STRING ActualNameW, RequestedNameW; PPROCESSINFO Win32Process; - UINT MatchScore; + ULONG MatchPenalty; + LOGFONTW *pLogFont; if (!pTextObj) { @@ -2930,35 +3387,46 @@ } } else + { TextObj = pTextObj; + } - if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName)) + RtlInitUnicodeString(&ActualNameW, NULL); + + pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; + if (! RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName)) { if (!pTextObj) TEXTOBJ_UnlockText(TextObj); return STATUS_NO_MEMORY; } - SubstituteFontFamily(&FaceName, 0); - MatchScore = 0; + + DPRINT("Font '%ls' is substituted by: ", RequestedNameW.Buffer); + SubstituteFontName(&RequestedNameW); + DPRINT("'%ls'.\n", RequestedNameW.Buffer); + + MatchPenalty = 0xFFFFFFFF; TextObj->Font = NULL; - /* First search private fonts */ Win32Process = PsGetCurrentProcessWin32Process(); + + /* Search private fonts */ IntLockProcessPrivateFonts(Win32Process); - FindBestFontFromList(&TextObj->Font, &MatchScore, - &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, + FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, + &RequestedNameW, &ActualNameW, &Win32Process->PrivateFontListHead); IntUnLockProcessPrivateFonts(Win32Process); /* Search system fonts */ IntLockGlobalFonts; - FindBestFontFromList(&TextObj->Font, &MatchScore, - &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, + FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, + &RequestedNameW, &ActualNameW, &FontListHead); IntUnLockGlobalFonts; + if (NULL == TextObj->Font) { DPRINT1("Requested font %S not found, no fonts loaded at all\n", - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName); + pLogFont->lfFaceName); Status = STATUS_NOT_FOUND; } else @@ -2969,13 +3437,25 @@ TextObj->Font->iUniq = 1; // Now it can be cached. IntFontType(FontGdi); FontGdi->flType = TextObj->Font->flFontType; - FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0; - FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0; + FontGdi->Underline = pLogFont->lfUnderline ? 0xff : 0; + FontGdi->StrikeOut = pLogFont->lfStrikeOut ? 0xff : 0; + FontGdi->Italic = pLogFont->lfItalic ? 0xff : 0; + if (pLogFont->lfWeight != FW_DONTCARE) + FontGdi->Weight = pLogFont->lfWeight; + else + FontGdi->Weight = FW_NORMAL; + RtlCopyMemory(pLogFont->lfFaceName, ActualNameW.Buffer, + ActualNameW.Length); TextObj->fl |= TEXTOBJECT_INIT; Status = STATUS_SUCCESS; + + DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n", + RequestedNameW.Buffer, pLogFont->lfCharSet, + ActualNameW.Buffer, FontGdi->CharSet); } - RtlFreeUnicodeString(&FaceName); + RtlFreeUnicodeString(&RequestedNameW); + RtlFreeUnicodeString(&ActualNameW); if (!pTextObj) TEXTOBJ_UnlockText(TextObj); ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);