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