3 #undef WIN32_LEAN_AND_MEAN
6 #include <internal/safe.h>
7 #include <win32k/brush.h>
9 #include <win32k/text.h>
10 #include <win32k/kapi.h>
12 #include FT_FREETYPE_H
14 #include "../eng/handle.h"
16 #include <include/inteng.h>
19 #include <win32k/debug1.h>
23 typedef struct _FONTTABLE {
26 } FONTTABLE, *PFONTTABLE;
28 FONTTABLE FontTable[256];
31 BOOL InitFontSupport()
35 error = FT_Init_FreeType(&library);
42 W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\arial.ttf");
44 W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\helb____.ttf");
45 W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\timr____.ttf");
47 DPRINT("All fonts loaded\n");
53 GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj, PFONTGDI *FontGDI)
56 NTSTATUS Status = STATUS_SUCCESS;
58 ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
59 if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
61 if (NT_SUCCESS(Status) && NULL != FontHandle)
63 *FontHandle = TextObj->GDIFontHandle;
65 if (NT_SUCCESS(Status) && NULL != FontObj)
67 *FontObj = AccessUserObject((ULONG) TextObj->GDIFontHandle);
71 Status = STATUS_INVALID_HANDLE;
74 if (NT_SUCCESS(Status) && NULL != FontGDI)
76 *FontGDI = AccessInternalObject((ULONG) TextObj->GDIFontHandle);
80 Status = STATUS_INVALID_HANDLE;
86 Status = STATUS_INVALID_HANDLE;
94 W32kAddFontResource(LPCWSTR Filename)
99 UNICODE_STRING uFileName;
102 OBJECT_ATTRIBUTES ObjectAttributes;
103 FILE_STANDARD_INFORMATION FileStdInfo;
109 UNICODE_STRING StringU;
110 IO_STATUS_BLOCK Iosb;
112 NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
113 FontObj = (PFONTOBJ) AccessUserObject( (ULONG) NewFont );
114 FontGDI = (PFONTGDI) AccessInternalObject( (ULONG) NewFont );
116 RtlCreateUnicodeString(&uFileName, (LPWSTR)Filename);
119 InitializeObjectAttributes(&ObjectAttributes, &uFileName, 0, NULL, NULL);
121 Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &Iosb, 0, 0);
123 if (!NT_SUCCESS(Status))
125 DPRINT1("Could not open module file: %S\n", Filename);
129 // Get the size of the file
130 Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
131 if (!NT_SUCCESS(Status))
133 DPRINT1("Could not get file size\n");
137 // Allocate nonpageable memory for driver
138 size = FileStdInfo.EndOfFile.u.LowPart;
139 buffer = ExAllocatePool(NonPagedPool, size);
143 DPRINT1("could not allocate memory for module");
147 // Load driver into memory chunk
148 Status = NtReadFile(FileHandle, 0, 0, 0, &Iosb, buffer, FileStdInfo.EndOfFile.u.LowPart, 0, 0);
149 if (!NT_SUCCESS(Status))
151 DPRINT1("could not read module file into memory");
158 error = FT_New_Memory_Face(library, buffer, size, 0, &face);
159 if (error == FT_Err_Unknown_File_Format)
161 DPRINT1("Unknown font file format\n");
166 DPRINT1("Error reading font file (error code: %u)\n", error); // 48
170 // FontGDI->Filename = Filename; perform strcpy
171 FontGDI->face = face;
173 // FIXME: Complete text metrics
174 FontGDI->TextMetric.tmAscent = face->size->metrics.ascender; // units above baseline
175 FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
176 FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
178 DPRINT("Font loaded: %s (%s)\n", face->family_name, face->style_name);
179 DPRINT("Num glyphs: %u\n", face->num_glyphs);
181 // Add this font resource to the font table
182 FontTable[FontsLoaded].hFont = NewFont;
184 RtlInitAnsiString(&StringA, (LPSTR)face->family_name);
185 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
186 FontTable[FontsLoaded].FaceName = ExAllocatePool(NonPagedPool, (StringU.Length + 1) * 2);
187 wcscpy((LPWSTR)FontTable[FontsLoaded].FaceName, StringU.Buffer);
188 RtlFreeUnicodeString(&StringU);
196 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
199 NTSTATUS Status = STATUS_SUCCESS;
201 *NewFont = TEXTOBJ_AllocText();
202 if (NULL != *NewFont)
204 TextObj = TEXTOBJ_LockText(*NewFont);
207 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
208 if (lf->lfEscapement != lf->lfOrientation)
210 /* this should really depend on whether GM_ADVANCED is set */
211 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
213 TEXTOBJ_UnlockText(*NewFont);
218 Status = STATUS_INVALID_HANDLE;
223 Status = STATUS_NO_MEMORY;
231 W32kCreateFont(int Height,
240 DWORD OutputPrecision,
243 DWORD PitchAndFamily,
248 NTSTATUS Status = STATUS_SUCCESS;
250 logfont.lfHeight = Height;
251 logfont.lfWidth = Width;
252 logfont.lfEscapement = Escapement;
253 logfont.lfOrientation = Orientation;
254 logfont.lfWeight = Weight;
255 logfont.lfItalic = Italic;
256 logfont.lfUnderline = Underline;
257 logfont.lfStrikeOut = StrikeOut;
258 logfont.lfCharSet = CharSet;
259 logfont.lfOutPrecision = OutputPrecision;
260 logfont.lfClipPrecision = ClipPrecision;
261 logfont.lfQuality = Quality;
262 logfont.lfPitchAndFamily = PitchAndFamily;
266 Status = MmCopyFromCaller(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
270 logfont.lfFaceName[0] = L'\0';
273 if (NT_SUCCESS(Status))
275 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
278 return NT_SUCCESS(Status) ? NewFont : NULL;
283 W32kCreateFontIndirect(CONST LPLOGFONTW lf)
285 LOGFONTW SafeLogfont;
287 NTSTATUS Status = STATUS_SUCCESS;
291 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
292 if (NT_SUCCESS(Status))
294 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
299 Status = STATUS_INVALID_PARAMETER;
302 return NT_SUCCESS(Status) ? NewFont : NULL;
307 W32kCreateScalableFontResource(DWORD Hidden,
317 W32kEnumFontFamilies(HDC hDC,
319 FONTENUMPROCW EnumFontFamProc,
327 W32kEnumFontFamiliesEx(HDC hDC,
329 FONTENUMPROCW EnumFontFamExProc,
338 W32kEnumFonts(HDC hDC,
340 FONTENUMPROCW FontFunc,
348 W32kExtTextOut(HDC hDC,
362 W32kGetAspectRatioFilterEx(HDC hDC,
370 W32kGetCharABCWidths(HDC hDC,
380 W32kGetCharABCWidthsFloat(HDC hDC,
390 W32kGetCharacterPlacement(HDC hDC,
394 LPGCP_RESULTS Results,
402 W32kGetCharWidth(HDC hDC,
412 W32kGetCharWidth32(HDC hDC,
422 W32kGetCharWidthFloat(HDC hDC,
432 W32kGetFontLanguageInfo(HDC hDC)
439 W32kGetGlyphOutline(HDC hDC,
454 W32kGetKerningPairs(HDC hDC,
456 LPKERNINGPAIR krnpair)
463 W32kGetOutlineTextMetrics(HDC hDC,
465 LPOUTLINETEXTMETRICW otm)
472 W32kGetRasterizerCaps(LPRASTERIZER_STATUS rs,
480 W32kGetTextCharset(HDC hDC)
487 W32kGetTextCharsetInfo(HDC hDC,
496 W32kGetTextExtentExPoint(HDC hDC,
509 W32kGetTextExtentPoint(HDC hDC,
514 PDC dc = (PDC)AccessUserObject((ULONG) hDC);
518 INT error, pitch, glyph_index, i;
519 ULONG TotalWidth = 0, MaxHeight = 0, CurrentChar = 0, SpaceBetweenChars = 5;
521 FontGDI = (PFONTGDI)AccessInternalObject((ULONG) dc->w.hFont);
523 for(i=0; i<Count; i++)
525 glyph_index = FT_Get_Char_Index(face, *String);
526 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
527 if(error) DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
530 if (glyph->format == ft_glyph_format_outline)
532 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
533 if(error) DPRINT1("WARNING: Failed to render glyph!\n");
534 pitch = glyph->bitmap.pitch;
536 pitch = glyph->bitmap.width;
539 TotalWidth += pitch-1;
540 if((glyph->bitmap.rows-1) > MaxHeight) MaxHeight = glyph->bitmap.rows-1;
544 if(CurrentChar < Size->cx) TotalWidth += SpaceBetweenChars;
548 Size->cx = TotalWidth;
549 Size->cy = MaxHeight;
554 W32kGetTextExtentPoint32(HDC hDC,
564 W32kGetTextFace(HDC hDC,
573 W32kGetTextMetrics(HDC hDC,
579 NTSTATUS Status = STATUS_SUCCESS;
584 dc = DC_HandleToPtr(hDC);
585 if (NULL == dc || NULL == tm)
587 Status = STATUS_INVALID_PARAMETER;
591 TextObj = TEXTOBJ_LockText(dc->w.hFont);
594 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
595 if (NT_SUCCESS(Status))
597 Face = FontGDI->face;
598 Error = FT_Set_Pixel_Sizes(Face, TextObj->logfont.lfHeight,
599 TextObj->logfont.lfWidth);
602 DPRINT1("Error in setting pixel sizes: %u\n", Error);
603 Status = STATUS_UNSUCCESSFUL;
607 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
608 SafeTm.tmAscent = (Face->size->metrics.ascender + 32) / 64; // units above baseline
609 SafeTm.tmDescent = (Face->size->metrics.descender + 32) / 64; // units below baseline
610 SafeTm.tmHeight = (Face->size->metrics.ascender +
611 Face->size->metrics.descender + 32) / 64;
612 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
615 TEXTOBJ_UnlockText(dc->w.hFont);
620 Status = STATUS_INVALID_HANDLE;
625 return NT_SUCCESS(Status);
630 W32kPolyTextOut(HDC hDC,
631 CONST LPPOLYTEXT txt,
639 W32kRemoveFontResource(LPCWSTR FileName)
646 W32kSetMapperFlags(HDC hDC,
654 W32kSetTextAlign(HDC hDC,
660 dc = DC_HandleToPtr(hDC);
665 prevAlign = dc->w.textAlign;
666 dc->w.textAlign = Mode;
667 DC_ReleasePtr( hDC );
673 W32kSetTextColor(HDC hDC,
677 PDC dc = DC_HandleToPtr(hDC);
684 oldColor = dc->w.textColor;
685 dc->w.textColor = color;
686 DC_ReleasePtr( hDC );
692 W32kSetTextJustification(HDC hDC,
707 // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
709 DC *dc = DC_HandleToPtr(hDC);
710 SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
711 int error, glyph_index, n, i;
714 ULONG TextLeft, TextTop, pitch, previous;
716 RECTL DestRect, MaskRect;
717 POINTL SourcePoint, BrushOrigin;
718 HBRUSH hBrush = NULL;
719 PBRUSHOBJ Brush = NULL;
720 HBITMAP HSourceGlyph;
721 PSURFOBJ SourceGlyphSurf;
723 FT_CharMap found = 0, charmap;
734 XStart += dc->w.DCOrgX;
735 YStart += dc->w.DCOrgY;
739 TextObj = TEXTOBJ_LockText(dc->w.hFont);
741 if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
745 face = FontGDI->face;
747 if (face->charmap == NULL)
749 DPRINT("WARNING: No charmap selected!\n");
750 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
752 for (n = 0; n < face->num_charmaps; n++)
754 charmap = face->charmaps[n];
755 DPRINT("found charmap encoding: %u\n", charmap->encoding);
756 if (charmap->encoding != 0)
762 if (!found) DPRINT1("WARNING: Could not find desired charmap!\n");
763 error = FT_Set_Charmap(face, found);
764 if (error) DPRINT1("WARNING: Could not set the charmap!\n");
767 error = FT_Set_Pixel_Sizes(face, TextObj->logfont.lfHeight, TextObj->logfont.lfWidth);
769 DPRINT1("Error in setting pixel sizes: %u\n", error);
774 PalDestGDI = (PPALGDI)AccessInternalObject((ULONG) dc->w.hPalette);
775 XlateObj = (PXLATEOBJ)IntEngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
776 hBrush = W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
777 Brush = BRUSHOBJ_LockBrush(hBrush);
778 EngDeleteXlate(XlateObj);
787 // Determine the yoff from the dc's w.textAlign
788 if (dc->w.textAlign & TA_BASELINE) {
792 if (dc->w.textAlign & TA_BOTTOM) {
793 yoff = -face->size->metrics.descender / 64;
796 yoff = face->size->metrics.ascender / 64;
799 use_kerning = FT_HAS_KERNING(face);
802 for(i=0; i<Count; i++)
804 glyph_index = FT_Get_Char_Index(face, *String);
805 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
807 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
812 // retrieve kerning distance and move pen position
813 if (use_kerning && previous && glyph_index)
816 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
817 TextLeft += delta.x >> 6;
820 if (glyph->format == ft_glyph_format_outline)
822 error = FT_Render_Glyph(glyph, ft_render_mode_mono);
824 DPRINT1("WARNING: Failed to render glyph!\n");
827 pitch = glyph->bitmap.pitch;
829 pitch = glyph->bitmap.width;
832 DestRect.left = TextLeft;
833 DestRect.top = TextTop + yoff - glyph->bitmap_top;
834 DestRect.right = TextLeft + glyph->bitmap.width;
835 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
837 bitSize.cy = glyph->bitmap.rows;
838 MaskRect.right = glyph->bitmap.width;
839 MaskRect.bottom = glyph->bitmap.rows;
841 // We should create the bitmap out of the loop at the biggest possible glyph size
842 // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
844 HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
845 SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
847 // Use the font data as a mask to paint onto the DCs surface using a brush
848 IntEngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
850 EngDeleteSurface(HSourceGlyph);
852 TextLeft += glyph->advance.x >> 6;
853 previous = glyph_index;
857 TEXTOBJ_UnlockText( dc->w.hFont );
858 BRUSHOBJ_UnlockBrush(hBrush);
859 W32kDeleteObject( hBrush );
860 DC_ReleasePtr( hDC );
864 TEXTOBJ_UnlockText( dc->w.hFont );
866 BRUSHOBJ_UnlockBrush(hBrush);
867 W32kDeleteObject( hBrush );
869 DC_ReleasePtr( hDC );
875 W32kTranslateCharsetInfo(PDWORD Src,
883 TextIntRealizeFont(HFONT FontHandle)
886 NTSTATUS Status = STATUS_SUCCESS;
889 TextObj = TEXTOBJ_LockText(FontHandle);
893 for(i = 0; NULL == TextObj->GDIFontHandle && i < FontsLoaded; i++)
895 if (0 == wcscmp(FontTable[i].FaceName, TextObj->logfont.lfFaceName))
897 TextObj->GDIFontHandle = FontTable[i].hFont;
901 if (NULL == TextObj->GDIFontHandle)
903 if (0 != FontsLoaded)
905 DPRINT("Requested font %S not found, using first available font\n",
906 TextObj->logfont.lfFaceName)
907 TextObj->GDIFontHandle = FontTable[0].hFont;
911 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
912 TextObj->logfont.lfFaceName)
913 Status = STATUS_NOT_FOUND;
917 ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
919 TEXTOBJ_UnlockText(FontHandle);
923 Status = STATUS_INVALID_HANDLE;