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