📄 text.c
字号:
/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* Parts based on Wine code
* Copyright 1993 Alexandre Julliard
* 1997 Alex Korobka
* Copyright 2002,2003 Shachar Shemesh
* Copyright 2001 Huw D M Davies for CodeWeavers.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: text.c 28248 2007-08-08 18:58:06Z jimtabor $ */
#include <w32k.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <freetype/tttables.h>
#include <freetype/fttrigon.h>
#include <freetype/ftglyph.h>
#include <freetype/ftoutln.h>
#include <freetype/ftwinfnt.h>
#define NDEBUG
#include <debug.h>
FT_Library library;
typedef struct _FONT_ENTRY {
LIST_ENTRY ListEntry;
FONTGDI *Font;
UNICODE_STRING FaceName;
BYTE NotEnum;
} FONT_ENTRY, *PFONT_ENTRY;
/* The FreeType library is not thread safe, so we have
to serialize access to it */
static FAST_MUTEX FreeTypeLock;
static LIST_ENTRY FontListHead;
static FAST_MUTEX FontListLock;
static BOOL RenderingEnabled = TRUE;
#define MAX_FONT_CACHE 256
UINT Hits;
UINT Misses;
typedef struct _FONT_CACHE_ENTRY {
LIST_ENTRY ListEntry;
int GlyphIndex;
FT_Face Face;
FT_Glyph Glyph;
int Height;
} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
static LIST_ENTRY FontCacheListHead;
static UINT FontCacheNumEntries;
static PWCHAR ElfScripts[32] = { /* these are in the order of the fsCsb[0] bits */
L"Western", /*00*/
L"Central_European",
L"Cyrillic",
L"Greek",
L"Turkish",
L"Hebrew",
L"Arabic",
L"Baltic",
L"Vietnamese", /*08*/
NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
L"Thai",
L"Japanese",
L"CHINESE_GB2312",
L"Hangul",
L"CHINESE_BIG5",
L"Hangul(Johab)",
NULL, NULL, /*23*/
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
L"Symbol" /*31*/
};
/*
* For NtGdiTranslateCharsetInfo
*/
#define FS(x) {{0,0,0,0},{0x1<<(x),0}}
#define MAXTCIINDEX 32
static CHARSETINFO FontTci[MAXTCIINDEX] = {
/* ANSI */
{ ANSI_CHARSET, 1252, FS(0)},
{ EASTEUROPE_CHARSET, 1250, FS(1)},
{ RUSSIAN_CHARSET, 1251, FS(2)},
{ GREEK_CHARSET, 1253, FS(3)},
{ TURKISH_CHARSET, 1254, FS(4)},
{ HEBREW_CHARSET, 1255, FS(5)},
{ ARABIC_CHARSET, 1256, FS(6)},
{ BALTIC_CHARSET, 1257, FS(7)},
{ VIETNAMESE_CHARSET, 1258, FS(8)},
/* reserved by ANSI */
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
/* ANSI and OEM */
{ THAI_CHARSET, 874, FS(16)},
{ SHIFTJIS_CHARSET, 932, FS(17)},
{ GB2312_CHARSET, 936, FS(18)},
{ HANGEUL_CHARSET, 949, FS(19)},
{ CHINESEBIG5_CHARSET, 950, FS(20)},
{ JOHAB_CHARSET, 1361, FS(21)},
/* reserved for alternate ANSI and OEM */
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
{ DEFAULT_CHARSET, 0, FS(0)},
/* reserved for system */
{ DEFAULT_CHARSET, 0, FS(0)},
{ SYMBOL_CHARSET, 42 /* CP_SYMBOL */, FS(31)},
};
VOID FASTCALL
IntLoadSystemFonts(VOID);
INT FASTCALL
IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics);
BOOL FASTCALL
InitFontSupport(VOID)
{
ULONG ulError;
InitializeListHead(&FontListHead);
InitializeListHead(&FontCacheListHead);
FontCacheNumEntries = 0;
ExInitializeFastMutex(&FontListLock);
ExInitializeFastMutex(&FreeTypeLock);
ulError = FT_Init_FreeType(&library);
if (ulError) {
DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
return FALSE;
}
IntLoadSystemFonts();
return TRUE;
}
/*
* IntLoadSystemFonts
*
* Search the system font directory and adds each font found.
*/
VOID FASTCALL
IntLoadSystemFonts(VOID)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING Directory, SearchPattern, FileName, TempString;
IO_STATUS_BLOCK Iosb;
HANDLE hDirectory;
BYTE *DirInfoBuffer;
PFILE_DIRECTORY_INFORMATION DirInfo;
BOOL bRestartScan = TRUE;
NTSTATUS Status;
RtlInitUnicodeString(&Directory, L"\\SystemRoot\\media\\fonts\\");
/* FIXME: Add support for other font types */
RtlInitUnicodeString(&SearchPattern, L"*.ttf");
InitializeObjectAttributes(
&ObjectAttributes,
&Directory,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenFile(
&hDirectory,
SYNCHRONIZE | FILE_LIST_DIRECTORY,
&ObjectAttributes,
&Iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
if (NT_SUCCESS(Status))
{
DirInfoBuffer = ExAllocatePool(PagedPool, 0x4000);
if (DirInfoBuffer == NULL)
{
ZwClose(hDirectory);
return;
}
FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
if (FileName.Buffer == NULL)
{
ExFreePool(DirInfoBuffer);
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)
{
break;
}
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;
}
ExFreePool(FileName.Buffer);
ExFreePool(DirInfoBuffer);
ZwClose(hDirectory);
}
}
/*
* IntGdiAddFontResource
*
* Adds the font resource from the specified file to the system.
*/
INT FASTCALL
IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
{
FONTGDI *FontGDI;
NTSTATUS Status;
HANDLE FileHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
PVOID Buffer = NULL;
IO_STATUS_BLOCK Iosb;
INT Error;
FT_Face Face;
ANSI_STRING AnsiFaceName;
PFONT_ENTRY Entry;
PSECTION_OBJECT SectionObject;
ULONG ViewSize = 0;
FT_Fixed XScale, YScale;
UNICODE_STRING FileNameCopy;
/* 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 font file: %wZ\n", FileName);
return 0;
}
Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
NULL, NULL, PAGE_READONLY,
0, 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);
return Status;
}
IntLockFreeType;
Error = FT_New_Memory_Face(
library,
Buffer,
ViewSize,
0,
&Face);
IntUnLockFreeType;
if (Error)
{
if (Error == FT_Err_Unknown_File_Format)
DPRINT("Unknown font file format\n");
else
DPRINT("Error reading font file (error code: %u)\n", Error);
ObDereferenceObject(SectionObject);
return 0;
}
Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
if (!Entry)
{
FT_Done_Face(Face);
ObDereferenceObject(SectionObject);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
if(FontGDI == NULL)
{
FT_Done_Face(Face);
ObDereferenceObject(SectionObject);
ExFreePool(Entry);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, FileName, &FileNameCopy);
FontGDI->Filename = FileNameCopy.Buffer;
FontGDI->face = Face;
/* FIXME: Complete text metrics */
XScale = Face->size->metrics.x_scale;
YScale = Face->size->metrics.y_scale;
#if 1 /* This (Wine) code doesn't seem to work correctly for us */
FontGDI->TextMetric.tmAscent = (FT_MulFix(Face->ascender, YScale) + 32) >> 6;
FontGDI->TextMetric.tmDescent = (FT_MulFix(Face->descender, YScale) + 32) >> 6;
FontGDI->TextMetric.tmHeight = (FT_MulFix(Face->ascender, YScale) -
FT_MulFix(Face->descender, YScale)) >> 6;
#else
FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender - Face->size->metrics.descender) >> 6;
#endif
DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
DPRINT("Num glyphs: %u\n", Face->num_glyphs);
/* Add this font resource to the font table */
Entry->Font = FontGDI;
Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
if (Characteristics & FR_PRIVATE)
{
PW32PROCESS Win32Process = PsGetCurrentProcessWin32Process();
IntLockProcessPrivateFonts(Win32Process);
InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
IntUnLockProcessPrivateFonts(Win32Process);
}
else
{
IntLockGlobalFonts;
InsertTailList(&FontListHead, &Entry->ListEntry);
IntUnLockGlobalFonts;
}
return 1;
}
BOOL FASTCALL
IntIsFontRenderingEnabled(VOID)
{
BOOL Ret = RenderingEnabled;
HDC hDC;
hDC = IntGetScreenDC();
if (hDC)
Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
return Ret;
}
VOID FASTCALL
IntEnableFontRendering(BOOL Enable)
{
RenderingEnabled = Enable;
}
FT_Render_Mode FASTCALL
IntGetFontRenderMode(LOGFONTW *logfont)
{
switch(logfont->lfQuality)
{
case NONANTIALIASED_QUALITY:
return FT_RENDER_MODE_MONO;
case DRAFT_QUALITY:
return FT_RENDER_MODE_LIGHT;
/* case CLEARTYPE_QUALITY:
return FT_RENDER_MODE_LCD; */
}
return FT_RENDER_MODE_NORMAL;
}
int
STDCALL
NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
{
UNICODE_STRING SafeFileName;
PWSTR src;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -