Corrected comment
[reactos.git] / reactos / subsys / win32k / objects / text.c
1
2
3 #undef WIN32_LEAN_AND_MEAN
4 #include <windows.h>
5 #include <ddk/ntddk.h>
6 #include <win32k/dc.h>
7 #include <win32k/text.h>
8 #include <win32k/kapi.h>
9 #include <freetype/freetype.h>
10
11 #include "../eng/handle.h"
12
13 // #define NDEBUG
14 #include <win32k/debug1.h>
15
16 FT_Library library;
17
18 typedef struct _FONTTABLE {
19 HFONT hFont;
20 LPCWSTR FaceName;
21 } FONTTABLE, *PFONTTABLE;
22
23 FONTTABLE FontTable[256];
24 INT FontsLoaded = 0;
25
26 BOOL InitFontSupport()
27 {
28 ULONG error;
29
30 error = FT_Init_FreeType(&library);
31 if(error)
32 {
33 return FALSE;
34 }
35
36 W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\helb____.ttf");
37 W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\timr____.ttf");
38
39 DbgPrint("All fonts loaded\n");
40
41 return TRUE;
42 }
43
44 int
45 STDCALL
46 W32kAddFontResource(LPCWSTR Filename)
47 {
48 HFONT NewFont;
49 PFONTOBJ FontObj;
50 PFONTGDI FontGDI;
51 UNICODE_STRING uFileName;
52 NTSTATUS Status;
53 HANDLE FileHandle;
54 OBJECT_ATTRIBUTES ObjectAttributes;
55 FILE_STANDARD_INFORMATION FileStdInfo;
56 PVOID buffer;
57 ULONG size;
58 INT error;
59 FT_Face face;
60 ANSI_STRING StringA;
61 UNICODE_STRING StringU;
62 IO_STATUS_BLOCK Iosb;
63
64 NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
65 FontObj = (PFONTOBJ) AccessUserObject( NewFont );
66 FontGDI = (PFONTGDI) AccessInternalObject( NewFont );
67
68 RtlCreateUnicodeString(&uFileName, (LPWSTR)Filename);
69
70 // Open the Module
71 InitializeObjectAttributes(&ObjectAttributes, &uFileName, 0, NULL, NULL);
72
73 Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &Iosb, 0, 0);
74
75 if (!NT_SUCCESS(Status))
76 {
77 DbgPrint("Could not open module file: %S\n", Filename);
78 return 0;
79 }
80
81 // Get the size of the file
82 Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
83 if (!NT_SUCCESS(Status))
84 {
85 DbgPrint("Could not get file size\n");
86 return 0;
87 }
88
89 // Allocate nonpageable memory for driver
90 size = FileStdInfo.EndOfFile.u.LowPart;
91 buffer = ExAllocatePool(NonPagedPool, size);
92
93 if (buffer == NULL)
94 {
95 DbgPrint("could not allocate memory for module");
96 return 0;
97 }
98
99 // Load driver into memory chunk
100 Status = NtReadFile(FileHandle, 0, 0, 0, &Iosb, buffer, FileStdInfo.EndOfFile.u.LowPart, 0, 0);
101 if (!NT_SUCCESS(Status))
102 {
103 DbgPrint("could not read module file into memory");
104 ExFreePool(buffer);
105 return 0;
106 }
107
108 NtClose(FileHandle);
109
110 error = FT_New_Memory_Face(library, buffer, size, 0, &face);
111 if (error == FT_Err_Unknown_File_Format)
112 {
113 DbgPrint("Unknown font file format\n");
114 return 0;
115 }
116 else if (error)
117 {
118 DbgPrint("Error reading font file (error code: %u)\n", error); // 48
119 return 0;
120 }
121
122 // FontGDI->Filename = Filename; perform strcpy
123 FontGDI->face = face;
124
125 // FIXME: Complete text metrics
126 FontGDI->TextMetric.tmAscent = face->size->metrics.ascender; // units above baseline
127 FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
128 FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
129
130 DbgPrint("Family name: %s\n", face->family_name);
131 DbgPrint("Style name: %s\n", face->style_name);
132 DbgPrint("Num glyphs: %u\n", face->num_glyphs);
133
134 // Add this font resource to the font table
135 FontTable[FontsLoaded].hFont = NewFont;
136
137 RtlInitAnsiString(&StringA, (LPSTR)face->family_name);
138 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
139 FontTable[FontsLoaded].FaceName = ExAllocatePool(NonPagedPool, (StringU.Length + 1) * 2);
140 wcscpy((LPWSTR)FontTable[FontsLoaded].FaceName, StringU.Buffer);
141 RtlFreeUnicodeString(&StringU);
142
143 FontsLoaded++;
144
145 return 1;
146 }
147
148 HFONT
149 STDCALL
150 W32kCreateFont(int Height,
151 int Width,
152 int Escapement,
153 int Orientation,
154 int Weight,
155 DWORD Italic,
156 DWORD Underline,
157 DWORD StrikeOut,
158 DWORD CharSet,
159 DWORD OutputPrecision,
160 DWORD ClipPrecision,
161 DWORD Quality,
162 DWORD PitchAndFamily,
163 LPCWSTR Face)
164 {
165 LOGFONT logfont;
166
167 logfont.lfHeight = Height;
168 logfont.lfWidth = Width;
169 logfont.lfEscapement = Escapement;
170 logfont.lfOrientation = Orientation;
171 logfont.lfWeight = Weight;
172 logfont.lfItalic = Italic;
173 logfont.lfUnderline = Underline;
174 logfont.lfStrikeOut = StrikeOut;
175 logfont.lfCharSet = CharSet;
176 logfont.lfOutPrecision = OutputPrecision;
177 logfont.lfClipPrecision = ClipPrecision;
178 logfont.lfQuality = Quality;
179 logfont.lfPitchAndFamily = PitchAndFamily;
180
181 if(Face)
182 memcpy(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
183 else
184 logfont.lfFaceName[0] = '\0';
185
186 return W32kCreateFontIndirect(&logfont);
187 }
188
189 HFONT
190 STDCALL
191 W32kCreateFontIndirect(CONST LPLOGFONT lf)
192 {
193 HFONT hFont = 0;
194 PTEXTOBJ fontPtr;
195
196 if (lf)
197 {
198 if(hFont = TEXTOBJ_AllocText())
199 {
200 fontPtr = TEXTOBJ_LockText( hFont );
201 ASSERT( fontPtr ); //I want to know when this happens
202 if( fontPtr ){
203 memcpy(&fontPtr->logfont, lf, sizeof(LOGFONT));
204
205 if (lf->lfEscapement != lf->lfOrientation) {
206 /* this should really depend on whether GM_ADVANCED is set */
207 fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
208 }
209 TEXTOBJ_UnlockText( hFont );
210 }
211 }
212 }
213
214 return hFont;
215 }
216
217 BOOL
218 STDCALL
219 W32kCreateScalableFontResource(DWORD Hidden,
220 LPCWSTR FontRes,
221 LPCWSTR FontFile,
222 LPCWSTR CurrentPath)
223 {
224 UNIMPLEMENTED;
225 }
226
227 int
228 STDCALL
229 W32kEnumFontFamilies(HDC hDC,
230 LPCWSTR Family,
231 FONTENUMPROC EnumFontFamProc,
232 LPARAM lParam)
233 {
234 UNIMPLEMENTED;
235 }
236
237 int
238 STDCALL
239 W32kEnumFontFamiliesEx(HDC hDC,
240 LPLOGFONT Logfont,
241 FONTENUMPROC EnumFontFamExProc,
242 LPARAM lParam,
243 DWORD Flags)
244 {
245 UNIMPLEMENTED;
246 }
247
248 int
249 STDCALL
250 W32kEnumFonts(HDC hDC,
251 LPCWSTR FaceName,
252 FONTENUMPROC FontFunc,
253 LPARAM lParam)
254 {
255 UNIMPLEMENTED;
256 }
257
258 BOOL
259 STDCALL
260 W32kExtTextOut(HDC hDC,
261 int X,
262 int Y,
263 UINT Options,
264 CONST LPRECT rc,
265 LPCWSTR String,
266 UINT Count,
267 CONST LPINT Dx)
268 {
269 UNIMPLEMENTED;
270 }
271
272 BOOL
273 STDCALL
274 W32kGetAspectRatioFilterEx(HDC hDC,
275 LPSIZE AspectRatio)
276 {
277 UNIMPLEMENTED;
278 }
279
280 BOOL
281 STDCALL
282 W32kGetCharABCWidths(HDC hDC,
283 UINT FirstChar,
284 UINT LastChar,
285 LPABC abc)
286 {
287 UNIMPLEMENTED;
288 }
289
290 BOOL
291 STDCALL
292 W32kGetCharABCWidthsFloat(HDC hDC,
293 UINT FirstChar,
294 UINT LastChar,
295 LPABCFLOAT abcF)
296 {
297 UNIMPLEMENTED;
298 }
299
300 DWORD
301 STDCALL
302 W32kGetCharacterPlacement(HDC hDC,
303 LPCWSTR String,
304 int Count,
305 int MaxExtent,
306 LPGCP_RESULTS Results,
307 DWORD Flags)
308 {
309 UNIMPLEMENTED;
310 }
311
312 BOOL
313 STDCALL
314 W32kGetCharWidth(HDC hDC,
315 UINT FirstChar,
316 UINT LastChar,
317 LPINT Buffer)
318 {
319 UNIMPLEMENTED;
320 }
321
322 BOOL
323 STDCALL
324 W32kGetCharWidth32(HDC hDC,
325 UINT FirstChar,
326 UINT LastChar,
327 LPINT Buffer)
328 {
329 UNIMPLEMENTED;
330 }
331
332 BOOL
333 STDCALL
334 W32kGetCharWidthFloat(HDC hDC,
335 UINT FirstChar,
336 UINT LastChar,
337 PFLOAT Buffer)
338 {
339 UNIMPLEMENTED;
340 }
341
342 DWORD
343 STDCALL
344 W32kGetFontLanguageInfo(HDC hDC)
345 {
346 UNIMPLEMENTED;
347 }
348
349 DWORD
350 STDCALL
351 W32kGetGlyphOutline(HDC hDC,
352 UINT Char,
353 UINT Format,
354 LPGLYPHMETRICS gm,
355 DWORD Bufsize,
356 LPVOID Buffer,
357 CONST LPMAT2 mat2)
358 {
359 UNIMPLEMENTED;
360
361
362 }
363
364 DWORD
365 STDCALL
366 W32kGetKerningPairs(HDC hDC,
367 DWORD NumPairs,
368 LPKERNINGPAIR krnpair)
369 {
370 UNIMPLEMENTED;
371 }
372
373 UINT
374 STDCALL
375 W32kGetOutlineTextMetrics(HDC hDC,
376 UINT Data,
377 LPOUTLINETEXTMETRIC otm)
378 {
379 UNIMPLEMENTED;
380 }
381
382 BOOL
383 STDCALL
384 W32kGetRasterizerCaps(LPRASTERIZER_STATUS rs,
385 UINT Size)
386 {
387 UNIMPLEMENTED;
388 }
389
390 UINT
391 STDCALL
392 W32kGetTextCharset(HDC hDC)
393 {
394 UNIMPLEMENTED;
395 }
396
397 UINT
398 STDCALL
399 W32kGetTextCharsetInfo(HDC hDC,
400 LPFONTSIGNATURE Sig,
401 DWORD Flags)
402 {
403 UNIMPLEMENTED;
404 }
405
406 BOOL
407 STDCALL
408 W32kGetTextExtentExPoint(HDC hDC,
409 LPCWSTR String,
410 int Count,
411 int MaxExtent,
412 LPINT Fit,
413 LPINT Dx,
414 LPSIZE Size)
415 {
416 UNIMPLEMENTED;
417 }
418
419 BOOL
420 STDCALL
421 W32kGetTextExtentPoint(HDC hDC,
422 LPCWSTR String,
423 int Count,
424 LPSIZE Size)
425 {
426 PDC dc = (PDC)AccessUserObject(hDC);
427 PFONTGDI FontGDI;
428 FT_Face face;
429 FT_GlyphSlot glyph;
430 INT error, pitch, glyph_index, i;
431 ULONG TotalWidth = 0, MaxHeight = 0, CurrentChar = 0, SpaceBetweenChars = 5;
432
433 FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
434
435 for(i=0; i<Count; i++)
436 {
437 glyph_index = FT_Get_Char_Index(face, *String);
438 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
439 if(error) DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
440 glyph = face->glyph;
441
442 if (glyph->format == ft_glyph_format_outline)
443 {
444 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
445 if(error) DbgPrint("WARNING: Failed to render glyph!\n");
446 pitch = glyph->bitmap.pitch;
447 } else {
448 pitch = glyph->bitmap.width;
449 }
450
451 TotalWidth += pitch-1;
452 if((glyph->bitmap.rows-1) > MaxHeight) MaxHeight = glyph->bitmap.rows-1;
453
454 CurrentChar++;
455
456 if(CurrentChar < Size->cx) TotalWidth += SpaceBetweenChars;
457 String++;
458 }
459
460 Size->cx = TotalWidth;
461 Size->cy = MaxHeight;
462 }
463
464 BOOL
465 STDCALL
466 W32kGetTextExtentPoint32(HDC hDC,
467 LPCWSTR String,
468 int Count,
469 LPSIZE Size)
470 {
471 UNIMPLEMENTED;
472 }
473
474 int
475 STDCALL
476 W32kGetTextFace(HDC hDC,
477 int Count,
478 LPWSTR FaceName)
479 {
480 UNIMPLEMENTED;
481 }
482
483 BOOL
484 STDCALL
485 W32kGetTextMetrics(HDC hDC,
486 LPTEXTMETRIC tm)
487 {
488 PDC dc = (PDC)AccessUserObject(hDC);
489 PFONTGDI FontGDI;
490
491 FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
492 memcpy(tm, &FontGDI->TextMetric, sizeof(TEXTMETRIC));
493
494 return TRUE;
495 }
496
497 BOOL
498 STDCALL
499 W32kPolyTextOut(HDC hDC,
500 CONST LPPOLYTEXT txt,
501 int Count)
502 {
503 UNIMPLEMENTED;
504 }
505
506 BOOL
507 STDCALL
508 W32kRemoveFontResource(LPCWSTR FileName)
509 {
510 UNIMPLEMENTED;
511 }
512
513 DWORD
514 STDCALL
515 W32kSetMapperFlags(HDC hDC,
516 DWORD Flag)
517 {
518 UNIMPLEMENTED;
519 }
520
521 UINT
522 STDCALL
523 W32kSetTextAlign(HDC hDC,
524 UINT Mode)
525 {
526 UINT prevAlign;
527 DC *dc;
528
529 dc = DC_HandleToPtr(hDC);
530 if (!dc)
531 {
532 return 0;
533 }
534 prevAlign = dc->w.textAlign;
535 dc->w.textAlign = Mode;
536 DC_ReleasePtr( hDC );
537 return prevAlign;
538 }
539
540 COLORREF
541 STDCALL
542 W32kSetTextColor(HDC hDC,
543 COLORREF color)
544 {
545 COLORREF oldColor;
546 PDC dc = DC_HandleToPtr(hDC);
547
548 if (!dc)
549 {
550 return 0x80000000;
551 }
552
553 oldColor = dc->w.textColor;
554 dc->w.textColor = color;
555 DC_ReleasePtr( hDC );
556 return oldColor;
557 }
558
559 BOOL
560 STDCALL
561 W32kSetTextJustification(HDC hDC,
562 int BreakExtra,
563 int BreakCount)
564 {
565 UNIMPLEMENTED;
566 }
567
568 BOOL
569 STDCALL
570 W32kTextOut(HDC hDC,
571 int XStart,
572 int YStart,
573 LPCWSTR String,
574 int Count)
575 {
576 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
577
578 DC *dc = DC_HandleToPtr(hDC);
579 SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject(dc->Surface);
580 int error, glyph_index, n, load_flags = FT_LOAD_RENDER, i, j, sx, sy, scc;
581 FT_Face face;
582 FT_GlyphSlot glyph;
583 ULONG TextLeft, TextTop, SpaceBetweenChars = 2, pitch, previous;
584 FT_Bool use_kerning;
585 RECTL DestRect, MaskRect;
586 POINTL SourcePoint, BrushOrigin;
587 HBRUSH hBrush = NULL;
588 PBRUSHOBJ Brush = NULL;
589 HBITMAP HSourceGlyph;
590 PSURFOBJ SourceGlyphSurf;
591 SIZEL bitSize;
592 FT_CharMap found = 0, charmap;
593 INT yoff;
594 HFONT hFont = 0;
595 PFONTOBJ FontObj;
596 PFONTGDI FontGDI;
597 PTEXTOBJ TextObj;
598 PPALGDI PalDestGDI;
599 PXLATEOBJ XlateObj;
600
601 if( !dc )
602 return FALSE;
603
604 XStart += dc->w.DCOrgX;
605 YStart += dc->w.DCOrgY;
606 TextLeft = XStart;
607 TextTop = YStart;
608
609 TextObj = TEXTOBJ_LockText(dc->w.hFont);
610
611 for(i=0; i<FontsLoaded; i++)
612 {
613 if(wcscmp(FontTable[i].FaceName, (LPSTR)TextObj->logfont.lfFaceName) == 0)
614 hFont = FontTable[i].hFont;
615 }
616
617 if(hFont == 0)
618 {
619 DbgPrint("Specified font %s is not loaded\n", TextObj->logfont.lfFaceName);
620 goto fail;
621 }
622
623 FontObj = (PFONTOBJ)AccessUserObject(hFont);
624 FontGDI = (PFONTGDI)AccessInternalObject(hFont);
625 face = FontGDI->face;
626
627 if (face->charmap == NULL)
628 {
629 DbgPrint("WARNING: No charmap selected!\n");
630 DbgPrint("This font face has %d charmaps\n", face->num_charmaps);
631
632 for (n = 0; n < face->num_charmaps; n++)
633 {
634 charmap = face->charmaps[n];
635 DbgPrint("found charmap encoding: %u\n", charmap->encoding);
636 if (charmap->encoding != 0)
637 {
638 found = charmap;
639 break;
640 }
641 }
642 if (!found) DbgPrint("WARNING: Could not find desired charmap!\n");
643 error = FT_Set_Charmap(face, found);
644 if (error) DbgPrint("WARNING: Could not set the charmap!\n");
645 }
646
647 error = FT_Set_Pixel_Sizes(face, TextObj->logfont.lfHeight, TextObj->logfont.lfWidth);
648 if(error) {
649 DbgPrint("Error in setting pixel sizes: %u\n", error);
650 goto fail;
651 }
652
653 // Create the brush
654 PalDestGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
655 XlateObj = (PXLATEOBJ)EngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
656 hBrush = W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
657 Brush = BRUSHOBJ_LockBrush(hBrush);
658 EngDeleteXlate(XlateObj);
659
660 SourcePoint.x = 0;
661 SourcePoint.y = 0;
662 MaskRect.left = 0;
663 MaskRect.top = 0;
664 BrushOrigin.x = 0;
665 BrushOrigin.y = 0;
666
667 // Determine the yoff from the dc's w.textAlign
668 if (dc->w.textAlign & TA_BASELINE) {
669 yoff = 0;
670 }
671 else
672 if (dc->w.textAlign & TA_BOTTOM) {
673 yoff = -face->size->metrics.descender / 64;
674 }
675 else { // TA_TOP
676 yoff = face->size->metrics.ascender / 64;
677 }
678
679 use_kerning = FT_HAS_KERNING(face);
680 previous = 0;
681
682 for(i=0; i<Count; i++)
683 {
684 glyph_index = FT_Get_Char_Index(face, *String);
685 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
686 if(error) {
687 DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
688 goto fail;
689 }
690 glyph = face->glyph;
691
692 // retrieve kerning distance and move pen position
693 if (use_kerning && previous && glyph_index)
694 {
695 FT_Vector delta;
696 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
697 TextLeft += delta.x >> 6;
698 }
699
700 if (glyph->format == ft_glyph_format_outline)
701 {
702 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
703 if(error) {
704 DbgPrint("WARNING: Failed to render glyph!\n");
705 goto fail;
706 }
707 pitch = glyph->bitmap.pitch;
708 } else {
709 pitch = glyph->bitmap.width;
710 }
711
712 DestRect.left = TextLeft;
713 DestRect.top = TextTop + yoff - glyph->bitmap_top;
714 DestRect.right = TextLeft + glyph->bitmap.width;
715 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
716 bitSize.cx = pitch-1;
717 bitSize.cy = glyph->bitmap.rows-1;
718 MaskRect.right = glyph->bitmap.width;
719 MaskRect.bottom = glyph->bitmap.rows;
720
721 // We should create the bitmap out of the loop at the biggest possible glyph size
722 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
723
724 HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
725 SourceGlyphSurf = (PSURFOBJ)AccessUserObject(HSourceGlyph);
726
727 // Use the font data as a mask to paint onto the DCs surface using a brush
728 EngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
729
730 EngDeleteSurface(HSourceGlyph);
731
732 TextLeft += glyph->advance.x >> 6;
733 previous = glyph_index;
734
735 String++;
736 }
737 TEXTOBJ_UnlockText( dc->w.hFont );
738 BRUSHOBJ_UnlockBrush(hBrush);
739 W32kDeleteObject( hBrush );
740 DC_ReleasePtr( hDC );
741 return TRUE;
742
743 fail:
744 TEXTOBJ_UnlockText( dc->w.hFont );
745 if( hBrush ){
746 BRUSHOBJ_UnlockBrush(hBrush);
747 W32kDeleteObject( hBrush );
748 }
749 DC_ReleasePtr( hDC );
750 return FALSE;
751 }
752
753 UINT
754 STDCALL
755 W32kTranslateCharsetInfo(PDWORD Src,
756 LPCHARSETINFO CSI,
757 DWORD Flags)
758 {
759 UNIMPLEMENTED;
760 }