- Minor correction of NtGdiExtTextOut.
[reactos.git] / reactos / subsys / win32k / objects / text.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: text.c,v 1.76 2004/02/21 21:15:22 navaraf Exp $ */
20
21
22 #undef WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #include <ddk/ntddk.h>
25 #include <napi/win32.h>
26 #include <internal/safe.h>
27 #include <win32k/brush.h>
28 #include <win32k/dc.h>
29 #include <win32k/text.h>
30 #include <win32k/kapi.h>
31 #include <include/error.h>
32 #include <include/desktop.h>
33 #include <ft2build.h>
34 #include FT_FREETYPE_H
35 #include <freetype/tttables.h>
36
37 #include "../eng/handle.h"
38
39 #include <include/inteng.h>
40 #include <include/text.h>
41 #include <include/eng.h>
42 #include <include/palette.h>
43 #include <include/tags.h>
44
45 #define NDEBUG
46 #include <win32k/debug1.h>
47
48 FT_Library library;
49
50 typedef struct _FONT_ENTRY {
51 LIST_ENTRY ListEntry;
52 HFONT hFont;
53 UNICODE_STRING FaceName;
54 BYTE NotEnum;
55 } FONT_ENTRY, *PFONT_ENTRY;
56
57 /* The FreeType library is not thread safe, so we have
58 to serialize access to it */
59 static FAST_MUTEX FreeTypeLock;
60
61 static LIST_ENTRY FontListHead;
62 static FAST_MUTEX FontListLock;
63 static INT FontsLoaded = 0; /* number of all fonts loaded (including private fonts */
64 static BOOL RenderingEnabled = TRUE;
65
66 BOOL FASTCALL
67 IntIsFontRenderingEnabled(VOID)
68 {
69 BOOL Ret;
70 HDC hDC;
71 PDC dc;
72 PSURFOBJ SurfObj;
73 Ret = RenderingEnabled;
74 hDC = IntGetScreenDC();
75 if(hDC)
76 {
77 dc = DC_LockDc(hDC);
78 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
79 if(SurfObj)
80 Ret = (SurfObj->iBitmapFormat >= BMF_8BPP);
81 DC_UnlockDc(hDC);
82 }
83 return Ret;
84 }
85
86 VOID FASTCALL
87 IntEnableFontRendering(BOOL Enable)
88 {
89 RenderingEnabled = Enable;
90 }
91
92 FT_Render_Mode FASTCALL
93 IntGetFontRenderMode(LOGFONTW *logfont)
94 {
95 switch(logfont->lfQuality)
96 {
97 //case ANTIALIASED_QUALITY:
98 case DEFAULT_QUALITY:
99 return FT_RENDER_MODE_NORMAL;
100 case DRAFT_QUALITY:
101 return FT_RENDER_MODE_LIGHT;
102 //case NONANTIALIASED_QUALITY:
103 case PROOF_QUALITY:
104 return FT_RENDER_MODE_MONO;
105 //case CLEARTYPE_QUALITY:
106 // return FT_RENDER_MODE_LCD;
107 }
108 return FT_RENDER_MODE_MONO;
109 }
110
111 int FASTCALL
112 IntGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
113 {
114 HFONT NewFont;
115 PFONTOBJ FontObj;
116 PFONTGDI FontGDI;
117 NTSTATUS Status;
118 HANDLE FileHandle;
119 OBJECT_ATTRIBUTES ObjectAttributes;
120 FILE_STANDARD_INFORMATION FileStdInfo;
121 PVOID buffer;
122 ULONG size;
123 INT error;
124 FT_Face face;
125 ANSI_STRING StringA;
126 IO_STATUS_BLOCK Iosb;
127 PFONT_ENTRY entry;
128
129 NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
130 FontObj = (PFONTOBJ) AccessUserObject( (ULONG) NewFont );
131 FontGDI = (PFONTGDI) AccessInternalObject( (ULONG) NewFont );
132
133 // Open the Module
134 InitializeObjectAttributes(&ObjectAttributes, Filename, 0, NULL, NULL);
135
136 Status = ZwOpenFile(&FileHandle,
137 GENERIC_READ|SYNCHRONIZE,
138 &ObjectAttributes,
139 &Iosb,
140 0, //ShareAccess
141 FILE_SYNCHRONOUS_IO_NONALERT);
142
143 if (!NT_SUCCESS(Status))
144 {
145 DPRINT1("Could not open module file: %wZ\n", Filename);
146 return 0;
147 }
148
149 // Get the size of the file
150 Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT1("Could not get file size\n");
154 return 0;
155 }
156
157 // Allocate nonpageable memory for driver
158 size = FileStdInfo.EndOfFile.u.LowPart;
159 buffer = ExAllocatePoolWithTag(NonPagedPool, size, TAG_GDITEXT);
160
161 if (buffer == NULL)
162 {
163 DPRINT1("could not allocate memory for module");
164 return 0;
165 }
166
167 // Load driver into memory chunk
168 Status = ZwReadFile(FileHandle,
169 NULL,
170 NULL,
171 NULL,
172 &Iosb,
173 buffer,
174 FileStdInfo.EndOfFile.u.LowPart,
175 NULL,
176 NULL);
177
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("could not read module file into memory");
181 ExFreePool(buffer);
182 return 0;
183 }
184
185 ZwClose(FileHandle);
186
187 ExAcquireFastMutex(&FreeTypeLock);
188 error = FT_New_Memory_Face(library, buffer, size, 0, &face);
189 ExReleaseFastMutex(&FreeTypeLock);
190 if (error == FT_Err_Unknown_File_Format)
191 {
192 DPRINT1("Unknown font file format\n");
193 return 0;
194 }
195 else if (error)
196 {
197 DPRINT1("Error reading font file (error code: %u)\n", error); // 48
198 return 0;
199 }
200
201 entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(FONT_ENTRY), TAG_FONT);
202 if(!entry)
203 {
204 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
205 return 0;
206 }
207
208 // FontGDI->Filename = Filename; perform strcpy
209 FontGDI->face = face;
210
211 // FIXME: Complete text metrics
212 FontGDI->TextMetric.tmAscent = (face->size->metrics.ascender + 32) / 64; // units above baseline
213 FontGDI->TextMetric.tmDescent = (- face->size->metrics.descender + 32) / 64; // units below baseline
214 FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
215
216 DPRINT("Font loaded: %s (%s)\n", face->family_name, face->style_name);
217 DPRINT("Num glyphs: %u\n", face->num_glyphs);
218
219 // Add this font resource to the font table
220 entry->hFont = NewFont;
221 entry->NotEnum = (fl & FR_NOT_ENUM);
222 RtlInitAnsiString(&StringA, (LPSTR)face->family_name);
223 RtlAnsiStringToUnicodeString(&entry->FaceName, &StringA, TRUE);
224
225 if(fl & FR_PRIVATE)
226 {
227 PW32PROCESS Win32Process = PsGetWin32Process();
228
229 ExAcquireFastMutex(&Win32Process->PrivateFontListLock);
230 InsertTailList(&Win32Process->PrivateFontListHead, &entry->ListEntry);
231 FontsLoaded++;
232 ExReleaseFastMutex(&Win32Process->PrivateFontListLock);
233 }
234 else
235 {
236 ExAcquireFastMutex(&FontListLock);
237 InsertTailList(&FontListHead, &entry->ListEntry);
238 FontsLoaded++;
239 ExReleaseFastMutex(&FontListLock);
240 }
241
242 return 1;
243 }
244
245 BOOL FASTCALL InitFontSupport(VOID)
246 {
247 ULONG ulError;
248 UNICODE_STRING cchDir, cchFilename, cchSearchPattern ;
249 OBJECT_ATTRIBUTES obAttr;
250 IO_STATUS_BLOCK Iosb;
251 HANDLE hDirectory;
252 NTSTATUS Status;
253 PFILE_DIRECTORY_INFORMATION iFileData;
254 PVOID pBuff;
255 BOOLEAN bRestartScan = TRUE;
256
257 InitializeListHead(&FontListHead);
258 ExInitializeFastMutex(&FontListLock);
259 ExInitializeFastMutex(&FreeTypeLock);
260
261 ulError = FT_Init_FreeType(&library);
262
263 if(!ulError)
264 {
265 RtlInitUnicodeString(&cchDir, L"\\SystemRoot\\Media\\Fonts\\");
266
267 RtlInitUnicodeString(&cchSearchPattern,L"*.ttf");
268 InitializeObjectAttributes( &obAttr,
269 &cchDir,
270 OBJ_CASE_INSENSITIVE,
271 NULL,
272 NULL );
273
274 Status = ZwOpenFile( &hDirectory,
275 SYNCHRONIZE | FILE_LIST_DIRECTORY,
276 &obAttr,
277 &Iosb,
278 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
279 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE );
280 if( NT_SUCCESS(Status) )
281 {
282 while(1)
283 {
284 iFileData = NULL;
285 pBuff = ExAllocatePool(NonPagedPool,0x4000);
286 RtlInitUnicodeString(&cchFilename,0);
287 cchFilename.MaximumLength = 0x1000;
288 cchFilename.Buffer = ExAllocatePoolWithTag(PagedPool,cchFilename.MaximumLength, TAG_STRING);
289
290 cchFilename.Length = 0;
291
292 Status = NtQueryDirectoryFile( hDirectory,
293 NULL,
294 NULL,
295 NULL,
296 &Iosb,
297 pBuff,
298 0x4000,
299 FileDirectoryInformation,
300 TRUE,
301 &cchSearchPattern,
302 bRestartScan );
303
304 iFileData = (PFILE_DIRECTORY_INFORMATION)pBuff;
305
306 RtlAppendUnicodeToString(&cchFilename, cchDir.Buffer);
307 RtlAppendUnicodeToString(&cchFilename, iFileData->FileName);
308 RtlAppendUnicodeToString(&cchFilename, L"\0");
309
310 if( !NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES )
311 break;
312
313 IntGdiAddFontResource(&cchFilename, 0);
314 ExFreePool(pBuff);
315 ExFreePool(cchFilename.Buffer);
316 bRestartScan = FALSE;
317 }
318 ExFreePool(cchFilename.Buffer);
319 ExFreePool(pBuff);
320 ZwClose(hDirectory);
321
322 return TRUE;
323 }
324 }
325 ZwClose(hDirectory);
326 return FALSE;
327 }
328
329 static NTSTATUS STDCALL
330 GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj, PFONTGDI *FontGDI)
331 {
332 NTSTATUS Status = STATUS_SUCCESS;
333
334 ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
335 if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
336 {
337 if (NT_SUCCESS(Status) && NULL != FontHandle)
338 {
339 *FontHandle = TextObj->GDIFontHandle;
340 }
341 if (NT_SUCCESS(Status) && NULL != FontObj)
342 {
343 *FontObj = AccessUserObject((ULONG) TextObj->GDIFontHandle);
344 if (NULL == *FontObj)
345 {
346 ASSERT(FALSE);
347 Status = STATUS_INVALID_HANDLE;
348 }
349 }
350 if (NT_SUCCESS(Status) && NULL != FontGDI)
351 {
352 *FontGDI = AccessInternalObject((ULONG) TextObj->GDIFontHandle);
353 if (NULL == *FontGDI)
354 {
355 ASSERT(FALSE);
356 Status = STATUS_INVALID_HANDLE;
357 }
358 }
359 }
360 else
361 {
362 Status = STATUS_INVALID_HANDLE;
363 }
364
365 return Status;
366 }
367
368 int
369 STDCALL
370 NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
371 {
372 UNICODE_STRING SafeFileName;
373 PWSTR src;
374 NTSTATUS Status;
375 int Ret;
376
377 /* Copy the UNICODE_STRING structure */
378 Status = MmCopyFromCaller(&SafeFileName, Filename, sizeof(UNICODE_STRING));
379 if(!NT_SUCCESS(Status))
380 {
381 SetLastNtError(Status);
382 return 0;
383 }
384
385 src = SafeFileName.Buffer;
386 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
387 if(!SafeFileName.Buffer)
388 {
389 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
390 return 0;
391 }
392
393 Status = MmCopyFromCaller(&SafeFileName.Buffer, src, SafeFileName.MaximumLength);
394 if(!NT_SUCCESS(Status))
395 {
396 ExFreePool(SafeFileName.Buffer);
397 SetLastNtError(Status);
398 return 0;
399 }
400
401 Ret = IntGdiAddFontResource(&SafeFileName, fl);
402
403 ExFreePool(SafeFileName.Buffer);
404 return Ret;
405 }
406
407 NTSTATUS FASTCALL
408 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
409 {
410 PTEXTOBJ TextObj;
411 NTSTATUS Status = STATUS_SUCCESS;
412
413 *NewFont = TEXTOBJ_AllocText();
414 if (NULL != *NewFont)
415 {
416 TextObj = TEXTOBJ_LockText(*NewFont);
417 if (NULL != TextObj)
418 {
419 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
420 if (lf->lfEscapement != lf->lfOrientation)
421 {
422 /* this should really depend on whether GM_ADVANCED is set */
423 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
424 }
425 TEXTOBJ_UnlockText(*NewFont);
426 }
427 else
428 {
429 /* FIXME */
430 /* ASSERT(FALSE);*/
431 Status = STATUS_INVALID_HANDLE;
432 }
433 }
434 else
435 {
436 Status = STATUS_NO_MEMORY;
437 }
438
439 return Status;
440 }
441
442 HFONT
443 STDCALL
444 NtGdiCreateFont(int Height,
445 int Width,
446 int Escapement,
447 int Orientation,
448 int Weight,
449 DWORD Italic,
450 DWORD Underline,
451 DWORD StrikeOut,
452 DWORD CharSet,
453 DWORD OutputPrecision,
454 DWORD ClipPrecision,
455 DWORD Quality,
456 DWORD PitchAndFamily,
457 LPCWSTR Face)
458 {
459 LOGFONTW logfont;
460 HFONT NewFont;
461 NTSTATUS Status = STATUS_SUCCESS;
462
463 logfont.lfHeight = Height;
464 logfont.lfWidth = Width;
465 logfont.lfEscapement = Escapement;
466 logfont.lfOrientation = Orientation;
467 logfont.lfWeight = Weight;
468 logfont.lfItalic = Italic;
469 logfont.lfUnderline = Underline;
470 logfont.lfStrikeOut = StrikeOut;
471 logfont.lfCharSet = CharSet;
472 logfont.lfOutPrecision = OutputPrecision;
473 logfont.lfClipPrecision = ClipPrecision;
474 logfont.lfQuality = Quality;
475 logfont.lfPitchAndFamily = PitchAndFamily;
476
477 if (NULL != Face)
478 {
479 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
480 wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
481 /* Be 101% sure to have '\0' at end of string */
482 logfont.lfFaceName[Size - 1] = '\0';
483 }
484 else
485 {
486 logfont.lfFaceName[0] = L'\0';
487 }
488
489 if (NT_SUCCESS(Status))
490 {
491 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
492 }
493
494 return NT_SUCCESS(Status) ? NewFont : NULL;
495 }
496
497 HFONT
498 STDCALL
499 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
500 {
501 LOGFONTW SafeLogfont;
502 HFONT NewFont;
503 NTSTATUS Status = STATUS_SUCCESS;
504
505 if (NULL != lf)
506 {
507 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
508 if (NT_SUCCESS(Status))
509 {
510 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
511 }
512 }
513 else
514 {
515 Status = STATUS_INVALID_PARAMETER;
516 }
517
518 return NT_SUCCESS(Status) ? NewFont : NULL;
519 }
520
521 BOOL
522 STDCALL
523 NtGdiCreateScalableFontResource(DWORD Hidden,
524 LPCWSTR FontRes,
525 LPCWSTR FontFile,
526 LPCWSTR CurrentPath)
527 {
528 UNIMPLEMENTED;
529 }
530
531 int
532 STDCALL
533 NtGdiEnumFontFamilies(HDC hDC,
534 LPCWSTR Family,
535 FONTENUMPROCW EnumFontFamProc,
536 LPARAM lParam)
537 {
538 UNIMPLEMENTED;
539 }
540
541 int
542 STDCALL
543 NtGdiEnumFontFamiliesEx(HDC hDC,
544 LPLOGFONTW Logfont,
545 FONTENUMEXPROCW EnumFontFamExProc,
546 LPARAM lParam,
547 DWORD Flags)
548 {
549 UNIMPLEMENTED;
550 }
551
552 int
553 STDCALL
554 NtGdiEnumFonts(HDC hDC,
555 LPCWSTR FaceName,
556 FONTENUMPROCW FontFunc,
557 LPARAM lParam)
558 {
559 UNIMPLEMENTED;
560 }
561
562 BOOL STDCALL
563 NtGdiExtTextOut(HDC hDC, int XStart, int YStart, UINT fuOptions,
564 CONST RECT *lprc, LPCWSTR String, UINT Count, CONST INT *lpDx)
565 {
566 /*
567 * FIXME:
568 * Call EngTextOut, which does the real work (calling DrvTextOut where
569 * appropriate)
570 */
571
572 DC *dc;
573 SURFOBJ *SurfObj;
574 int error, glyph_index, n, i;
575 FT_Face face;
576 FT_GlyphSlot glyph;
577 ULONG TextLeft, TextTop, pitch, previous, BackgroundLeft;
578 FT_Bool use_kerning;
579 RECTL DestRect, MaskRect;
580 POINTL SourcePoint, BrushOrigin;
581 HBRUSH hBrushFg = NULL;
582 PBRUSHOBJ BrushFg = NULL;
583 HBRUSH hBrushBg = NULL;
584 PBRUSHOBJ BrushBg = NULL;
585 HBITMAP HSourceGlyph;
586 PSURFOBJ SourceGlyphSurf;
587 SIZEL bitSize;
588 FT_CharMap found = 0, charmap;
589 INT yoff;
590 PFONTOBJ FontObj;
591 PFONTGDI FontGDI;
592 PTEXTOBJ TextObj;
593 PPALGDI PalDestGDI;
594 PXLATEOBJ XlateObj, XlateObj2;
595 ULONG Mode;
596 FT_Render_Mode RenderMode;
597 BOOL Render;
598
599 dc = DC_LockDc(hDC);
600 if (!dc)
601 return FALSE;
602
603 SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
604
605 XStart += dc->w.DCOrgX;
606 YStart += dc->w.DCOrgY;
607 TextLeft = XStart;
608 TextTop = YStart;
609 BackgroundLeft = XStart;
610
611 TextObj = TEXTOBJ_LockText(dc->w.hFont);
612
613 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
614 {
615 goto fail;
616 }
617
618 face = FontGDI->face;
619 if (face->charmap == NULL)
620 {
621 DPRINT("WARNING: No charmap selected!\n");
622 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
623
624 for (n = 0; n < face->num_charmaps; n++)
625 {
626 charmap = face->charmaps[n];
627 DPRINT("found charmap encoding: %u\n", charmap->encoding);
628 if (charmap->encoding != 0)
629 {
630 found = charmap;
631 break;
632 }
633 }
634 if (!found)
635 DPRINT1("WARNING: Could not find desired charmap!\n");
636 ExAcquireFastMutex(&FreeTypeLock);
637 error = FT_Set_Charmap(face, found);
638 ExReleaseFastMutex(&FreeTypeLock);
639 if (error)
640 DPRINT1("WARNING: Could not set the charmap!\n");
641 }
642
643 Render = IntIsFontRenderingEnabled();
644 if (Render)
645 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
646 else
647 RenderMode = FT_RENDER_MODE_MONO;
648
649 ExAcquireFastMutex(&FreeTypeLock);
650 error = FT_Set_Pixel_Sizes(
651 face,
652 /* FIXME should set character height if neg */
653 (TextObj->logfont.lfHeight < 0 ?
654 - TextObj->logfont.lfHeight :
655 TextObj->logfont.lfHeight),
656 TextObj->logfont.lfWidth);
657 ExReleaseFastMutex(&FreeTypeLock);
658 if (error)
659 {
660 DPRINT1("Error in setting pixel sizes: %u\n", error);
661 goto fail;
662 }
663
664 /* Create the brushes */
665 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
666 Mode = PalDestGDI->Mode;
667 PALETTE_UnlockPalette(dc->w.hPalette);
668 XlateObj = (PXLATEOBJ)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
669 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
670 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
671 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
672 {
673 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
674 if (hBrushBg)
675 {
676 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
677 }
678 else
679 {
680 EngDeleteXlate(XlateObj);
681 goto fail;
682 }
683 }
684 XlateObj2 = (PXLATEOBJ)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
685
686 SourcePoint.x = 0;
687 SourcePoint.y = 0;
688 MaskRect.left = 0;
689 MaskRect.top = 0;
690 BrushOrigin.x = 0;
691 BrushOrigin.y = 0;
692
693 if ((fuOptions & ETO_OPAQUE) && lprc)
694 {
695 MmCopyFromCaller(&DestRect, lprc, sizeof(RECT));
696 DestRect.left += dc->w.DCOrgX;
697 DestRect.top += dc->w.DCOrgY;
698 DestRect.right += dc->w.DCOrgX;
699 DestRect.bottom += dc->w.DCOrgY;
700 IntEngBitBlt(
701 SurfObj,
702 NULL,
703 NULL,
704 dc->CombinedClip,
705 NULL,
706 &DestRect,
707 &SourcePoint,
708 &SourcePoint,
709 BrushBg,
710 &BrushOrigin,
711 PATCOPY);
712 fuOptions &= ~ETO_OPAQUE;
713 }
714 else
715 {
716 if (dc->w.backgroundMode == OPAQUE)
717 {
718 fuOptions |= ETO_OPAQUE;
719 }
720 }
721
722 // Determine the yoff from the dc's w.textAlign
723 if (dc->w.textAlign & TA_BASELINE) {
724 yoff = 0;
725 }
726 else
727 if (dc->w.textAlign & TA_BOTTOM) {
728 yoff = -face->size->metrics.descender / 64;
729 }
730 else { // TA_TOP
731 yoff = face->size->metrics.ascender / 64;
732 }
733
734 use_kerning = FT_HAS_KERNING(face);
735 previous = 0;
736
737 for(i=0; i<Count; i++)
738 {
739 ExAcquireFastMutex(&FreeTypeLock);
740 glyph_index = FT_Get_Char_Index(face, *String);
741 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
742 ExReleaseFastMutex(&FreeTypeLock);
743 if(error) {
744 EngDeleteXlate(XlateObj);
745 EngDeleteXlate(XlateObj2);
746 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
747 goto fail;
748 }
749 glyph = face->glyph;
750
751 // retrieve kerning distance and move pen position
752 if (use_kerning && previous && glyph_index)
753 {
754 FT_Vector delta;
755 ExAcquireFastMutex(&FreeTypeLock);
756 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
757 ExReleaseFastMutex(&FreeTypeLock);
758 TextLeft += delta.x >> 6;
759 }
760
761 if (glyph->format == ft_glyph_format_outline)
762 {
763 ExAcquireFastMutex(&FreeTypeLock);
764 error = FT_Render_Glyph(glyph, RenderMode);
765 ExReleaseFastMutex(&FreeTypeLock);
766 if(error) {
767 EngDeleteXlate(XlateObj);
768 EngDeleteXlate(XlateObj2);
769 DPRINT1("WARNING: Failed to render glyph!\n");
770 goto fail;
771 }
772 pitch = glyph->bitmap.pitch;
773 } else {
774 pitch = glyph->bitmap.width;
775 }
776
777 if (fuOptions & ETO_OPAQUE)
778 {
779 DestRect.left = BackgroundLeft;
780 DestRect.right = TextLeft + (glyph->advance.x + 32) / 64;
781 DestRect.top = TextTop + yoff - (face->size->metrics.ascender + 32) / 64;
782 DestRect.bottom = TextTop + yoff + (- face->size->metrics.descender + 32) / 64;
783 IntEngBitBlt(SurfObj,
784 NULL,
785 NULL,
786 dc->CombinedClip,
787 NULL,
788 &DestRect,
789 &SourcePoint,
790 &SourcePoint,
791 BrushBg,
792 &BrushOrigin,
793 PATCOPY);
794 BackgroundLeft = DestRect.right;
795 }
796
797 DestRect.left = TextLeft;
798 DestRect.right = TextLeft + glyph->bitmap.width;
799 DestRect.top = TextTop + yoff - glyph->bitmap_top;
800 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
801
802 bitSize.cx = glyph->bitmap.width;
803 bitSize.cy = glyph->bitmap.rows;
804 MaskRect.right = glyph->bitmap.width;
805 MaskRect.bottom = glyph->bitmap.rows;
806
807 // We should create the bitmap out of the loop at the biggest possible glyph size
808 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
809 HSourceGlyph = EngCreateBitmap(bitSize, pitch, (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ? BMF_8BPP : BMF_1BPP, 0, glyph->bitmap.buffer);
810 SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
811
812 // Use the font data as a mask to paint onto the DCs surface using a brush
813 IntEngMaskBlt (
814 SurfObj,
815 SourceGlyphSurf,
816 dc->CombinedClip,
817 XlateObj,
818 XlateObj2,
819 &DestRect,
820 &SourcePoint,
821 (PPOINTL)&MaskRect,
822 BrushFg,
823 &BrushOrigin);
824
825 EngDeleteSurface(HSourceGlyph);
826
827 TextLeft += (glyph->advance.x + 32) / 64;
828 previous = glyph_index;
829
830 String++;
831 }
832 EngDeleteXlate(XlateObj);
833 EngDeleteXlate(XlateObj2);
834 TEXTOBJ_UnlockText(dc->w.hFont);
835 if (NULL != hBrushBg)
836 {
837 BRUSHOBJ_UnlockBrush(hBrushBg);
838 NtGdiDeleteObject(hBrushBg);
839 }
840 BRUSHOBJ_UnlockBrush(hBrushFg);
841 NtGdiDeleteObject(hBrushFg);
842 DC_UnlockDc(hDC);
843 return TRUE;
844
845 fail:
846 TEXTOBJ_UnlockText( dc->w.hFont );
847 if (NULL != hBrushBg)
848 {
849 BRUSHOBJ_UnlockBrush(hBrushBg);
850 NtGdiDeleteObject(hBrushBg);
851 }
852 if (NULL != hBrushFg)
853 {
854 BRUSHOBJ_UnlockBrush(hBrushFg);
855 NtGdiDeleteObject(hBrushFg);
856 }
857 DC_UnlockDc( hDC );
858 return FALSE;
859 }
860
861 BOOL
862 STDCALL
863 NtGdiGetAspectRatioFilterEx(HDC hDC,
864 LPSIZE AspectRatio)
865 {
866 UNIMPLEMENTED;
867 }
868
869 BOOL
870 STDCALL
871 NtGdiGetCharABCWidths(HDC hDC,
872 UINT FirstChar,
873 UINT LastChar,
874 LPABC abc)
875 {
876 DPRINT1("NtGdiGetCharABCWidths Is unimplemented, keep going anyway\n");
877 return 1;
878 }
879
880 BOOL
881 STDCALL
882 NtGdiGetCharABCWidthsFloat(HDC hDC,
883 UINT FirstChar,
884 UINT LastChar,
885 LPABCFLOAT abcF)
886 {
887 UNIMPLEMENTED;
888 }
889
890 DWORD
891 STDCALL
892 NtGdiGetCharacterPlacement(HDC hDC,
893 LPCWSTR String,
894 int Count,
895 int MaxExtent,
896 LPGCP_RESULTSW Results,
897 DWORD Flags)
898 {
899 UNIMPLEMENTED;
900 }
901
902 BOOL
903 STDCALL
904 NtGdiGetCharWidth(HDC hDC,
905 UINT FirstChar,
906 UINT LastChar,
907 LPINT Buffer)
908 {
909 DPRINT1("NtGdiGetCharWidth isnt really unimplemented - keep going anyway\n");
910 return 1;
911 }
912
913 BOOL
914 STDCALL
915 NtGdiGetCharWidth32(HDC hDC,
916 UINT FirstChar,
917 UINT LastChar,
918 LPINT Buffer)
919 {
920 LPINT SafeBuffer;
921 PDC dc;
922 PTEXTOBJ TextObj;
923 PFONTGDI FontGDI;
924 FT_Face face;
925 FT_CharMap charmap, found = NULL;
926 UINT i, glyph_index, BufferSize;
927
928 if (LastChar < FirstChar)
929 {
930 SetLastWin32Error(ERROR_INVALID_PARAMETER);
931 return FALSE;
932 }
933
934 BufferSize = (LastChar - FirstChar) * sizeof(INT);
935 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
936 if (SafeBuffer == NULL)
937 {
938 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
939 return FALSE;
940 }
941
942 dc = DC_LockDc(hDC);
943 if (dc == NULL)
944 {
945 ExFreePool(SafeBuffer);
946 SetLastWin32Error(ERROR_INVALID_HANDLE);
947 return FALSE;
948 }
949 TextObj = TEXTOBJ_LockText(dc->w.hFont);
950 DC_UnlockDc(hDC);
951
952 GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
953
954 face = FontGDI->face;
955 if (face->charmap == NULL)
956 {
957 for (i = 0; i < face->num_charmaps; i++)
958 {
959 charmap = face->charmaps[i];
960 if (charmap->encoding != 0)
961 {
962 found = charmap;
963 break;
964 }
965 }
966
967 if (!found)
968 {
969 DPRINT1("WARNING: Could not find desired charmap!\n");
970 ExFreePool(SafeBuffer);
971 SetLastWin32Error(ERROR_INVALID_HANDLE);
972 return FALSE;
973 }
974
975 ExAcquireFastMutex(&FreeTypeLock);
976 FT_Set_Charmap(face, found);
977 ExReleaseFastMutex(&FreeTypeLock);
978 }
979
980 ExAcquireFastMutex(&FreeTypeLock);
981 FT_Set_Pixel_Sizes(face,
982 /* FIXME should set character height if neg */
983 (TextObj->logfont.lfHeight < 0 ?
984 - TextObj->logfont.lfHeight :
985 TextObj->logfont.lfHeight),
986 TextObj->logfont.lfWidth);
987
988 for (i = FirstChar; i <= LastChar; i++)
989 {
990 glyph_index = FT_Get_Char_Index(face, i);
991 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
992 SafeBuffer[i] = face->glyph->advance.x >> 6;
993 }
994 ExReleaseFastMutex(&FreeTypeLock);
995 TEXTOBJ_UnlockText(dc->w.hFont);
996 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
997 ExFreePool(SafeBuffer);
998 return TRUE;
999 }
1000
1001 BOOL
1002 STDCALL
1003 NtGdiGetCharWidthFloat(HDC hDC,
1004 UINT FirstChar,
1005 UINT LastChar,
1006 PFLOAT Buffer)
1007 {
1008 UNIMPLEMENTED;
1009 }
1010
1011 DWORD
1012 STDCALL
1013 NtGdiGetFontLanguageInfo(HDC hDC)
1014 {
1015 UNIMPLEMENTED;
1016 }
1017
1018 DWORD
1019 STDCALL
1020 NtGdiGetGlyphOutline(HDC hDC,
1021 UINT Char,
1022 UINT Format,
1023 LPGLYPHMETRICS gm,
1024 DWORD Bufsize,
1025 LPVOID Buffer,
1026 CONST LPMAT2 mat2)
1027 {
1028 UNIMPLEMENTED;
1029
1030
1031 }
1032
1033 DWORD
1034 STDCALL
1035 NtGdiGetKerningPairs(HDC hDC,
1036 DWORD NumPairs,
1037 LPKERNINGPAIR krnpair)
1038 {
1039 UNIMPLEMENTED;
1040 }
1041
1042 UINT
1043 STDCALL
1044 NtGdiGetOutlineTextMetrics(HDC hDC,
1045 UINT Data,
1046 LPOUTLINETEXTMETRICW otm)
1047 {
1048 UNIMPLEMENTED;
1049 }
1050
1051 BOOL
1052 STDCALL
1053 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
1054 UINT Size)
1055 {
1056 UNIMPLEMENTED;
1057 }
1058
1059 UINT
1060 STDCALL
1061 NtGdiGetTextCharset(HDC hDC)
1062 {
1063 UNIMPLEMENTED;
1064 }
1065
1066 UINT
1067 STDCALL
1068 NtGdiGetTextCharsetInfo(HDC hDC,
1069 LPFONTSIGNATURE Sig,
1070 DWORD Flags)
1071 {
1072 UNIMPLEMENTED;
1073 }
1074
1075 static BOOL
1076 FASTCALL
1077 TextIntGetTextExtentPoint(HDC hDC,
1078 PTEXTOBJ TextObj,
1079 LPCWSTR String,
1080 int Count,
1081 int MaxExtent,
1082 LPINT Fit,
1083 LPINT Dx,
1084 LPSIZE Size)
1085 {
1086 PFONTGDI FontGDI;
1087 FT_Face face;
1088 FT_GlyphSlot glyph;
1089 INT error, n, glyph_index, i, previous;
1090 LONG TotalWidth = 0;
1091 FT_CharMap charmap, found = NULL;
1092 BOOL use_kerning;
1093
1094 GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
1095 face = FontGDI->face;
1096 if (NULL != Fit)
1097 {
1098 *Fit = 0;
1099 }
1100
1101 if (face->charmap == NULL)
1102 {
1103 DPRINT("WARNING: No charmap selected!\n");
1104 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1105
1106 for (n = 0; n < face->num_charmaps; n++)
1107 {
1108 charmap = face->charmaps[n];
1109 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1110 if (charmap->encoding != 0)
1111 {
1112 found = charmap;
1113 break;
1114 }
1115 }
1116
1117 if (! found)
1118 {
1119 DPRINT1("WARNING: Could not find desired charmap!\n");
1120 }
1121
1122 ExAcquireFastMutex(&FreeTypeLock);
1123 error = FT_Set_Charmap(face, found);
1124 ExReleaseFastMutex(&FreeTypeLock);
1125 if (error)
1126 {
1127 DPRINT1("WARNING: Could not set the charmap!\n");
1128 }
1129 }
1130
1131 ExAcquireFastMutex(&FreeTypeLock);
1132 error = FT_Set_Pixel_Sizes(face,
1133 /* FIXME should set character height if neg */
1134 (TextObj->logfont.lfHeight < 0 ?
1135 - TextObj->logfont.lfHeight :
1136 TextObj->logfont.lfHeight),
1137 TextObj->logfont.lfWidth);
1138 ExReleaseFastMutex(&FreeTypeLock);
1139 if (error)
1140 {
1141 DPRINT1("Error in setting pixel sizes: %u\n", error);
1142 }
1143
1144 use_kerning = FT_HAS_KERNING(face);
1145 previous = 0;
1146
1147 for (i = 0; i < Count; i++)
1148 {
1149 ExAcquireFastMutex(&FreeTypeLock);
1150 glyph_index = FT_Get_Char_Index(face, *String);
1151 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1152 ExReleaseFastMutex(&FreeTypeLock);
1153 if (error)
1154 {
1155 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1156 }
1157 glyph = face->glyph;
1158
1159 /* retrieve kerning distance */
1160 if (use_kerning && previous && glyph_index)
1161 {
1162 FT_Vector delta;
1163 ExAcquireFastMutex(&FreeTypeLock);
1164 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1165 ExReleaseFastMutex(&FreeTypeLock);
1166 TotalWidth += delta.x >> 6;
1167 }
1168
1169 TotalWidth += glyph->advance.x >> 6;
1170 if (glyph->format == ft_glyph_format_outline)
1171 {
1172 ExAcquireFastMutex(&FreeTypeLock);
1173 error = FT_Render_Glyph(glyph, FT_RENDER_MODE_MONO);
1174 ExReleaseFastMutex(&FreeTypeLock);
1175 if (error)
1176 {
1177 DPRINT1("WARNING: Failed to render glyph!\n");
1178 }
1179 }
1180
1181 if (TotalWidth <= MaxExtent && NULL != Fit)
1182 {
1183 *Fit = i + 1;
1184 }
1185 if (NULL != Dx)
1186 {
1187 Dx[i] = TotalWidth;
1188 }
1189
1190 previous = glyph_index;
1191 String++;
1192 }
1193
1194 Size->cx = TotalWidth;
1195 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
1196 Size->cy = EngMulDiv(Size->cy, NtGdiGetDeviceCaps(hDC, LOGPIXELSY), 72);
1197
1198 return TRUE;
1199 }
1200
1201 BOOL
1202 STDCALL
1203 NtGdiGetTextExtentExPoint(HDC hDC,
1204 LPCWSTR UnsafeString,
1205 int Count,
1206 int MaxExtent,
1207 LPINT UnsafeFit,
1208 LPINT UnsafeDx,
1209 LPSIZE UnsafeSize)
1210 {
1211 PDC dc;
1212 LPWSTR String;
1213 SIZE Size;
1214 NTSTATUS Status;
1215 BOOLEAN Result;
1216 INT Fit;
1217 LPINT Dx;
1218 PTEXTOBJ TextObj;
1219
1220 if (Count < 0)
1221 {
1222 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1223 return FALSE;
1224 }
1225 if (0 == Count)
1226 {
1227 Size.cx = 0;
1228 Size.cy = 0;
1229 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
1230 if (! NT_SUCCESS(Status))
1231 {
1232 SetLastNtError(Status);
1233 return FALSE;
1234 }
1235 return TRUE;
1236 }
1237
1238 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
1239 if (NULL == String)
1240 {
1241 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1242 return FALSE;
1243 }
1244
1245 if (NULL != UnsafeDx)
1246 {
1247 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1248 if (NULL == Dx)
1249 {
1250 ExFreePool(String);
1251 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1252 return FALSE;
1253 }
1254 }
1255 else
1256 {
1257 Dx = NULL;
1258 }
1259
1260 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
1261 if (! NT_SUCCESS(Status))
1262 {
1263 if (NULL != Dx)
1264 {
1265 ExFreePool(Dx);
1266 }
1267 ExFreePool(String);
1268 SetLastNtError(Status);
1269 return FALSE;
1270 }
1271
1272 dc = DC_LockDc(hDC);
1273 if (NULL == dc)
1274 {
1275 if (NULL != Dx)
1276 {
1277 ExFreePool(Dx);
1278 }
1279 ExFreePool(String);
1280 SetLastWin32Error(ERROR_INVALID_HANDLE);
1281 return FALSE;
1282 }
1283 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1284 DC_UnlockDc(hDC);
1285 Result = TextIntGetTextExtentPoint(hDC, TextObj, String, Count, MaxExtent,
1286 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
1287 TEXTOBJ_UnlockText(dc->w.hFont);
1288
1289 ExFreePool(String);
1290 if (! Result)
1291 {
1292 if (NULL != Dx)
1293 {
1294 ExFreePool(Dx);
1295 }
1296 return FALSE;
1297 }
1298
1299 if (NULL != UnsafeFit)
1300 {
1301 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
1302 if (! NT_SUCCESS(Status))
1303 {
1304 if (NULL != Dx)
1305 {
1306 ExFreePool(Dx);
1307 }
1308 SetLastNtError(Status);
1309 return FALSE;
1310 }
1311 }
1312
1313 if (NULL != UnsafeDx)
1314 {
1315 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
1316 if (! NT_SUCCESS(Status))
1317 {
1318 if (NULL != Dx)
1319 {
1320 ExFreePool(Dx);
1321 }
1322 SetLastNtError(Status);
1323 return FALSE;
1324 }
1325 }
1326 if (NULL != Dx)
1327 {
1328 ExFreePool(Dx);
1329 }
1330
1331 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
1332 if (! NT_SUCCESS(Status))
1333 {
1334 SetLastNtError(Status);
1335 return FALSE;
1336 }
1337
1338 return TRUE;
1339 }
1340
1341 BOOL
1342 STDCALL
1343 NtGdiGetTextExtentPoint(HDC hDC,
1344 LPCWSTR String,
1345 int Count,
1346 LPSIZE Size)
1347 {
1348 return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
1349 }
1350
1351 BOOL
1352 STDCALL
1353 NtGdiGetTextExtentPoint32(HDC hDC,
1354 LPCWSTR UnsafeString,
1355 int Count,
1356 LPSIZE UnsafeSize)
1357 {
1358 PDC dc;
1359 LPWSTR String;
1360 SIZE Size;
1361 NTSTATUS Status;
1362 BOOLEAN Result;
1363 PTEXTOBJ TextObj;
1364
1365 if (Count < 0)
1366 {
1367 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1368 return FALSE;
1369 }
1370 if (0 == Count)
1371 {
1372 Size.cx = 0;
1373 Size.cy = 0;
1374 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
1375 if (! NT_SUCCESS(Status))
1376 {
1377 SetLastNtError(Status);
1378 return FALSE;
1379 }
1380 return TRUE;
1381 }
1382
1383 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
1384 if (NULL == String)
1385 {
1386 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1387 return FALSE;
1388 }
1389
1390 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
1391 if (! NT_SUCCESS(Status))
1392 {
1393 ExFreePool(String);
1394 SetLastNtError(Status);
1395 return FALSE;
1396 }
1397
1398 dc = DC_LockDc(hDC);
1399 if (NULL == dc)
1400 {
1401 ExFreePool(String);
1402 SetLastWin32Error(ERROR_INVALID_HANDLE);
1403 return FALSE;
1404 }
1405 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1406 DC_UnlockDc(hDC);
1407 Result = TextIntGetTextExtentPoint (
1408 hDC, TextObj, String, Count, 0, NULL, NULL, &Size);
1409 dc = DC_LockDc(hDC);
1410 ASSERT(dc); // it succeeded earlier, it should now, too
1411 TEXTOBJ_UnlockText(dc->w.hFont);
1412 DC_UnlockDc(hDC);
1413
1414 ExFreePool(String);
1415 if (! Result)
1416 {
1417 return FALSE;
1418 }
1419
1420 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
1421 if (! NT_SUCCESS(Status))
1422 {
1423 SetLastNtError(Status);
1424 return FALSE;
1425 }
1426
1427 return TRUE;
1428 }
1429
1430 int
1431 STDCALL
1432 NtGdiGetTextFace(HDC hDC,
1433 int Count,
1434 LPWSTR FaceName)
1435 {
1436 UNIMPLEMENTED;
1437 }
1438
1439 BOOL
1440 STDCALL
1441 NtGdiGetTextMetrics(HDC hDC,
1442 LPTEXTMETRICW tm)
1443 {
1444 PDC dc;
1445 PTEXTOBJ TextObj;
1446 PFONTGDI FontGDI;
1447 NTSTATUS Status = STATUS_SUCCESS;
1448 TEXTMETRICW SafeTm;
1449 FT_Face Face;
1450 TT_OS2 *pOS2;
1451 ULONG Error;
1452
1453 dc = DC_LockDc(hDC);
1454 if (NULL == dc || NULL == tm)
1455 {
1456 Status = STATUS_INVALID_PARAMETER;
1457 }
1458 else
1459 {
1460 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1461 if (NULL != TextObj)
1462 {
1463 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
1464 if (NT_SUCCESS(Status))
1465 {
1466 Face = FontGDI->face;
1467 ExAcquireFastMutex(&FreeTypeLock);
1468 Error = FT_Set_Pixel_Sizes(Face,
1469 /* FIXME should set character height if neg */
1470 (TextObj->logfont.lfHeight < 0 ?
1471 - TextObj->logfont.lfHeight :
1472 TextObj->logfont.lfHeight),
1473 TextObj->logfont.lfWidth);
1474 ExReleaseFastMutex(&FreeTypeLock);
1475 if (0 != Error)
1476 {
1477 DPRINT1("Error in setting pixel sizes: %u\n", Error);
1478 Status = STATUS_UNSUCCESSFUL;
1479 }
1480 else
1481 {
1482 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
1483 ExAcquireFastMutex(&FreeTypeLock);
1484 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1485 ExReleaseFastMutex(&FreeTypeLock);
1486 if (NULL == pOS2)
1487 {
1488 DPRINT1("Can't find OS/2 table - not TT font?\n");
1489 Status = STATUS_UNSUCCESSFUL;
1490 }
1491 else
1492 {
1493 SafeTm.tmAveCharWidth = (pOS2->xAvgCharWidth + 32) / 64;
1494 }
1495 SafeTm.tmAscent = (Face->size->metrics.ascender + 32) / 64; // units above baseline
1496 SafeTm.tmDescent = (- Face->size->metrics.descender + 32) / 64; // units below baseline
1497 SafeTm.tmHeight = SafeTm.tmAscent + SafeTm.tmDescent;
1498 SafeTm.tmMaxCharWidth = (Face->size->metrics.max_advance + 32) / 64;
1499 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
1500 }
1501 }
1502 TEXTOBJ_UnlockText(dc->w.hFont);
1503 }
1504 else
1505 {
1506 ASSERT(FALSE);
1507 Status = STATUS_INVALID_HANDLE;
1508 }
1509 DC_UnlockDc(hDC);
1510 }
1511
1512 return NT_SUCCESS(Status);
1513 }
1514
1515 BOOL
1516 STDCALL
1517 NtGdiPolyTextOut(HDC hDC,
1518 CONST LPPOLYTEXTW txt,
1519 int Count)
1520 {
1521 UNIMPLEMENTED;
1522 }
1523
1524 BOOL
1525 STDCALL
1526 NtGdiRemoveFontResource(LPCWSTR FileName)
1527 {
1528 UNIMPLEMENTED;
1529 }
1530
1531 DWORD
1532 STDCALL
1533 NtGdiSetMapperFlags(HDC hDC,
1534 DWORD Flag)
1535 {
1536 UNIMPLEMENTED;
1537 }
1538
1539 UINT
1540 STDCALL
1541 NtGdiSetTextAlign(HDC hDC,
1542 UINT Mode)
1543 {
1544 UINT prevAlign;
1545 DC *dc;
1546
1547 dc = DC_LockDc(hDC);
1548 if (!dc)
1549 {
1550 return 0;
1551 }
1552 prevAlign = dc->w.textAlign;
1553 dc->w.textAlign = Mode;
1554 DC_UnlockDc( hDC );
1555 return prevAlign;
1556 }
1557
1558 COLORREF
1559 STDCALL
1560 NtGdiSetTextColor(HDC hDC,
1561 COLORREF color)
1562 {
1563 COLORREF oldColor;
1564 PDC dc = DC_LockDc(hDC);
1565
1566 if (!dc)
1567 {
1568 return 0x80000000;
1569 }
1570
1571 oldColor = dc->w.textColor;
1572 dc->w.textColor = color;
1573 DC_UnlockDc( hDC );
1574 return oldColor;
1575 }
1576
1577 BOOL
1578 STDCALL
1579 NtGdiSetTextJustification(HDC hDC,
1580 int BreakExtra,
1581 int BreakCount)
1582 {
1583 UNIMPLEMENTED;
1584 }
1585
1586 BOOL STDCALL
1587 NtGdiTextOut(
1588 HDC hDC,
1589 INT XStart,
1590 INT YStart,
1591 LPCWSTR String,
1592 INT Count)
1593 {
1594 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
1595 }
1596
1597 UINT
1598 STDCALL
1599 NtGdiTranslateCharsetInfo(PDWORD Src,
1600 LPCHARSETINFO CSI,
1601 DWORD Flags)
1602 {
1603 UNIMPLEMENTED;
1604 }
1605
1606 NTSTATUS FASTCALL
1607 TextIntRealizeFont(HFONT FontHandle)
1608 {
1609 NTSTATUS Status = STATUS_SUCCESS;
1610 PTEXTOBJ TextObj;
1611 UNICODE_STRING FaceName;
1612 PLIST_ENTRY Entry;
1613 PFONT_ENTRY CurrentEntry;
1614 PW32PROCESS Win32Process;
1615 BOOL Private = FALSE;
1616
1617 TextObj = TEXTOBJ_LockText(FontHandle);
1618 ASSERT(TextObj);
1619 if (NULL != TextObj)
1620 {
1621 RtlInitUnicodeString(&FaceName, TextObj->logfont.lfFaceName);
1622
1623 /* find font in private fonts */
1624 Win32Process = PsGetWin32Process();
1625
1626 ExAcquireFastMutex(&Win32Process->PrivateFontListLock);
1627
1628 Entry = Win32Process->PrivateFontListHead.Flink;
1629 while(Entry != &Win32Process->PrivateFontListHead)
1630 {
1631 CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1632
1633 if (0 == RtlCompareUnicodeString(&CurrentEntry->FaceName, &FaceName, TRUE))
1634 {
1635 TextObj->GDIFontHandle = CurrentEntry->hFont;
1636 Private = TRUE;
1637 goto check;
1638 }
1639 Entry = Entry->Flink;
1640 }
1641 ExReleaseFastMutex(&Win32Process->PrivateFontListLock);
1642
1643 /* find font in system fonts */
1644 ExAcquireFastMutex(&FontListLock);
1645
1646 Entry = FontListHead.Flink;
1647 while(Entry != &FontListHead)
1648 {
1649 CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1650
1651 if (0 == RtlCompareUnicodeString(&CurrentEntry->FaceName, &FaceName, TRUE))
1652 {
1653 TextObj->GDIFontHandle = CurrentEntry->hFont;
1654 break;
1655 }
1656 Entry = Entry->Flink;
1657 }
1658
1659 check:
1660 if (NULL == TextObj->GDIFontHandle)
1661 {
1662 Entry = (Private ? Win32Process->PrivateFontListHead.Flink : FontListHead.Flink);
1663
1664 if(Entry != (Private ? &Win32Process->PrivateFontListHead : &FontListHead))
1665 {
1666 DPRINT("Requested font %S not found, using first available font\n",
1667 TextObj->logfont.lfFaceName)
1668 CurrentEntry = (PFONT_ENTRY)CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1669 TextObj->GDIFontHandle = CurrentEntry->hFont;
1670 }
1671 else
1672 {
1673 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
1674 TextObj->logfont.lfFaceName);
1675 Status = STATUS_NOT_FOUND;
1676 }
1677
1678 }
1679
1680 ExReleaseFastMutex((Private ? &Win32Process->PrivateFontListLock : &FontListLock));
1681
1682 ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
1683
1684 TEXTOBJ_UnlockText(FontHandle);
1685 }
1686 else
1687 {
1688 Status = STATUS_INVALID_HANDLE;
1689 }
1690
1691 return Status;
1692 }
1693
1694 /* EOF */