ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

freetype.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.