Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfreetype.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS win32 kernel mode subsystem 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: subsystems/win32/win32k/objects/freetype.c 00005 * PURPOSE: FreeType font engine interface 00006 * PROGRAMMER: Copyright 2001 Huw D M Davies for CodeWeavers. 00007 * Copyright 2006 Dmitry Timoshkov for CodeWeavers. 00008 */ 00009 00012 #include <win32k.h> 00013 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 #ifndef FT_MAKE_TAG 00018 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \ 00019 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \ 00020 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) ) 00021 #endif 00022 00023 FT_Library library; 00024 00025 typedef struct _FONT_ENTRY 00026 { 00027 LIST_ENTRY ListEntry; 00028 FONTGDI *Font; 00029 UNICODE_STRING FaceName; 00030 BYTE NotEnum; 00031 } FONT_ENTRY, *PFONT_ENTRY; 00032 00033 /* The FreeType library is not thread safe, so we have 00034 to serialize access to it */ 00035 static PFAST_MUTEX FreeTypeLock; 00036 00037 static LIST_ENTRY FontListHead; 00038 static PFAST_MUTEX FontListLock; 00039 static BOOL RenderingEnabled = TRUE; 00040 00041 #define IntLockGlobalFonts \ 00042 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock) 00043 00044 #define IntUnLockGlobalFonts \ 00045 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock) 00046 00047 #define IntLockFreeType \ 00048 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock) 00049 00050 #define IntUnLockFreeType \ 00051 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock) 00052 00053 #define MAX_FONT_CACHE 256 00054 00055 typedef struct _FONT_CACHE_ENTRY 00056 { 00057 LIST_ENTRY ListEntry; 00058 int GlyphIndex; 00059 FT_Face Face; 00060 FT_BitmapGlyph BitmapGlyph; 00061 int Height; 00062 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; 00063 static LIST_ENTRY FontCacheListHead; 00064 static UINT FontCacheNumEntries; 00065 00066 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */ 00067 { 00068 L"Western", /* 00 */ 00069 L"Central_European", 00070 L"Cyrillic", 00071 L"Greek", 00072 L"Turkish", 00073 L"Hebrew", 00074 L"Arabic", 00075 L"Baltic", 00076 L"Vietnamese", /* 08 */ 00077 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */ 00078 L"Thai", 00079 L"Japanese", 00080 L"CHINESE_GB2312", 00081 L"Hangul", 00082 L"CHINESE_BIG5", 00083 L"Hangul(Johab)", 00084 NULL, NULL, /* 23 */ 00085 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 00086 L"Symbol" /* 31 */ 00087 }; 00088 00089 /* 00090 * For TranslateCharsetInfo 00091 */ 00092 #define CP_SYMBOL 42 00093 #define MAXTCIINDEX 32 00094 static const CHARSETINFO FontTci[MAXTCIINDEX] = 00095 { 00096 /* ANSI */ 00097 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} }, 00098 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} }, 00099 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} }, 00100 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} }, 00101 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} }, 00102 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} }, 00103 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} }, 00104 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} }, 00105 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} }, 00106 /* reserved by ANSI */ 00107 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00108 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00109 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00110 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00111 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00112 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00113 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00114 /* ANSI and OEM */ 00115 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} }, 00116 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} }, 00117 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} }, 00118 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} }, 00119 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} }, 00120 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} }, 00121 /* Reserved for alternate ANSI and OEM */ 00122 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00123 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00124 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00125 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00126 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00127 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00128 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00129 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00130 /* Reserved for system */ 00131 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} }, 00132 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} } 00133 }; 00134 00135 BOOL FASTCALL 00136 InitFontSupport(VOID) 00137 { 00138 ULONG ulError; 00139 00140 InitializeListHead(&FontListHead); 00141 InitializeListHead(&FontCacheListHead); 00142 FontCacheNumEntries = 0; 00143 /* Fast Mutexes must be allocated from non paged pool */ 00144 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC); 00145 ExInitializeFastMutex(FontListLock); 00146 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC); 00147 ExInitializeFastMutex(FreeTypeLock); 00148 00149 ulError = FT_Init_FreeType(&library); 00150 if (ulError) 00151 { 00152 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError); 00153 return FALSE; 00154 } 00155 00156 IntLoadSystemFonts(); 00157 00158 return TRUE; 00159 } 00160 00161 /* 00162 * IntLoadSystemFonts 00163 * 00164 * Search the system font directory and adds each font found. 00165 */ 00166 00167 VOID FASTCALL 00168 IntLoadSystemFonts(VOID) 00169 { 00170 OBJECT_ATTRIBUTES ObjectAttributes; 00171 UNICODE_STRING Directory, SearchPattern, FileName, TempString; 00172 IO_STATUS_BLOCK Iosb; 00173 HANDLE hDirectory; 00174 BYTE *DirInfoBuffer; 00175 PFILE_DIRECTORY_INFORMATION DirInfo; 00176 BOOLEAN bRestartScan = TRUE; 00177 NTSTATUS Status; 00178 00179 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\"); 00180 /* FIXME: Add support for other font types */ 00181 RtlInitUnicodeString(&SearchPattern, L"*.ttf"); 00182 00183 InitializeObjectAttributes( 00184 &ObjectAttributes, 00185 &Directory, 00186 OBJ_CASE_INSENSITIVE, 00187 NULL, 00188 NULL); 00189 00190 Status = ZwOpenFile( 00191 &hDirectory, 00192 SYNCHRONIZE | FILE_LIST_DIRECTORY, 00193 &ObjectAttributes, 00194 &Iosb, 00195 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00196 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); 00197 00198 if (NT_SUCCESS(Status)) 00199 { 00200 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT); 00201 if (DirInfoBuffer == NULL) 00202 { 00203 ZwClose(hDirectory); 00204 return; 00205 } 00206 00207 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT); 00208 if (FileName.Buffer == NULL) 00209 { 00210 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); 00211 ZwClose(hDirectory); 00212 return; 00213 } 00214 FileName.Length = 0; 00215 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR); 00216 00217 while (1) 00218 { 00219 Status = ZwQueryDirectoryFile( 00220 hDirectory, 00221 NULL, 00222 NULL, 00223 NULL, 00224 &Iosb, 00225 DirInfoBuffer, 00226 0x4000, 00227 FileDirectoryInformation, 00228 FALSE, 00229 &SearchPattern, 00230 bRestartScan); 00231 00232 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES) 00233 { 00234 break; 00235 } 00236 00237 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer; 00238 while (1) 00239 { 00240 TempString.Buffer = DirInfo->FileName; 00241 TempString.Length = 00242 TempString.MaximumLength = DirInfo->FileNameLength; 00243 RtlCopyUnicodeString(&FileName, &Directory); 00244 RtlAppendUnicodeStringToString(&FileName, &TempString); 00245 IntGdiAddFontResource(&FileName, 0); 00246 if (DirInfo->NextEntryOffset == 0) 00247 break; 00248 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset); 00249 } 00250 00251 bRestartScan = FALSE; 00252 } 00253 00254 ExFreePoolWithTag(FileName.Buffer, TAG_FONT); 00255 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT); 00256 ZwClose(hDirectory); 00257 } 00258 } 00259 00260 00261 /* 00262 * IntGdiAddFontResource 00263 * 00264 * Adds the font resource from the specified file to the system. 00265 */ 00266 00267 INT FASTCALL 00268 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics) 00269 { 00270 FONTGDI *FontGDI; 00271 NTSTATUS Status; 00272 HANDLE FileHandle, KeyHandle; 00273 OBJECT_ATTRIBUTES ObjectAttributes; 00274 PVOID Buffer = NULL; 00275 IO_STATUS_BLOCK Iosb; 00276 INT Error; 00277 FT_Face Face; 00278 ANSI_STRING AnsiFaceName; 00279 PFONT_ENTRY Entry; 00280 PSECTION_OBJECT SectionObject; 00281 ULONG ViewSize = 0; 00282 LARGE_INTEGER SectionSize; 00283 UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); 00284 00285 /* Open the font file */ 00286 00287 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL); 00288 Status = ZwOpenFile( 00289 &FileHandle, 00290 FILE_GENERIC_READ | SYNCHRONIZE, 00291 &ObjectAttributes, 00292 &Iosb, 00293 FILE_SHARE_READ, 00294 FILE_SYNCHRONOUS_IO_NONALERT); 00295 00296 if (!NT_SUCCESS(Status)) 00297 { 00298 DPRINT("Could not load font file: %wZ\n", FileName); 00299 return 0; 00300 } 00301 00302 SectionSize.QuadPart = 0LL; 00303 Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS, 00304 NULL, &SectionSize, PAGE_READONLY, 00305 SEC_COMMIT, FileHandle, NULL); 00306 if (!NT_SUCCESS(Status)) 00307 { 00308 DPRINT("Could not map file: %wZ\n", FileName); 00309 ZwClose(FileHandle); 00310 return 0; 00311 } 00312 00313 ZwClose(FileHandle); 00314 00315 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize); 00316 if (!NT_SUCCESS(Status)) 00317 { 00318 DPRINT("Could not map file: %wZ\n", FileName); 00319 return Status; 00320 } 00321 00322 IntLockFreeType; 00323 Error = FT_New_Memory_Face( 00324 library, 00325 Buffer, 00326 ViewSize, 00327 0, 00328 &Face); 00329 IntUnLockFreeType; 00330 00331 if (Error) 00332 { 00333 if (Error == FT_Err_Unknown_File_Format) 00334 DPRINT("Unknown font file format\n"); 00335 else 00336 DPRINT("Error reading font file (error code: %u)\n", Error); 00337 ObDereferenceObject(SectionObject); 00338 return 0; 00339 } 00340 00341 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT); 00342 if (!Entry) 00343 { 00344 FT_Done_Face(Face); 00345 ObDereferenceObject(SectionObject); 00346 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 00347 return 0; 00348 } 00349 00350 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT); 00351 if (FontGDI == NULL) 00352 { 00353 FT_Done_Face(Face); 00354 ObDereferenceObject(SectionObject); 00355 ExFreePoolWithTag(Entry, TAG_FONT); 00356 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 00357 return 0; 00358 } 00359 00360 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), GDITAG_PFF); 00361 if (FontGDI->Filename == NULL) 00362 { 00363 EngFreeMem(FontGDI); 00364 FT_Done_Face(Face); 00365 ObDereferenceObject(SectionObject); 00366 ExFreePoolWithTag(Entry, TAG_FONT); 00367 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 00368 return 0; 00369 } 00370 RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length); 00371 FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0'; 00372 FontGDI->face = Face; 00373 00374 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name); 00375 DPRINT("Num glyphs: %u\n", Face->num_glyphs); 00376 00377 /* Add this font resource to the font table */ 00378 00379 Entry->Font = FontGDI; 00380 Entry->NotEnum = (Characteristics & FR_NOT_ENUM); 00381 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name); 00382 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE); 00383 00384 if (Characteristics & FR_PRIVATE) 00385 { 00386 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); 00387 IntLockProcessPrivateFonts(Win32Process); 00388 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry); 00389 IntUnLockProcessPrivateFonts(Win32Process); 00390 } 00391 else 00392 { 00393 IntLockGlobalFonts; 00394 InsertTailList(&FontListHead, &Entry->ListEntry); 00395 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL); 00396 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); 00397 if (NT_SUCCESS(Status)) 00398 { 00399 LPWSTR pName = wcsrchr(FileName->Buffer, L'\\'); 00400 if (pName) 00401 { 00402 pName++; 00403 ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR)); 00404 } 00405 ZwClose(KeyHandle); 00406 } 00407 IntUnLockGlobalFonts; 00408 } 00409 return 1; 00410 } 00411 00412 BOOL FASTCALL 00413 IntIsFontRenderingEnabled(VOID) 00414 { 00415 BOOL Ret = RenderingEnabled; 00416 HDC hDC; 00417 00418 hDC = IntGetScreenDC(); 00419 if (hDC) 00420 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled; 00421 00422 return Ret; 00423 } 00424 00425 VOID FASTCALL 00426 IntEnableFontRendering(BOOL Enable) 00427 { 00428 RenderingEnabled = Enable; 00429 } 00430 00431 FT_Render_Mode FASTCALL 00432 IntGetFontRenderMode(LOGFONTW *logfont) 00433 { 00434 switch (logfont->lfQuality) 00435 { 00436 case NONANTIALIASED_QUALITY: 00437 return FT_RENDER_MODE_MONO; 00438 case DRAFT_QUALITY: 00439 return FT_RENDER_MODE_LIGHT; 00440 /* case CLEARTYPE_QUALITY: 00441 return FT_RENDER_MODE_LCD; */ 00442 } 00443 return FT_RENDER_MODE_NORMAL; 00444 } 00445 00446 00447 NTSTATUS FASTCALL 00448 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont) 00449 { 00450 PTEXTOBJ TextObj; 00451 00452 TextObj = TEXTOBJ_AllocTextWithHandle(); 00453 if (!TextObj) 00454 { 00455 return STATUS_NO_MEMORY; 00456 } 00457 00458 *NewFont = TextObj->BaseObject.hHmgr; 00459 RtlCopyMemory(&TextObj->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW)); 00460 if (lf->lfEscapement != lf->lfOrientation) 00461 { 00462 /* This should really depend on whether GM_ADVANCED is set */ 00463 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 00464 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement; 00465 } 00466 TEXTOBJ_UnlockText(TextObj); 00467 00468 return STATUS_SUCCESS; 00469 } 00470 00471 /************************************************************************* 00472 * TranslateCharsetInfo 00473 * 00474 * Fills a CHARSETINFO structure for a character set, code page, or 00475 * font. This allows making the correspondance between different labelings 00476 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges) 00477 * of the same encoding. 00478 * 00479 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used, 00480 * only one codepage should be set in *Src. 00481 * 00482 * RETURNS 00483 * TRUE on success, FALSE on failure. 00484 * 00485 */ 00486 static BOOLEAN APIENTRY 00487 IntTranslateCharsetInfo(PDWORD Src, /* [in] 00488 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE 00489 if flags == TCI_SRCCHARSET: a character set value 00490 if flags == TCI_SRCCODEPAGE: a code page value */ 00491 LPCHARSETINFO Cs, /* [out] structure to receive charset information */ 00492 DWORD Flags /* [in] determines interpretation of lpSrc */) 00493 { 00494 int Index = 0; 00495 00496 switch (Flags) 00497 { 00498 case TCI_SRCFONTSIG: 00499 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX) 00500 { 00501 Index++; 00502 } 00503 break; 00504 case TCI_SRCCODEPAGE: 00505 while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX) 00506 { 00507 Index++; 00508 } 00509 break; 00510 case TCI_SRCCHARSET: 00511 while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX) 00512 { 00513 Index++; 00514 } 00515 break; 00516 default: 00517 return FALSE; 00518 } 00519 00520 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset) 00521 { 00522 return FALSE; 00523 } 00524 00525 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO)); 00526 00527 return TRUE; 00528 } 00529 00530 00531 static BOOL face_has_symbol_charmap(FT_Face ft_face) 00532 { 00533 int i; 00534 00535 for(i = 0; i < ft_face->num_charmaps; i++) 00536 { 00537 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL) 00538 return TRUE; 00539 } 00540 return FALSE; 00541 } 00542 00543 static void FASTCALL 00544 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin) 00545 { 00546 FT_Fixed XScale, YScale; 00547 int Ascent, Descent; 00548 FT_Face Face = FontGDI->face; 00549 00550 XScale = Face->size->metrics.x_scale; 00551 YScale = Face->size->metrics.y_scale; 00552 00553 if (pWin) 00554 { 00555 TM->tmHeight = pWin->pixel_height; 00556 TM->tmAscent = pWin->ascent; 00557 TM->tmDescent = TM->tmHeight - TM->tmAscent; 00558 TM->tmInternalLeading = pWin->internal_leading; 00559 TM->tmExternalLeading = pWin->external_leading; 00560 TM->tmAveCharWidth = pWin->avg_width; 00561 TM->tmMaxCharWidth = pWin->max_width; 00562 TM->tmWeight = pWin->weight; 00563 TM->tmOverhang = 0; 00564 TM->tmDigitizedAspectX = pWin->horizontal_resolution; 00565 TM->tmDigitizedAspectY = pWin->vertical_resolution; 00566 TM->tmFirstChar = pWin->first_char; 00567 TM->tmLastChar = pWin->last_char; 00568 TM->tmDefaultChar = pWin->default_char + pWin->first_char; 00569 TM->tmBreakChar = pWin->break_char + pWin->first_char; 00570 TM->tmItalic = pWin->italic; 00571 TM->tmUnderlined = FontGDI->Underline; 00572 TM->tmStruckOut = FontGDI->StrikeOut; 00573 TM->tmPitchAndFamily = pWin->pitch_and_family; 00574 TM->tmCharSet = pWin->charset; 00575 return; 00576 } 00577 00578 if (pOS2->usWinAscent + pOS2->usWinDescent == 0) 00579 { 00580 Ascent = pHori->Ascender; 00581 Descent = -pHori->Descender; 00582 } 00583 else 00584 { 00585 Ascent = pOS2->usWinAscent; 00586 Descent = pOS2->usWinDescent; 00587 } 00588 00589 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */ 00590 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6; 00591 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6; 00592 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */ 00593 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */ 00594 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */ 00595 #endif 00596 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6; 00597 00598 TM->tmHeight = TM->tmAscent + TM->tmDescent; 00599 00600 /* MSDN says: 00601 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender))) 00602 */ 00603 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap 00604 - ((Ascent + Descent) 00605 - (pHori->Ascender - pHori->Descender)), 00606 YScale) + 32) >> 6); 00607 00608 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6; 00609 if (TM->tmAveCharWidth == 0) 00610 { 00611 TM->tmAveCharWidth = 1; 00612 } 00613 00614 /* Correct forumla to get the maxcharwidth from unicode and ansi font */ 00615 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6; 00616 00617 TM->tmWeight = pOS2->usWeightClass; 00618 TM->tmOverhang = 0; 00619 TM->tmDigitizedAspectX = 96; 00620 TM->tmDigitizedAspectY = 96; 00621 if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100)) 00622 { 00623 USHORT cpOEM, cpAnsi; 00624 00625 EngGetCurrentCodePage(&cpOEM, &cpAnsi); 00626 TM->tmFirstChar = 0; 00627 switch(cpAnsi) 00628 { 00629 case 1257: /* Baltic */ 00630 TM->tmLastChar = 0xf8fd; 00631 break; 00632 default: 00633 TM->tmLastChar = 0xf0ff; 00634 } 00635 TM->tmBreakChar = 0x20; 00636 TM->tmDefaultChar = 0x1f; 00637 } 00638 else 00639 { 00640 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */ 00641 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */ 00642 00643 if(pOS2->usFirstCharIndex <= 1) 00644 TM->tmBreakChar = pOS2->usFirstCharIndex + 2; 00645 else if (pOS2->usFirstCharIndex > 0xff) 00646 TM->tmBreakChar = 0x20; 00647 else 00648 TM->tmBreakChar = pOS2->usFirstCharIndex; 00649 TM->tmDefaultChar = TM->tmBreakChar - 1; 00650 } 00651 TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0; 00652 TM->tmUnderlined = FontGDI->Underline; 00653 TM->tmStruckOut = FontGDI->StrikeOut; 00654 00655 /* Yes TPMF_FIXED_PITCH is correct; braindead api */ 00656 if (! FT_IS_FIXED_WIDTH(Face)) 00657 { 00658 TM->tmPitchAndFamily = TMPF_FIXED_PITCH; 00659 } 00660 else 00661 { 00662 TM->tmPitchAndFamily = 0; 00663 } 00664 00665 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX]) 00666 { 00667 case PAN_FAMILY_SCRIPT: 00668 TM->tmPitchAndFamily |= FF_SCRIPT; 00669 break; 00670 case PAN_FAMILY_DECORATIVE: 00671 TM->tmPitchAndFamily |= FF_DECORATIVE; 00672 break; 00673 00674 case PAN_ANY: 00675 case PAN_NO_FIT: 00676 case PAN_FAMILY_TEXT_DISPLAY: 00677 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */ 00678 /* Which is clearly not what the panose spec says. */ 00679 if (TM->tmPitchAndFamily == 0) /* Fixed */ 00680 { 00681 TM->tmPitchAndFamily = FF_MODERN; 00682 } 00683 else 00684 { 00685 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX]) 00686 { 00687 case PAN_ANY: 00688 case PAN_NO_FIT: 00689 default: 00690 TM->tmPitchAndFamily |= FF_DONTCARE; 00691 break; 00692 00693 case PAN_SERIF_COVE: 00694 case PAN_SERIF_OBTUSE_COVE: 00695 case PAN_SERIF_SQUARE_COVE: 00696 case PAN_SERIF_OBTUSE_SQUARE_COVE: 00697 case PAN_SERIF_SQUARE: 00698 case PAN_SERIF_THIN: 00699 case PAN_SERIF_BONE: 00700 case PAN_SERIF_EXAGGERATED: 00701 case PAN_SERIF_TRIANGLE: 00702 TM->tmPitchAndFamily |= FF_ROMAN; 00703 break; 00704 00705 case PAN_SERIF_NORMAL_SANS: 00706 case PAN_SERIF_OBTUSE_SANS: 00707 case PAN_SERIF_PERP_SANS: 00708 case PAN_SERIF_FLARED: 00709 case PAN_SERIF_ROUNDED: 00710 TM->tmPitchAndFamily |= FF_SWISS; 00711 break; 00712 } 00713 } 00714 break; 00715 default: 00716 TM->tmPitchAndFamily |= FF_DONTCARE; 00717 } 00718 00719 if (FT_IS_SCALABLE(Face)) 00720 { 00721 TM->tmPitchAndFamily |= TMPF_VECTOR; 00722 } 00723 if (FT_IS_SFNT(Face)) 00724 { 00725 TM->tmPitchAndFamily |= TMPF_TRUETYPE; 00726 } 00727 00728 TM->tmCharSet = DEFAULT_CHARSET; 00729 } 00730 00731 /************************************************************* 00732 * IntGetOutlineTextMetrics 00733 * 00734 */ 00735 INT FASTCALL 00736 IntGetOutlineTextMetrics(PFONTGDI FontGDI, 00737 UINT Size, 00738 OUTLINETEXTMETRICW *Otm) 00739 { 00740 unsigned Needed; 00741 TT_OS2 *pOS2; 00742 TT_HoriHeader *pHori; 00743 TT_Postscript *pPost; 00744 FT_Fixed XScale, YScale; 00745 ANSI_STRING FamilyNameA, StyleNameA; 00746 UNICODE_STRING FamilyNameW, StyleNameW, Regular; 00747 FT_WinFNT_HeaderRec Win; 00748 FT_Error Error; 00749 char *Cp; 00750 00751 Needed = sizeof(OUTLINETEXTMETRICW); 00752 00753 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name); 00754 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE); 00755 00756 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name); 00757 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); 00758 00759 /* These names should be read from the TT name table */ 00760 00761 /* Length of otmpFamilyName */ 00762 Needed += FamilyNameW.Length + sizeof(WCHAR); 00763 00764 RtlInitUnicodeString(&Regular, L"regular"); 00765 /* Length of otmpFaceName */ 00766 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) 00767 { 00768 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */ 00769 } 00770 else 00771 { 00772 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */ 00773 } 00774 00775 /* Length of otmpStyleName */ 00776 Needed += StyleNameW.Length + sizeof(WCHAR); 00777 00778 /* Length of otmpFullName */ 00779 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); 00780 00781 if (Size < Needed) 00782 { 00783 RtlFreeUnicodeString(&FamilyNameW); 00784 RtlFreeUnicodeString(&StyleNameW); 00785 return Needed; 00786 } 00787 00788 XScale = FontGDI->face->size->metrics.x_scale; 00789 YScale = FontGDI->face->size->metrics.y_scale; 00790 00791 IntLockFreeType; 00792 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); 00793 if (NULL == pOS2) 00794 { 00795 IntUnLockFreeType; 00796 DPRINT1("Can't find OS/2 table - not TT font?\n"); 00797 RtlFreeUnicodeString(&StyleNameW); 00798 RtlFreeUnicodeString(&FamilyNameW); 00799 return 0; 00800 } 00801 00802 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea); 00803 if (NULL == pHori) 00804 { 00805 IntUnLockFreeType; 00806 DPRINT1("Can't find HHEA table - not TT font?\n"); 00807 RtlFreeUnicodeString(&StyleNameW); 00808 RtlFreeUnicodeString(&FamilyNameW); 00809 return 0; 00810 } 00811 00812 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* We can live with this failing */ 00813 00814 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); 00815 00816 Otm->otmSize = Needed; 00817 00818 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0); 00819 00820 Otm->otmFiller = 0; 00821 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT); 00822 Otm->otmfsSelection = pOS2->fsSelection; 00823 Otm->otmfsType = pOS2->fsType; 00824 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise; 00825 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run; 00826 Otm->otmItalicAngle = 0; /* POST table */ 00827 Otm->otmEMSquare = FontGDI->face->units_per_EM; 00828 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6; 00829 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6; 00830 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6; 00831 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6; 00832 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6; 00833 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6; 00834 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6; 00835 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6; 00836 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6; 00837 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent; 00838 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent; 00839 Otm->otmMacLineGap = Otm->otmLineGap; 00840 Otm->otmusMinimumPPEM = 0; /* TT Header */ 00841 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6; 00842 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6; 00843 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6; 00844 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6; 00845 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6; 00846 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6; 00847 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6; 00848 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6; 00849 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6; 00850 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6; 00851 if (!pPost) 00852 { 00853 Otm->otmsUnderscoreSize = 0; 00854 Otm->otmsUnderscorePosition = 0; 00855 } 00856 else 00857 { 00858 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6; 00859 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6; 00860 } 00861 00862 IntUnLockFreeType; 00863 00864 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */ 00865 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW); 00866 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm); 00867 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); 00868 Cp += FamilyNameW.Length + sizeof(WCHAR); 00869 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm); 00870 wcscpy((WCHAR*) Cp, StyleNameW.Buffer); 00871 Cp += StyleNameW.Length + sizeof(WCHAR); 00872 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm); 00873 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); 00874 if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) 00875 { 00876 wcscat((WCHAR*) Cp, L" "); 00877 wcscat((WCHAR*) Cp, StyleNameW.Buffer); 00878 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); 00879 } 00880 else 00881 { 00882 Cp += FamilyNameW.Length + sizeof(WCHAR); 00883 } 00884 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm); 00885 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); 00886 wcscat((WCHAR*) Cp, L" "); 00887 wcscat((WCHAR*) Cp, StyleNameW.Buffer); 00888 00889 RtlFreeUnicodeString(&StyleNameW); 00890 RtlFreeUnicodeString(&FamilyNameW); 00891 00892 return Needed; 00893 } 00894 00895 static PFONTGDI FASTCALL 00896 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head) 00897 { 00898 PLIST_ENTRY Entry; 00899 PFONT_ENTRY CurrentEntry; 00900 ANSI_STRING EntryFaceNameA; 00901 UNICODE_STRING EntryFaceNameW; 00902 FONTGDI *FontGDI; 00903 00904 Entry = Head->Flink; 00905 while (Entry != Head) 00906 { 00907 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 00908 00909 FontGDI = CurrentEntry->Font; 00910 ASSERT(FontGDI); 00911 00912 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); 00913 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); 00914 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) 00915 { 00916 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); 00917 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; 00918 } 00919 00920 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) 00921 { 00922 RtlFreeUnicodeString(&EntryFaceNameW); 00923 return FontGDI; 00924 } 00925 00926 RtlFreeUnicodeString(&EntryFaceNameW); 00927 Entry = Entry->Flink; 00928 } 00929 00930 return NULL; 00931 } 00932 00933 static PFONTGDI FASTCALL 00934 FindFaceNameInLists(PUNICODE_STRING FaceName) 00935 { 00936 PPROCESSINFO Win32Process; 00937 PFONTGDI Font; 00938 00939 /* Search the process local list */ 00940 Win32Process = PsGetCurrentProcessWin32Process(); 00941 IntLockProcessPrivateFonts(Win32Process); 00942 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead); 00943 IntUnLockProcessPrivateFonts(Win32Process); 00944 if (NULL != Font) 00945 { 00946 return Font; 00947 } 00948 00949 /* Search the global list */ 00950 IntLockGlobalFonts; 00951 Font = FindFaceNameInList(FaceName, &FontListHead); 00952 IntUnLockGlobalFonts; 00953 00954 return Font; 00955 } 00956 00957 static void FASTCALL 00958 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI) 00959 { 00960 ANSI_STRING StyleA; 00961 UNICODE_STRING StyleW; 00962 TT_OS2 *pOS2; 00963 FONTSIGNATURE fs; 00964 CHARSETINFO CharSetInfo; 00965 unsigned i, Size; 00966 OUTLINETEXTMETRICW *Otm; 00967 LOGFONTW *Lf; 00968 TEXTMETRICW *TM; 00969 NEWTEXTMETRICW *Ntm; 00970 DWORD fs0; 00971 00972 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); 00973 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 00974 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 00975 if (!Otm) 00976 { 00977 return; 00978 } 00979 IntGetOutlineTextMetrics(FontGDI, Size, Otm); 00980 00981 Lf = &Info->EnumLogFontEx.elfLogFont; 00982 TM = &Otm->otmTextMetrics; 00983 00984 Lf->lfHeight = TM->tmHeight; 00985 Lf->lfWidth = TM->tmAveCharWidth; 00986 Lf->lfWeight = TM->tmWeight; 00987 Lf->lfItalic = TM->tmItalic; 00988 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1; 00989 Lf->lfCharSet = TM->tmCharSet; 00990 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS; 00991 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; 00992 Lf->lfQuality = PROOF_QUALITY; 00993 00994 Ntm = &Info->NewTextMetricEx.ntmTm; 00995 Ntm->tmHeight = TM->tmHeight; 00996 Ntm->tmAscent = TM->tmAscent; 00997 Ntm->tmDescent = TM->tmDescent; 00998 Ntm->tmInternalLeading = TM->tmInternalLeading; 00999 Ntm->tmExternalLeading = TM->tmExternalLeading; 01000 Ntm->tmAveCharWidth = TM->tmAveCharWidth; 01001 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth; 01002 Ntm->tmWeight = TM->tmWeight; 01003 Ntm->tmOverhang = TM->tmOverhang; 01004 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX; 01005 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY; 01006 Ntm->tmFirstChar = TM->tmFirstChar; 01007 Ntm->tmLastChar = TM->tmLastChar; 01008 Ntm->tmDefaultChar = TM->tmDefaultChar; 01009 Ntm->tmBreakChar = TM->tmBreakChar; 01010 Ntm->tmItalic = TM->tmItalic; 01011 Ntm->tmUnderlined = TM->tmUnderlined; 01012 Ntm->tmStruckOut = TM->tmStruckOut; 01013 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily; 01014 Ntm->tmCharSet = TM->tmCharSet; 01015 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0; 01016 01017 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD; 01018 01019 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR; 01020 01021 Ntm->ntmSizeEM = Otm->otmEMSquare; 01022 Ntm->ntmCellHeight = 0; 01023 Ntm->ntmAvgWidth = 0; 01024 01025 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE) 01026 ? TRUETYPE_FONTTYPE : 0); 01027 01028 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR)) 01029 Info->FontType |= RASTER_FONTTYPE; 01030 01031 ExFreePoolWithTag(Otm, GDITAG_TEXT); 01032 01033 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName, 01034 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName), 01035 FaceName); 01036 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, 01037 sizeof(Info->EnumLogFontEx.elfFullName), 01038 FaceName); 01039 RtlInitAnsiString(&StyleA, FontGDI->face->style_name); 01040 StyleW.Buffer = Info->EnumLogFontEx.elfStyle; 01041 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle); 01042 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE); 01043 01044 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET; 01045 Info->EnumLogFontEx.elfScript[0] = L'\0'; 01046 IntLockFreeType; 01047 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); 01048 IntUnLockFreeType; 01049 if (NULL != pOS2) 01050 { 01051 fs.fsCsb[0] = pOS2->ulCodePageRange1; 01052 fs.fsCsb[1] = pOS2->ulCodePageRange2; 01053 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 01054 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 01055 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 01056 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 01057 01058 if (0 == pOS2->version) 01059 { 01060 FT_UInt Dummy; 01061 01062 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100) 01063 fs.fsCsb[0] |= FS_LATIN1; 01064 else 01065 fs.fsCsb[0] |= FS_SYMBOL; 01066 } 01067 if (fs.fsCsb[0] == 0) 01068 { /* Let's see if we can find any interesting cmaps */ 01069 for (i = 0; i < FontGDI->face->num_charmaps; i++) 01070 { 01071 switch (FontGDI->face->charmaps[i]->encoding) 01072 { 01073 case FT_ENCODING_UNICODE: 01074 case FT_ENCODING_APPLE_ROMAN: 01075 fs.fsCsb[0] |= FS_LATIN1; 01076 break; 01077 case FT_ENCODING_MS_SYMBOL: 01078 fs.fsCsb[0] |= FS_SYMBOL; 01079 break; 01080 default: 01081 break; 01082 } 01083 } 01084 } 01085 for (i = 0; i < MAXTCIINDEX; i++) 01086 { 01087 fs0 = 1L << i; 01088 if (fs.fsCsb[0] & fs0) 01089 { 01090 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG)) 01091 { 01092 CharSetInfo.ciCharset = DEFAULT_CHARSET; 01093 } 01094 if (DEFAULT_CHARSET != CharSetInfo.ciCharset) 01095 { 01096 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset; 01097 if (NULL != ElfScripts[i]) 01098 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]); 01099 else 01100 { 01101 DPRINT1("Unknown elfscript for bit %d\n", i); 01102 } 01103 } 01104 } 01105 } 01106 Info->NewTextMetricEx.ntmFontSig = fs; 01107 } 01108 } 01109 01110 static int FASTCALL 01111 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries) 01112 { 01113 DWORD i; 01114 UNICODE_STRING InfoFaceName; 01115 01116 for (i = 0; i < InfoEntries; i++) 01117 { 01118 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); 01119 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE)) 01120 { 01121 return i; 01122 } 01123 } 01124 01125 return -1; 01126 } 01127 01128 static BOOLEAN FASTCALL 01129 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, 01130 PFONTFAMILYINFO Info, DWORD InfoEntries) 01131 { 01132 UNICODE_STRING LogFontFaceName; 01133 01134 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); 01135 if (0 != LogFontFaceName.Length 01136 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE)) 01137 { 01138 return FALSE; 01139 } 01140 01141 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0; 01142 } 01143 01144 static BOOLEAN FASTCALL 01145 GetFontFamilyInfoForList(LPLOGFONTW LogFont, 01146 PFONTFAMILYINFO Info, 01147 DWORD *Count, 01148 DWORD Size, 01149 PLIST_ENTRY Head) 01150 { 01151 PLIST_ENTRY Entry; 01152 PFONT_ENTRY CurrentEntry; 01153 ANSI_STRING EntryFaceNameA; 01154 UNICODE_STRING EntryFaceNameW; 01155 FONTGDI *FontGDI; 01156 01157 Entry = Head->Flink; 01158 while (Entry != Head) 01159 { 01160 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 01161 01162 FontGDI = CurrentEntry->Font; 01163 ASSERT(FontGDI); 01164 01165 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); 01166 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); 01167 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) 01168 { 01169 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); 01170 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; 01171 } 01172 01173 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size))) 01174 { 01175 if (*Count < Size) 01176 { 01177 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI); 01178 } 01179 (*Count)++; 01180 } 01181 RtlFreeUnicodeString(&EntryFaceNameW); 01182 Entry = Entry->Flink; 01183 } 01184 01185 return TRUE; 01186 } 01187 01188 typedef struct FontFamilyInfoCallbackContext 01189 { 01190 LPLOGFONTW LogFont; 01191 PFONTFAMILYINFO Info; 01192 DWORD Count; 01193 DWORD Size; 01194 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT; 01195 01196 static NTSTATUS APIENTRY 01197 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType, 01198 IN PVOID ValueData, IN ULONG ValueLength, 01199 IN PVOID Context, IN PVOID EntryContext) 01200 { 01201 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext; 01202 UNICODE_STRING RegistryName, RegistryValue; 01203 int Existing; 01204 PFONTGDI FontGDI; 01205 01206 if (REG_SZ != ValueType) 01207 { 01208 return STATUS_SUCCESS; 01209 } 01210 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context; 01211 RtlInitUnicodeString(&RegistryName, ValueName); 01212 01213 /* Do we need to include this font family? */ 01214 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info, 01215 min(InfoContext->Count, InfoContext->Size))) 01216 { 01217 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData); 01218 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info, 01219 min(InfoContext->Count, InfoContext->Size)); 01220 if (0 <= Existing) 01221 { 01222 /* We already have the information about the "real" font. Just copy it */ 01223 if (InfoContext->Count < InfoContext->Size) 01224 { 01225 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing]; 01226 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName, 01227 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName), 01228 RegistryName.Buffer, 01229 RegistryName.Length); 01230 } 01231 InfoContext->Count++; 01232 return STATUS_SUCCESS; 01233 } 01234 01235 /* Try to find information about the "real" font */ 01236 FontGDI = FindFaceNameInLists(&RegistryValue); 01237 if (NULL == FontGDI) 01238 { 01239 /* "Real" font not found, discard this registry entry */ 01240 return STATUS_SUCCESS; 01241 } 01242 01243 /* Return info about the "real" font but with the name of the alias */ 01244 if (InfoContext->Count < InfoContext->Size) 01245 { 01246 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count, 01247 RegistryName.Buffer, FontGDI); 01248 } 01249 InfoContext->Count++; 01250 return STATUS_SUCCESS; 01251 } 01252 01253 return STATUS_SUCCESS; 01254 } 01255 01256 static BOOLEAN FASTCALL 01257 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, 01258 PFONTFAMILYINFO Info, 01259 DWORD *Count, 01260 DWORD Size) 01261 { 01262 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; 01263 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context; 01264 NTSTATUS Status; 01265 01266 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes 01267 The real work is done in the registry callback function */ 01268 Context.LogFont = LogFont; 01269 Context.Info = Info; 01270 Context.Count = *Count; 01271 Context.Size = Size; 01272 01273 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback; 01274 QueryTable[0].Flags = 0; 01275 QueryTable[0].Name = NULL; 01276 QueryTable[0].EntryContext = NULL; 01277 QueryTable[0].DefaultType = REG_NONE; 01278 QueryTable[0].DefaultData = NULL; 01279 QueryTable[0].DefaultLength = 0; 01280 01281 QueryTable[1].QueryRoutine = NULL; 01282 QueryTable[1].Name = NULL; 01283 01284 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, 01285 L"SysFontSubstitutes", 01286 QueryTable, 01287 &Context, 01288 NULL); 01289 if (NT_SUCCESS(Status)) 01290 { 01291 *Count = Context.Count; 01292 } 01293 01294 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status; 01295 } 01296 01297 BOOL 01298 FASTCALL 01299 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) 01300 { 01301 if ( lprs ) 01302 { 01303 lprs->nSize = sizeof(RASTERIZER_STATUS); 01304 lprs->wFlags = TT_AVAILABLE | TT_ENABLED; 01305 lprs->nLanguageID = gusLanguageID; 01306 return TRUE; 01307 } 01308 EngSetLastError(ERROR_INVALID_PARAMETER); 01309 return FALSE; 01310 } 01311 01312 01313 FT_BitmapGlyph APIENTRY 01314 ftGdiGlyphCacheGet( 01315 FT_Face Face, 01316 INT GlyphIndex, 01317 INT Height) 01318 { 01319 PLIST_ENTRY CurrentEntry; 01320 PFONT_CACHE_ENTRY FontEntry; 01321 01322 CurrentEntry = FontCacheListHead.Flink; 01323 while (CurrentEntry != &FontCacheListHead) 01324 { 01325 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry; 01326 if (FontEntry->Face == Face && 01327 FontEntry->GlyphIndex == GlyphIndex && 01328 FontEntry->Height == Height) 01329 break; 01330 CurrentEntry = CurrentEntry->Flink; 01331 } 01332 01333 if (CurrentEntry == &FontCacheListHead) 01334 { 01335 return NULL; 01336 } 01337 01338 RemoveEntryList(CurrentEntry); 01339 InsertHeadList(&FontCacheListHead, CurrentEntry); 01340 return FontEntry->BitmapGlyph; 01341 } 01342 01343 FT_BitmapGlyph APIENTRY 01344 ftGdiGlyphCacheSet( 01345 FT_Face Face, 01346 INT GlyphIndex, 01347 INT Height, 01348 FT_GlyphSlot GlyphSlot, 01349 FT_Render_Mode RenderMode) 01350 { 01351 FT_Glyph GlyphCopy; 01352 INT error; 01353 PFONT_CACHE_ENTRY NewEntry; 01354 FT_Bitmap AlignedBitmap; 01355 FT_BitmapGlyph BitmapGlyph; 01356 01357 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy); 01358 if (error) 01359 { 01360 DPRINT1("Failure caching glyph.\n"); 01361 return NULL; 01362 }; 01363 01364 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1); 01365 if (error) 01366 { 01367 FT_Done_Glyph(GlyphCopy); 01368 DPRINT1("Failure rendering glyph.\n"); 01369 return NULL; 01370 }; 01371 01372 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT); 01373 if (!NewEntry) 01374 { 01375 DPRINT1("Alloc failure caching glyph.\n"); 01376 FT_Done_Glyph(GlyphCopy); 01377 return NULL; 01378 } 01379 01380 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy; 01381 FT_Bitmap_New(&AlignedBitmap); 01382 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4)) 01383 { 01384 DPRINT1("Conversion failed\n"); 01385 ExFreePoolWithTag(NewEntry, TAG_FONT); 01386 FT_Done_Glyph((FT_Glyph)BitmapGlyph); 01387 return NULL; 01388 } 01389 01390 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap); 01391 BitmapGlyph->bitmap = AlignedBitmap; 01392 01393 NewEntry->GlyphIndex = GlyphIndex; 01394 NewEntry->Face = Face; 01395 NewEntry->BitmapGlyph = BitmapGlyph; 01396 NewEntry->Height = Height; 01397 01398 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry); 01399 if (FontCacheNumEntries++ > MAX_FONT_CACHE) 01400 { 01401 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink; 01402 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph); 01403 RemoveTailList(&FontCacheListHead); 01404 ExFreePool(NewEntry); 01405 FontCacheNumEntries--; 01406 } 01407 01408 return BitmapGlyph; 01409 } 01410 01411 01412 static 01413 void 01414 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt) 01415 { 01416 pt->x.value = vec->x >> 6; 01417 pt->x.fract = (vec->x & 0x3f) << 10; 01418 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12)); 01419 pt->y.value = vec->y >> 6; 01420 pt->y.fract = (vec->y & 0x3f) << 10; 01421 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12)); 01422 return; 01423 } 01424 01425 /* 01426 This function builds an FT_Fixed from a float. It puts the integer part 01427 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed. 01428 It fails if the integer part of the float number is greater than SHORT_MAX. 01429 */ 01430 static __inline FT_Fixed FT_FixedFromFloat(float f) 01431 { 01432 short value = f; 01433 unsigned short fract = (f - value) * 0xFFFF; 01434 return (FT_Fixed)((long)value << 16 | (unsigned long)fract); 01435 } 01436 01437 /* 01438 This function builds an FT_Fixed from a FIXED. It simply put f.value 01439 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed. 01440 */ 01441 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f) 01442 { 01443 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract); 01444 } 01445 01446 /* 01447 * Based on WineEngGetGlyphOutline 01448 * 01449 */ 01450 ULONG 01451 FASTCALL 01452 ftGdiGetGlyphOutline( 01453 PDC dc, 01454 WCHAR wch, 01455 UINT iFormat, 01456 LPGLYPHMETRICS pgm, 01457 ULONG cjBuf, 01458 PVOID pvBuf, 01459 LPMAT2 pmat2, 01460 BOOL bIgnoreRotation) 01461 { 01462 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)}; 01463 PDC_ATTR pdcattr; 01464 PTEXTOBJ TextObj; 01465 PFONTGDI FontGDI; 01466 HFONT hFont = 0; 01467 GLYPHMETRICS gm; 01468 ULONG Size; 01469 FT_Face ft_face; 01470 FT_UInt glyph_index; 01471 DWORD width, height, pitch, needed = 0; 01472 FT_Bitmap ft_bitmap; 01473 FT_Error error; 01474 INT left, right, top = 0, bottom = 0; 01475 FT_Angle angle = 0; 01476 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 01477 FLOAT eM11, widthRatio = 1.0; 01478 FT_Matrix transMat = identityMat; 01479 BOOL needsTransform = FALSE; 01480 INT orientation; 01481 LONG aveWidth; 01482 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */ 01483 OUTLINETEXTMETRICW *potm; 01484 int n = 0; 01485 FT_CharMap found = 0, charmap; 01486 XFORM xForm; 01487 01488 DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm, 01489 cjBuf, pvBuf, pmat2); 01490 01491 pdcattr = dc->pdcattr; 01492 01493 MatrixS2XForm(&xForm, &dc->dclevel.mxWorldToDevice); 01494 eM11 = xForm.eM11; 01495 01496 hFont = pdcattr->hlfntNew; 01497 TextObj = RealizeFontInit(hFont); 01498 01499 if (!TextObj) 01500 { 01501 EngSetLastError(ERROR_INVALID_HANDLE); 01502 return GDI_ERROR; 01503 } 01504 FontGDI = ObjToGDI(TextObj->Font, FONT); 01505 ft_face = FontGDI->face; 01506 01507 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0; 01508 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0; 01509 01510 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 01511 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 01512 if (!potm) 01513 { 01514 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 01515 TEXTOBJ_UnlockText(TextObj); 01516 return GDI_ERROR; 01517 } 01518 IntGetOutlineTextMetrics(FontGDI, Size, potm); 01519 01520 IntLockFreeType; 01521 01522 /* During testing, I never saw this used. It is here just in case. */ 01523 if (ft_face->charmap == NULL) 01524 { 01525 DPRINT("WARNING: No charmap selected!\n"); 01526 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps); 01527 01528 for (n = 0; n < ft_face->num_charmaps; n++) 01529 { 01530 charmap = ft_face->charmaps[n]; 01531 DPRINT("Found charmap encoding: %u\n", charmap->encoding); 01532 if (charmap->encoding != 0) 01533 { 01534 found = charmap; 01535 break; 01536 } 01537 } 01538 if (!found) 01539 { 01540 DPRINT1("WARNING: Could not find desired charmap!\n"); 01541 } 01542 error = FT_Set_Charmap(ft_face, found); 01543 if (error) 01544 { 01545 DPRINT1("WARNING: Could not set the charmap!\n"); 01546 } 01547 } 01548 01549 // FT_Set_Pixel_Sizes(ft_face, 01550 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 01551 /* FIXME: Should set character height if neg */ 01552 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 01553 // dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 01554 01555 TEXTOBJ_UnlockText(TextObj); 01556 01557 if (iFormat & GGO_GLYPH_INDEX) 01558 { 01559 glyph_index = wch; 01560 iFormat &= ~GGO_GLYPH_INDEX; 01561 } 01562 else glyph_index = FT_Get_Char_Index(ft_face, wch); 01563 01564 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2) 01565 load_flags |= FT_LOAD_NO_BITMAP; 01566 01567 if (iFormat & GGO_UNHINTED) 01568 { 01569 load_flags |= FT_LOAD_NO_HINTING; 01570 iFormat &= ~GGO_UNHINTED; 01571 } 01572 01573 error = FT_Load_Glyph(ft_face, glyph_index, load_flags); 01574 if (error) 01575 { 01576 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index); 01577 IntUnLockFreeType; 01578 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); 01579 return GDI_ERROR; 01580 } 01581 IntUnLockFreeType; 01582 01583 if (aveWidth && potm) 01584 { 01585 widthRatio = (FLOAT)aveWidth * eM11 / 01586 (FLOAT) potm->otmTextMetrics.tmAveCharWidth; 01587 } 01588 01589 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64; 01590 right = (INT)((ft_face->glyph->metrics.horiBearingX + 01591 ft_face->glyph->metrics.width) * widthRatio + 63) & -64; 01592 01593 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6; 01594 lsb = left >> 6; 01595 bbx = (right - left) >> 6; 01596 01597 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx); 01598 01599 IntLockFreeType; 01600 01601 /* Scaling transform */ 01602 if (aveWidth) 01603 { 01604 FT_Matrix scaleMat; 01605 DPRINT("Scaling Trans!\n"); 01606 scaleMat.xx = FT_FixedFromFloat(widthRatio); 01607 scaleMat.xy = 0; 01608 scaleMat.yx = 0; 01609 scaleMat.yy = (1 << 16); 01610 FT_Matrix_Multiply(&scaleMat, &transMat); 01611 needsTransform = TRUE; 01612 } 01613 01614 /* Slant transform */ 01615 if (potm->otmTextMetrics.tmItalic) 01616 { 01617 FT_Matrix slantMat; 01618 DPRINT("Slant Trans!\n"); 01619 slantMat.xx = (1 << 16); 01620 slantMat.xy = ((1 << 16) >> 2); 01621 slantMat.yx = 0; 01622 slantMat.yy = (1 << 16); 01623 FT_Matrix_Multiply(&slantMat, &transMat); 01624 needsTransform = TRUE; 01625 } 01626 01627 /* Rotation transform */ 01628 if (orientation) 01629 { 01630 FT_Matrix rotationMat; 01631 FT_Vector vecAngle; 01632 DPRINT("Rotation Trans!\n"); 01633 angle = FT_FixedFromFloat((float)orientation / 10.0); 01634 FT_Vector_Unit(&vecAngle, angle); 01635 rotationMat.xx = vecAngle.x; 01636 rotationMat.xy = -vecAngle.y; 01637 rotationMat.yx = -rotationMat.xy; 01638 rotationMat.yy = rotationMat.xx; 01639 FT_Matrix_Multiply(&rotationMat, &transMat); 01640 needsTransform = TRUE; 01641 } 01642 01643 /* Extra transformation specified by caller */ 01644 if (pmat2) 01645 { 01646 FT_Matrix extraMat; 01647 DPRINT("MAT2 Matrix Trans!\n"); 01648 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11); 01649 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21); 01650 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12); 01651 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22); 01652 FT_Matrix_Multiply(&extraMat, &transMat); 01653 needsTransform = TRUE; 01654 } 01655 01656 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */ 01657 01658 if (!needsTransform) 01659 { 01660 DPRINT("No Need to be Transformed!\n"); 01661 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64; 01662 bottom = (ft_face->glyph->metrics.horiBearingY - 01663 ft_face->glyph->metrics.height) & -64; 01664 gm.gmCellIncX = adv; 01665 gm.gmCellIncY = 0; 01666 } 01667 else 01668 { 01669 INT xc, yc; 01670 FT_Vector vec; 01671 for (xc = 0; xc < 2; xc++) 01672 { 01673 for (yc = 0; yc < 2; yc++) 01674 { 01675 vec.x = (ft_face->glyph->metrics.horiBearingX + 01676 xc * ft_face->glyph->metrics.width); 01677 vec.y = ft_face->glyph->metrics.horiBearingY - 01678 yc * ft_face->glyph->metrics.height; 01679 DPRINT("Vec %ld,%ld\n", vec.x, vec.y); 01680 FT_Vector_Transform(&vec, &transMat); 01681 if (xc == 0 && yc == 0) 01682 { 01683 left = right = vec.x; 01684 top = bottom = vec.y; 01685 } 01686 else 01687 { 01688 if (vec.x < left) left = vec.x; 01689 else if (vec.x > right) right = vec.x; 01690 if (vec.y < bottom) bottom = vec.y; 01691 else if (vec.y > top) top = vec.y; 01692 } 01693 } 01694 } 01695 left = left & -64; 01696 right = (right + 63) & -64; 01697 bottom = bottom & -64; 01698 top = (top + 63) & -64; 01699 01700 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom); 01701 vec.x = ft_face->glyph->metrics.horiAdvance; 01702 vec.y = 0; 01703 FT_Vector_Transform(&vec, &transMat); 01704 gm.gmCellIncX = (vec.x+63) >> 6; 01705 gm.gmCellIncY = -((vec.y+63) >> 6); 01706 } 01707 gm.gmBlackBoxX = (right - left) >> 6; 01708 gm.gmBlackBoxY = (top - bottom) >> 6; 01709 gm.gmptGlyphOrigin.x = left >> 6; 01710 gm.gmptGlyphOrigin.y = top >> 6; 01711 01712 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n", 01713 gm.gmCellIncX, gm.gmCellIncY, 01714 gm.gmBlackBoxX, gm.gmBlackBoxY, 01715 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y); 01716 01717 IntUnLockFreeType; 01718 01719 if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS)); 01720 01721 if (iFormat == GGO_METRICS) 01722 { 01723 DPRINT("GGO_METRICS Exit!\n"); 01724 return 1; /* FIXME */ 01725 } 01726 01727 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP) 01728 { 01729 DPRINT1("Loaded a bitmap\n"); 01730 return GDI_ERROR; 01731 } 01732 01733 switch (iFormat) 01734 { 01735 case GGO_BITMAP: 01736 width = gm.gmBlackBoxX; 01737 height = gm.gmBlackBoxY; 01738 pitch = ((width + 31) >> 5) << 2; 01739 needed = pitch * height; 01740 01741 if (!pvBuf || !cjBuf) break; 01742 01743 switch (ft_face->glyph->format) 01744 { 01745 case ft_glyph_format_bitmap: 01746 { 01747 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 01748 INT w = (ft_face->glyph->bitmap.width + 7) >> 3; 01749 INT h = ft_face->glyph->bitmap.rows; 01750 while (h--) 01751 { 01752 RtlCopyMemory(dst, src, w); 01753 src += ft_face->glyph->bitmap.pitch; 01754 dst += pitch; 01755 } 01756 break; 01757 } 01758 01759 case ft_glyph_format_outline: 01760 ft_bitmap.width = width; 01761 ft_bitmap.rows = height; 01762 ft_bitmap.pitch = pitch; 01763 ft_bitmap.pixel_mode = ft_pixel_mode_mono; 01764 ft_bitmap.buffer = pvBuf; 01765 01766 IntLockFreeType; 01767 if (needsTransform) 01768 { 01769 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 01770 } 01771 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 01772 /* Note: FreeType will only set 'black' bits for us. */ 01773 RtlZeroMemory(pvBuf, needed); 01774 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); 01775 IntUnLockFreeType; 01776 break; 01777 01778 default: 01779 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 01780 return GDI_ERROR; 01781 } 01782 break; 01783 01784 case GGO_GRAY2_BITMAP: 01785 case GGO_GRAY4_BITMAP: 01786 case GGO_GRAY8_BITMAP: 01787 { 01788 unsigned int mult, row, col; 01789 BYTE *start, *ptr; 01790 01791 width = gm.gmBlackBoxX; 01792 height = gm.gmBlackBoxY; 01793 pitch = (width + 3) / 4 * 4; 01794 needed = pitch * height; 01795 01796 if (!pvBuf || !cjBuf) break; 01797 01798 switch (ft_face->glyph->format) 01799 { 01800 case ft_glyph_format_bitmap: 01801 { 01802 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf; 01803 INT h = ft_face->glyph->bitmap.rows; 01804 INT x; 01805 while (h--) 01806 { 01807 for (x = 0; x < pitch; x++) 01808 { 01809 if (x < ft_face->glyph->bitmap.width) 01810 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0; 01811 else 01812 dst[x] = 0; 01813 } 01814 src += ft_face->glyph->bitmap.pitch; 01815 dst += pitch; 01816 } 01817 return needed; 01818 } 01819 case ft_glyph_format_outline: 01820 { 01821 ft_bitmap.width = width; 01822 ft_bitmap.rows = height; 01823 ft_bitmap.pitch = pitch; 01824 ft_bitmap.pixel_mode = ft_pixel_mode_grays; 01825 ft_bitmap.buffer = pvBuf; 01826 01827 IntLockFreeType; 01828 if (needsTransform) 01829 { 01830 FT_Outline_Transform(&ft_face->glyph->outline, &transMat); 01831 } 01832 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom ); 01833 RtlZeroMemory(ft_bitmap.buffer, cjBuf); 01834 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap); 01835 IntUnLockFreeType; 01836 01837 if (iFormat == GGO_GRAY2_BITMAP) 01838 mult = 4; 01839 else if (iFormat == GGO_GRAY4_BITMAP) 01840 mult = 16; 01841 else if (iFormat == GGO_GRAY8_BITMAP) 01842 mult = 64; 01843 else 01844 { 01845 return GDI_ERROR; 01846 } 01847 } 01848 default: 01849 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format); 01850 return GDI_ERROR; 01851 } 01852 start = pvBuf; 01853 for (row = 0; row < height; row++) 01854 { 01855 ptr = start; 01856 for (col = 0; col < width; col++, ptr++) 01857 { 01858 *ptr = (((int)*ptr) * mult + 128) / 256; 01859 } 01860 start += pitch; 01861 } 01862 break; 01863 } 01864 01865 case GGO_NATIVE: 01866 { 01867 int contour, point = 0, first_pt; 01868 FT_Outline *outline = &ft_face->glyph->outline; 01869 TTPOLYGONHEADER *pph; 01870 TTPOLYCURVE *ppc; 01871 DWORD pph_start, cpfx, type; 01872 01873 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */ 01874 01875 IntLockFreeType; 01876 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat); 01877 01878 for (contour = 0; contour < outline->n_contours; contour++) 01879 { 01880 pph_start = needed; 01881 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed); 01882 first_pt = point; 01883 if (pvBuf) 01884 { 01885 pph->dwType = TT_POLYGON_TYPE; 01886 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 01887 } 01888 needed += sizeof(*pph); 01889 point++; 01890 while (point <= outline->contours[contour]) 01891 { 01892 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed); 01893 type = (outline->tags[point] & FT_Curve_Tag_On) ? 01894 TT_PRIM_LINE : TT_PRIM_QSPLINE; 01895 cpfx = 0; 01896 do 01897 { 01898 if (pvBuf) 01899 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 01900 cpfx++; 01901 point++; 01902 } 01903 while (point <= outline->contours[contour] && 01904 (outline->tags[point] & FT_Curve_Tag_On) == 01905 (outline->tags[point-1] & FT_Curve_Tag_On)); 01906 01907 /* At the end of a contour Windows adds the start point, but 01908 only for Beziers */ 01909 if (point > outline->contours[contour] && 01910 !(outline->tags[point-1] & FT_Curve_Tag_On)) 01911 { 01912 if (pvBuf) 01913 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]); 01914 cpfx++; 01915 } 01916 else if (point <= outline->contours[contour] && 01917 outline->tags[point] & FT_Curve_Tag_On) 01918 { 01919 /* Add closing pt for bezier */ 01920 if (pvBuf) 01921 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 01922 cpfx++; 01923 point++; 01924 } 01925 if (pvBuf) 01926 { 01927 ppc->wType = type; 01928 ppc->cpfx = cpfx; 01929 } 01930 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 01931 } 01932 if (pvBuf) pph->cb = needed - pph_start; 01933 } 01934 IntUnLockFreeType; 01935 break; 01936 } 01937 case GGO_BEZIER: 01938 { 01939 /* Convert the quadratic Beziers to cubic Beziers. 01940 The parametric eqn for a cubic Bezier is, from PLRM: 01941 r(t) = at^3 + bt^2 + ct + r0 01942 with the control points: 01943 r1 = r0 + c/3 01944 r2 = r1 + (c + b)/3 01945 r3 = r0 + c + b + a 01946 01947 A quadratic Beizer has the form: 01948 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2 01949 01950 So equating powers of t leads to: 01951 r1 = 2/3 p1 + 1/3 p0 01952 r2 = 2/3 p1 + 1/3 p2 01953 and of course r0 = p0, r3 = p2 01954 */ 01955 01956 int contour, point = 0, first_pt; 01957 FT_Outline *outline = &ft_face->glyph->outline; 01958 TTPOLYGONHEADER *pph; 01959 TTPOLYCURVE *ppc; 01960 DWORD pph_start, cpfx, type; 01961 FT_Vector cubic_control[4]; 01962 if (cjBuf == 0) pvBuf = NULL; 01963 01964 if (needsTransform && pvBuf) 01965 { 01966 IntLockFreeType; 01967 FT_Outline_Transform(outline, &transMat); 01968 IntUnLockFreeType; 01969 } 01970 01971 for (contour = 0; contour < outline->n_contours; contour++) 01972 { 01973 pph_start = needed; 01974 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed); 01975 first_pt = point; 01976 if (pvBuf) 01977 { 01978 pph->dwType = TT_POLYGON_TYPE; 01979 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart); 01980 } 01981 needed += sizeof(*pph); 01982 point++; 01983 while (point <= outline->contours[contour]) 01984 { 01985 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed); 01986 type = (outline->tags[point] & FT_Curve_Tag_On) ? 01987 TT_PRIM_LINE : TT_PRIM_CSPLINE; 01988 cpfx = 0; 01989 do 01990 { 01991 if (type == TT_PRIM_LINE) 01992 { 01993 if (pvBuf) 01994 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]); 01995 cpfx++; 01996 point++; 01997 } 01998 else 01999 { 02000 /* Unlike QSPLINEs, CSPLINEs always have their endpoint 02001 so cpfx = 3n */ 02002 02003 /* FIXME: Possible optimization in endpoint calculation 02004 if there are two consecutive curves */ 02005 cubic_control[0] = outline->points[point-1]; 02006 if (!(outline->tags[point-1] & FT_Curve_Tag_On)) 02007 { 02008 cubic_control[0].x += outline->points[point].x + 1; 02009 cubic_control[0].y += outline->points[point].y + 1; 02010 cubic_control[0].x >>= 1; 02011 cubic_control[0].y >>= 1; 02012 } 02013 if (point+1 > outline->contours[contour]) 02014 cubic_control[3] = outline->points[first_pt]; 02015 else 02016 { 02017 cubic_control[3] = outline->points[point+1]; 02018 if (!(outline->tags[point+1] & FT_Curve_Tag_On)) 02019 { 02020 cubic_control[3].x += outline->points[point].x + 1; 02021 cubic_control[3].y += outline->points[point].y + 1; 02022 cubic_control[3].x >>= 1; 02023 cubic_control[3].y >>= 1; 02024 } 02025 } 02026 /* r1 = 1/3 p0 + 2/3 p1 02027 r2 = 1/3 p2 + 2/3 p1 */ 02028 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3; 02029 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3; 02030 cubic_control[2] = cubic_control[1]; 02031 cubic_control[1].x += (cubic_control[0].x + 1) / 3; 02032 cubic_control[1].y += (cubic_control[0].y + 1) / 3; 02033 cubic_control[2].x += (cubic_control[3].x + 1) / 3; 02034 cubic_control[2].y += (cubic_control[3].y + 1) / 3; 02035 if (pvBuf) 02036 { 02037 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]); 02038 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]); 02039 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]); 02040 } 02041 cpfx += 3; 02042 point++; 02043 } 02044 } 02045 while (point <= outline->contours[contour] && 02046 (outline->tags[point] & FT_Curve_Tag_On) == 02047 (outline->tags[point-1] & FT_Curve_Tag_On)); 02048 /* At the end of a contour Windows adds the start point, 02049 but only for Beziers and we've already done that. */ 02050 if (point <= outline->contours[contour] && 02051 outline->tags[point] & FT_Curve_Tag_On) 02052 { 02053 /* This is the closing pt of a bezier, but we've already 02054 added it, so just inc point and carry on */ 02055 point++; 02056 } 02057 if (pvBuf) 02058 { 02059 ppc->wType = type; 02060 ppc->cpfx = cpfx; 02061 } 02062 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX); 02063 } 02064 if (pvBuf) pph->cb = needed - pph_start; 02065 } 02066 break; 02067 } 02068 02069 default: 02070 DPRINT1("Unsupported format %d\n", iFormat); 02071 return GDI_ERROR; 02072 } 02073 02074 DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed); 02075 return needed; 02076 } 02077 02078 BOOL 02079 FASTCALL 02080 TextIntGetTextExtentPoint(PDC dc, 02081 PTEXTOBJ TextObj, 02082 LPCWSTR String, 02083 INT Count, 02084 ULONG MaxExtent, 02085 LPINT Fit, 02086 LPINT Dx, 02087 LPSIZE Size, 02088 FLONG fl) 02089 { 02090 PFONTGDI FontGDI; 02091 FT_Face face; 02092 FT_GlyphSlot glyph; 02093 FT_BitmapGlyph realglyph; 02094 INT error, n, glyph_index, i, previous; 02095 ULONGLONG TotalWidth = 0; 02096 FT_CharMap charmap, found = NULL; 02097 BOOL use_kerning; 02098 FT_Render_Mode RenderMode; 02099 BOOLEAN Render; 02100 02101 FontGDI = ObjToGDI(TextObj->Font, FONT); 02102 02103 face = FontGDI->face; 02104 if (NULL != Fit) 02105 { 02106 *Fit = 0; 02107 } 02108 02109 IntLockFreeType; 02110 if (face->charmap == NULL) 02111 { 02112 DPRINT("WARNING: No charmap selected!\n"); 02113 DPRINT("This font face has %d charmaps\n", face->num_charmaps); 02114 02115 for (n = 0; n < face->num_charmaps; n++) 02116 { 02117 charmap = face->charmaps[n]; 02118 DPRINT("Found charmap encoding: %u\n", charmap->encoding); 02119 if (charmap->encoding != 0) 02120 { 02121 found = charmap; 02122 break; 02123 } 02124 } 02125 02126 if (! found) 02127 { 02128 DPRINT1("WARNING: Could not find desired charmap!\n"); 02129 } 02130 02131 error = FT_Set_Charmap(face, found); 02132 if (error) 02133 { 02134 DPRINT1("WARNING: Could not set the charmap!\n"); 02135 } 02136 } 02137 02138 Render = IntIsFontRenderingEnabled(); 02139 if (Render) 02140 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont); 02141 else 02142 RenderMode = FT_RENDER_MODE_MONO; 02143 02144 error = FT_Set_Pixel_Sizes(face, 02145 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 02146 /* FIXME: Should set character height if neg */ 02147 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 02148 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 02149 if (error) 02150 { 02151 DPRINT1("Error in setting pixel sizes: %u\n", error); 02152 } 02153 02154 use_kerning = FT_HAS_KERNING(face); 02155 previous = 0; 02156 02157 for (i = 0; i < Count; i++) 02158 { 02159 if (fl & GTEF_INDICES) 02160 glyph_index = *String; 02161 else 02162 glyph_index = FT_Get_Char_Index(face, *String); 02163 02164 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, 02165 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) 02166 { 02167 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 02168 if (error) 02169 { 02170 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index); 02171 break; 02172 } 02173 02174 glyph = face->glyph; 02175 realglyph = ftGdiGlyphCacheSet(face, glyph_index, 02176 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode); 02177 if (!realglyph) 02178 { 02179 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index); 02180 break; 02181 } 02182 } 02183 02184 /* Retrieve kerning distance */ 02185 if (use_kerning && previous && glyph_index) 02186 { 02187 FT_Vector delta; 02188 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 02189 TotalWidth += delta.x; 02190 } 02191 02192 TotalWidth += realglyph->root.advance.x >> 10; 02193 02194 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit) 02195 { 02196 *Fit = i + 1; 02197 } 02198 if (NULL != Dx) 02199 { 02200 Dx[i] = (TotalWidth + 32) >> 6; 02201 } 02202 02203 previous = glyph_index; 02204 String++; 02205 } 02206 IntUnLockFreeType; 02207 02208 Size->cx = (TotalWidth + 32) >> 6; 02209 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 02210 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)); 02211 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72); 02212 02213 return TRUE; 02214 } 02215 02216 02217 INT 02218 FASTCALL 02219 ftGdiGetTextCharsetInfo( 02220 PDC Dc, 02221 LPFONTSIGNATURE lpSig, 02222 DWORD dwFlags) 02223 { 02224 PDC_ATTR pdcattr; 02225 UINT Ret = DEFAULT_CHARSET, i; 02226 HFONT hFont; 02227 PTEXTOBJ TextObj; 02228 PFONTGDI FontGdi; 02229 FONTSIGNATURE fs; 02230 TT_OS2 *pOS2; 02231 FT_Face Face; 02232 CHARSETINFO csi; 02233 DWORD cp, fs0; 02234 USHORT usACP, usOEM; 02235 02236 pdcattr = Dc->pdcattr; 02237 hFont = pdcattr->hlfntNew; 02238 TextObj = RealizeFontInit(hFont); 02239 02240 if (!TextObj) 02241 { 02242 EngSetLastError(ERROR_INVALID_HANDLE); 02243 return Ret; 02244 } 02245 FontGdi = ObjToGDI(TextObj->Font, FONT); 02246 Face = FontGdi->face; 02247 TEXTOBJ_UnlockText(TextObj); 02248 02249 IntLockFreeType; 02250 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2); 02251 IntUnLockFreeType; 02252 memset(&fs, 0, sizeof(FONTSIGNATURE)); 02253 if (NULL != pOS2) 02254 { 02255 fs.fsCsb[0] = pOS2->ulCodePageRange1; 02256 fs.fsCsb[1] = pOS2->ulCodePageRange2; 02257 fs.fsUsb[0] = pOS2->ulUnicodeRange1; 02258 fs.fsUsb[1] = pOS2->ulUnicodeRange2; 02259 fs.fsUsb[2] = pOS2->ulUnicodeRange3; 02260 fs.fsUsb[3] = pOS2->ulUnicodeRange4; 02261 if (pOS2->version == 0) 02262 { 02263 FT_UInt dummy; 02264 02265 if (FT_Get_First_Char( Face, &dummy ) < 0x100) 02266 fs.fsCsb[0] |= FS_LATIN1; 02267 else 02268 fs.fsCsb[0] |= FS_SYMBOL; 02269 } 02270 } 02271 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]); 02272 if (fs.fsCsb[0] == 0) 02273 { /* Let's see if we can find any interesting cmaps */ 02274 for (i = 0; i < Face->num_charmaps; i++) 02275 { 02276 switch (Face->charmaps[i]->encoding) 02277 { 02278 case FT_ENCODING_UNICODE: 02279 case FT_ENCODING_APPLE_ROMAN: 02280 fs.fsCsb[0] |= FS_LATIN1; 02281 break; 02282 case FT_ENCODING_MS_SYMBOL: 02283 fs.fsCsb[0] |= FS_SYMBOL; 02284 break; 02285 default: 02286 break; 02287 } 02288 } 02289 } 02290 if (lpSig) 02291 { 02292 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE)); 02293 } 02294 02295 RtlGetDefaultCodePage(&usACP, &usOEM); 02296 cp = usACP; 02297 02298 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE)) 02299 if (csi.fs.fsCsb[0] & fs.fsCsb[0]) 02300 { 02301 DPRINT("Hit 1\n"); 02302 Ret = csi.ciCharset; 02303 goto Exit; 02304 } 02305 02306 for (i = 0; i < MAXTCIINDEX; i++) 02307 { 02308 fs0 = 1L << i; 02309 if (fs.fsCsb[0] & fs0) 02310 { 02311 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG)) 02312 { 02313 // *cp = csi.ciACP; 02314 DPRINT("Hit 2\n"); 02315 Ret = csi.ciCharset; 02316 goto Exit; 02317 } 02318 else 02319 DPRINT1("TCI failing on %x\n", fs0); 02320 } 02321 } 02322 Exit: 02323 DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP); 02324 return (MAKELONG(csi.ciACP, csi.ciCharset)); 02325 } 02326 02327 02328 DWORD 02329 FASTCALL 02330 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) 02331 { 02332 DWORD size = 0; 02333 DWORD num_ranges = 0; 02334 FT_Face face = Font->face; 02335 02336 if (face->charmap->encoding == FT_ENCODING_UNICODE) 02337 { 02338 FT_UInt glyph_code = 0; 02339 FT_ULong char_code, char_code_prev; 02340 02341 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code); 02342 02343 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n", 02344 face->num_glyphs, glyph_code, char_code); 02345 02346 if (!glyph_code) return 0; 02347 02348 if (glyphset) 02349 { 02350 glyphset->ranges[0].wcLow = (USHORT)char_code; 02351 glyphset->ranges[0].cGlyphs = 0; 02352 glyphset->cGlyphsSupported = 0; 02353 } 02354 02355 num_ranges = 1; 02356 while (glyph_code) 02357 { 02358 if (char_code < char_code_prev) 02359 { 02360 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n"); 02361 return 0; 02362 } 02363 if (char_code - char_code_prev > 1) 02364 { 02365 num_ranges++; 02366 if (glyphset) 02367 { 02368 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code; 02369 glyphset->ranges[num_ranges - 1].cGlyphs = 1; 02370 glyphset->cGlyphsSupported++; 02371 } 02372 } 02373 else if (glyphset) 02374 { 02375 glyphset->ranges[num_ranges - 1].cGlyphs++; 02376 glyphset->cGlyphsSupported++; 02377 } 02378 char_code_prev = char_code; 02379 char_code = FT_Get_Next_Char(face, char_code, &glyph_code); 02380 } 02381 } 02382 else 02383 DPRINT1("Encoding %u not supported\n", face->charmap->encoding); 02384 02385 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1); 02386 if (glyphset) 02387 { 02388 glyphset->cbThis = size; 02389 glyphset->cRanges = num_ranges; 02390 } 02391 return size; 02392 } 02393 02394 02395 BOOL 02396 FASTCALL 02397 ftGdiGetTextMetricsW( 02398 HDC hDC, 02399 PTMW_INTERNAL ptmwi) 02400 { 02401 PDC dc; 02402 PDC_ATTR pdcattr; 02403 PTEXTOBJ TextObj; 02404 PFONTGDI FontGDI; 02405 FT_Face Face; 02406 TT_OS2 *pOS2; 02407 TT_HoriHeader *pHori; 02408 FT_WinFNT_HeaderRec Win; 02409 ULONG Error; 02410 NTSTATUS Status = STATUS_SUCCESS; 02411 02412 if (!ptmwi) 02413 { 02414 EngSetLastError(STATUS_INVALID_PARAMETER); 02415 return FALSE; 02416 } 02417 02418 if (!(dc = DC_LockDc(hDC))) 02419 { 02420 EngSetLastError(ERROR_INVALID_HANDLE); 02421 return FALSE; 02422 } 02423 pdcattr = dc->pdcattr; 02424 TextObj = RealizeFontInit(pdcattr->hlfntNew); 02425 if (NULL != TextObj) 02426 { 02427 FontGDI = ObjToGDI(TextObj->Font, FONT); 02428 02429 Face = FontGDI->face; 02430 IntLockFreeType; 02431 Error = FT_Set_Pixel_Sizes(Face, 02432 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 02433 /* FIXME: Should set character height if neg */ 02434 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 02435 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 02436 IntUnLockFreeType; 02437 if (0 != Error) 02438 { 02439 DPRINT1("Error in setting pixel sizes: %u\n", Error); 02440 Status = STATUS_UNSUCCESSFUL; 02441 } 02442 else 02443 { 02444 Status = STATUS_SUCCESS; 02445 02446 IntLockFreeType; 02447 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); 02448 if (NULL == pOS2) 02449 { 02450 DPRINT1("Can't find OS/2 table - not TT font?\n"); 02451 Status = STATUS_INTERNAL_ERROR; 02452 } 02453 02454 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea); 02455 if (NULL == pHori) 02456 { 02457 DPRINT1("Can't find HHEA table - not TT font?\n"); 02458 Status = STATUS_INTERNAL_ERROR; 02459 } 02460 02461 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win); 02462 02463 IntUnLockFreeType; 02464 02465 if (NT_SUCCESS(Status)) 02466 { 02467 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0); 02468 02469 /* FIXME: Fill Diff member */ 02470 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff)); 02471 } 02472 } 02473 TEXTOBJ_UnlockText(TextObj); 02474 } 02475 else 02476 { 02477 Status = STATUS_INVALID_HANDLE; 02478 } 02479 DC_UnlockDc(dc); 02480 02481 if (!NT_SUCCESS(Status)) 02482 { 02483 SetLastNtError(Status); 02484 return FALSE; 02485 } 02486 return TRUE; 02487 } 02488 02489 02490 DWORD 02491 FASTCALL 02492 ftGdiGetFontData( 02493 PFONTGDI FontGdi, 02494 DWORD Table, 02495 DWORD Offset, 02496 PVOID Buffer, 02497 DWORD Size) 02498 { 02499 DWORD Result = GDI_ERROR; 02500 02501 IntLockFreeType; 02502 02503 if (FT_IS_SFNT(FontGdi->face)) 02504 { 02505 if (Table) 02506 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) | 02507 (Table << 8 & 0xFF0000); 02508 02509 if (!Buffer) Size = 0; 02510 02511 if (Buffer && Size) 02512 { 02513 FT_Error Error; 02514 FT_ULong Needed = 0; 02515 02516 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed); 02517 02518 if ( !Error && Needed < Size) Size = Needed; 02519 } 02520 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size)) 02521 Result = Size; 02522 } 02523 02524 IntUnLockFreeType; 02525 02526 return Result; 02527 } 02528 02529 static UINT FASTCALL 02530 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI) 02531 { 02532 ANSI_STRING EntryFaceNameA; 02533 UNICODE_STRING EntryFaceNameW; 02534 unsigned Size; 02535 OUTLINETEXTMETRICW *Otm; 02536 LONG WeightDiff; 02537 NTSTATUS Status; 02538 UINT Score = 1; 02539 02540 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); 02541 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); 02542 if (NT_SUCCESS(Status)) 02543 { 02544 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) 02545 { 02546 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); 02547 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; 02548 } 02549 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) 02550 { 02551 Score += 49; 02552 } 02553 RtlFreeUnicodeString(&EntryFaceNameW); 02554 } 02555 02556 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 02557 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 02558 if (NULL == Otm) 02559 { 02560 return Score; 02561 } 02562 IntGetOutlineTextMetrics(FontGDI, Size, Otm); 02563 02564 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) || 02565 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic)) 02566 { 02567 Score += 25; 02568 } 02569 if (LogFont->lfWeight != FW_DONTCARE) 02570 { 02571 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight) 02572 { 02573 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight; 02574 } 02575 else 02576 { 02577 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight; 02578 } 02579 Score += (1000 - WeightDiff) / (1000 / 25); 02580 } 02581 else 02582 { 02583 Score += 25; 02584 } 02585 02586 ExFreePool(Otm); 02587 02588 return Score; 02589 } 02590 02591 static __inline VOID 02592 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont, 02593 PUNICODE_STRING FaceName, PLIST_ENTRY Head) 02594 { 02595 PLIST_ENTRY Entry; 02596 PFONT_ENTRY CurrentEntry; 02597 FONTGDI *FontGDI; 02598 UINT Score; 02599 ASSERT(FontObj && MatchScore && LogFont && FaceName && Head); 02600 Entry = Head->Flink; 02601 while (Entry != Head) 02602 { 02603 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); 02604 02605 FontGDI = CurrentEntry->Font; 02606 ASSERT(FontGDI); 02607 02608 Score = GetFontScore(LogFont, FaceName, FontGDI); 02609 if (*MatchScore == 0 || *MatchScore < Score) 02610 { 02611 *FontObj = GDIToObj(FontGDI, FONT); 02612 *MatchScore = Score; 02613 } 02614 Entry = Entry->Flink; 02615 } 02616 } 02617 02618 static __inline BOOLEAN 02619 SubstituteFontFamilyKey(PUNICODE_STRING FaceName, 02620 LPCWSTR Key) 02621 { 02622 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; 02623 NTSTATUS Status; 02624 UNICODE_STRING Value; 02625 02626 RtlInitUnicodeString(&Value, NULL); 02627 02628 QueryTable[0].QueryRoutine = NULL; 02629 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | 02630 RTL_QUERY_REGISTRY_REQUIRED; 02631 QueryTable[0].Name = FaceName->Buffer; 02632 QueryTable[0].EntryContext = &Value; 02633 QueryTable[0].DefaultType = REG_NONE; 02634 QueryTable[0].DefaultData = NULL; 02635 QueryTable[0].DefaultLength = 0; 02636 02637 QueryTable[1].QueryRoutine = NULL; 02638 QueryTable[1].Name = NULL; 02639 02640 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, 02641 Key, 02642 QueryTable, 02643 NULL, 02644 NULL); 02645 if (NT_SUCCESS(Status)) 02646 { 02647 RtlFreeUnicodeString(FaceName); 02648 *FaceName = Value; 02649 } 02650 02651 return NT_SUCCESS(Status); 02652 } 02653 02654 static __inline void 02655 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level) 02656 { 02657 if (10 < Level) /* Enough is enough */ 02658 { 02659 return; 02660 } 02661 02662 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") || 02663 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes")) 02664 { 02665 SubstituteFontFamily(FaceName, Level + 1); 02666 } 02667 } 02668 02669 static 02670 VOID 02671 FASTCALL 02672 IntFontType(PFONTGDI Font) 02673 { 02674 PS_FontInfoRec psfInfo; 02675 FT_ULong tmp_size = 0; 02676 02677 if (FT_HAS_MULTIPLE_MASTERS(Font->face)) 02678 Font->FontObj.flFontType |= FO_MULTIPLEMASTER; 02679 if (FT_HAS_VERTICAL( Font->face )) 02680 Font->FontObj.flFontType |= FO_VERT_FACE; 02681 if (FT_IS_SCALABLE( Font->face )) 02682 Font->FontObj.flFontType |= FO_TYPE_RASTER; 02683 if (FT_IS_SFNT(Font->face)) 02684 { 02685 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE; 02686 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post)) 02687 Font->FontObj.flFontType |= FO_POSTSCRIPT; 02688 } 02689 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo )) 02690 { 02691 Font->FontObj.flFontType |= FO_POSTSCRIPT; 02692 } 02693 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */ 02694 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size)) 02695 { 02696 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT); 02697 } 02698 } 02699 02700 NTSTATUS 02701 FASTCALL 02702 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj) 02703 { 02704 NTSTATUS Status = STATUS_SUCCESS; 02705 PTEXTOBJ TextObj; 02706 UNICODE_STRING FaceName; 02707 PPROCESSINFO Win32Process; 02708 UINT MatchScore; 02709 02710 if (!pTextObj) 02711 { 02712 TextObj = TEXTOBJ_LockText(FontHandle); 02713 if (NULL == TextObj) 02714 { 02715 return STATUS_INVALID_HANDLE; 02716 } 02717 02718 if (TextObj->fl & TEXTOBJECT_INIT) 02719 { 02720 TEXTOBJ_UnlockText(TextObj); 02721 return STATUS_SUCCESS; 02722 } 02723 } 02724 else 02725 TextObj = pTextObj; 02726 02727 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName)) 02728 { 02729 if (!pTextObj) TEXTOBJ_UnlockText(TextObj); 02730 return STATUS_NO_MEMORY; 02731 } 02732 SubstituteFontFamily(&FaceName, 0); 02733 MatchScore = 0; 02734 TextObj->Font = NULL; 02735 02736 /* First search private fonts */ 02737 Win32Process = PsGetCurrentProcessWin32Process(); 02738 IntLockProcessPrivateFonts(Win32Process); 02739 FindBestFontFromList(&TextObj->Font, &MatchScore, 02740 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, 02741 &Win32Process->PrivateFontListHead); 02742 IntUnLockProcessPrivateFonts(Win32Process); 02743 02744 /* Search system fonts */ 02745 IntLockGlobalFonts; 02746 FindBestFontFromList(&TextObj->Font, &MatchScore, 02747 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName, 02748 &FontListHead); 02749 IntUnLockGlobalFonts; 02750 if (NULL == TextObj->Font) 02751 { 02752 DPRINT1("Requested font %S not found, no fonts loaded at all\n", 02753 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName); 02754 Status = STATUS_NOT_FOUND; 02755 } 02756 else 02757 { 02758 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT); 02759 // Need hdev, when freetype is loaded need to create DEVOBJ for 02760 // Consumer and Producer. 02761 TextObj->Font->iUniq = 1; // Now it can be cached. 02762 IntFontType(FontGdi); 02763 FontGdi->flType = TextObj->Font->flFontType; 02764 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0; 02765 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0; 02766 TextObj->fl |= TEXTOBJECT_INIT; 02767 Status = STATUS_SUCCESS; 02768 } 02769 02770 RtlFreeUnicodeString(&FaceName); 02771 if (!pTextObj) TEXTOBJ_UnlockText(TextObj); 02772 02773 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0); 02774 02775 return Status; 02776 } 02777 02778 02779 static 02780 BOOL 02781 FASTCALL 02782 IntGetFullFileName( 02783 POBJECT_NAME_INFORMATION NameInfo, 02784 ULONG Size, 02785 PUNICODE_STRING FileName) 02786 { 02787 NTSTATUS Status; 02788 OBJECT_ATTRIBUTES ObjectAttributes; 02789 HANDLE hFile; 02790 IO_STATUS_BLOCK IoStatusBlock; 02791 ULONG Desired; 02792 02793 InitializeObjectAttributes(&ObjectAttributes, 02794 FileName, 02795 OBJ_CASE_INSENSITIVE, 02796 NULL, 02797 NULL); 02798 02799 Status = ZwOpenFile( 02800 &hFile, 02801 0, // FILE_READ_ATTRIBUTES, 02802 &ObjectAttributes, 02803 &IoStatusBlock, 02804 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 02805 0); 02806 02807 if (!NT_SUCCESS(Status)) 02808 { 02809 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status); 02810 return FALSE; 02811 } 02812 02813 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired); 02814 ZwClose(hFile); 02815 if (!NT_SUCCESS(Status)) 02816 { 02817 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status); 02818 return FALSE; 02819 } 02820 02821 return TRUE; 02822 } 02823 02824 BOOL 02825 FASTCALL 02826 IntGdiGetFontResourceInfo( 02827 PUNICODE_STRING FileName, 02828 PVOID pBuffer, 02829 DWORD *pdwBytes, 02830 DWORD dwType) 02831 { 02832 UNICODE_STRING EntryFileName; 02833 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2; 02834 PLIST_ENTRY ListEntry; 02835 PFONT_ENTRY FontEntry; 02836 FONTFAMILYINFO Info; 02837 ULONG Size; 02838 BOOL bFound = FALSE; 02839 02840 /* Create buffer for full path name */ 02841 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR); 02842 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF); 02843 if (!NameInfo1) 02844 { 02845 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 02846 return FALSE; 02847 } 02848 02849 /* Get the full path name */ 02850 if (!IntGetFullFileName(NameInfo1, Size, FileName)) 02851 { 02852 ExFreePool(NameInfo1); 02853 return FALSE; 02854 } 02855 02856 /* Create a buffer for the entries' names */ 02857 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF); 02858 if (!NameInfo2) 02859 { 02860 ExFreePool(NameInfo1); 02861 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 02862 return FALSE; 02863 } 02864 02865 /* Try to find the pathname in the global font list */ 02866 IntLockGlobalFonts; 02867 for (ListEntry = FontListHead.Flink; 02868 ListEntry != &FontListHead; 02869 ListEntry = ListEntry->Flink) 02870 { 02871 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry); 02872 if (FontEntry->Font->Filename != NULL) 02873 { 02874 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename); 02875 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName)) 02876 { 02877 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE)) 02878 { 02879 /* Found */ 02880 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font); 02881 bFound = TRUE; 02882 break; 02883 } 02884 } 02885 } 02886 } 02887 IntUnLockGlobalFonts; 02888 02889 /* Free the buffers */ 02890 ExFreePool(NameInfo1); 02891 ExFreePool(NameInfo2); 02892 02893 if (!bFound && dwType != 5) 02894 { 02895 /* Font could not be found in system table 02896 dwType == 5 will still handle this */ 02897 return FALSE; 02898 } 02899 02900 switch (dwType) 02901 { 02902 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */ 02903 *(DWORD*)pBuffer = 1; 02904 *pdwBytes = sizeof(DWORD); 02905 break; 02906 02907 case 1: /* Copy the full font name */ 02908 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1; 02909 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR); 02910 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size); 02911 // FIXME: Do we have to zeroterminate? 02912 *pdwBytes = Size; 02913 break; 02914 02915 case 2: /* Copy a LOGFONTW structure */ 02916 Info.EnumLogFontEx.elfLogFont.lfWidth = 0; 02917 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW)); 02918 *pdwBytes = sizeof(LOGFONTW); 02919 break; 02920 02921 case 3: /* FIXME: What exactly is copied here? */ 02922 *(DWORD*)pBuffer = 1; 02923 *pdwBytes = sizeof(DWORD*); 02924 break; 02925 02926 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */ 02927 *(BOOL*)pBuffer = !bFound; 02928 *pdwBytes = sizeof(BOOL); 02929 break; 02930 02931 default: 02932 return FALSE; 02933 } 02934 02935 return TRUE; 02936 } 02937 02938 02939 BOOL 02940 FASTCALL 02941 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info) 02942 { 02943 if (FT_HAS_FIXED_SIZES(Font->face)) 02944 Info->iTechnology = RI_TECH_BITMAP; 02945 else 02946 { 02947 if (FT_IS_SCALABLE(Font->face)) 02948 Info->iTechnology = RI_TECH_SCALABLE; 02949 else 02950 Info->iTechnology = RI_TECH_FIXED; 02951 } 02952 Info->iUniq = Font->FontObj.iUniq; 02953 Info->dwUnknown = -1; 02954 return TRUE; 02955 } 02956 02957 02958 DWORD 02959 FASTCALL 02960 ftGdiGetKerningPairs( PFONTGDI Font, 02961 DWORD cPairs, 02962 LPKERNINGPAIR pKerningPair) 02963 { 02964 DWORD Count = 0; 02965 INT i = 0; 02966 FT_Face face = Font->face; 02967 02968 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE) 02969 { 02970 FT_UInt previous_index = 0, glyph_index = 0; 02971 FT_ULong char_code, char_previous; 02972 FT_Vector delta; 02973 02974 char_previous = char_code = FT_Get_First_Char(face, &glyph_index); 02975 02976 IntLockFreeType; 02977 02978 while (glyph_index) 02979 { 02980 if (previous_index && glyph_index) 02981 { 02982 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta); 02983 02984 if (pKerningPair && cPairs) 02985 { 02986 pKerningPair[i].wFirst = char_previous; 02987 pKerningPair[i].wSecond = char_code; 02988 pKerningPair[i].iKernAmount = delta.x; 02989 i++; 02990 if (i == cPairs) break; 02991 } 02992 Count++; 02993 } 02994 previous_index = glyph_index; 02995 char_previous = char_code; 02996 char_code = FT_Get_Next_Char(face, char_code, &glyph_index); 02997 } 02998 IntUnLockFreeType; 02999 } 03000 return Count; 03001 } 03002 03003 03005 // 03006 // Functions needing sorting. 03007 // 03009 int APIENTRY 03010 NtGdiGetFontFamilyInfo(HDC Dc, 03011 LPLOGFONTW UnsafeLogFont, 03012 PFONTFAMILYINFO UnsafeInfo, 03013 DWORD Size) 03014 { 03015 NTSTATUS Status; 03016 LOGFONTW LogFont; 03017 PFONTFAMILYINFO Info; 03018 DWORD Count; 03019 PPROCESSINFO Win32Process; 03020 03021 /* Make a safe copy */ 03022 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); 03023 if (! NT_SUCCESS(Status)) 03024 { 03025 EngSetLastError(ERROR_INVALID_PARAMETER); 03026 return -1; 03027 } 03028 03029 /* Allocate space for a safe copy */ 03030 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT); 03031 if (NULL == Info) 03032 { 03033 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 03034 return -1; 03035 } 03036 03037 /* Enumerate font families in the global list */ 03038 IntLockGlobalFonts; 03039 Count = 0; 03040 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) ) 03041 { 03042 IntUnLockGlobalFonts; 03043 ExFreePool(Info); 03044 return -1; 03045 } 03046 IntUnLockGlobalFonts; 03047 03048 /* Enumerate font families in the process local list */ 03049 Win32Process = PsGetCurrentProcessWin32Process(); 03050 IntLockProcessPrivateFonts(Win32Process); 03051 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, 03052 &Win32Process->PrivateFontListHead)) 03053 { 03054 IntUnLockProcessPrivateFonts(Win32Process); 03055 ExFreePool(Info); 03056 return -1; 03057 } 03058 IntUnLockProcessPrivateFonts(Win32Process); 03059 03060 /* Enumerate font families in the registry */ 03061 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size)) 03062 { 03063 ExFreePool(Info); 03064 return -1; 03065 } 03066 03067 /* Return data to caller */ 03068 if (0 != Count) 03069 { 03070 Status = MmCopyToCaller(UnsafeInfo, Info, 03071 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); 03072 if (! NT_SUCCESS(Status)) 03073 { 03074 ExFreePool(Info); 03075 EngSetLastError(ERROR_INVALID_PARAMETER); 03076 return -1; 03077 } 03078 } 03079 03080 ExFreePool(Info); 03081 03082 return Count; 03083 } 03084 03085 BOOL 03086 APIENTRY 03087 GreExtTextOutW( 03088 IN HDC hDC, 03089 IN INT XStart, 03090 IN INT YStart, 03091 IN UINT fuOptions, 03092 IN OPTIONAL PRECTL lprc, 03093 IN LPWSTR String, 03094 IN INT Count, 03095 IN OPTIONAL LPINT Dx, 03096 IN DWORD dwCodePage) 03097 { 03098 /* 03099 * FIXME: 03100 * Call EngTextOut, which does the real work (calling DrvTextOut where 03101 * appropriate) 03102 */ 03103 03104 DC *dc; 03105 PDC_ATTR pdcattr; 03106 SURFOBJ *SurfObj; 03107 SURFACE *psurf = NULL; 03108 int error, glyph_index, n, i; 03109 FT_Face face; 03110 FT_GlyphSlot glyph; 03111 FT_BitmapGlyph realglyph; 03112 LONGLONG TextLeft, RealXStart; 03113 ULONG TextTop, previous, BackgroundLeft; 03114 FT_Bool use_kerning; 03115 RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0}; 03116 POINTL SourcePoint, BrushOrigin; 03117 HBITMAP HSourceGlyph; 03118 SURFOBJ *SourceGlyphSurf; 03119 SIZEL bitSize; 03120 FT_CharMap found = 0, charmap; 03121 INT yoff; 03122 FONTOBJ *FontObj; 03123 PFONTGDI FontGDI; 03124 PTEXTOBJ TextObj = NULL; 03125 EXLATEOBJ exloRGB2Dst, exloDst2RGB; 03126 FT_Render_Mode RenderMode; 03127 BOOLEAN Render; 03128 POINT Start; 03129 BOOL DoBreak = FALSE; 03130 USHORT DxShift; 03131 03132 // TODO: Write test-cases to exactly match real Windows in different 03133 // bad parameters (e.g. does Windows check the DC or the RECT first?). 03134 dc = DC_LockDc(hDC); 03135 if (!dc) 03136 { 03137 EngSetLastError(ERROR_INVALID_HANDLE); 03138 return FALSE; 03139 } 03140 if (dc->dctype == DC_TYPE_INFO) 03141 { 03142 DC_UnlockDc(dc); 03143 /* Yes, Windows really returns TRUE in this case */ 03144 return TRUE; 03145 } 03146 03147 pdcattr = dc->pdcattr; 03148 03149 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE) 03150 { 03151 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND) 03152 DC_vUpdateBackgroundBrush(dc); 03153 } 03154 03155 /* Check if String is valid */ 03156 if ((Count > 0xFFFF) || (Count > 0 && String == NULL)) 03157 { 03158 EngSetLastError(ERROR_INVALID_PARAMETER); 03159 goto fail; 03160 } 03161 03162 DxShift = fuOptions & ETO_PDY ? 1 : 0; 03163 03164 if (PATH_IsPathOpen(dc->dclevel)) 03165 { 03166 if (!PATH_ExtTextOut( dc, 03167 XStart, 03168 YStart, 03169 fuOptions, 03170 (const RECTL *)lprc, 03171 String, 03172 Count, 03173 (const INT *)Dx)) goto fail; 03174 goto good; 03175 } 03176 03177 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED))) 03178 { 03179 IntLPtoDP(dc, (POINT *)lprc, 2); 03180 } 03181 03182 Start.x = XStart; 03183 Start.y = YStart; 03184 IntLPtoDP(dc, &Start, 1); 03185 03186 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6; 03187 YStart = Start.y + dc->ptlDCOrig.y; 03188 03189 SourcePoint.x = 0; 03190 SourcePoint.y = 0; 03191 MaskRect.left = 0; 03192 MaskRect.top = 0; 03193 BrushOrigin.x = 0; 03194 BrushOrigin.y = 0; 03195 03196 if ((fuOptions & ETO_OPAQUE) && lprc) 03197 { 03198 DestRect.left = lprc->left; 03199 DestRect.top = lprc->top; 03200 DestRect.right = lprc->right; 03201 DestRect.bottom = lprc->bottom; 03202 03203 DestRect.left += dc->ptlDCOrig.x; 03204 DestRect.top += dc->ptlDCOrig.y; 03205 DestRect.right += dc->ptlDCOrig.x; 03206 DestRect.bottom += dc->ptlDCOrig.y; 03207 03208 DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect); 03209 03210 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND) 03211 DC_vUpdateBackgroundBrush(dc); 03212 03213 IntEngBitBlt( 03214 &dc->dclevel.pSurface->SurfObj, 03215 NULL, 03216 NULL, 03217 dc->rosdc.CombinedClip, 03218 NULL, 03219 &DestRect, 03220 &SourcePoint, 03221 &SourcePoint, 03222 &dc->eboBackground.BrushObject, 03223 &BrushOrigin, 03224 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 03225 fuOptions &= ~ETO_OPAQUE; 03226 DC_vFinishBlit(dc, NULL); 03227 } 03228 else 03229 { 03230 if (pdcattr->jBkMode == OPAQUE) 03231 { 03232 fuOptions |= ETO_OPAQUE; 03233 } 03234 } 03235 03236 TextObj = RealizeFontInit(pdcattr->hlfntNew); 03237 if (TextObj == NULL) 03238 { 03239 goto fail; 03240 } 03241 03242 FontObj = TextObj->Font; 03243 ASSERT(FontObj); 03244 FontGDI = ObjToGDI(FontObj, FONT); 03245 ASSERT(FontGDI); 03246 03247 IntLockFreeType; 03248 face = FontGDI->face; 03249 if (face->charmap == NULL) 03250 { 03251 DPRINT("WARNING: No charmap selected!\n"); 03252 DPRINT("This font face has %d charmaps\n", face->num_charmaps); 03253 03254 for (n = 0; n < face->num_charmaps; n++) 03255 { 03256 charmap = face->charmaps[n]; 03257 DPRINT("Found charmap encoding: %u\n", charmap->encoding); 03258 if (charmap->encoding != 0) 03259 { 03260 found = charmap; 03261 break; 03262 } 03263 } 03264 if (!found) 03265 { 03266 DPRINT1("WARNING: Could not find desired charmap!\n"); 03267 } 03268 error = FT_Set_Charmap(face, found); 03269 if (error) 03270 { 03271 DPRINT1("WARNING: Could not set the charmap!\n"); 03272 } 03273 } 03274 03275 Render = IntIsFontRenderingEnabled(); 03276 if (Render) 03277 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont); 03278 else 03279 RenderMode = FT_RENDER_MODE_MONO; 03280 03281 error = FT_Set_Pixel_Sizes( 03282 face, 03283 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 03284 /* FIXME: Should set character height if neg */ 03285 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 03286 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 03287 if (error) 03288 { 03289 DPRINT1("Error in setting pixel sizes: %u\n", error); 03290 IntUnLockFreeType; 03291 goto fail; 03292 } 03293 03294 /* 03295 * Process the vertical alignment and determine the yoff. 03296 */ 03297 03298 if (pdcattr->lTextAlign & TA_BASELINE) 03299 yoff = 0; 03300 else if (pdcattr->lTextAlign & TA_BOTTOM) 03301 yoff = -face->size->metrics.descender >> 6; 03302 else /* TA_TOP */ 03303 yoff = face->size->metrics.ascender >> 6; 03304 03305 use_kerning = FT_HAS_KERNING(face); 03306 previous = 0; 03307 03308 /* 03309 * Process the horizontal alignment and modify XStart accordingly. 03310 */ 03311 03312 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER)) 03313 { 03314 ULONGLONG TextWidth = 0; 03315 LPCWSTR TempText = String; 03316 int Start; 03317 03318 /* 03319 * Calculate width of the text. 03320 */ 03321 03322 if (NULL != Dx) 03323 { 03324 Start = Count < 2 ? 0 : Count - 2; 03325 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6); 03326 } 03327 else 03328 { 03329 Start = 0; 03330 } 03331 TempText = String + Start; 03332 03333 for (i = Start; i < Count; i++) 03334 { 03335 if (fuOptions & ETO_GLYPH_INDEX) 03336 glyph_index = *TempText; 03337 else 03338 glyph_index = FT_Get_Char_Index(face, *TempText); 03339 03340 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, 03341 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) 03342 { 03343 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 03344 if (error) 03345 { 03346 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index); 03347 } 03348 03349 glyph = face->glyph; 03350 realglyph = ftGdiGlyphCacheSet(face, glyph_index, 03351 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode); 03352 if (!realglyph) 03353 { 03354 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index); 03355 IntUnLockFreeType; 03356 goto fail; 03357 } 03358 03359 } 03360 /* Retrieve kerning distance */ 03361 if (use_kerning && previous && glyph_index) 03362 { 03363 FT_Vector delta; 03364 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 03365 TextWidth += delta.x; 03366 } 03367 03368 TextWidth += realglyph->root.advance.x >> 10; 03369 03370 previous = glyph_index; 03371 TempText++; 03372 } 03373 03374 previous = 0; 03375 03376 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER) 03377 { 03378 RealXStart -= TextWidth / 2; 03379 } 03380 else 03381 { 03382 RealXStart -= TextWidth; 03383 } 03384 } 03385 03386 TextLeft = RealXStart; 03387 TextTop = YStart; 03388 BackgroundLeft = (RealXStart + 32) >> 6; 03389 03390 /* Lock blit with a dummy rect */ 03391 DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect); 03392 03393 psurf = dc->dclevel.pSurface ; 03394 SurfObj = &psurf->SurfObj ; 03395 03396 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0); 03397 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0); 03398 03399 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND)) 03400 DC_vUpdateBackgroundBrush(dc) ; 03401 03402 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT) 03403 DC_vUpdateTextBrush(dc) ; 03404 03405 /* 03406 * The main rendering loop. 03407 */ 03408 for (i = 0; i < Count; i++) 03409 { 03410 if (fuOptions & ETO_GLYPH_INDEX) 03411 glyph_index = *String; 03412 else 03413 glyph_index = FT_Get_Char_Index(face, *String); 03414 03415 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, 03416 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) 03417 { 03418 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 03419 if (error) 03420 { 03421 DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index); 03422 IntUnLockFreeType; 03423 goto fail2; 03424 } 03425 glyph = face->glyph; 03426 realglyph = ftGdiGlyphCacheSet(face, 03427 glyph_index, 03428 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, 03429 glyph, 03430 RenderMode); 03431 if (!realglyph) 03432 { 03433 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index); 03434 IntUnLockFreeType; 03435 goto fail2; 03436 } 03437 } 03438 03439 /* retrieve kerning distance and move pen position */ 03440 if (use_kerning && previous && glyph_index && NULL == Dx) 03441 { 03442 FT_Vector delta; 03443 FT_Get_Kerning(face, previous, glyph_index, 0, &delta); 03444 TextLeft += delta.x; 03445 } 03446 DPRINT("TextLeft: %d\n", TextLeft); 03447 DPRINT("TextTop: %d\n", TextTop); 03448 DPRINT("Advance: %d\n", realglyph->root.advance.x); 03449 03450 if (fuOptions & ETO_OPAQUE) 03451 { 03452 DestRect.left = BackgroundLeft; 03453 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; 03454 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6); 03455 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6); 03456 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 03457 IntEngBitBlt( 03458 &psurf->SurfObj, 03459 NULL, 03460 NULL, 03461 dc->rosdc.CombinedClip, 03462 NULL, 03463 &DestRect, 03464 &SourcePoint, 03465 &SourcePoint, 03466 &dc->eboBackground.BrushObject, 03467 &BrushOrigin, 03468 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 03469 MouseSafetyOnDrawEnd(dc->ppdev); 03470 BackgroundLeft = DestRect.right; 03471 03472 } 03473 03474 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left; 03475 DestRect.right = DestRect.left + realglyph->bitmap.width; 03476 DestRect.top = TextTop + yoff - realglyph->top; 03477 DestRect.bottom = DestRect.top + realglyph->bitmap.rows; 03478 03479 bitSize.cx = realglyph->bitmap.width; 03480 bitSize.cy = realglyph->bitmap.rows; 03481 MaskRect.right = realglyph->bitmap.width; 03482 MaskRect.bottom = realglyph->bitmap.rows; 03483 03484 /* 03485 * We should create the bitmap out of the loop at the biggest possible 03486 * glyph size. Then use memset with 0 to clear it and sourcerect to 03487 * limit the work of the transbitblt. 03488 */ 03489 03490 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch, 03491 BMF_8BPP, BMF_TOPDOWN, 03492 realglyph->bitmap.buffer); 03493 if ( !HSourceGlyph ) 03494 { 03495 DPRINT1("WARNING: EngLockSurface() failed!\n"); 03496 // FT_Done_Glyph(realglyph); 03497 IntUnLockFreeType; 03498 goto fail2; 03499 } 03500 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph); 03501 if ( !SourceGlyphSurf ) 03502 { 03503 EngDeleteSurface((HSURF)HSourceGlyph); 03504 DPRINT1("WARNING: EngLockSurface() failed!\n"); 03505 IntUnLockFreeType; 03506 goto fail2; 03507 } 03508 03509 /* 03510 * Use the font data as a mask to paint onto the DCs surface using a 03511 * brush. 03512 */ 03513 03514 if (lprc && (fuOptions & ETO_CLIPPED) && 03515 DestRect.right >= lprc->right + dc->ptlDCOrig.x) 03516 { 03517 // We do the check '>=' instead of '>' to possibly save an iteration 03518 // through this loop, since it's breaking after the drawing is done, 03519 // and x is always incremented. 03520 DestRect.right = lprc->right + dc->ptlDCOrig.x; 03521 DoBreak = TRUE; 03522 } 03523 if (lprc && (fuOptions & ETO_CLIPPED) && 03524 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y) 03525 { 03526 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y; 03527 } 03528 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); 03529 IntEngMaskBlt( 03530 SurfObj, 03531 SourceGlyphSurf, 03532 dc->rosdc.CombinedClip, 03533 &exloRGB2Dst.xlo, 03534 &exloDst2RGB.xlo, 03535 &DestRect, 03536 (PPOINTL)&MaskRect, 03537 &dc->eboText.BrushObject, 03538 &BrushOrigin); 03539 MouseSafetyOnDrawEnd(dc->ppdev) ; 03540 03541 EngUnlockSurface(SourceGlyphSurf); 03542 EngDeleteSurface((HSURF)HSourceGlyph); 03543 03544 if (DoBreak) 03545 { 03546 break; 03547 } 03548 03549 if (NULL == Dx) 03550 { 03551 TextLeft += realglyph->root.advance.x >> 10; 03552 DPRINT("New TextLeft: %d\n", TextLeft); 03553 } 03554 else 03555 { 03556 TextLeft += Dx[i<<DxShift] << 6; 03557 DPRINT("New TextLeft2: %d\n", TextLeft); 03558 } 03559 03560 if (DxShift) 03561 { 03562 TextTop -= Dx[2 * i + 1] << 6; 03563 } 03564 03565 previous = glyph_index; 03566 03567 String++; 03568 } 03569 IntUnLockFreeType; 03570 03571 DC_vFinishBlit(dc, NULL) ; 03572 EXLATEOBJ_vCleanup(&exloRGB2Dst); 03573 EXLATEOBJ_vCleanup(&exloDst2RGB); 03574 if (TextObj != NULL) 03575 TEXTOBJ_UnlockText(TextObj); 03576 good: 03577 DC_UnlockDc( dc ); 03578 03579 return TRUE; 03580 03581 fail2: 03582 EXLATEOBJ_vCleanup(&exloRGB2Dst); 03583 EXLATEOBJ_vCleanup(&exloDst2RGB); 03584 fail: 03585 if (TextObj != NULL) 03586 TEXTOBJ_UnlockText(TextObj); 03587 03588 DC_UnlockDc(dc); 03589 03590 return FALSE; 03591 } 03592 03593 #define STACK_TEXT_BUFFER_SIZE 100 03594 BOOL 03595 APIENTRY 03596 NtGdiExtTextOutW( 03597 IN HDC hDC, 03598 IN INT XStart, 03599 IN INT YStart, 03600 IN UINT fuOptions, 03601 IN OPTIONAL LPRECT UnsafeRect, 03602 IN LPWSTR UnsafeString, 03603 IN INT Count, 03604 IN OPTIONAL LPINT UnsafeDx, 03605 IN DWORD dwCodePage) 03606 { 03607 BOOL Result = FALSE; 03608 NTSTATUS Status = STATUS_SUCCESS; 03609 RECTL SafeRect; 03610 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE]; 03611 PVOID Buffer = LocalBuffer; 03612 LPWSTR SafeString = NULL; 03613 LPINT SafeDx = NULL; 03614 ULONG BufSize, StringSize, DxSize = 0; 03615 03616 /* Check if String is valid */ 03617 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL)) 03618 { 03619 EngSetLastError(ERROR_INVALID_PARAMETER); 03620 return FALSE; 03621 } 03622 03623 if (Count > 0) 03624 { 03625 /* Calculate buffer size for string and Dx values */ 03626 BufSize = StringSize = Count * sizeof(WCHAR); 03627 if (UnsafeDx) 03628 { 03629 /* If ETO_PDY is specified, we have pairs of INTs */ 03630 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1); 03631 BufSize += DxSize; 03632 } 03633 03634 /* Check if our local buffer is large enough */ 03635 if (BufSize > STACK_TEXT_BUFFER_SIZE) 03636 { 03637 /* It's not, allocate a temp buffer */ 03638 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT); 03639 if (!Buffer) 03640 { 03641 return FALSE; 03642 } 03643 } 03644 03645 /* Probe and copy user mode data to the buffer */ 03646 _SEH2_TRY 03647 { 03648 /* Put the Dx before the String to assure alignment of 4 */ 03649 SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize); 03650 03651 /* Probe and copy the string */ 03652 ProbeForRead(UnsafeString, StringSize, 1); 03653 memcpy((PVOID)SafeString, UnsafeString, StringSize); 03654 03655 /* If we have Dx values... */ 03656 if (UnsafeDx) 03657 { 03658 /* ... probe and copy them */ 03659 SafeDx = Buffer; 03660 ProbeForRead(UnsafeDx, DxSize, 1); 03661 memcpy(SafeDx, UnsafeDx, DxSize); 03662 } 03663 } 03664 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 03665 { 03666 Status = _SEH2_GetExceptionCode(); 03667 } 03668 _SEH2_END 03669 if (!NT_SUCCESS(Status)) 03670 { 03671 goto cleanup; 03672 } 03673 } 03674 03675 /* If we have a rect, copy it */ 03676 if (UnsafeRect) 03677 { 03678 _SEH2_TRY 03679 { 03680 ProbeForRead(UnsafeRect, sizeof(RECT), 1); 03681 SafeRect = *UnsafeRect; 03682 } 03683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 03684 { 03685 Status = _SEH2_GetExceptionCode(); 03686 } 03687 _SEH2_END 03688 if (!NT_SUCCESS(Status)) 03689 { 03690 goto cleanup; 03691 } 03692 } 03693 03694 /* Finally call the internal routine */ 03695 Result = GreExtTextOutW(hDC, 03696 XStart, 03697 YStart, 03698 fuOptions, 03699 &SafeRect, 03700 SafeString, 03701 Count, 03702 SafeDx, 03703 dwCodePage); 03704 03705 cleanup: 03706 /* If we allocated a buffer, free it */ 03707 if (Buffer != LocalBuffer) 03708 { 03709 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 03710 } 03711 03712 return Result; 03713 } 03714 03715 03716 /* 03717 * @implemented 03718 */ 03719 BOOL 03720 APIENTRY 03721 NtGdiGetCharABCWidthsW( 03722 IN HDC hDC, 03723 IN UINT FirstChar, 03724 IN ULONG Count, 03725 IN OPTIONAL PWCHAR pwch, 03726 IN FLONG fl, 03727 OUT PVOID Buffer) 03728 { 03729 LPABC SafeBuff; 03730 LPABCFLOAT SafeBuffF = NULL; 03731 PDC dc; 03732 PDC_ATTR pdcattr; 03733 PTEXTOBJ TextObj; 03734 PFONTGDI FontGDI; 03735 FT_Face face; 03736 FT_CharMap charmap, found = NULL; 03737 UINT i, glyph_index, BufferSize; 03738 HFONT hFont = 0; 03739 NTSTATUS Status = STATUS_SUCCESS; 03740 03741 if (pwch) 03742 { 03743 _SEH2_TRY 03744 { 03745 ProbeForRead(pwch, 03746 sizeof(PWSTR), 03747 1); 03748 } 03749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 03750 { 03751 Status = _SEH2_GetExceptionCode(); 03752 } 03753 _SEH2_END; 03754 } 03755 if (!NT_SUCCESS(Status)) 03756 { 03757 EngSetLastError(Status); 03758 return FALSE; 03759 } 03760 03761 if (!Buffer) 03762 { 03763 EngSetLastError(ERROR_INVALID_PARAMETER); 03764 return FALSE; 03765 } 03766 03767 BufferSize = Count * sizeof(ABC); // Same size! 03768 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 03769 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff; 03770 if (SafeBuff == NULL) 03771 { 03772 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 03773 return FALSE; 03774 } 03775 03776 dc = DC_LockDc(hDC); 03777 if (dc == NULL) 03778 { 03779 ExFreePool(SafeBuff); 03780 EngSetLastError(ERROR_INVALID_HANDLE); 03781 return FALSE; 03782 } 03783 pdcattr = dc->pdcattr; 03784 hFont = pdcattr->hlfntNew; 03785 TextObj = RealizeFontInit(hFont); 03786 DC_UnlockDc(dc); 03787 03788 if (TextObj == NULL) 03789 { 03790 ExFreePool(SafeBuff); 03791 EngSetLastError(ERROR_INVALID_HANDLE); 03792 return FALSE; 03793 } 03794 03795 FontGDI = ObjToGDI(TextObj->Font, FONT); 03796 03797 face = FontGDI->face; 03798 if (face->charmap == NULL) 03799 { 03800 for (i = 0; i < face->num_charmaps; i++) 03801 { 03802 charmap = face->charmaps[i]; 03803 if (charmap->encoding != 0) 03804 { 03805 found = charmap; 03806 break; 03807 } 03808 } 03809 03810 if (!found) 03811 { 03812 DPRINT1("WARNING: Could not find desired charmap!\n"); 03813 ExFreePool(SafeBuff); 03814 EngSetLastError(ERROR_INVALID_HANDLE); 03815 return FALSE; 03816 } 03817 03818 IntLockFreeType; 03819 FT_Set_Charmap(face, found); 03820 IntUnLockFreeType; 03821 } 03822 03823 IntLockFreeType; 03824 FT_Set_Pixel_Sizes(face, 03825 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 03826 /* FIXME: Should set character height if neg */ 03827 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 03828 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 03829 03830 for (i = FirstChar; i < FirstChar+Count; i++) 03831 { 03832 int adv, lsb, bbx, left, right; 03833 03834 if (pwch) 03835 { 03836 if (fl & GCABCW_INDICES) 03837 glyph_index = pwch[i - FirstChar]; 03838 else 03839 glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]); 03840 } 03841 else 03842 { 03843 if (fl & GCABCW_INDICES) 03844 glyph_index = i; 03845 else 03846 glyph_index = FT_Get_Char_Index(face, i); 03847 } 03848 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 03849 03850 left = (INT)face->glyph->metrics.horiBearingX & -64; 03851 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64; 03852 adv = (face->glyph->advance.x + 32) >> 6; 03853 03854 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6; 03855 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */ 03856 03857 lsb = left >> 6; 03858 bbx = (right - left) >> 6; 03859 /* 03860 DPRINT1("lsb %d and bbx %d\n", lsb, bbx ); 03861 */ 03862 if (!fl) 03863 { 03864 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb; 03865 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx; 03866 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx); 03867 } 03868 else 03869 { 03870 SafeBuff[i - FirstChar].abcA = lsb; 03871 SafeBuff[i - FirstChar].abcB = bbx; 03872 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx; 03873 } 03874 } 03875 IntUnLockFreeType; 03876 TEXTOBJ_UnlockText(TextObj); 03877 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize); 03878 if (! NT_SUCCESS(Status)) 03879 { 03880 SetLastNtError(Status); 03881 ExFreePool(SafeBuff); 03882 return FALSE; 03883 } 03884 ExFreePool(SafeBuff); 03885 DPRINT("NtGdiGetCharABCWidths Worked!\n"); 03886 return TRUE; 03887 } 03888 03889 /* 03890 * @implemented 03891 */ 03892 BOOL 03893 APIENTRY 03894 NtGdiGetCharWidthW( 03895 IN HDC hDC, 03896 IN UINT FirstChar, 03897 IN UINT Count, 03898 IN OPTIONAL PWCHAR pwc, 03899 IN FLONG fl, 03900 OUT PVOID Buffer) 03901 { 03902 NTSTATUS Status = STATUS_SUCCESS; 03903 LPINT SafeBuff; 03904 PFLOAT SafeBuffF = NULL; 03905 PDC dc; 03906 PDC_ATTR pdcattr; 03907 PTEXTOBJ TextObj; 03908 PFONTGDI FontGDI; 03909 FT_Face face; 03910 FT_CharMap charmap, found = NULL; 03911 UINT i, glyph_index, BufferSize; 03912 HFONT hFont = 0; 03913 03914 if (pwc) 03915 { 03916 _SEH2_TRY 03917 { 03918 ProbeForRead(pwc, 03919 sizeof(PWSTR), 03920 1); 03921 } 03922 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 03923 { 03924 Status = _SEH2_GetExceptionCode(); 03925 } 03926 _SEH2_END; 03927 } 03928 if (!NT_SUCCESS(Status)) 03929 { 03930 EngSetLastError(Status); 03931 return FALSE; 03932 } 03933 03934 BufferSize = Count * sizeof(INT); // Same size! 03935 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); 03936 if (!fl) SafeBuffF = (PFLOAT) SafeBuff; 03937 if (SafeBuff == NULL) 03938 { 03939 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 03940 return FALSE; 03941 } 03942 03943 dc = DC_LockDc(hDC); 03944 if (dc == NULL) 03945 { 03946 ExFreePool(SafeBuff); 03947 EngSetLastError(ERROR_INVALID_HANDLE); 03948 return FALSE; 03949 } 03950 pdcattr = dc->pdcattr; 03951 hFont = pdcattr->hlfntNew; 03952 TextObj = RealizeFontInit(hFont); 03953 DC_UnlockDc(dc); 03954 03955 if (TextObj == NULL) 03956 { 03957 ExFreePool(SafeBuff); 03958 EngSetLastError(ERROR_INVALID_HANDLE); 03959 return FALSE; 03960 } 03961 03962 FontGDI = ObjToGDI(TextObj->Font, FONT); 03963 03964 face = FontGDI->face; 03965 if (face->charmap == NULL) 03966 { 03967 for (i = 0; i < face->num_charmaps; i++) 03968 { 03969 charmap = face->charmaps[i]; 03970 if (charmap->encoding != 0) 03971 { 03972 found = charmap; 03973 break; 03974 } 03975 } 03976 03977 if (!found) 03978 { 03979 DPRINT1("WARNING: Could not find desired charmap!\n"); 03980 ExFreePool(SafeBuff); 03981 EngSetLastError(ERROR_INVALID_HANDLE); 03982 return FALSE; 03983 } 03984 03985 IntLockFreeType; 03986 FT_Set_Charmap(face, found); 03987 IntUnLockFreeType; 03988 } 03989 03990 IntLockFreeType; 03991 FT_Set_Pixel_Sizes(face, 03992 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth, 03993 /* FIXME: Should set character height if neg */ 03994 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 03995 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); 03996 03997 for (i = FirstChar; i < FirstChar+Count; i++) 03998 { 03999 if (pwc) 04000 { 04001 if (fl & GCW_INDICES) 04002 glyph_index = pwc[i - FirstChar]; 04003 else 04004 glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]); 04005 } 04006 else 04007 { 04008 if (fl & GCW_INDICES) 04009 glyph_index = i; 04010 else 04011 glyph_index = FT_Get_Char_Index(face, i); 04012 } 04013 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); 04014 if (!fl) 04015 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6); 04016 else 04017 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6; 04018 } 04019 IntUnLockFreeType; 04020 TEXTOBJ_UnlockText(TextObj); 04021 MmCopyToCaller(Buffer, SafeBuff, BufferSize); 04022 ExFreePool(SafeBuff); 04023 return TRUE; 04024 } 04025 04026 DWORD 04027 FASTCALL 04028 GreGetGlyphIndicesW( 04029 HDC hdc, 04030 LPWSTR pwc, 04031 INT cwc, 04032 LPWORD pgi, 04033 DWORD iMode, 04034 DWORD Unknown) 04035 { 04036 PDC dc; 04037 PDC_ATTR pdcattr; 04038 PTEXTOBJ TextObj; 04039 PFONTGDI FontGDI; 04040 HFONT hFont = 0; 04041 OUTLINETEXTMETRICW *potm; 04042 INT i; 04043 FT_Face face; 04044 WCHAR DefChar = 0xffff; 04045 PWSTR Buffer = NULL; 04046 ULONG Size; 04047 04048 if ((!pwc) && (!pgi)) return cwc; 04049 04050 dc = DC_LockDc(hdc); 04051 if (!dc) 04052 { 04053 EngSetLastError(ERROR_INVALID_HANDLE); 04054 return GDI_ERROR; 04055 } 04056 pdcattr = dc->pdcattr; 04057 hFont = pdcattr->hlfntNew; 04058 TextObj = RealizeFontInit(hFont); 04059 DC_UnlockDc(dc); 04060 if (!TextObj) 04061 { 04062 EngSetLastError(ERROR_INVALID_HANDLE); 04063 return GDI_ERROR; 04064 } 04065 04066 FontGDI = ObjToGDI(TextObj->Font, FONT); 04067 TEXTOBJ_UnlockText(TextObj); 04068 04069 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT); 04070 if (!Buffer) 04071 { 04072 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 04073 return GDI_ERROR; 04074 } 04075 04076 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */ 04077 else 04078 { 04079 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 04080 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 04081 if (!potm) 04082 { 04083 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 04084 cwc = GDI_ERROR; 04085 goto ErrorRet; 04086 } 04087 IntGetOutlineTextMetrics(FontGDI, Size, potm); 04088 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this. 04089 ExFreePool(potm); 04090 } 04091 04092 IntLockFreeType; 04093 face = FontGDI->face; 04094 04095 for (i = 0; i < cwc; i++) 04096 { 04097 Buffer[i] = FT_Get_Char_Index(face, pwc[i]); 04098 if (Buffer[i] == 0) 04099 { 04100 if (DefChar == 0xffff && FT_IS_SFNT(face)) 04101 { 04102 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 04103 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0); 04104 } 04105 Buffer[i] = DefChar; 04106 } 04107 } 04108 04109 IntUnLockFreeType; 04110 04111 RtlCopyMemory( pgi, Buffer, cwc*sizeof(WORD)); 04112 04113 ErrorRet: 04114 if (Buffer) ExFreePoolWithTag(Buffer, GDITAG_TEXT); 04115 return cwc; 04116 } 04117 04118 04119 /* 04120 * @implemented 04121 */ 04122 DWORD 04123 APIENTRY 04124 NtGdiGetGlyphIndicesW( 04125 IN HDC hdc, 04126 IN OPTIONAL LPWSTR UnSafepwc, 04127 IN INT cwc, 04128 OUT OPTIONAL LPWORD UnSafepgi, 04129 IN DWORD iMode) 04130 { 04131 PDC dc; 04132 PDC_ATTR pdcattr; 04133 PTEXTOBJ TextObj; 04134 PFONTGDI FontGDI; 04135 HFONT hFont = 0; 04136 NTSTATUS Status = STATUS_SUCCESS; 04137 OUTLINETEXTMETRICW *potm; 04138 INT i; 04139 FT_Face face; 04140 WCHAR DefChar = 0xffff; 04141 PWSTR Buffer = NULL; 04142 ULONG Size; 04143 04144 if ((!UnSafepwc) && (!UnSafepgi)) return cwc; 04145 04146 dc = DC_LockDc(hdc); 04147 if (!dc) 04148 { 04149 EngSetLastError(ERROR_INVALID_HANDLE); 04150 return GDI_ERROR; 04151 } 04152 pdcattr = dc->pdcattr; 04153 hFont = pdcattr->hlfntNew; 04154 TextObj = RealizeFontInit(hFont); 04155 DC_UnlockDc(dc); 04156 if (!TextObj) 04157 { 04158 EngSetLastError(ERROR_INVALID_HANDLE); 04159 return GDI_ERROR; 04160 } 04161 04162 FontGDI = ObjToGDI(TextObj->Font, FONT); 04163 TEXTOBJ_UnlockText(TextObj); 04164 04165 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT); 04166 if (!Buffer) 04167 { 04168 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 04169 return GDI_ERROR; 04170 } 04171 04172 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */ 04173 else 04174 { 04175 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); 04176 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT); 04177 if (!potm) 04178 { 04179 Status = ERROR_NOT_ENOUGH_MEMORY; 04180 goto ErrorRet; 04181 } 04182 IntGetOutlineTextMetrics(FontGDI, Size, potm); 04183 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this. 04184 ExFreePool(potm); 04185 } 04186 04187 _SEH2_TRY 04188 { 04189 ProbeForRead(UnSafepwc, 04190 sizeof(PWSTR), 04191 1); 04192 } 04193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 04194 { 04195 Status = _SEH2_GetExceptionCode(); 04196 } 04197 _SEH2_END; 04198 04199 if (!NT_SUCCESS(Status)) goto ErrorRet; 04200 04201 IntLockFreeType; 04202 face = FontGDI->face; 04203 04204 if (DefChar == 0xffff && FT_IS_SFNT(face)) 04205 { 04206 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 04207 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0); 04208 } 04209 04210 for (i = 0; i < cwc; i++) 04211 { 04212 Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]); // FIXME: Unsafe! 04213 if (Buffer[i] == 0) 04214 { 04215 Buffer[i] = DefChar; 04216 } 04217 } 04218 04219 IntUnLockFreeType; 04220 04221 _SEH2_TRY 04222 { 04223 ProbeForWrite(UnSafepgi, 04224 sizeof(WORD), 04225 1); 04226 RtlCopyMemory(UnSafepgi, 04227 Buffer, 04228 cwc*sizeof(WORD)); 04229 } 04230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 04231 { 04232 Status = _SEH2_GetExceptionCode(); 04233 } 04234 _SEH2_END; 04235 04236 ErrorRet: 04237 ExFreePoolWithTag(Buffer, GDITAG_TEXT); 04238 if (NT_SUCCESS(Status)) return cwc; 04239 EngSetLastError(Status); 04240 return GDI_ERROR; 04241 } 04242 04243 /* EOF */ Generated on Sat May 26 2012 04:37:14 for ReactOS by
1.7.6.1
|