[LT2013]
[reactos.git] / win32ss / gdi / ntgdi / freetype.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMER: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8 */
9
10 /** Includes ******************************************************************/
11
12 #include <win32k.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #ifndef FT_MAKE_TAG
18 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
19 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
20 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
21 #endif
22
23 FT_Library library;
24
25 typedef struct _FONT_ENTRY
26 {
27 LIST_ENTRY ListEntry;
28 FONTGDI *Font;
29 UNICODE_STRING FaceName;
30 BYTE NotEnum;
31 } FONT_ENTRY, *PFONT_ENTRY;
32
33 /* The FreeType library is not thread safe, so we have
34 to serialize access to it */
35 static PFAST_MUTEX FreeTypeLock;
36
37 static LIST_ENTRY FontListHead;
38 static PFAST_MUTEX FontListLock;
39 static BOOL RenderingEnabled = TRUE;
40
41 #define IntLockGlobalFonts \
42 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
43
44 #define IntUnLockGlobalFonts \
45 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
46
47 #define IntLockFreeType \
48 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
49
50 #define IntUnLockFreeType \
51 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
52
53 #define MAX_FONT_CACHE 256
54
55 typedef struct _FONT_CACHE_ENTRY
56 {
57 LIST_ENTRY ListEntry;
58 int GlyphIndex;
59 FT_Face Face;
60 FT_BitmapGlyph BitmapGlyph;
61 int Height;
62 MATRIX mxWorldToDevice;
63 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
64 static LIST_ENTRY FontCacheListHead;
65 static UINT FontCacheNumEntries;
66
67 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
68 {
69 L"Western", /* 00 */
70 L"Central_European",
71 L"Cyrillic",
72 L"Greek",
73 L"Turkish",
74 L"Hebrew",
75 L"Arabic",
76 L"Baltic",
77 L"Vietnamese", /* 08 */
78 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
79 L"Thai",
80 L"Japanese",
81 L"CHINESE_GB2312",
82 L"Hangul",
83 L"CHINESE_BIG5",
84 L"Hangul(Johab)",
85 NULL, NULL, /* 23 */
86 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
87 L"Symbol" /* 31 */
88 };
89
90 /*
91 * For TranslateCharsetInfo
92 */
93 #define CP_SYMBOL 42
94 #define MAXTCIINDEX 32
95 static const CHARSETINFO FontTci[MAXTCIINDEX] =
96 {
97 /* ANSI */
98 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
99 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
100 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
101 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
102 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
103 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
104 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
105 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
106 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
107 /* reserved by ANSI */
108 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
109 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
110 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
111 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
112 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
113 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
114 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
115 /* ANSI and OEM */
116 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
117 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
118 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
119 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
120 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
121 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
122 /* Reserved for alternate ANSI and OEM */
123 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
124 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
125 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
126 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
127 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
128 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
129 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
130 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
131 /* Reserved for system */
132 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
133 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
134 };
135
136 BOOL FASTCALL
137 InitFontSupport(VOID)
138 {
139 ULONG ulError;
140
141 InitializeListHead(&FontListHead);
142 InitializeListHead(&FontCacheListHead);
143 FontCacheNumEntries = 0;
144 /* Fast Mutexes must be allocated from non paged pool */
145 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
146 ExInitializeFastMutex(FontListLock);
147 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
148 ExInitializeFastMutex(FreeTypeLock);
149
150 ulError = FT_Init_FreeType(&library);
151 if (ulError)
152 {
153 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
154 return FALSE;
155 }
156
157 IntLoadSystemFonts();
158
159 return TRUE;
160 }
161
162 VOID
163 FtSetCoordinateTransform(
164 FT_Face face,
165 PMATRIX pmx)
166 {
167 FT_Matrix ftmatrix;
168 FLOATOBJ efTemp;
169
170 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
171 efTemp = pmx->efM11;
172 FLOATOBJ_MulLong(&efTemp, 0x00010000);
173 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
174
175 efTemp = pmx->efM12;
176 FLOATOBJ_MulLong(&efTemp, 0x00010000);
177 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
178
179 efTemp = pmx->efM21;
180 FLOATOBJ_MulLong(&efTemp, 0x00010000);
181 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
182
183 efTemp = pmx->efM22;
184 FLOATOBJ_MulLong(&efTemp, 0x00010000);
185 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
186
187 /* Set the transformation matrix */
188 FT_Set_Transform(face, &ftmatrix, 0);
189 }
190
191 /*
192 * IntLoadSystemFonts
193 *
194 * Search the system font directory and adds each font found.
195 */
196
197 VOID FASTCALL
198 IntLoadSystemFonts(VOID)
199 {
200 OBJECT_ATTRIBUTES ObjectAttributes;
201 UNICODE_STRING Directory, SearchPattern, FileName, TempString;
202 IO_STATUS_BLOCK Iosb;
203 HANDLE hDirectory;
204 BYTE *DirInfoBuffer;
205 PFILE_DIRECTORY_INFORMATION DirInfo;
206 BOOLEAN bRestartScan = TRUE;
207 NTSTATUS Status;
208
209 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
210 /* FIXME: Add support for other font types */
211 RtlInitUnicodeString(&SearchPattern, L"*.ttf");
212
213 InitializeObjectAttributes(
214 &ObjectAttributes,
215 &Directory,
216 OBJ_CASE_INSENSITIVE,
217 NULL,
218 NULL);
219
220 Status = ZwOpenFile(
221 &hDirectory,
222 SYNCHRONIZE | FILE_LIST_DIRECTORY,
223 &ObjectAttributes,
224 &Iosb,
225 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
226 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
227
228 if (NT_SUCCESS(Status))
229 {
230 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
231 if (DirInfoBuffer == NULL)
232 {
233 ZwClose(hDirectory);
234 return;
235 }
236
237 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
238 if (FileName.Buffer == NULL)
239 {
240 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
241 ZwClose(hDirectory);
242 return;
243 }
244 FileName.Length = 0;
245 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
246
247 while (1)
248 {
249 Status = ZwQueryDirectoryFile(
250 hDirectory,
251 NULL,
252 NULL,
253 NULL,
254 &Iosb,
255 DirInfoBuffer,
256 0x4000,
257 FileDirectoryInformation,
258 FALSE,
259 &SearchPattern,
260 bRestartScan);
261
262 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
263 {
264 break;
265 }
266
267 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
268 while (1)
269 {
270 TempString.Buffer = DirInfo->FileName;
271 TempString.Length =
272 TempString.MaximumLength = DirInfo->FileNameLength;
273 RtlCopyUnicodeString(&FileName, &Directory);
274 RtlAppendUnicodeStringToString(&FileName, &TempString);
275 IntGdiAddFontResource(&FileName, 0);
276 if (DirInfo->NextEntryOffset == 0)
277 break;
278 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
279 }
280
281 bRestartScan = FALSE;
282 }
283
284 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
285 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
286 ZwClose(hDirectory);
287 }
288 }
289
290
291 /*
292 * IntGdiAddFontResource
293 *
294 * Adds the font resource from the specified file to the system.
295 */
296
297 INT FASTCALL
298 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
299 {
300 FONTGDI *FontGDI;
301 NTSTATUS Status;
302 HANDLE FileHandle, KeyHandle;
303 OBJECT_ATTRIBUTES ObjectAttributes;
304 PVOID Buffer = NULL;
305 IO_STATUS_BLOCK Iosb;
306 INT Error;
307 FT_Face Face;
308 ANSI_STRING AnsiFaceName;
309 PFONT_ENTRY Entry;
310 PSECTION_OBJECT SectionObject;
311 ULONG ViewSize = 0;
312 LARGE_INTEGER SectionSize;
313 UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
314
315 /* Open the font file */
316
317 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
318 Status = ZwOpenFile(
319 &FileHandle,
320 FILE_GENERIC_READ | SYNCHRONIZE,
321 &ObjectAttributes,
322 &Iosb,
323 FILE_SHARE_READ,
324 FILE_SYNCHRONOUS_IO_NONALERT);
325
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("Could not load font file: %wZ\n", FileName);
329 return 0;
330 }
331
332 SectionSize.QuadPart = 0LL;
333 Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
334 NULL, &SectionSize, PAGE_READONLY,
335 SEC_COMMIT, FileHandle, NULL);
336 if (!NT_SUCCESS(Status))
337 {
338 DPRINT("Could not map file: %wZ\n", FileName);
339 ZwClose(FileHandle);
340 return 0;
341 }
342
343 ZwClose(FileHandle);
344
345 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
346 if (!NT_SUCCESS(Status))
347 {
348 DPRINT("Could not map file: %wZ\n", FileName);
349 return Status;
350 }
351
352 IntLockFreeType;
353 Error = FT_New_Memory_Face(
354 library,
355 Buffer,
356 ViewSize,
357 0,
358 &Face);
359 IntUnLockFreeType;
360
361 if (Error)
362 {
363 if (Error == FT_Err_Unknown_File_Format)
364 DPRINT("Unknown font file format\n");
365 else
366 DPRINT("Error reading font file (error code: %u)\n", Error);
367 ObDereferenceObject(SectionObject);
368 return 0;
369 }
370
371 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
372 if (!Entry)
373 {
374 FT_Done_Face(Face);
375 ObDereferenceObject(SectionObject);
376 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
377 return 0;
378 }
379
380 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
381 if (FontGDI == NULL)
382 {
383 FT_Done_Face(Face);
384 ObDereferenceObject(SectionObject);
385 ExFreePoolWithTag(Entry, TAG_FONT);
386 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
387 return 0;
388 }
389
390 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), GDITAG_PFF);
391 if (FontGDI->Filename == NULL)
392 {
393 EngFreeMem(FontGDI);
394 FT_Done_Face(Face);
395 ObDereferenceObject(SectionObject);
396 ExFreePoolWithTag(Entry, TAG_FONT);
397 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
398 return 0;
399 }
400 RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length);
401 FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0';
402 FontGDI->face = Face;
403
404 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
405 DPRINT("Num glyphs: %u\n", Face->num_glyphs);
406
407 /* Add this font resource to the font table */
408
409 Entry->Font = FontGDI;
410 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
411 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
412 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
413
414 if (Characteristics & FR_PRIVATE)
415 {
416 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
417 IntLockProcessPrivateFonts(Win32Process);
418 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
419 IntUnLockProcessPrivateFonts(Win32Process);
420 }
421 else
422 {
423 IntLockGlobalFonts;
424 InsertTailList(&FontListHead, &Entry->ListEntry);
425 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
426 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
427 if (NT_SUCCESS(Status))
428 {
429 LPWSTR pName = wcsrchr(FileName->Buffer, L'\\');
430 if (pName)
431 {
432 pName++;
433 ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR));
434 }
435 ZwClose(KeyHandle);
436 }
437 IntUnLockGlobalFonts;
438 }
439 return 1;
440 }
441
442 BOOL FASTCALL
443 IntIsFontRenderingEnabled(VOID)
444 {
445 BOOL Ret = RenderingEnabled;
446 HDC hDC;
447
448 hDC = IntGetScreenDC();
449 if (hDC)
450 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
451
452 return Ret;
453 }
454
455 VOID FASTCALL
456 IntEnableFontRendering(BOOL Enable)
457 {
458 RenderingEnabled = Enable;
459 }
460
461 FT_Render_Mode FASTCALL
462 IntGetFontRenderMode(LOGFONTW *logfont)
463 {
464 switch (logfont->lfQuality)
465 {
466 case NONANTIALIASED_QUALITY:
467 return FT_RENDER_MODE_MONO;
468 case DRAFT_QUALITY:
469 return FT_RENDER_MODE_LIGHT;
470 /* case CLEARTYPE_QUALITY:
471 return FT_RENDER_MODE_LCD; */
472 }
473 return FT_RENDER_MODE_NORMAL;
474 }
475
476
477 NTSTATUS FASTCALL
478 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
479 {
480 PLFONT plfont;
481
482 plfont = LFONT_AllocFontWithHandle();
483 if (!plfont)
484 {
485 return STATUS_NO_MEMORY;
486 }
487
488 ExInitializePushLock(&plfont->lock);
489 *NewFont = plfont->BaseObject.hHmgr;
490 RtlCopyMemory(&plfont->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW));
491 if (lf->lfEscapement != lf->lfOrientation)
492 {
493 /* This should really depend on whether GM_ADVANCED is set */
494 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
495 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
496 }
497 LFONT_UnlockFont(plfont);
498
499 return STATUS_SUCCESS;
500 }
501
502 /*************************************************************************
503 * TranslateCharsetInfo
504 *
505 * Fills a CHARSETINFO structure for a character set, code page, or
506 * font. This allows making the correspondance between different labelings
507 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
508 * of the same encoding.
509 *
510 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
511 * only one codepage should be set in *Src.
512 *
513 * RETURNS
514 * TRUE on success, FALSE on failure.
515 *
516 */
517 static BOOLEAN APIENTRY
518 IntTranslateCharsetInfo(PDWORD Src, /* [in]
519 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
520 if flags == TCI_SRCCHARSET: a character set value
521 if flags == TCI_SRCCODEPAGE: a code page value */
522 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
523 DWORD Flags /* [in] determines interpretation of lpSrc */)
524 {
525 int Index = 0;
526
527 switch (Flags)
528 {
529 case TCI_SRCFONTSIG:
530 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
531 {
532 Index++;
533 }
534 break;
535 case TCI_SRCCODEPAGE:
536 while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX)
537 {
538 Index++;
539 }
540 break;
541 case TCI_SRCCHARSET:
542 while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
543 {
544 Index++;
545 }
546 break;
547 default:
548 return FALSE;
549 }
550
551 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
552 {
553 return FALSE;
554 }
555
556 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
557
558 return TRUE;
559 }
560
561
562 static BOOL face_has_symbol_charmap(FT_Face ft_face)
563 {
564 int i;
565
566 for(i = 0; i < ft_face->num_charmaps; i++)
567 {
568 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
569 return TRUE;
570 }
571 return FALSE;
572 }
573
574 static void FASTCALL
575 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin)
576 {
577 FT_Fixed XScale, YScale;
578 int Ascent, Descent;
579 FT_Face Face = FontGDI->face;
580
581 XScale = Face->size->metrics.x_scale;
582 YScale = Face->size->metrics.y_scale;
583
584 if (pWin)
585 {
586 TM->tmHeight = pWin->pixel_height;
587 TM->tmAscent = pWin->ascent;
588 TM->tmDescent = TM->tmHeight - TM->tmAscent;
589 TM->tmInternalLeading = pWin->internal_leading;
590 TM->tmExternalLeading = pWin->external_leading;
591 TM->tmAveCharWidth = pWin->avg_width;
592 TM->tmMaxCharWidth = pWin->max_width;
593 TM->tmWeight = pWin->weight;
594 TM->tmOverhang = 0;
595 TM->tmDigitizedAspectX = pWin->horizontal_resolution;
596 TM->tmDigitizedAspectY = pWin->vertical_resolution;
597 TM->tmFirstChar = pWin->first_char;
598 TM->tmLastChar = pWin->last_char;
599 TM->tmDefaultChar = pWin->default_char + pWin->first_char;
600 TM->tmBreakChar = pWin->break_char + pWin->first_char;
601 TM->tmItalic = pWin->italic;
602 TM->tmUnderlined = FontGDI->Underline;
603 TM->tmStruckOut = FontGDI->StrikeOut;
604 TM->tmPitchAndFamily = pWin->pitch_and_family;
605 TM->tmCharSet = pWin->charset;
606 return;
607 }
608
609 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
610 {
611 Ascent = pHori->Ascender;
612 Descent = -pHori->Descender;
613 }
614 else
615 {
616 Ascent = pOS2->usWinAscent;
617 Descent = pOS2->usWinDescent;
618 }
619
620 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
621 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
622 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
623 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
624 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
625 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
626 #endif
627 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
628
629 TM->tmHeight = TM->tmAscent + TM->tmDescent;
630
631 /* MSDN says:
632 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
633 */
634 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
635 - ((Ascent + Descent)
636 - (pHori->Ascender - pHori->Descender)),
637 YScale) + 32) >> 6);
638
639 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
640 if (TM->tmAveCharWidth == 0)
641 {
642 TM->tmAveCharWidth = 1;
643 }
644
645 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
646 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
647
648 TM->tmWeight = pOS2->usWeightClass;
649 TM->tmOverhang = 0;
650 TM->tmDigitizedAspectX = 96;
651 TM->tmDigitizedAspectY = 96;
652 if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
653 {
654 USHORT cpOEM, cpAnsi;
655
656 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
657 TM->tmFirstChar = 0;
658 switch(cpAnsi)
659 {
660 case 1257: /* Baltic */
661 TM->tmLastChar = 0xf8fd;
662 break;
663 default:
664 TM->tmLastChar = 0xf0ff;
665 }
666 TM->tmBreakChar = 0x20;
667 TM->tmDefaultChar = 0x1f;
668 }
669 else
670 {
671 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
672 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
673
674 if(pOS2->usFirstCharIndex <= 1)
675 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
676 else if (pOS2->usFirstCharIndex > 0xff)
677 TM->tmBreakChar = 0x20;
678 else
679 TM->tmBreakChar = pOS2->usFirstCharIndex;
680 TM->tmDefaultChar = TM->tmBreakChar - 1;
681 }
682 TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
683 TM->tmUnderlined = FontGDI->Underline;
684 TM->tmStruckOut = FontGDI->StrikeOut;
685
686 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
687 if (! FT_IS_FIXED_WIDTH(Face))
688 {
689 TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
690 }
691 else
692 {
693 TM->tmPitchAndFamily = 0;
694 }
695
696 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
697 {
698 case PAN_FAMILY_SCRIPT:
699 TM->tmPitchAndFamily |= FF_SCRIPT;
700 break;
701 case PAN_FAMILY_DECORATIVE:
702 TM->tmPitchAndFamily |= FF_DECORATIVE;
703 break;
704
705 case PAN_ANY:
706 case PAN_NO_FIT:
707 case PAN_FAMILY_TEXT_DISPLAY:
708 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
709 /* Which is clearly not what the panose spec says. */
710 if (TM->tmPitchAndFamily == 0) /* Fixed */
711 {
712 TM->tmPitchAndFamily = FF_MODERN;
713 }
714 else
715 {
716 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
717 {
718 case PAN_ANY:
719 case PAN_NO_FIT:
720 default:
721 TM->tmPitchAndFamily |= FF_DONTCARE;
722 break;
723
724 case PAN_SERIF_COVE:
725 case PAN_SERIF_OBTUSE_COVE:
726 case PAN_SERIF_SQUARE_COVE:
727 case PAN_SERIF_OBTUSE_SQUARE_COVE:
728 case PAN_SERIF_SQUARE:
729 case PAN_SERIF_THIN:
730 case PAN_SERIF_BONE:
731 case PAN_SERIF_EXAGGERATED:
732 case PAN_SERIF_TRIANGLE:
733 TM->tmPitchAndFamily |= FF_ROMAN;
734 break;
735
736 case PAN_SERIF_NORMAL_SANS:
737 case PAN_SERIF_OBTUSE_SANS:
738 case PAN_SERIF_PERP_SANS:
739 case PAN_SERIF_FLARED:
740 case PAN_SERIF_ROUNDED:
741 TM->tmPitchAndFamily |= FF_SWISS;
742 break;
743 }
744 }
745 break;
746 default:
747 TM->tmPitchAndFamily |= FF_DONTCARE;
748 }
749
750 if (FT_IS_SCALABLE(Face))
751 {
752 TM->tmPitchAndFamily |= TMPF_VECTOR;
753 }
754 if (FT_IS_SFNT(Face))
755 {
756 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
757 }
758
759 TM->tmCharSet = DEFAULT_CHARSET;
760 }
761
762 /*************************************************************
763 * IntGetOutlineTextMetrics
764 *
765 */
766 INT FASTCALL
767 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
768 UINT Size,
769 OUTLINETEXTMETRICW *Otm)
770 {
771 unsigned Needed;
772 TT_OS2 *pOS2;
773 TT_HoriHeader *pHori;
774 TT_Postscript *pPost;
775 FT_Fixed XScale, YScale;
776 ANSI_STRING FamilyNameA, StyleNameA;
777 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
778 FT_WinFNT_HeaderRec Win;
779 FT_Error Error;
780 char *Cp;
781
782 Needed = sizeof(OUTLINETEXTMETRICW);
783
784 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
785 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
786
787 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
788 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
789
790 /* These names should be read from the TT name table */
791
792 /* Length of otmpFamilyName */
793 Needed += FamilyNameW.Length + sizeof(WCHAR);
794
795 RtlInitUnicodeString(&Regular, L"regular");
796 /* Length of otmpFaceName */
797 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
798 {
799 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
800 }
801 else
802 {
803 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
804 }
805
806 /* Length of otmpStyleName */
807 Needed += StyleNameW.Length + sizeof(WCHAR);
808
809 /* Length of otmpFullName */
810 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
811
812 if (Size < Needed)
813 {
814 RtlFreeUnicodeString(&FamilyNameW);
815 RtlFreeUnicodeString(&StyleNameW);
816 return Needed;
817 }
818
819 XScale = FontGDI->face->size->metrics.x_scale;
820 YScale = FontGDI->face->size->metrics.y_scale;
821
822 IntLockFreeType;
823 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
824 if (NULL == pOS2)
825 {
826 IntUnLockFreeType;
827 DPRINT1("Can't find OS/2 table - not TT font?\n");
828 RtlFreeUnicodeString(&StyleNameW);
829 RtlFreeUnicodeString(&FamilyNameW);
830 return 0;
831 }
832
833 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
834 if (NULL == pHori)
835 {
836 IntUnLockFreeType;
837 DPRINT1("Can't find HHEA table - not TT font?\n");
838 RtlFreeUnicodeString(&StyleNameW);
839 RtlFreeUnicodeString(&FamilyNameW);
840 return 0;
841 }
842
843 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* We can live with this failing */
844
845 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
846
847 Otm->otmSize = Needed;
848
849 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
850
851 Otm->otmFiller = 0;
852 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
853 Otm->otmfsSelection = pOS2->fsSelection;
854 Otm->otmfsType = pOS2->fsType;
855 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
856 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
857 Otm->otmItalicAngle = 0; /* POST table */
858 Otm->otmEMSquare = FontGDI->face->units_per_EM;
859 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
860 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
861 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
862 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
863 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
864 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
865 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
866 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
867 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
868 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
869 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
870 Otm->otmMacLineGap = Otm->otmLineGap;
871 Otm->otmusMinimumPPEM = 0; /* TT Header */
872 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
873 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
874 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
875 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
876 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
877 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
878 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
879 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
880 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
881 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
882 if (!pPost)
883 {
884 Otm->otmsUnderscoreSize = 0;
885 Otm->otmsUnderscorePosition = 0;
886 }
887 else
888 {
889 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
890 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
891 }
892
893 IntUnLockFreeType;
894
895 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
896 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
897 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
898 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
899 Cp += FamilyNameW.Length + sizeof(WCHAR);
900 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
901 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
902 Cp += StyleNameW.Length + sizeof(WCHAR);
903 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
904 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
905 if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
906 {
907 wcscat((WCHAR*) Cp, L" ");
908 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
909 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
910 }
911 else
912 {
913 Cp += FamilyNameW.Length + sizeof(WCHAR);
914 }
915 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
916 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
917 wcscat((WCHAR*) Cp, L" ");
918 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
919
920 RtlFreeUnicodeString(&StyleNameW);
921 RtlFreeUnicodeString(&FamilyNameW);
922
923 return Needed;
924 }
925
926 static PFONTGDI FASTCALL
927 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
928 {
929 PLIST_ENTRY Entry;
930 PFONT_ENTRY CurrentEntry;
931 ANSI_STRING EntryFaceNameA;
932 UNICODE_STRING EntryFaceNameW;
933 FONTGDI *FontGDI;
934
935 Entry = Head->Flink;
936 while (Entry != Head)
937 {
938 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
939
940 FontGDI = CurrentEntry->Font;
941 ASSERT(FontGDI);
942
943 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
944 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
945 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
946 {
947 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
948 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
949 }
950
951 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
952 {
953 RtlFreeUnicodeString(&EntryFaceNameW);
954 return FontGDI;
955 }
956
957 RtlFreeUnicodeString(&EntryFaceNameW);
958 Entry = Entry->Flink;
959 }
960
961 return NULL;
962 }
963
964 static PFONTGDI FASTCALL
965 FindFaceNameInLists(PUNICODE_STRING FaceName)
966 {
967 PPROCESSINFO Win32Process;
968 PFONTGDI Font;
969
970 /* Search the process local list */
971 Win32Process = PsGetCurrentProcessWin32Process();
972 IntLockProcessPrivateFonts(Win32Process);
973 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
974 IntUnLockProcessPrivateFonts(Win32Process);
975 if (NULL != Font)
976 {
977 return Font;
978 }
979
980 /* Search the global list */
981 IntLockGlobalFonts;
982 Font = FindFaceNameInList(FaceName, &FontListHead);
983 IntUnLockGlobalFonts;
984
985 return Font;
986 }
987
988 static void FASTCALL
989 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
990 {
991 ANSI_STRING StyleA;
992 UNICODE_STRING StyleW;
993 TT_OS2 *pOS2;
994 FONTSIGNATURE fs;
995 CHARSETINFO CharSetInfo;
996 unsigned i, Size;
997 OUTLINETEXTMETRICW *Otm;
998 LOGFONTW *Lf;
999 TEXTMETRICW *TM;
1000 NEWTEXTMETRICW *Ntm;
1001 DWORD fs0;
1002
1003 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
1004 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1005 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1006 if (!Otm)
1007 {
1008 return;
1009 }
1010 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1011
1012 Lf = &Info->EnumLogFontEx.elfLogFont;
1013 TM = &Otm->otmTextMetrics;
1014
1015 Lf->lfHeight = TM->tmHeight;
1016 Lf->lfWidth = TM->tmAveCharWidth;
1017 Lf->lfWeight = TM->tmWeight;
1018 Lf->lfItalic = TM->tmItalic;
1019 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1020 Lf->lfCharSet = TM->tmCharSet;
1021 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
1022 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1023 Lf->lfQuality = PROOF_QUALITY;
1024
1025 Ntm = &Info->NewTextMetricEx.ntmTm;
1026 Ntm->tmHeight = TM->tmHeight;
1027 Ntm->tmAscent = TM->tmAscent;
1028 Ntm->tmDescent = TM->tmDescent;
1029 Ntm->tmInternalLeading = TM->tmInternalLeading;
1030 Ntm->tmExternalLeading = TM->tmExternalLeading;
1031 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1032 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1033 Ntm->tmWeight = TM->tmWeight;
1034 Ntm->tmOverhang = TM->tmOverhang;
1035 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1036 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1037 Ntm->tmFirstChar = TM->tmFirstChar;
1038 Ntm->tmLastChar = TM->tmLastChar;
1039 Ntm->tmDefaultChar = TM->tmDefaultChar;
1040 Ntm->tmBreakChar = TM->tmBreakChar;
1041 Ntm->tmItalic = TM->tmItalic;
1042 Ntm->tmUnderlined = TM->tmUnderlined;
1043 Ntm->tmStruckOut = TM->tmStruckOut;
1044 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1045 Ntm->tmCharSet = TM->tmCharSet;
1046 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1047
1048 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
1049
1050 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
1051
1052 Ntm->ntmSizeEM = Otm->otmEMSquare;
1053 Ntm->ntmCellHeight = 0;
1054 Ntm->ntmAvgWidth = 0;
1055
1056 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1057 ? TRUETYPE_FONTTYPE : 0);
1058
1059 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1060 Info->FontType |= RASTER_FONTTYPE;
1061
1062 ExFreePoolWithTag(Otm, GDITAG_TEXT);
1063
1064 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1065 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1066 FaceName);
1067 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1068 sizeof(Info->EnumLogFontEx.elfFullName),
1069 FaceName);
1070 RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
1071 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
1072 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
1073 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
1074
1075 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1076 Info->EnumLogFontEx.elfScript[0] = L'\0';
1077 IntLockFreeType;
1078 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
1079 IntUnLockFreeType;
1080 if (NULL != pOS2)
1081 {
1082 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1083 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1084 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1085 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1086 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1087 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1088
1089 if (0 == pOS2->version)
1090 {
1091 FT_UInt Dummy;
1092
1093 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
1094 fs.fsCsb[0] |= FS_LATIN1;
1095 else
1096 fs.fsCsb[0] |= FS_SYMBOL;
1097 }
1098 if (fs.fsCsb[0] == 0)
1099 { /* Let's see if we can find any interesting cmaps */
1100 for (i = 0; i < FontGDI->face->num_charmaps; i++)
1101 {
1102 switch (FontGDI->face->charmaps[i]->encoding)
1103 {
1104 case FT_ENCODING_UNICODE:
1105 case FT_ENCODING_APPLE_ROMAN:
1106 fs.fsCsb[0] |= FS_LATIN1;
1107 break;
1108 case FT_ENCODING_MS_SYMBOL:
1109 fs.fsCsb[0] |= FS_SYMBOL;
1110 break;
1111 default:
1112 break;
1113 }
1114 }
1115 }
1116 for (i = 0; i < MAXTCIINDEX; i++)
1117 {
1118 fs0 = 1L << i;
1119 if (fs.fsCsb[0] & fs0)
1120 {
1121 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
1122 {
1123 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1124 }
1125 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1126 {
1127 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1128 if (NULL != ElfScripts[i])
1129 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1130 else
1131 {
1132 DPRINT1("Unknown elfscript for bit %d\n", i);
1133 }
1134 }
1135 }
1136 }
1137 Info->NewTextMetricEx.ntmFontSig = fs;
1138 }
1139 }
1140
1141 static int FASTCALL
1142 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1143 {
1144 DWORD i;
1145 UNICODE_STRING InfoFaceName;
1146
1147 for (i = 0; i < InfoEntries; i++)
1148 {
1149 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1150 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
1151 {
1152 return i;
1153 }
1154 }
1155
1156 return -1;
1157 }
1158
1159 static BOOLEAN FASTCALL
1160 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1161 PFONTFAMILYINFO Info, DWORD InfoEntries)
1162 {
1163 UNICODE_STRING LogFontFaceName;
1164
1165 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1166 if (0 != LogFontFaceName.Length
1167 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
1168 {
1169 return FALSE;
1170 }
1171
1172 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1173 }
1174
1175 static BOOLEAN FASTCALL
1176 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1177 PFONTFAMILYINFO Info,
1178 DWORD *Count,
1179 DWORD Size,
1180 PLIST_ENTRY Head)
1181 {
1182 PLIST_ENTRY Entry;
1183 PFONT_ENTRY CurrentEntry;
1184 ANSI_STRING EntryFaceNameA;
1185 UNICODE_STRING EntryFaceNameW;
1186 FONTGDI *FontGDI;
1187
1188 Entry = Head->Flink;
1189 while (Entry != Head)
1190 {
1191 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1192
1193 FontGDI = CurrentEntry->Font;
1194 ASSERT(FontGDI);
1195
1196 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
1197 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1198 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1199 {
1200 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1201 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1202 }
1203
1204 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1205 {
1206 if (*Count < Size)
1207 {
1208 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1209 }
1210 (*Count)++;
1211 }
1212 RtlFreeUnicodeString(&EntryFaceNameW);
1213 Entry = Entry->Flink;
1214 }
1215
1216 return TRUE;
1217 }
1218
1219 typedef struct FontFamilyInfoCallbackContext
1220 {
1221 LPLOGFONTW LogFont;
1222 PFONTFAMILYINFO Info;
1223 DWORD Count;
1224 DWORD Size;
1225 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1226
1227 static NTSTATUS APIENTRY
1228 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1229 IN PVOID ValueData, IN ULONG ValueLength,
1230 IN PVOID Context, IN PVOID EntryContext)
1231 {
1232 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1233 UNICODE_STRING RegistryName, RegistryValue;
1234 int Existing;
1235 PFONTGDI FontGDI;
1236
1237 if (REG_SZ != ValueType)
1238 {
1239 return STATUS_SUCCESS;
1240 }
1241 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1242 RtlInitUnicodeString(&RegistryName, ValueName);
1243
1244 /* Do we need to include this font family? */
1245 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1246 min(InfoContext->Count, InfoContext->Size)))
1247 {
1248 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1249 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1250 min(InfoContext->Count, InfoContext->Size));
1251 if (0 <= Existing)
1252 {
1253 /* We already have the information about the "real" font. Just copy it */
1254 if (InfoContext->Count < InfoContext->Size)
1255 {
1256 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1257 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1258 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
1259 RegistryName.Buffer,
1260 RegistryName.Length);
1261 }
1262 InfoContext->Count++;
1263 return STATUS_SUCCESS;
1264 }
1265
1266 /* Try to find information about the "real" font */
1267 FontGDI = FindFaceNameInLists(&RegistryValue);
1268 if (NULL == FontGDI)
1269 {
1270 /* "Real" font not found, discard this registry entry */
1271 return STATUS_SUCCESS;
1272 }
1273
1274 /* Return info about the "real" font but with the name of the alias */
1275 if (InfoContext->Count < InfoContext->Size)
1276 {
1277 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1278 RegistryName.Buffer, FontGDI);
1279 }
1280 InfoContext->Count++;
1281 return STATUS_SUCCESS;
1282 }
1283
1284 return STATUS_SUCCESS;
1285 }
1286
1287 static BOOLEAN FASTCALL
1288 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1289 PFONTFAMILYINFO Info,
1290 DWORD *Count,
1291 DWORD Size)
1292 {
1293 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
1294 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1295 NTSTATUS Status;
1296
1297 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
1298 The real work is done in the registry callback function */
1299 Context.LogFont = LogFont;
1300 Context.Info = Info;
1301 Context.Count = *Count;
1302 Context.Size = Size;
1303
1304 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1305 QueryTable[0].Flags = 0;
1306 QueryTable[0].Name = NULL;
1307 QueryTable[0].EntryContext = NULL;
1308 QueryTable[0].DefaultType = REG_NONE;
1309 QueryTable[0].DefaultData = NULL;
1310 QueryTable[0].DefaultLength = 0;
1311
1312 QueryTable[1].QueryRoutine = NULL;
1313 QueryTable[1].Name = NULL;
1314
1315 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1316 L"FontSubstitutes",
1317 QueryTable,
1318 &Context,
1319 NULL);
1320 if (NT_SUCCESS(Status))
1321 {
1322 *Count = Context.Count;
1323 }
1324
1325 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1326 }
1327
1328 BOOL
1329 FASTCALL
1330 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
1331 {
1332 if ( lprs )
1333 {
1334 lprs->nSize = sizeof(RASTERIZER_STATUS);
1335 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
1336 lprs->nLanguageID = gusLanguageID;
1337 return TRUE;
1338 }
1339 EngSetLastError(ERROR_INVALID_PARAMETER);
1340 return FALSE;
1341 }
1342
1343 static
1344 BOOL
1345 SameScaleMatrix(
1346 PMATRIX pmx1,
1347 PMATRIX pmx2)
1348 {
1349 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
1350 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
1351 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
1352 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
1353 }
1354
1355 FT_BitmapGlyph APIENTRY
1356 ftGdiGlyphCacheGet(
1357 FT_Face Face,
1358 INT GlyphIndex,
1359 INT Height,
1360 PMATRIX pmx)
1361 {
1362 PLIST_ENTRY CurrentEntry;
1363 PFONT_CACHE_ENTRY FontEntry;
1364
1365 CurrentEntry = FontCacheListHead.Flink;
1366 while (CurrentEntry != &FontCacheListHead)
1367 {
1368 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
1369 if ((FontEntry->Face == Face) &&
1370 (FontEntry->GlyphIndex == GlyphIndex) &&
1371 (FontEntry->Height == Height) &&
1372 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
1373 break;
1374 CurrentEntry = CurrentEntry->Flink;
1375 }
1376
1377 if (CurrentEntry == &FontCacheListHead)
1378 {
1379 return NULL;
1380 }
1381
1382 RemoveEntryList(CurrentEntry);
1383 InsertHeadList(&FontCacheListHead, CurrentEntry);
1384 return FontEntry->BitmapGlyph;
1385 }
1386
1387 FT_BitmapGlyph APIENTRY
1388 ftGdiGlyphCacheSet(
1389 FT_Face Face,
1390 INT GlyphIndex,
1391 INT Height,
1392 PMATRIX pmx,
1393 FT_GlyphSlot GlyphSlot,
1394 FT_Render_Mode RenderMode)
1395 {
1396 FT_Glyph GlyphCopy;
1397 INT error;
1398 PFONT_CACHE_ENTRY NewEntry;
1399 FT_Bitmap AlignedBitmap;
1400 FT_BitmapGlyph BitmapGlyph;
1401
1402 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
1403 if (error)
1404 {
1405 DPRINT1("Failure caching glyph.\n");
1406 return NULL;
1407 };
1408
1409 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
1410 if (error)
1411 {
1412 FT_Done_Glyph(GlyphCopy);
1413 DPRINT1("Failure rendering glyph.\n");
1414 return NULL;
1415 };
1416
1417 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1418 if (!NewEntry)
1419 {
1420 DPRINT1("Alloc failure caching glyph.\n");
1421 FT_Done_Glyph(GlyphCopy);
1422 return NULL;
1423 }
1424
1425 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
1426 FT_Bitmap_New(&AlignedBitmap);
1427 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
1428 {
1429 DPRINT1("Conversion failed\n");
1430 ExFreePoolWithTag(NewEntry, TAG_FONT);
1431 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
1432 return NULL;
1433 }
1434
1435 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
1436 BitmapGlyph->bitmap = AlignedBitmap;
1437
1438 NewEntry->GlyphIndex = GlyphIndex;
1439 NewEntry->Face = Face;
1440 NewEntry->BitmapGlyph = BitmapGlyph;
1441 NewEntry->Height = Height;
1442 NewEntry->mxWorldToDevice = *pmx;
1443
1444 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1445 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
1446 {
1447 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1448 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
1449 RemoveTailList(&FontCacheListHead);
1450 ExFreePoolWithTag(NewEntry, TAG_FONT);
1451 FontCacheNumEntries--;
1452 }
1453
1454 return BitmapGlyph;
1455 }
1456
1457
1458 static
1459 void
1460 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1461 {
1462 pt->x.value = vec->x >> 6;
1463 pt->x.fract = (vec->x & 0x3f) << 10;
1464 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1465 pt->y.value = vec->y >> 6;
1466 pt->y.fract = (vec->y & 0x3f) << 10;
1467 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1468 return;
1469 }
1470
1471 /*
1472 This function builds an FT_Fixed from a float. It puts the integer part
1473 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
1474 It fails if the integer part of the float number is greater than SHORT_MAX.
1475 */
1476 static __inline FT_Fixed FT_FixedFromFloat(float f)
1477 {
1478 short value = f;
1479 unsigned short fract = (f - value) * 0xFFFF;
1480 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
1481 }
1482
1483 /*
1484 This function builds an FT_Fixed from a FIXED. It simply put f.value
1485 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
1486 */
1487 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
1488 {
1489 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
1490 }
1491
1492 /*
1493 * Based on WineEngGetGlyphOutline
1494 *
1495 */
1496 ULONG
1497 FASTCALL
1498 ftGdiGetGlyphOutline(
1499 PDC dc,
1500 WCHAR wch,
1501 UINT iFormat,
1502 LPGLYPHMETRICS pgm,
1503 ULONG cjBuf,
1504 PVOID pvBuf,
1505 LPMAT2 pmat2,
1506 BOOL bIgnoreRotation)
1507 {
1508 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1509 PDC_ATTR pdcattr;
1510 PTEXTOBJ TextObj;
1511 PFONTGDI FontGDI;
1512 HFONT hFont = 0;
1513 GLYPHMETRICS gm;
1514 ULONG Size;
1515 FT_Face ft_face;
1516 FT_UInt glyph_index;
1517 DWORD width, height, pitch, needed = 0;
1518 FT_Bitmap ft_bitmap;
1519 FT_Error error;
1520 INT left, right, top = 0, bottom = 0;
1521 FT_Angle angle = 0;
1522 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1523 FLOAT eM11, widthRatio = 1.0;
1524 FT_Matrix transMat = identityMat;
1525 BOOL needsTransform = FALSE;
1526 INT orientation;
1527 LONG aveWidth;
1528 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
1529 OUTLINETEXTMETRICW *potm;
1530 int n = 0;
1531 FT_CharMap found = 0, charmap;
1532 XFORM xForm;
1533
1534 DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
1535 cjBuf, pvBuf, pmat2);
1536
1537 pdcattr = dc->pdcattr;
1538
1539 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
1540 eM11 = xForm.eM11;
1541
1542 hFont = pdcattr->hlfntNew;
1543 TextObj = RealizeFontInit(hFont);
1544
1545 if (!TextObj)
1546 {
1547 EngSetLastError(ERROR_INVALID_HANDLE);
1548 return GDI_ERROR;
1549 }
1550 FontGDI = ObjToGDI(TextObj->Font, FONT);
1551 ft_face = FontGDI->face;
1552
1553 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
1554 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
1555
1556 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1557 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1558 if (!potm)
1559 {
1560 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1561 TEXTOBJ_UnlockText(TextObj);
1562 return GDI_ERROR;
1563 }
1564 IntGetOutlineTextMetrics(FontGDI, Size, potm);
1565
1566 IntLockFreeType;
1567
1568 /* During testing, I never saw this used. It is here just in case. */
1569 if (ft_face->charmap == NULL)
1570 {
1571 DPRINT("WARNING: No charmap selected!\n");
1572 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
1573
1574 for (n = 0; n < ft_face->num_charmaps; n++)
1575 {
1576 charmap = ft_face->charmaps[n];
1577 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
1578 if (charmap->encoding != 0)
1579 {
1580 found = charmap;
1581 break;
1582 }
1583 }
1584 if (!found)
1585 {
1586 DPRINT1("WARNING: Could not find desired charmap!\n");
1587 }
1588 error = FT_Set_Charmap(ft_face, found);
1589 if (error)
1590 {
1591 DPRINT1("WARNING: Could not set the charmap!\n");
1592 }
1593 }
1594
1595 // FT_Set_Pixel_Sizes(ft_face,
1596 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
1597 /* FIXME: Should set character height if neg */
1598 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
1599 // dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
1600 // FtSetCoordinateTransform(face, DC_pmxWorldToDevice(dc));
1601
1602 TEXTOBJ_UnlockText(TextObj);
1603
1604 if (iFormat & GGO_GLYPH_INDEX)
1605 {
1606 glyph_index = wch;
1607 iFormat &= ~GGO_GLYPH_INDEX;
1608 }
1609 else glyph_index = FT_Get_Char_Index(ft_face, wch);
1610
1611 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
1612 load_flags |= FT_LOAD_NO_BITMAP;
1613
1614 if (iFormat & GGO_UNHINTED)
1615 {
1616 load_flags |= FT_LOAD_NO_HINTING;
1617 iFormat &= ~GGO_UNHINTED;
1618 }
1619
1620 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
1621 if (error)
1622 {
1623 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1624 IntUnLockFreeType;
1625 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
1626 return GDI_ERROR;
1627 }
1628 IntUnLockFreeType;
1629
1630 if (aveWidth && potm)
1631 {
1632 widthRatio = (FLOAT)aveWidth * eM11 /
1633 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
1634 }
1635
1636 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1637 right = (INT)((ft_face->glyph->metrics.horiBearingX +
1638 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1639
1640 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1641 lsb = left >> 6;
1642 bbx = (right - left) >> 6;
1643
1644 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
1645
1646 IntLockFreeType;
1647
1648 /* Scaling transform */
1649 if (aveWidth)
1650 {
1651 FT_Matrix scaleMat;
1652 DPRINT("Scaling Trans!\n");
1653 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1654 scaleMat.xy = 0;
1655 scaleMat.yx = 0;
1656 scaleMat.yy = (1 << 16);
1657 FT_Matrix_Multiply(&scaleMat, &transMat);
1658 needsTransform = TRUE;
1659 }
1660
1661 /* Slant transform */
1662 if (potm->otmTextMetrics.tmItalic)
1663 {
1664 FT_Matrix slantMat;
1665 DPRINT("Slant Trans!\n");
1666 slantMat.xx = (1 << 16);
1667 slantMat.xy = ((1 << 16) >> 2);
1668 slantMat.yx = 0;
1669 slantMat.yy = (1 << 16);
1670 FT_Matrix_Multiply(&slantMat, &transMat);
1671 needsTransform = TRUE;
1672 }
1673
1674 /* Rotation transform */
1675 if (orientation)
1676 {
1677 FT_Matrix rotationMat;
1678 FT_Vector vecAngle;
1679 DPRINT("Rotation Trans!\n");
1680 angle = FT_FixedFromFloat((float)orientation / 10.0);
1681 FT_Vector_Unit(&vecAngle, angle);
1682 rotationMat.xx = vecAngle.x;
1683 rotationMat.xy = -vecAngle.y;
1684 rotationMat.yx = -rotationMat.xy;
1685 rotationMat.yy = rotationMat.xx;
1686 FT_Matrix_Multiply(&rotationMat, &transMat);
1687 needsTransform = TRUE;
1688 }
1689
1690 /* Extra transformation specified by caller */
1691 if (pmat2)
1692 {
1693 FT_Matrix extraMat;
1694 DPRINT("MAT2 Matrix Trans!\n");
1695 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
1696 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
1697 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
1698 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
1699 FT_Matrix_Multiply(&extraMat, &transMat);
1700 needsTransform = TRUE;
1701 }
1702
1703 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
1704
1705 if (!needsTransform)
1706 {
1707 DPRINT("No Need to be Transformed!\n");
1708 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1709 bottom = (ft_face->glyph->metrics.horiBearingY -
1710 ft_face->glyph->metrics.height) & -64;
1711 gm.gmCellIncX = adv;
1712 gm.gmCellIncY = 0;
1713 }
1714 else
1715 {
1716 INT xc, yc;
1717 FT_Vector vec;
1718 for (xc = 0; xc < 2; xc++)
1719 {
1720 for (yc = 0; yc < 2; yc++)
1721 {
1722 vec.x = (ft_face->glyph->metrics.horiBearingX +
1723 xc * ft_face->glyph->metrics.width);
1724 vec.y = ft_face->glyph->metrics.horiBearingY -
1725 yc * ft_face->glyph->metrics.height;
1726 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
1727 FT_Vector_Transform(&vec, &transMat);
1728 if (xc == 0 && yc == 0)
1729 {
1730 left = right = vec.x;
1731 top = bottom = vec.y;
1732 }
1733 else
1734 {
1735 if (vec.x < left) left = vec.x;
1736 else if (vec.x > right) right = vec.x;
1737 if (vec.y < bottom) bottom = vec.y;
1738 else if (vec.y > top) top = vec.y;
1739 }
1740 }
1741 }
1742 left = left & -64;
1743 right = (right + 63) & -64;
1744 bottom = bottom & -64;
1745 top = (top + 63) & -64;
1746
1747 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1748 vec.x = ft_face->glyph->metrics.horiAdvance;
1749 vec.y = 0;
1750 FT_Vector_Transform(&vec, &transMat);
1751 gm.gmCellIncX = (vec.x+63) >> 6;
1752 gm.gmCellIncY = -((vec.y+63) >> 6);
1753 }
1754 gm.gmBlackBoxX = (right - left) >> 6;
1755 gm.gmBlackBoxY = (top - bottom) >> 6;
1756 gm.gmptGlyphOrigin.x = left >> 6;
1757 gm.gmptGlyphOrigin.y = top >> 6;
1758
1759 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
1760 gm.gmCellIncX, gm.gmCellIncY,
1761 gm.gmBlackBoxX, gm.gmBlackBoxY,
1762 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1763
1764 IntUnLockFreeType;
1765
1766 if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
1767
1768 if (iFormat == GGO_METRICS)
1769 {
1770 DPRINT("GGO_METRICS Exit!\n");
1771 return 1; /* FIXME */
1772 }
1773
1774 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
1775 {
1776 DPRINT1("Loaded a bitmap\n");
1777 return GDI_ERROR;
1778 }
1779
1780 switch (iFormat)
1781 {
1782 case GGO_BITMAP:
1783 width = gm.gmBlackBoxX;
1784 height = gm.gmBlackBoxY;
1785 pitch = ((width + 31) >> 5) << 2;
1786 needed = pitch * height;
1787
1788 if (!pvBuf || !cjBuf) break;
1789
1790 switch (ft_face->glyph->format)
1791 {
1792 case ft_glyph_format_bitmap:
1793 {
1794 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1795 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1796 INT h = ft_face->glyph->bitmap.rows;
1797 while (h--)
1798 {
1799 RtlCopyMemory(dst, src, w);
1800 src += ft_face->glyph->bitmap.pitch;
1801 dst += pitch;
1802 }
1803 break;
1804 }
1805
1806 case ft_glyph_format_outline:
1807 ft_bitmap.width = width;
1808 ft_bitmap.rows = height;
1809 ft_bitmap.pitch = pitch;
1810 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1811 ft_bitmap.buffer = pvBuf;
1812
1813 IntLockFreeType;
1814 if (needsTransform)
1815 {
1816 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1817 }
1818 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1819 /* Note: FreeType will only set 'black' bits for us. */
1820 RtlZeroMemory(pvBuf, needed);
1821 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1822 IntUnLockFreeType;
1823 break;
1824
1825 default:
1826 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
1827 return GDI_ERROR;
1828 }
1829 break;
1830
1831 case GGO_GRAY2_BITMAP:
1832 case GGO_GRAY4_BITMAP:
1833 case GGO_GRAY8_BITMAP:
1834 {
1835 unsigned int mult, row, col;
1836 BYTE *start, *ptr;
1837
1838 width = gm.gmBlackBoxX;
1839 height = gm.gmBlackBoxY;
1840 pitch = (width + 3) / 4 * 4;
1841 needed = pitch * height;
1842
1843 if (!pvBuf || !cjBuf) break;
1844
1845 switch (ft_face->glyph->format)
1846 {
1847 case ft_glyph_format_bitmap:
1848 {
1849 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1850 INT h = ft_face->glyph->bitmap.rows;
1851 INT x;
1852 while (h--)
1853 {
1854 for (x = 0; x < pitch; x++)
1855 {
1856 if (x < ft_face->glyph->bitmap.width)
1857 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
1858 else
1859 dst[x] = 0;
1860 }
1861 src += ft_face->glyph->bitmap.pitch;
1862 dst += pitch;
1863 }
1864 return needed;
1865 }
1866 case ft_glyph_format_outline:
1867 {
1868 ft_bitmap.width = width;
1869 ft_bitmap.rows = height;
1870 ft_bitmap.pitch = pitch;
1871 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1872 ft_bitmap.buffer = pvBuf;
1873
1874 IntLockFreeType;
1875 if (needsTransform)
1876 {
1877 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1878 }
1879 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1880 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
1881 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1882 IntUnLockFreeType;
1883
1884 if (iFormat == GGO_GRAY2_BITMAP)
1885 mult = 4;
1886 else if (iFormat == GGO_GRAY4_BITMAP)
1887 mult = 16;
1888 else if (iFormat == GGO_GRAY8_BITMAP)
1889 mult = 64;
1890 else
1891 {
1892 return GDI_ERROR;
1893 }
1894 }
1895 default:
1896 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
1897 return GDI_ERROR;
1898 }
1899 start = pvBuf;
1900 for (row = 0; row < height; row++)
1901 {
1902 ptr = start;
1903 for (col = 0; col < width; col++, ptr++)
1904 {
1905 *ptr = (((int)*ptr) * mult + 128) / 256;
1906 }
1907 start += pitch;
1908 }
1909 break;
1910 }
1911
1912 case GGO_NATIVE:
1913 {
1914 int contour, point = 0, first_pt;
1915 FT_Outline *outline = &ft_face->glyph->outline;
1916 TTPOLYGONHEADER *pph;
1917 TTPOLYCURVE *ppc;
1918 DWORD pph_start, cpfx, type;
1919
1920 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
1921
1922 IntLockFreeType;
1923 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
1924
1925 for (contour = 0; contour < outline->n_contours; contour++)
1926 {
1927 pph_start = needed;
1928 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1929 first_pt = point;
1930 if (pvBuf)
1931 {
1932 pph->dwType = TT_POLYGON_TYPE;
1933 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1934 }
1935 needed += sizeof(*pph);
1936 point++;
1937 while (point <= outline->contours[contour])
1938 {
1939 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1940 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1941 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1942 cpfx = 0;
1943 do
1944 {
1945 if (pvBuf)
1946 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1947 cpfx++;
1948 point++;
1949 }
1950 while (point <= outline->contours[contour] &&
1951 (outline->tags[point] & FT_Curve_Tag_On) ==
1952 (outline->tags[point-1] & FT_Curve_Tag_On));
1953
1954 /* At the end of a contour Windows adds the start point, but
1955 only for Beziers */
1956 if (point > outline->contours[contour] &&
1957 !(outline->tags[point-1] & FT_Curve_Tag_On))
1958 {
1959 if (pvBuf)
1960 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1961 cpfx++;
1962 }
1963 else if (point <= outline->contours[contour] &&
1964 outline->tags[point] & FT_Curve_Tag_On)
1965 {
1966 /* Add closing pt for bezier */
1967 if (pvBuf)
1968 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1969 cpfx++;
1970 point++;
1971 }
1972 if (pvBuf)
1973 {
1974 ppc->wType = type;
1975 ppc->cpfx = cpfx;
1976 }
1977 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1978 }
1979 if (pvBuf) pph->cb = needed - pph_start;
1980 }
1981 IntUnLockFreeType;
1982 break;
1983 }
1984 case GGO_BEZIER:
1985 {
1986 /* Convert the quadratic Beziers to cubic Beziers.
1987 The parametric eqn for a cubic Bezier is, from PLRM:
1988 r(t) = at^3 + bt^2 + ct + r0
1989 with the control points:
1990 r1 = r0 + c/3
1991 r2 = r1 + (c + b)/3
1992 r3 = r0 + c + b + a
1993
1994 A quadratic Beizer has the form:
1995 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1996
1997 So equating powers of t leads to:
1998 r1 = 2/3 p1 + 1/3 p0
1999 r2 = 2/3 p1 + 1/3 p2
2000 and of course r0 = p0, r3 = p2
2001 */
2002
2003 int contour, point = 0, first_pt;
2004 FT_Outline *outline = &ft_face->glyph->outline;
2005 TTPOLYGONHEADER *pph;
2006 TTPOLYCURVE *ppc;
2007 DWORD pph_start, cpfx, type;
2008 FT_Vector cubic_control[4];
2009 if (cjBuf == 0) pvBuf = NULL;
2010
2011 if (needsTransform && pvBuf)
2012 {
2013 IntLockFreeType;
2014 FT_Outline_Transform(outline, &transMat);
2015 IntUnLockFreeType;
2016 }
2017
2018 for (contour = 0; contour < outline->n_contours; contour++)
2019 {
2020 pph_start = needed;
2021 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2022 first_pt = point;
2023 if (pvBuf)
2024 {
2025 pph->dwType = TT_POLYGON_TYPE;
2026 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2027 }
2028 needed += sizeof(*pph);
2029 point++;
2030 while (point <= outline->contours[contour])
2031 {
2032 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2033 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2034 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2035 cpfx = 0;
2036 do
2037 {
2038 if (type == TT_PRIM_LINE)
2039 {
2040 if (pvBuf)
2041 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2042 cpfx++;
2043 point++;
2044 }
2045 else
2046 {
2047 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2048 so cpfx = 3n */
2049
2050 /* FIXME: Possible optimization in endpoint calculation
2051 if there are two consecutive curves */
2052 cubic_control[0] = outline->points[point-1];
2053 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2054 {
2055 cubic_control[0].x += outline->points[point].x + 1;
2056 cubic_control[0].y += outline->points[point].y + 1;
2057 cubic_control[0].x >>= 1;
2058 cubic_control[0].y >>= 1;
2059 }
2060 if (point+1 > outline->contours[contour])
2061 cubic_control[3] = outline->points[first_pt];
2062 else
2063 {
2064 cubic_control[3] = outline->points[point+1];
2065 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2066 {
2067 cubic_control[3].x += outline->points[point].x + 1;
2068 cubic_control[3].y += outline->points[point].y + 1;
2069 cubic_control[3].x >>= 1;
2070 cubic_control[3].y >>= 1;
2071 }
2072 }
2073 /* r1 = 1/3 p0 + 2/3 p1
2074 r2 = 1/3 p2 + 2/3 p1 */
2075 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2076 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2077 cubic_control[2] = cubic_control[1];
2078 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2079 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2080 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2081 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2082 if (pvBuf)
2083 {
2084 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2085 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2086 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2087 }
2088 cpfx += 3;
2089 point++;
2090 }
2091 }
2092 while (point <= outline->contours[contour] &&
2093 (outline->tags[point] & FT_Curve_Tag_On) ==
2094 (outline->tags[point-1] & FT_Curve_Tag_On));
2095 /* At the end of a contour Windows adds the start point,
2096 but only for Beziers and we've already done that. */
2097 if (point <= outline->contours[contour] &&
2098 outline->tags[point] & FT_Curve_Tag_On)
2099 {
2100 /* This is the closing pt of a bezier, but we've already
2101 added it, so just inc point and carry on */
2102 point++;
2103 }
2104 if (pvBuf)
2105 {
2106 ppc->wType = type;
2107 ppc->cpfx = cpfx;
2108 }
2109 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2110 }
2111 if (pvBuf) pph->cb = needed - pph_start;
2112 }
2113 break;
2114 }
2115
2116 default:
2117 DPRINT1("Unsupported format %d\n", iFormat);
2118 return GDI_ERROR;
2119 }
2120
2121 DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
2122 return needed;
2123 }
2124
2125 BOOL
2126 FASTCALL
2127 TextIntGetTextExtentPoint(PDC dc,
2128 PTEXTOBJ TextObj,
2129 LPCWSTR String,
2130 INT Count,
2131 ULONG MaxExtent,
2132 LPINT Fit,
2133 LPINT Dx,
2134 LPSIZE Size,
2135 FLONG fl)
2136 {
2137 PFONTGDI FontGDI;
2138 FT_Face face;
2139 FT_GlyphSlot glyph;
2140 FT_BitmapGlyph realglyph;
2141 INT error, n, glyph_index, i, previous;
2142 ULONGLONG TotalWidth = 0;
2143 FT_CharMap charmap, found = NULL;
2144 BOOL use_kerning;
2145 FT_Render_Mode RenderMode;
2146 BOOLEAN Render;
2147 PMATRIX pmxWorldToDevice;
2148
2149 FontGDI = ObjToGDI(TextObj->Font, FONT);
2150
2151 face = FontGDI->face;
2152 if (NULL != Fit)
2153 {
2154 *Fit = 0;
2155 }
2156
2157 IntLockFreeType;
2158 if (face->charmap == NULL)
2159 {
2160 DPRINT("WARNING: No charmap selected!\n");
2161 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2162
2163 for (n = 0; n < face->num_charmaps; n++)
2164 {
2165 charmap = face->charmaps[n];
2166 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
2167 if (charmap->encoding != 0)
2168 {
2169 found = charmap;
2170 break;
2171 }
2172 }
2173
2174 if (! found)
2175 {
2176 DPRINT1("WARNING: Could not find desired charmap!\n");
2177 }
2178
2179 error = FT_Set_Charmap(face, found);
2180 if (error)
2181 {
2182 DPRINT1("WARNING: Could not set the charmap!\n");
2183 }
2184 }
2185
2186 Render = IntIsFontRenderingEnabled();
2187 if (Render)
2188 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
2189 else
2190 RenderMode = FT_RENDER_MODE_MONO;
2191
2192 error = FT_Set_Pixel_Sizes(face,
2193 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2194 /* FIXME: Should set character height if neg */
2195 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2196 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2197 if (error)
2198 {
2199 DPRINT1("Error in setting pixel sizes: %u\n", error);
2200 }
2201
2202 /* Get the DC's world-to-device transformation matrix */
2203 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
2204 FtSetCoordinateTransform(face, pmxWorldToDevice);
2205
2206 use_kerning = FT_HAS_KERNING(face);
2207 previous = 0;
2208
2209 for (i = 0; i < Count; i++)
2210 {
2211 if (fl & GTEF_INDICES)
2212 glyph_index = *String;
2213 else
2214 glyph_index = FT_Get_Char_Index(face, *String);
2215
2216 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2217 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
2218 pmxWorldToDevice)))
2219 {
2220 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2221 if (error)
2222 {
2223 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2224 break;
2225 }
2226
2227 glyph = face->glyph;
2228 realglyph = ftGdiGlyphCacheSet(face,
2229 glyph_index,
2230 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
2231 pmxWorldToDevice,
2232 glyph,
2233 RenderMode);
2234 if (!realglyph)
2235 {
2236 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
2237 break;
2238 }
2239 }
2240
2241 /* Retrieve kerning distance */
2242 if (use_kerning && previous && glyph_index)
2243 {
2244 FT_Vector delta;
2245 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2246 TotalWidth += delta.x;
2247 }
2248
2249 TotalWidth += realglyph->root.advance.x >> 10;
2250
2251 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2252 {
2253 *Fit = i + 1;
2254 }
2255 if (NULL != Dx)
2256 {
2257 Dx[i] = (TotalWidth + 32) >> 6;
2258 }
2259
2260 previous = glyph_index;
2261 String++;
2262 }
2263 IntUnLockFreeType;
2264
2265 Size->cx = (TotalWidth + 32) >> 6;
2266 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2267 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2268 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
2269
2270 return TRUE;
2271 }
2272
2273
2274 INT
2275 FASTCALL
2276 ftGdiGetTextCharsetInfo(
2277 PDC Dc,
2278 LPFONTSIGNATURE lpSig,
2279 DWORD dwFlags)
2280 {
2281 PDC_ATTR pdcattr;
2282 UINT Ret = DEFAULT_CHARSET, i;
2283 HFONT hFont;
2284 PTEXTOBJ TextObj;
2285 PFONTGDI FontGdi;
2286 FONTSIGNATURE fs;
2287 TT_OS2 *pOS2;
2288 FT_Face Face;
2289 CHARSETINFO csi;
2290 DWORD cp, fs0;
2291 USHORT usACP, usOEM;
2292
2293 pdcattr = Dc->pdcattr;
2294 hFont = pdcattr->hlfntNew;
2295 TextObj = RealizeFontInit(hFont);
2296
2297 if (!TextObj)
2298 {
2299 EngSetLastError(ERROR_INVALID_HANDLE);
2300 return Ret;
2301 }
2302 FontGdi = ObjToGDI(TextObj->Font, FONT);
2303 Face = FontGdi->face;
2304 TEXTOBJ_UnlockText(TextObj);
2305
2306 IntLockFreeType;
2307 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2308 IntUnLockFreeType;
2309 memset(&fs, 0, sizeof(FONTSIGNATURE));
2310 if (NULL != pOS2)
2311 {
2312 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2313 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2314 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2315 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2316 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2317 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2318 if (pOS2->version == 0)
2319 {
2320 FT_UInt dummy;
2321
2322 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
2323 fs.fsCsb[0] |= FS_LATIN1;
2324 else
2325 fs.fsCsb[0] |= FS_SYMBOL;
2326 }
2327 }
2328 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
2329 if (fs.fsCsb[0] == 0)
2330 { /* Let's see if we can find any interesting cmaps */
2331 for (i = 0; i < Face->num_charmaps; i++)
2332 {
2333 switch (Face->charmaps[i]->encoding)
2334 {
2335 case FT_ENCODING_UNICODE:
2336 case FT_ENCODING_APPLE_ROMAN:
2337 fs.fsCsb[0] |= FS_LATIN1;
2338 break;
2339 case FT_ENCODING_MS_SYMBOL:
2340 fs.fsCsb[0] |= FS_SYMBOL;
2341 break;
2342 default:
2343 break;
2344 }
2345 }
2346 }
2347 if (lpSig)
2348 {
2349 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
2350 }
2351
2352 RtlGetDefaultCodePage(&usACP, &usOEM);
2353 cp = usACP;
2354
2355 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
2356 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
2357 {
2358 DPRINT("Hit 1\n");
2359 Ret = csi.ciCharset;
2360 goto Exit;
2361 }
2362
2363 for (i = 0; i < MAXTCIINDEX; i++)
2364 {
2365 fs0 = 1L << i;
2366 if (fs.fsCsb[0] & fs0)
2367 {
2368 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
2369 {
2370 // *cp = csi.ciACP;
2371 DPRINT("Hit 2\n");
2372 Ret = csi.ciCharset;
2373 goto Exit;
2374 }
2375 else
2376 DPRINT1("TCI failing on %x\n", fs0);
2377 }
2378 }
2379 Exit:
2380 DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
2381 return (MAKELONG(csi.ciACP, csi.ciCharset));
2382 }
2383
2384
2385 DWORD
2386 FASTCALL
2387 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
2388 {
2389 DWORD size = 0;
2390 DWORD num_ranges = 0;
2391 FT_Face face = Font->face;
2392
2393 if (face->charmap->encoding == FT_ENCODING_UNICODE)
2394 {
2395 FT_UInt glyph_code = 0;
2396 FT_ULong char_code, char_code_prev;
2397
2398 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
2399
2400 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2401 face->num_glyphs, glyph_code, char_code);
2402
2403 if (!glyph_code) return 0;
2404
2405 if (glyphset)
2406 {
2407 glyphset->ranges[0].wcLow = (USHORT)char_code;
2408 glyphset->ranges[0].cGlyphs = 0;
2409 glyphset->cGlyphsSupported = 0;
2410 }
2411
2412 num_ranges = 1;
2413 while (glyph_code)
2414 {
2415 if (char_code < char_code_prev)
2416 {
2417 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
2418 return 0;
2419 }
2420 if (char_code - char_code_prev > 1)
2421 {
2422 num_ranges++;
2423 if (glyphset)
2424 {
2425 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
2426 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
2427 glyphset->cGlyphsSupported++;
2428 }
2429 }
2430 else if (glyphset)
2431 {
2432 glyphset->ranges[num_ranges - 1].cGlyphs++;
2433 glyphset->cGlyphsSupported++;
2434 }
2435 char_code_prev = char_code;
2436 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
2437 }
2438 }
2439 else
2440 DPRINT1("Encoding %u not supported\n", face->charmap->encoding);
2441
2442 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
2443 if (glyphset)
2444 {
2445 glyphset->cbThis = size;
2446 glyphset->cRanges = num_ranges;
2447 }
2448 return size;
2449 }
2450
2451
2452 BOOL
2453 FASTCALL
2454 ftGdiGetTextMetricsW(
2455 HDC hDC,
2456 PTMW_INTERNAL ptmwi)
2457 {
2458 PDC dc;
2459 PDC_ATTR pdcattr;
2460 PTEXTOBJ TextObj;
2461 PFONTGDI FontGDI;
2462 FT_Face Face;
2463 TT_OS2 *pOS2;
2464 TT_HoriHeader *pHori;
2465 FT_WinFNT_HeaderRec Win;
2466 ULONG Error;
2467 NTSTATUS Status = STATUS_SUCCESS;
2468
2469 if (!ptmwi)
2470 {
2471 EngSetLastError(STATUS_INVALID_PARAMETER);
2472 return FALSE;
2473 }
2474
2475 if (!(dc = DC_LockDc(hDC)))
2476 {
2477 EngSetLastError(ERROR_INVALID_HANDLE);
2478 return FALSE;
2479 }
2480 pdcattr = dc->pdcattr;
2481 TextObj = RealizeFontInit(pdcattr->hlfntNew);
2482 if (NULL != TextObj)
2483 {
2484 FontGDI = ObjToGDI(TextObj->Font, FONT);
2485
2486 Face = FontGDI->face;
2487 IntLockFreeType;
2488 Error = FT_Set_Pixel_Sizes(Face,
2489 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2490 /* FIXME: Should set character height if neg */
2491 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2492 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2493 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
2494 IntUnLockFreeType;
2495 if (0 != Error)
2496 {
2497 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2498 Status = STATUS_UNSUCCESSFUL;
2499 }
2500 else
2501 {
2502 Status = STATUS_SUCCESS;
2503
2504 IntLockFreeType;
2505 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2506 if (NULL == pOS2)
2507 {
2508 DPRINT1("Can't find OS/2 table - not TT font?\n");
2509 Status = STATUS_INTERNAL_ERROR;
2510 }
2511
2512 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2513 if (NULL == pHori)
2514 {
2515 DPRINT1("Can't find HHEA table - not TT font?\n");
2516 Status = STATUS_INTERNAL_ERROR;
2517 }
2518
2519 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
2520
2521 IntUnLockFreeType;
2522
2523 if (NT_SUCCESS(Status))
2524 {
2525 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2526
2527 /* FIXME: Fill Diff member */
2528 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
2529 }
2530 }
2531 TEXTOBJ_UnlockText(TextObj);
2532 }
2533 else
2534 {
2535 Status = STATUS_INVALID_HANDLE;
2536 }
2537 DC_UnlockDc(dc);
2538
2539 if (!NT_SUCCESS(Status))
2540 {
2541 SetLastNtError(Status);
2542 return FALSE;
2543 }
2544 return TRUE;
2545 }
2546
2547
2548 DWORD
2549 FASTCALL
2550 ftGdiGetFontData(
2551 PFONTGDI FontGdi,
2552 DWORD Table,
2553 DWORD Offset,
2554 PVOID Buffer,
2555 DWORD Size)
2556 {
2557 DWORD Result = GDI_ERROR;
2558
2559 IntLockFreeType;
2560
2561 if (FT_IS_SFNT(FontGdi->face))
2562 {
2563 if (Table)
2564 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2565 (Table << 8 & 0xFF0000);
2566
2567 if (!Buffer) Size = 0;
2568
2569 if (Buffer && Size)
2570 {
2571 FT_Error Error;
2572 FT_ULong Needed = 0;
2573
2574 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
2575
2576 if ( !Error && Needed < Size) Size = Needed;
2577 }
2578 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2579 Result = Size;
2580 }
2581
2582 IntUnLockFreeType;
2583
2584 return Result;
2585 }
2586
2587 static UINT FASTCALL
2588 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2589 {
2590 ANSI_STRING EntryFaceNameA;
2591 UNICODE_STRING EntryFaceNameW;
2592 unsigned Size;
2593 OUTLINETEXTMETRICW *Otm;
2594 LONG WeightDiff;
2595 NTSTATUS Status;
2596 UINT Score = 1;
2597
2598 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2599 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2600 if (NT_SUCCESS(Status))
2601 {
2602 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2603 {
2604 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2605 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2606 }
2607 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2608 {
2609 Score += 49;
2610 }
2611 RtlFreeUnicodeString(&EntryFaceNameW);
2612 }
2613
2614 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2615 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2616 if (NULL == Otm)
2617 {
2618 return Score;
2619 }
2620 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2621
2622 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2623 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2624 {
2625 Score += 25;
2626 }
2627 if (LogFont->lfWeight != FW_DONTCARE)
2628 {
2629 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2630 {
2631 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2632 }
2633 else
2634 {
2635 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2636 }
2637 Score += (1000 - WeightDiff) / (1000 / 25);
2638 }
2639 else
2640 {
2641 Score += 25;
2642 }
2643
2644 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2645
2646 return Score;
2647 }
2648
2649 static __inline VOID
2650 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2651 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2652 {
2653 PLIST_ENTRY Entry;
2654 PFONT_ENTRY CurrentEntry;
2655 FONTGDI *FontGDI;
2656 UINT Score;
2657 ASSERT(FontObj && MatchScore && LogFont && FaceName && Head);
2658 Entry = Head->Flink;
2659 while (Entry != Head)
2660 {
2661 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2662
2663 FontGDI = CurrentEntry->Font;
2664 ASSERT(FontGDI);
2665
2666 Score = GetFontScore(LogFont, FaceName, FontGDI);
2667 if (*MatchScore == 0 || *MatchScore < Score)
2668 {
2669 *FontObj = GDIToObj(FontGDI, FONT);
2670 *MatchScore = Score;
2671 }
2672 Entry = Entry->Flink;
2673 }
2674 }
2675
2676 static __inline BOOLEAN
2677 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2678 LPCWSTR Key)
2679 {
2680 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2681 NTSTATUS Status;
2682 UNICODE_STRING Value;
2683
2684 RtlInitUnicodeString(&Value, NULL);
2685
2686 QueryTable[0].QueryRoutine = NULL;
2687 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2688 RTL_QUERY_REGISTRY_REQUIRED;
2689 QueryTable[0].Name = FaceName->Buffer;
2690 QueryTable[0].EntryContext = &Value;
2691 QueryTable[0].DefaultType = REG_NONE;
2692 QueryTable[0].DefaultData = NULL;
2693 QueryTable[0].DefaultLength = 0;
2694
2695 QueryTable[1].QueryRoutine = NULL;
2696 QueryTable[1].Name = NULL;
2697
2698 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2699 Key,
2700 QueryTable,
2701 NULL,
2702 NULL);
2703 if (NT_SUCCESS(Status))
2704 {
2705 RtlFreeUnicodeString(FaceName);
2706 *FaceName = Value;
2707 }
2708
2709 return NT_SUCCESS(Status);
2710 }
2711
2712 static __inline void
2713 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2714 {
2715 if (10 < Level) /* Enough is enough */
2716 {
2717 return;
2718 }
2719
2720 if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2721 {
2722 SubstituteFontFamily(FaceName, Level + 1);
2723 }
2724 }
2725
2726 static
2727 VOID
2728 FASTCALL
2729 IntFontType(PFONTGDI Font)
2730 {
2731 PS_FontInfoRec psfInfo;
2732 FT_ULong tmp_size = 0;
2733
2734 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2735 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2736 if (FT_HAS_VERTICAL( Font->face ))
2737 Font->FontObj.flFontType |= FO_VERT_FACE;
2738 if (FT_IS_SCALABLE( Font->face ))
2739 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2740 if (FT_IS_SFNT(Font->face))
2741 {
2742 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2743 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2744 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2745 }
2746 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2747 {
2748 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2749 }
2750 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
2751 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2752 {
2753 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2754 }
2755 }
2756
2757 NTSTATUS
2758 FASTCALL
2759 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2760 {
2761 NTSTATUS Status = STATUS_SUCCESS;
2762 PTEXTOBJ TextObj;
2763 UNICODE_STRING FaceName;
2764 PPROCESSINFO Win32Process;
2765 UINT MatchScore;
2766
2767 if (!pTextObj)
2768 {
2769 TextObj = TEXTOBJ_LockText(FontHandle);
2770 if (NULL == TextObj)
2771 {
2772 return STATUS_INVALID_HANDLE;
2773 }
2774
2775 if (TextObj->fl & TEXTOBJECT_INIT)
2776 {
2777 TEXTOBJ_UnlockText(TextObj);
2778 return STATUS_SUCCESS;
2779 }
2780 }
2781 else
2782 TextObj = pTextObj;
2783
2784 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2785 {
2786 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2787 return STATUS_NO_MEMORY;
2788 }
2789 SubstituteFontFamily(&FaceName, 0);
2790 MatchScore = 0;
2791 TextObj->Font = NULL;
2792
2793 /* First search private fonts */
2794 Win32Process = PsGetCurrentProcessWin32Process();
2795 IntLockProcessPrivateFonts(Win32Process);
2796 FindBestFontFromList(&TextObj->Font, &MatchScore,
2797 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2798 &Win32Process->PrivateFontListHead);
2799 IntUnLockProcessPrivateFonts(Win32Process);
2800
2801 /* Search system fonts */
2802 IntLockGlobalFonts;
2803 FindBestFontFromList(&TextObj->Font, &MatchScore,
2804 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2805 &FontListHead);
2806 IntUnLockGlobalFonts;
2807 if (NULL == TextObj->Font)
2808 {
2809 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2810 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2811 Status = STATUS_NOT_FOUND;
2812 }
2813 else
2814 {
2815 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2816 // Need hdev, when freetype is loaded need to create DEVOBJ for
2817 // Consumer and Producer.
2818 TextObj->Font->iUniq = 1; // Now it can be cached.
2819 IntFontType(FontGdi);
2820 FontGdi->flType = TextObj->Font->flFontType;
2821 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2822 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2823 TextObj->fl |= TEXTOBJECT_INIT;
2824 Status = STATUS_SUCCESS;
2825 }
2826
2827 RtlFreeUnicodeString(&FaceName);
2828 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2829
2830 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2831
2832 return Status;
2833 }
2834
2835
2836 static
2837 BOOL
2838 FASTCALL
2839 IntGetFullFileName(
2840 POBJECT_NAME_INFORMATION NameInfo,
2841 ULONG Size,
2842 PUNICODE_STRING FileName)
2843 {
2844 NTSTATUS Status;
2845 OBJECT_ATTRIBUTES ObjectAttributes;
2846 HANDLE hFile;
2847 IO_STATUS_BLOCK IoStatusBlock;
2848 ULONG Desired;
2849
2850 InitializeObjectAttributes(&ObjectAttributes,
2851 FileName,
2852 OBJ_CASE_INSENSITIVE,
2853 NULL,
2854 NULL);
2855
2856 Status = ZwOpenFile(
2857 &hFile,
2858 0, // FILE_READ_ATTRIBUTES,
2859 &ObjectAttributes,
2860 &IoStatusBlock,
2861 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2862 0);
2863
2864 if (!NT_SUCCESS(Status))
2865 {
2866 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2867 return FALSE;
2868 }
2869
2870 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2871 ZwClose(hFile);
2872 if (!NT_SUCCESS(Status))
2873 {
2874 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2875 return FALSE;
2876 }
2877
2878 return TRUE;
2879 }
2880
2881 BOOL
2882 FASTCALL
2883 IntGdiGetFontResourceInfo(
2884 PUNICODE_STRING FileName,
2885 PVOID pBuffer,
2886 DWORD *pdwBytes,
2887 DWORD dwType)
2888 {
2889 UNICODE_STRING EntryFileName;
2890 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2891 PLIST_ENTRY ListEntry;
2892 PFONT_ENTRY FontEntry;
2893 FONTFAMILYINFO Info;
2894 ULONG Size;
2895 BOOL bFound = FALSE;
2896
2897 /* Create buffer for full path name */
2898 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2899 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2900 if (!NameInfo1)
2901 {
2902 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2903 return FALSE;
2904 }
2905
2906 /* Get the full path name */
2907 if (!IntGetFullFileName(NameInfo1, Size, FileName))
2908 {
2909 ExFreePoolWithTag(NameInfo1, TAG_FINF);
2910 return FALSE;
2911 }
2912
2913 /* Create a buffer for the entries' names */
2914 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2915 if (!NameInfo2)
2916 {
2917 ExFreePoolWithTag(NameInfo1, TAG_FINF);
2918 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2919 return FALSE;
2920 }
2921
2922 /* Try to find the pathname in the global font list */
2923 IntLockGlobalFonts;
2924 for (ListEntry = FontListHead.Flink;
2925 ListEntry != &FontListHead;
2926 ListEntry = ListEntry->Flink)
2927 {
2928 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
2929 if (FontEntry->Font->Filename != NULL)
2930 {
2931 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
2932 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
2933 {
2934 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
2935 {
2936 /* Found */
2937 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
2938 bFound = TRUE;
2939 break;
2940 }
2941 }
2942 }
2943 }
2944 IntUnLockGlobalFonts;
2945
2946 /* Free the buffers */
2947 ExFreePoolWithTag(NameInfo1, TAG_FINF);
2948 ExFreePool(NameInfo2);
2949
2950 if (!bFound && dwType != 5)
2951 {
2952 /* Font could not be found in system table
2953 dwType == 5 will still handle this */
2954 return FALSE;
2955 }
2956
2957 switch (dwType)
2958 {
2959 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
2960 *(DWORD*)pBuffer = 1;
2961 *pdwBytes = sizeof(DWORD);
2962 break;
2963
2964 case 1: /* Copy the full font name */
2965 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
2966 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
2967 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
2968 // FIXME: Do we have to zeroterminate?
2969 *pdwBytes = Size;
2970 break;
2971
2972 case 2: /* Copy a LOGFONTW structure */
2973 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
2974 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
2975 *pdwBytes = sizeof(LOGFONTW);
2976 break;
2977
2978 case 3: /* FIXME: What exactly is copied here? */
2979 *(DWORD*)pBuffer = 1;
2980 *pdwBytes = sizeof(DWORD*);
2981 break;
2982
2983 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
2984 *(BOOL*)pBuffer = !bFound;
2985 *pdwBytes = sizeof(BOOL);
2986 break;
2987
2988 default:
2989 return FALSE;
2990 }
2991
2992 return TRUE;
2993 }
2994
2995
2996 BOOL
2997 FASTCALL
2998 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
2999 {
3000 if (FT_HAS_FIXED_SIZES(Font->face))
3001 Info->iTechnology = RI_TECH_BITMAP;
3002 else
3003 {
3004 if (FT_IS_SCALABLE(Font->face))
3005 Info->iTechnology = RI_TECH_SCALABLE;
3006 else
3007 Info->iTechnology = RI_TECH_FIXED;
3008 }
3009 Info->iUniq = Font->FontObj.iUniq;
3010 Info->dwUnknown = -1;
3011 return TRUE;
3012 }
3013
3014
3015 DWORD
3016 FASTCALL
3017 ftGdiGetKerningPairs( PFONTGDI Font,
3018 DWORD cPairs,
3019 LPKERNINGPAIR pKerningPair)
3020 {
3021 DWORD Count = 0;
3022 INT i = 0;
3023 FT_Face face = Font->face;
3024
3025 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
3026 {
3027 FT_UInt previous_index = 0, glyph_index = 0;
3028 FT_ULong char_code, char_previous;
3029 FT_Vector delta;
3030
3031 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
3032
3033 IntLockFreeType;
3034
3035 while (glyph_index)
3036 {
3037 if (previous_index && glyph_index)
3038 {
3039 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
3040
3041 if (pKerningPair && cPairs)
3042 {
3043 pKerningPair[i].wFirst = char_previous;
3044 pKerningPair[i].wSecond = char_code;
3045 pKerningPair[i].iKernAmount = delta.x;
3046 i++;
3047 if (i == cPairs) break;
3048 }
3049 Count++;
3050 }
3051 previous_index = glyph_index;
3052 char_previous = char_code;
3053 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
3054 }
3055 IntUnLockFreeType;
3056 }
3057 return Count;
3058 }
3059
3060
3061 ///////////////////////////////////////////////////////////////////////////
3062 //
3063 // Functions needing sorting.
3064 //
3065 ///////////////////////////////////////////////////////////////////////////
3066 int APIENTRY
3067 NtGdiGetFontFamilyInfo(HDC Dc,
3068 LPLOGFONTW UnsafeLogFont,
3069 PFONTFAMILYINFO UnsafeInfo,
3070 DWORD Size)
3071 {
3072 NTSTATUS Status;
3073 LOGFONTW LogFont;
3074 PFONTFAMILYINFO Info;
3075 DWORD Count;
3076 PPROCESSINFO Win32Process;
3077
3078 /* Make a safe copy */
3079 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
3080 if (! NT_SUCCESS(Status))
3081 {
3082 EngSetLastError(ERROR_INVALID_PARAMETER);
3083 return -1;
3084 }
3085
3086 /* Allocate space for a safe copy */
3087 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
3088 if (NULL == Info)
3089 {
3090 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3091 return -1;
3092 }
3093
3094 /* Enumerate font families in the global list */
3095 IntLockGlobalFonts;
3096 Count = 0;
3097 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
3098 {
3099 IntUnLockGlobalFonts;
3100 ExFreePoolWithTag(Info, GDITAG_TEXT);
3101 return -1;
3102 }
3103 IntUnLockGlobalFonts;
3104
3105 /* Enumerate font families in the process local list */
3106 Win32Process = PsGetCurrentProcessWin32Process();
3107 IntLockProcessPrivateFonts(Win32Process);
3108 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
3109 &Win32Process->PrivateFontListHead))
3110 {
3111 IntUnLockProcessPrivateFonts(Win32Process);
3112 ExFreePoolWithTag(Info, GDITAG_TEXT);
3113 return -1;
3114 }
3115 IntUnLockProcessPrivateFonts(Win32Process);
3116
3117 /* Enumerate font families in the registry */
3118 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
3119 {
3120 ExFreePoolWithTag(Info, GDITAG_TEXT);
3121 return -1;
3122 }
3123
3124 /* Return data to caller */
3125 if (0 != Count)
3126 {
3127 Status = MmCopyToCaller(UnsafeInfo, Info,
3128 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
3129 if (! NT_SUCCESS(Status))
3130 {
3131 ExFreePoolWithTag(Info, GDITAG_TEXT);
3132 EngSetLastError(ERROR_INVALID_PARAMETER);
3133 return -1;
3134 }
3135 }
3136
3137 ExFreePoolWithTag(Info, GDITAG_TEXT);
3138
3139 return Count;
3140 }
3141
3142 LONG
3143 FORCEINLINE
3144 ScaleLong(LONG lValue, PFLOATOBJ pef)
3145 {
3146 FLOATOBJ efTemp;
3147
3148 /* Check if we have scaling different from 1 */
3149 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
3150 {
3151 /* Need to multiply */
3152 FLOATOBJ_SetLong(&efTemp, lValue);
3153 FLOATOBJ_Mul(&efTemp, pef);
3154 lValue = FLOATOBJ_GetLong(&efTemp);
3155 }
3156
3157 return lValue;
3158 }
3159
3160 BOOL
3161 APIENTRY
3162 GreExtTextOutW(
3163 IN HDC hDC,
3164 IN INT XStart,
3165 IN INT YStart,
3166 IN UINT fuOptions,
3167 IN OPTIONAL PRECTL lprc,
3168 IN LPWSTR String,
3169 IN INT Count,
3170 IN OPTIONAL LPINT Dx,
3171 IN DWORD dwCodePage)
3172 {
3173 /*
3174 * FIXME:
3175 * Call EngTextOut, which does the real work (calling DrvTextOut where
3176 * appropriate)
3177 */
3178
3179 DC *dc;
3180 PDC_ATTR pdcattr;
3181 SURFOBJ *SurfObj;
3182 SURFACE *psurf = NULL;
3183 int error, glyph_index, n, i;
3184 FT_Face face;
3185 FT_GlyphSlot glyph;
3186 FT_BitmapGlyph realglyph;
3187 LONGLONG TextLeft, RealXStart;
3188 ULONG TextTop, previous, BackgroundLeft;
3189 FT_Bool use_kerning;
3190 RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
3191 POINTL SourcePoint, BrushOrigin;
3192 HBITMAP HSourceGlyph;
3193 SURFOBJ *SourceGlyphSurf;
3194 SIZEL bitSize;
3195 FT_CharMap found = 0, charmap;
3196 INT yoff;
3197 FONTOBJ *FontObj;
3198 PFONTGDI FontGDI;
3199 PTEXTOBJ TextObj = NULL;
3200 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
3201 FT_Render_Mode RenderMode;
3202 BOOLEAN Render;
3203 POINT Start;
3204 BOOL DoBreak = FALSE;
3205 USHORT DxShift;
3206 PMATRIX pmxWorldToDevice;
3207 LONG fixAscender, fixDescender;
3208
3209 // TODO: Write test-cases to exactly match real Windows in different
3210 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3211 dc = DC_LockDc(hDC);
3212 if (!dc)
3213 {
3214 EngSetLastError(ERROR_INVALID_HANDLE);
3215 return FALSE;
3216 }
3217 if (dc->dctype == DC_TYPE_INFO)
3218 {
3219 DC_UnlockDc(dc);
3220 /* Yes, Windows really returns TRUE in this case */
3221 return TRUE;
3222 }
3223
3224 pdcattr = dc->pdcattr;
3225
3226 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
3227 {
3228 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3229 DC_vUpdateBackgroundBrush(dc);
3230 }
3231
3232 /* Check if String is valid */
3233 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3234 {
3235 EngSetLastError(ERROR_INVALID_PARAMETER);
3236 goto fail;
3237 }
3238
3239 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3240
3241 if (PATH_IsPathOpen(dc->dclevel))
3242 {
3243 if (!PATH_ExtTextOut( dc,
3244 XStart,
3245 YStart,
3246 fuOptions,
3247 (const RECTL *)lprc,
3248 String,
3249 Count,
3250 (const INT *)Dx)) goto fail;
3251 goto good;
3252 }
3253
3254 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3255 {
3256 IntLPtoDP(dc, (POINT *)lprc, 2);
3257 }
3258
3259 Start.x = XStart;
3260 Start.y = YStart;
3261 IntLPtoDP(dc, &Start, 1);
3262
3263 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3264 YStart = Start.y + dc->ptlDCOrig.y;
3265
3266 SourcePoint.x = 0;
3267 SourcePoint.y = 0;
3268 MaskRect.left = 0;
3269 MaskRect.top = 0;
3270 BrushOrigin.x = 0;
3271 BrushOrigin.y = 0;
3272
3273 if ((fuOptions & ETO_OPAQUE) && lprc)
3274 {
3275 DestRect.left = lprc->left;
3276 DestRect.top = lprc->top;
3277 DestRect.right = lprc->right;
3278 DestRect.bottom = lprc->bottom;
3279
3280 DestRect.left += dc->ptlDCOrig.x;
3281 DestRect.top += dc->ptlDCOrig.y;
3282 DestRect.right += dc->ptlDCOrig.x;
3283 DestRect.bottom += dc->ptlDCOrig.y;
3284
3285 DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
3286
3287 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3288 DC_vUpdateBackgroundBrush(dc);
3289
3290 IntEngBitBlt(
3291 &dc->dclevel.pSurface->SurfObj,
3292 NULL,
3293 NULL,
3294 dc->rosdc.CombinedClip,
3295 NULL,
3296 &DestRect,
3297 &SourcePoint,
3298 &SourcePoint,
3299 &dc->eboBackground.BrushObject,
3300 &BrushOrigin,
3301 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3302 fuOptions &= ~ETO_OPAQUE;
3303 DC_vFinishBlit(dc, NULL);
3304 }
3305 else
3306 {
3307 if (pdcattr->jBkMode == OPAQUE)
3308 {
3309 fuOptions |= ETO_OPAQUE;
3310 }
3311 }
3312
3313 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3314 if (TextObj == NULL)
3315 {
3316 goto fail;
3317 }
3318
3319 FontObj = TextObj->Font;
3320 ASSERT(FontObj);
3321 FontGDI = ObjToGDI(FontObj, FONT);
3322 ASSERT(FontGDI);
3323
3324 IntLockFreeType;
3325 face = FontGDI->face;
3326 if (face->charmap == NULL)
3327 {
3328 DPRINT("WARNING: No charmap selected!\n");
3329 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3330
3331 for (n = 0; n < face->num_charmaps; n++)
3332 {
3333 charmap = face->charmaps[n];
3334 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
3335 if (charmap->encoding != 0)
3336 {
3337 found = charmap;
3338 break;
3339 }
3340 }
3341 if (!found)
3342 {
3343 DPRINT1("WARNING: Could not find desired charmap!\n");
3344 }
3345 error = FT_Set_Charmap(face, found);
3346 if (error)
3347 {
3348 DPRINT1("WARNING: Could not set the charmap!\n");
3349 }
3350 }
3351
3352 Render = IntIsFontRenderingEnabled();
3353 if (Render)
3354 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3355 else
3356 RenderMode = FT_RENDER_MODE_MONO;
3357
3358 error = FT_Set_Pixel_Sizes(
3359 face,
3360 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3361 /* FIXME: Should set character height if neg */
3362 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
3363 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
3364 if (error)
3365 {
3366 DPRINT1("Error in setting pixel sizes: %u\n", error);
3367 IntUnLockFreeType;
3368 goto fail;
3369 }
3370
3371 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3372 FtSetCoordinateTransform(face, pmxWorldToDevice);
3373
3374 /*
3375 * Process the vertical alignment and determine the yoff.
3376 */
3377
3378 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
3379 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
3380
3381 if (pdcattr->lTextAlign & TA_BASELINE)
3382 yoff = 0;
3383 else if (pdcattr->lTextAlign & TA_BOTTOM)
3384 yoff = -fixDescender >> 6;
3385 else /* TA_TOP */
3386 yoff = fixAscender >> 6;
3387
3388 use_kerning = FT_HAS_KERNING(face);
3389 previous = 0;
3390
3391 /*
3392 * Process the horizontal alignment and modify XStart accordingly.
3393 */
3394
3395 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
3396 {
3397 ULONGLONG TextWidth = 0;
3398 LPCWSTR TempText = String;
3399 int Start;
3400
3401 /*
3402 * Calculate width of the text.
3403 */
3404
3405 if (NULL != Dx)
3406 {
3407 Start = Count < 2 ? 0 : Count - 2;
3408 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3409 }
3410 else
3411 {
3412 Start = 0;
3413 }
3414 TempText = String + Start;
3415
3416 for (i = Start; i < Count; i++)
3417 {
3418 if (fuOptions & ETO_GLYPH_INDEX)
3419 glyph_index = *TempText;
3420 else
3421 glyph_index = FT_Get_Char_Index(face, *TempText);
3422
3423 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3424 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3425 pmxWorldToDevice)))
3426 {
3427 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3428 if (error)
3429 {
3430 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3431 }
3432
3433 glyph = face->glyph;
3434 realglyph = ftGdiGlyphCacheSet(face,
3435 glyph_index,
3436 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3437 pmxWorldToDevice,
3438 glyph,
3439 RenderMode);
3440 if (!realglyph)
3441 {
3442 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3443 IntUnLockFreeType;
3444 goto fail;
3445 }
3446
3447 }
3448 /* Retrieve kerning distance */
3449 if (use_kerning && previous && glyph_index)
3450 {
3451 FT_Vector delta;
3452 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3453 TextWidth += delta.x;
3454 }
3455
3456 TextWidth += realglyph->root.advance.x >> 10;
3457
3458 previous = glyph_index;
3459 TempText++;
3460 }
3461
3462 previous = 0;
3463
3464 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
3465 {
3466 RealXStart -= TextWidth / 2;
3467 }
3468 else
3469 {
3470 RealXStart -= TextWidth;
3471 }
3472 }
3473
3474 TextLeft = RealXStart;
3475 TextTop = YStart;
3476 BackgroundLeft = (RealXStart + 32) >> 6;
3477
3478 /* Lock blit with a dummy rect */
3479 DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
3480
3481 psurf = dc->dclevel.pSurface ;
3482 if(!psurf) psurf = psurfDefaultBitmap;
3483 SurfObj = &psurf->SurfObj ;
3484
3485 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
3486 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
3487
3488 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
3489 DC_vUpdateBackgroundBrush(dc) ;
3490
3491 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
3492 DC_vUpdateTextBrush(dc) ;
3493
3494 /*
3495 * The main rendering loop.
3496 */
3497 for (i = 0; i < Count; i++)
3498 {
3499 if (fuOptions & ETO_GLYPH_INDEX)
3500 glyph_index = *String;
3501 else
3502 glyph_index = FT_Get_Char_Index(face, *String);
3503
3504 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3505 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3506 pmxWorldToDevice)))
3507 {
3508 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3509 if (error)
3510 {
3511 DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
3512 IntUnLockFreeType;
3513 goto fail2;
3514 }
3515 glyph = face->glyph;
3516 realglyph = ftGdiGlyphCacheSet(face,
3517 glyph_index,
3518 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3519 pmxWorldToDevice,
3520 glyph,
3521 RenderMode);
3522 if (!realglyph)
3523 {
3524 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3525 IntUnLockFreeType;
3526 goto fail2;
3527 }
3528 }
3529
3530 /* retrieve kerning distance and move pen position */
3531 if (use_kerning && previous && glyph_index && NULL == Dx)
3532 {
3533 FT_Vector delta;
3534 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3535 TextLeft += delta.x;
3536 }
3537 DPRINT("TextLeft: %d\n", TextLeft);
3538 DPRINT("TextTop: %d\n", TextTop);
3539 DPRINT("Advance: %d\n", realglyph->root.advance.x);
3540
3541 if (fuOptions & ETO_OPAQUE)
3542 {
3543 DestRect.left = BackgroundLeft;
3544 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
3545 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
3546 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
3547 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3548 IntEngBitBlt(
3549 &psurf->SurfObj,
3550 NULL,
3551 NULL,
3552 dc->rosdc.CombinedClip,
3553 NULL,
3554 &DestRect,
3555 &SourcePoint,
3556 &SourcePoint,
3557 &dc->eboBackground.BrushObject,
3558 &BrushOrigin,
3559 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3560 MouseSafetyOnDrawEnd(dc->ppdev);
3561 BackgroundLeft = DestRect.right;
3562
3563 }
3564
3565 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
3566 DestRect.right = DestRect.left + realglyph->bitmap.width;
3567 DestRect.top = TextTop + yoff - realglyph->top;
3568 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
3569
3570 bitSize.cx = realglyph->bitmap.width;
3571 bitSize.cy = realglyph->bitmap.rows;
3572 MaskRect.right = realglyph->bitmap.width;
3573 MaskRect.bottom = realglyph->bitmap.rows;
3574
3575 /*
3576 * We should create the bitmap out of the loop at the biggest possible
3577 * glyph size. Then use memset with 0 to clear it and sourcerect to
3578 * limit the work of the transbitblt.
3579 */
3580
3581 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
3582 BMF_8BPP, BMF_TOPDOWN,
3583 realglyph->bitmap.buffer);
3584 if ( !HSourceGlyph )
3585 {
3586 DPRINT1("WARNING: EngLockSurface() failed!\n");
3587 // FT_Done_Glyph(realglyph);
3588 IntUnLockFreeType;
3589 goto fail2;
3590 }
3591 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
3592 if ( !SourceGlyphSurf )
3593 {
3594 EngDeleteSurface((HSURF)HSourceGlyph);
3595 DPRINT1("WARNING: EngLockSurface() failed!\n");
3596 IntUnLockFreeType;
3597 goto fail2;
3598 }
3599
3600 /*
3601 * Use the font data as a mask to paint onto the DCs surface using a
3602 * brush.
3603 */
3604
3605 if (lprc && (fuOptions & ETO_CLIPPED) &&
3606 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
3607 {
3608 // We do the check '>=' instead of '>' to possibly save an iteration
3609 // through this loop, since it's breaking after the drawing is done,
3610 // and x is always incremented.
3611 DestRect.right = lprc->right + dc->ptlDCOrig.x;
3612 DoBreak = TRUE;
3613 }
3614 if (lprc && (fuOptions & ETO_CLIPPED) &&
3615 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
3616 {
3617 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
3618 }
3619 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3620 IntEngMaskBlt(
3621 SurfObj,
3622 SourceGlyphSurf,
3623 dc->rosdc.CombinedClip,
3624 &exloRGB2Dst.xlo,
3625 &exloDst2RGB.xlo,
3626 &DestRect,
3627 (PPOINTL)&MaskRect,
3628 &dc->eboText.BrushObject,
3629 &BrushOrigin);
3630 MouseSafetyOnDrawEnd(dc->ppdev) ;
3631
3632 EngUnlockSurface(SourceGlyphSurf);
3633 EngDeleteSurface((HSURF)HSourceGlyph);
3634
3635 if (DoBreak)
3636 {
3637 break;
3638 }
3639
3640 if (NULL == Dx)
3641 {
3642 TextLeft += realglyph->root.advance.x >> 10;
3643 DPRINT("New TextLeft: %d\n", TextLeft);
3644 }
3645 else
3646 {
3647 TextLeft += Dx[i<<DxShift] << 6;
3648 DPRINT("New TextLeft2: %d\n", TextLeft);
3649 }
3650
3651 if (DxShift)
3652 {
3653 TextTop -= Dx[2 * i + 1] << 6;
3654 }
3655
3656 previous = glyph_index;
3657
3658 String++;
3659 }
3660 IntUnLockFreeType;
3661
3662 DC_vFinishBlit(dc, NULL) ;
3663 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3664 EXLATEOBJ_vCleanup(&exloDst2RGB);
3665 if (TextObj != NULL)
3666 TEXTOBJ_UnlockText(TextObj);
3667 good:
3668 DC_UnlockDc( dc );
3669
3670 return TRUE;
3671
3672 fail2:
3673 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3674 EXLATEOBJ_vCleanup(&exloDst2RGB);
3675 fail:
3676 if (TextObj != NULL)
3677 TEXTOBJ_UnlockText(TextObj);
3678
3679 DC_UnlockDc(dc);
3680
3681 return FALSE;
3682 }
3683
3684 #define STACK_TEXT_BUFFER_SIZE 100
3685 BOOL