7d1aebbb66ab2df0b2fab05863110654b301b804
[reactos.git] / win32ss / gdi / ntgdi / font.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/font.c
5 * PURPOSE: Font
6 * PROGRAMMERS: James Tabor <james.tabor@reactos.org>
7 * Timo Kreuzer <timo.kreuzer@reactos.org>
8 * Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
9 */
10
11 /** Includes ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 HFONT APIENTRY HfontCreate( IN PENUMLOGFONTEXDVW pelfw,IN ULONG cjElfw,IN LFTYPE lft,IN FLONG fl,IN PVOID pvCliData );
19
20 /** Internal ******************************************************************/
21
22 HFONT FASTCALL
23 GreCreateFontIndirectW( LOGFONTW *lplf )
24 {
25 if (lplf)
26 {
27 ENUMLOGFONTEXDVW Logfont;
28
29 RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
30 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfFullName,
31 sizeof(Logfont.elfEnumLogfontEx.elfFullName));
32 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfStyle,
33 sizeof(Logfont.elfEnumLogfontEx.elfStyle));
34 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfScript,
35 sizeof(Logfont.elfEnumLogfontEx.elfScript));
36
37 Logfont.elfDesignVector.dvNumAxes = 0;
38
39 RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
40
41 return HfontCreate((PENUMLOGFONTEXDVW)&Logfont, 0, 0, 0, NULL );
42 }
43 else return NULL;
44 }
45
46 DWORD
47 FASTCALL
48 GreGetKerningPairs(
49 HDC hDC,
50 ULONG NumPairs,
51 LPKERNINGPAIR krnpair)
52 {
53 PDC dc;
54 PDC_ATTR pdcattr;
55 PTEXTOBJ TextObj;
56 PFONTGDI FontGDI;
57 DWORD Count;
58 KERNINGPAIR *pKP;
59
60 dc = DC_LockDc(hDC);
61 if (!dc)
62 {
63 EngSetLastError(ERROR_INVALID_HANDLE);
64 return 0;
65 }
66
67 pdcattr = dc->pdcattr;
68 TextObj = RealizeFontInit(pdcattr->hlfntNew);
69 DC_UnlockDc(dc);
70
71 if (!TextObj)
72 {
73 EngSetLastError(ERROR_INVALID_HANDLE);
74 return 0;
75 }
76
77 FontGDI = ObjToGDI(TextObj->Font, FONT);
78 TEXTOBJ_UnlockText(TextObj);
79
80 Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
81
82 if ( Count && krnpair )
83 {
84 if (Count > NumPairs)
85 {
86 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
87 return 0;
88 }
89 pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
90 if (!pKP)
91 {
92 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
93 return 0;
94 }
95 ftGdiGetKerningPairs(FontGDI,Count,pKP);
96
97 RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
98
99 ExFreePoolWithTag(pKP,GDITAG_TEXT);
100 }
101 return Count;
102 }
103
104 /*
105
106 It is recommended that an application use the GetFontLanguageInfo function
107 to determine whether the GCP_DIACRITIC, GCP_DBCS, GCP_USEKERNING, GCP_LIGATE,
108 GCP_REORDER, GCP_GLYPHSHAPE, and GCP_KASHIDA values are valid for the
109 currently selected font. If not valid, GetCharacterPlacement ignores the
110 value.
111
112 M$ must use a preset "compiled in" support for each language based releases.
113 ReactOS uses FreeType, this will need to be supported. ATM this is hard coded
114 for GCPCLASS_LATIN!
115
116 */
117 #if 0
118 DWORD
119 FASTCALL
120 GreGetCharacterPlacementW(
121 HDC hdc,
122 LPCWSTR pwsz,
123 INT nCount,
124 INT nMaxExtent,
125 LPGCP_RESULTSW pgcpw,
126 DWORD dwFlags)
127 {
128 GCP_RESULTSW gcpwSave;
129 UINT i, nSet, cSet;
130 INT *tmpDxCaretPos;
131 LONG Cx;
132 SIZE Size = {0,0};
133
134 DPRINT1("GreGCPW Start\n");
135
136 if (!pgcpw)
137 {
138 if (GreGetTextExtentW( hdc, pwsz, nCount, &Size, 1))
139 return MAKELONG(Size.cx, Size.cy);
140 return 0;
141 }
142
143 DPRINT1("GreGCPW 1\n");
144
145 RtlCopyMemory(&gcpwSave, pgcpw, sizeof(GCP_RESULTSW));
146
147 cSet = nSet = nCount;
148
149 if ( nCount > gcpwSave.nGlyphs ) cSet = gcpwSave.nGlyphs;
150
151 /* GCP_JUSTIFY may only be used in conjunction with GCP_MAXEXTENT. */
152 if ( dwFlags & GCP_JUSTIFY) dwFlags |= GCP_MAXEXTENT;
153
154 if ( !gcpwSave.lpDx && gcpwSave.lpCaretPos )
155 tmpDxCaretPos = gcpwSave.lpCaretPos;
156 else
157 tmpDxCaretPos = gcpwSave.lpDx;
158
159 if ( !GreGetTextExtentExW( hdc,
160 pwsz,
161 cSet,
162 nMaxExtent,
163 ((dwFlags & GCP_MAXEXTENT) ? (PULONG) &cSet : NULL),
164 (PULONG) tmpDxCaretPos,
165 &Size,
166 0) )
167 {
168 return 0;
169 }
170
171 DPRINT1("GreGCPW 2\n");
172
173 nSet = cSet;
174
175 if ( tmpDxCaretPos && nSet > 0)
176 {
177 for (i = (nSet - 1); i > 0; i--)
178 {
179 tmpDxCaretPos[i] -= tmpDxCaretPos[i - 1];
180 }
181 }
182
183 if ( !(dwFlags & GCP_MAXEXTENT) || nSet )
184 {
185 if ( (dwFlags & GCP_USEKERNING) &&
186 ( gcpwSave.lpDx ||
187 gcpwSave.lpCaretPos ) &&
188 nSet >= 2 )
189 {
190 DWORD Count;
191 LPKERNINGPAIR pKP;
192
193 Count = GreGetKerningPairs( hdc, 0, NULL);
194 if (Count)
195 {
196 pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
197 if (pKP)
198 {
199 if ( GreGetKerningPairs( hdc, Count, pKP) != Count)
200 {
201 ExFreePoolWithTag( pKP, GDITAG_TEXT);
202 return 0;
203 }
204
205 if ( (ULONG_PTR)(pKP) < ((ULONG_PTR)(pKP) + (ULONG_PTR)(Count * sizeof(KERNINGPAIR))) )
206 {
207 DPRINT1("We Need to Do Something HERE!\n");
208 }
209
210 ExFreePoolWithTag( pKP, GDITAG_TEXT);
211
212 if ( dwFlags & GCP_MAXEXTENT )
213 {
214 if ( Size.cx > nMaxExtent )
215 {
216 for (Cx = Size.cx; nSet > 0; nSet--)
217 {
218 Cx -= tmpDxCaretPos[nSet - 1];
219 Size.cx = Cx;
220 if ( Cx <= nMaxExtent ) break;
221 }
222 }
223 if ( !nSet )
224 {
225 pgcpw->nGlyphs = 0;
226 pgcpw->nMaxFit = 0;
227 return 0;
228 }
229 }
230 }
231 }
232 }
233
234 if ( (dwFlags & GCP_JUSTIFY) &&
235 ( gcpwSave.lpDx ||
236 gcpwSave.lpCaretPos ) &&
237 nSet )
238 {
239 DPRINT1("We Need to Do Something HERE 2!\n");
240 }
241
242 if ( gcpwSave.lpDx && gcpwSave.lpCaretPos )
243 RtlCopyMemory( gcpwSave.lpCaretPos, gcpwSave.lpDx, nSet * sizeof(LONG));
244
245 if ( gcpwSave.lpCaretPos )
246 {
247 int pos = 0;
248 i = 0;
249 if ( nSet > 0 )
250 {
251 do
252 {
253 Cx = gcpwSave.lpCaretPos[i];
254 gcpwSave.lpCaretPos[i] = pos;
255 pos += Cx;
256 ++i;
257 }
258 while ( i < nSet );
259 }
260 }
261
262 if ( gcpwSave.lpOutString )
263 RtlCopyMemory(gcpwSave.lpOutString, pwsz, nSet * sizeof(WCHAR));
264
265 if ( gcpwSave.lpClass )
266 RtlFillMemory(gcpwSave.lpClass, nSet, GCPCLASS_LATIN);
267
268 if ( gcpwSave.lpOrder )
269 {
270 for (i = 0; i < nSet; i++)
271 gcpwSave.lpOrder[i] = i;
272 }
273
274 if ( gcpwSave.lpGlyphs )
275 {
276 if ( GreGetGlyphIndicesW( hdc, pwsz, nSet, gcpwSave.lpGlyphs, 0, 0) == GDI_ERROR )
277 {
278 nSet = 0;
279 Size.cx = 0;
280 Size.cy = 0;
281 }
282 }
283 pgcpw->nGlyphs = nSet;
284 pgcpw->nMaxFit = nSet;
285 }
286 DPRINT1("GreGCPW Exit\n");
287 return MAKELONG(Size.cx, Size.cy);
288 }
289 #endif
290
291 ULONG
292 FASTCALL
293 FontGetObject(PTEXTOBJ plfont, ULONG cjBuffer, PVOID pvBuffer)
294 {
295 ULONG cjMaxSize;
296 ENUMLOGFONTEXDVW *plf = &plfont->logfont;
297
298 /* If buffer is NULL, only the size is requested */
299 if (pvBuffer == NULL) return sizeof(LOGFONTW);
300
301 /* Calculate the maximum size according to number of axes */
302 cjMaxSize = FIELD_OFFSET(ENUMLOGFONTEXDVW,
303 elfDesignVector.dvValues[plf->elfDesignVector.dvNumAxes]);
304
305 if (cjBuffer > cjMaxSize) cjBuffer = cjMaxSize;
306
307 RtlCopyMemory(pvBuffer, plf, cjBuffer);
308
309 return cjBuffer;
310 }
311
312 DWORD
313 FASTCALL
314 IntGetCharDimensions(HDC hdc, PTEXTMETRICW ptm, PDWORD height)
315 {
316 PDC pdc;
317 PDC_ATTR pdcattr;
318 PTEXTOBJ TextObj;
319 SIZE sz;
320 TMW_INTERNAL tmwi;
321 BOOL Good;
322
323 static const WCHAR alphabet[] = {
324 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
325 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
326 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
327
328 if(!ftGdiGetTextMetricsW(hdc, &tmwi)) return 0;
329
330 pdc = DC_LockDc(hdc);
331
332 if (!pdc) return 0;
333
334 pdcattr = pdc->pdcattr;
335
336 TextObj = RealizeFontInit(pdcattr->hlfntNew);
337 if ( !TextObj )
338 {
339 DC_UnlockDc(pdc);
340 return 0;
341 }
342 Good = TextIntGetTextExtentPoint(pdc, TextObj, alphabet, 52, 0, NULL, 0, &sz, 0);
343 TEXTOBJ_UnlockText(TextObj);
344 DC_UnlockDc(pdc);
345
346 if (!Good) return 0;
347 if (ptm) *ptm = tmwi.TextMetric;
348 if (height) *height = tmwi.TextMetric.tmHeight;
349
350 return (sz.cx / 26 + 1) / 2;
351 }
352
353
354 DWORD
355 FASTCALL
356 IntGetFontLanguageInfo(PDC Dc)
357 {
358 PDC_ATTR pdcattr;
359 FONTSIGNATURE fontsig;
360 static const DWORD GCP_DBCS_MASK=0x003F0000,
361 GCP_DIACRITIC_MASK=0x00000000,
362 FLI_GLYPHS_MASK=0x00000000,
363 GCP_GLYPHSHAPE_MASK=0x00000040,
364 GCP_KASHIDA_MASK=0x00000000,
365 GCP_LIGATE_MASK=0x00000000,
366 GCP_USEKERNING_MASK=0x00000000,
367 GCP_REORDER_MASK=0x00000060;
368
369 DWORD result=0;
370
371 ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
372
373 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
374 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
375 result|=GCP_DBCS;
376
377 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
378 result|=GCP_DIACRITIC;
379
380 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
381 result|=FLI_GLYPHS;
382
383 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
384 result|=GCP_GLYPHSHAPE;
385
386 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
387 result|=GCP_KASHIDA;
388
389 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
390 result|=GCP_LIGATE;
391
392 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
393 result|=GCP_USEKERNING;
394
395 pdcattr = Dc->pdcattr;
396
397 /* This might need a test for a HEBREW- or ARABIC_CHARSET as well */
398 if ( pdcattr->lTextAlign & TA_RTLREADING )
399 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
400 result|=GCP_REORDER;
401
402 return result;
403 }
404
405 PTEXTOBJ
406 FASTCALL
407 RealizeFontInit(HFONT hFont)
408 {
409 NTSTATUS Status = STATUS_SUCCESS;
410 PTEXTOBJ pTextObj;
411
412 pTextObj = TEXTOBJ_LockText(hFont);
413
414 if ( pTextObj && !(pTextObj->fl & TEXTOBJECT_INIT))
415 {
416 Status = TextIntRealizeFont(hFont, pTextObj);
417 if (!NT_SUCCESS(Status))
418 {
419 TEXTOBJ_UnlockText(pTextObj);
420 return NULL;
421 }
422 }
423 return pTextObj;
424 }
425
426
427 /** Functions ******************************************************************/
428
429 INT
430 APIENTRY
431 NtGdiAddFontResourceW(
432 IN WCHAR *pwcFiles,
433 IN ULONG cwc,
434 IN ULONG cFiles,
435 IN FLONG fl,
436 IN DWORD dwPidTid,
437 IN OPTIONAL DESIGNVECTOR *pdv)
438 {
439 UNICODE_STRING SafeFileName;
440 INT Ret;
441
442 DBG_UNREFERENCED_PARAMETER(cFiles);
443 DBG_UNREFERENCED_PARAMETER(dwPidTid);
444 DBG_UNREFERENCED_PARAMETER(pdv);
445
446 DPRINT("NtGdiAddFontResourceW\n");
447
448 /* cwc = Length + trailing zero. */
449 if ((cwc <= 1) || (cwc > UNICODE_STRING_MAX_CHARS))
450 return 0;
451
452 SafeFileName.MaximumLength = (USHORT)(cwc * sizeof(WCHAR));
453 SafeFileName.Length = SafeFileName.MaximumLength - sizeof(UNICODE_NULL);
454 SafeFileName.Buffer = ExAllocatePoolWithTag(PagedPool,
455 SafeFileName.MaximumLength,
456 TAG_STRING);
457 if (!SafeFileName.Buffer)
458 {
459 return 0;
460 }
461
462 _SEH2_TRY
463 {
464 ProbeForRead(pwcFiles, cwc * sizeof(WCHAR), sizeof(WCHAR));
465 RtlCopyMemory(SafeFileName.Buffer, pwcFiles, SafeFileName.Length);
466 }
467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
468 {
469 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
470 _SEH2_YIELD(return 0);
471 }
472 _SEH2_END;
473
474 SafeFileName.Buffer[SafeFileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
475 Ret = IntGdiAddFontResource(&SafeFileName, fl);
476
477 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
478 return Ret;
479 }
480
481 HANDLE
482 APIENTRY
483 NtGdiAddFontMemResourceEx(
484 IN PVOID pvBuffer,
485 IN DWORD cjBuffer,
486 IN DESIGNVECTOR *pdv,
487 IN ULONG cjDV,
488 OUT DWORD *pNumFonts)
489 {
490 _SEH2_VOLATILE PVOID Buffer = NULL;
491 HANDLE Ret;
492 DWORD NumFonts = 0;
493
494 DPRINT("NtGdiAddFontMemResourceEx\n");
495 DBG_UNREFERENCED_PARAMETER(pdv);
496 DBG_UNREFERENCED_PARAMETER(cjDV);
497
498 if (!pvBuffer || !cjBuffer)
499 return NULL;
500
501 _SEH2_TRY
502 {
503 ProbeForRead(pvBuffer, cjBuffer, sizeof(BYTE));
504 Buffer = ExAllocatePoolWithQuotaTag(PagedPool, cjBuffer, TAG_FONT);
505 RtlCopyMemory(Buffer, pvBuffer, cjBuffer);
506 }
507 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
508 {
509 if (Buffer != NULL)
510 {
511 ExFreePoolWithTag(Buffer, TAG_FONT);
512 }
513 _SEH2_YIELD(return NULL);
514 }
515 _SEH2_END;
516
517 Ret = IntGdiAddFontMemResource(Buffer, cjBuffer, &NumFonts);
518 ExFreePoolWithTag(Buffer, TAG_FONT);
519
520 _SEH2_TRY
521 {
522 ProbeForWrite(pNumFonts, sizeof(NumFonts), 1);
523 *pNumFonts = NumFonts;
524 }
525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
526 {
527 /* Leak it? */
528 _SEH2_YIELD(return NULL);
529 }
530 _SEH2_END;
531
532
533 return Ret;
534 }
535
536
537 BOOL
538 APIENTRY
539 NtGdiRemoveFontMemResourceEx(
540 IN HANDLE hMMFont)
541 {
542 return IntGdiRemoveFontMemResource(hMMFont);
543 }
544
545
546 /*
547 * @unimplemented
548 */
549 DWORD
550 APIENTRY
551 NtGdiGetCharacterPlacementW(
552 IN HDC hdc,
553 IN LPWSTR pwsz,
554 IN INT nCount,
555 IN INT nMaxExtent,
556 IN OUT LPGCP_RESULTSW pgcpw,
557 IN DWORD dwFlags)
558 {
559 UNIMPLEMENTED;
560 return 0;
561 #if 0
562 return GreGetCharacterPlacementW( hdc,
563 pwsz,
564 nCount,
565 nMaxExtent,
566 pgcpw,
567 dwFlags);
568 #endif
569 }
570
571 DWORD
572 APIENTRY
573 NtGdiGetFontData(
574 HDC hDC,
575 DWORD Table,
576 DWORD Offset,
577 LPVOID Buffer,
578 DWORD Size)
579 {
580 PDC Dc;
581 PDC_ATTR pdcattr;
582 HFONT hFont;
583 PTEXTOBJ TextObj;
584 PFONTGDI FontGdi;
585 DWORD Result = GDI_ERROR;
586 NTSTATUS Status = STATUS_SUCCESS;
587
588 if (Buffer && Size)
589 {
590 _SEH2_TRY
591 {
592 ProbeForRead(Buffer, Size, 1);
593 }
594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595 {
596 Status = _SEH2_GetExceptionCode();
597 }
598 _SEH2_END
599 }
600
601 if (!NT_SUCCESS(Status)) return Result;
602
603 Dc = DC_LockDc(hDC);
604 if (Dc == NULL)
605 {
606 EngSetLastError(ERROR_INVALID_HANDLE);
607 return GDI_ERROR;
608 }
609 pdcattr = Dc->pdcattr;
610
611 hFont = pdcattr->hlfntNew;
612 TextObj = RealizeFontInit(hFont);
613 DC_UnlockDc(Dc);
614
615 if (TextObj == NULL)
616 {
617 EngSetLastError(ERROR_INVALID_HANDLE);
618 return GDI_ERROR;
619 }
620
621 FontGdi = ObjToGDI(TextObj->Font, FONT);
622
623 Result = ftGdiGetFontData(FontGdi, Table, Offset, Buffer, Size);
624
625 TEXTOBJ_UnlockText(TextObj);
626
627 return Result;
628 }
629
630 /*
631 * @implemented
632 */
633 DWORD
634 APIENTRY
635 NtGdiGetFontUnicodeRanges(
636 IN HDC hdc,
637 OUT OPTIONAL LPGLYPHSET pgs)
638 {
639 PDC pDc;
640 PDC_ATTR pdcattr;
641 HFONT hFont;
642 PTEXTOBJ TextObj;
643 PFONTGDI FontGdi;
644 DWORD Size = 0;
645 PGLYPHSET pgsSafe;
646 NTSTATUS Status = STATUS_SUCCESS;
647
648 pDc = DC_LockDc(hdc);
649 if (!pDc)
650 {
651 EngSetLastError(ERROR_INVALID_HANDLE);
652 return 0;
653 }
654
655 pdcattr = pDc->pdcattr;
656
657 hFont = pdcattr->hlfntNew;
658 TextObj = RealizeFontInit(hFont);
659
660 if ( TextObj == NULL)
661 {
662 EngSetLastError(ERROR_INVALID_HANDLE);
663 goto Exit;
664 }
665 FontGdi = ObjToGDI(TextObj->Font, FONT);
666
667 Size = ftGetFontUnicodeRanges( FontGdi, NULL);
668
669 if (Size && pgs)
670 {
671 pgsSafe = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
672 if (!pgsSafe)
673 {
674 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
675 Size = 0;
676 goto Exit;
677 }
678
679 Size = ftGetFontUnicodeRanges( FontGdi, pgsSafe);
680
681 if (Size)
682 {
683 _SEH2_TRY
684 {
685 ProbeForWrite(pgs, Size, 1);
686 RtlCopyMemory(pgs, pgsSafe, Size);
687 }
688 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
689 {
690 Status = _SEH2_GetExceptionCode();
691 }
692 _SEH2_END
693
694 if (!NT_SUCCESS(Status)) Size = 0;
695 }
696 ExFreePoolWithTag(pgsSafe, GDITAG_TEXT);
697 }
698 Exit:
699 TEXTOBJ_UnlockText(TextObj);
700 DC_UnlockDc(pDc);
701 return Size;
702 }
703
704 ULONG
705 APIENTRY
706 NtGdiGetGlyphOutline(
707 IN HDC hdc,
708 IN WCHAR wch,
709 IN UINT iFormat,
710 OUT LPGLYPHMETRICS pgm,
711 IN ULONG cjBuf,
712 OUT OPTIONAL PVOID UnsafeBuf,
713 IN LPMAT2 pmat2,
714 IN BOOL bIgnoreRotation)
715 {
716 ULONG Ret = GDI_ERROR;
717 PDC dc;
718 PVOID pvBuf = NULL;
719 GLYPHMETRICS gm;
720 NTSTATUS Status = STATUS_SUCCESS;
721
722 dc = DC_LockDc(hdc);
723 if (!dc)
724 {
725 EngSetLastError(ERROR_INVALID_HANDLE);
726 return GDI_ERROR;
727 }
728
729 if (UnsafeBuf && cjBuf)
730 {
731 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, GDITAG_TEXT);
732 if (!pvBuf)
733 {
734 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
735 goto Exit;
736 }
737 }
738
739 Ret = ftGdiGetGlyphOutline( dc,
740 wch,
741 iFormat,
742 pgm ? &gm : NULL,
743 cjBuf,
744 pvBuf,
745 pmat2,
746 bIgnoreRotation);
747
748 if (pvBuf)
749 {
750 _SEH2_TRY
751 {
752 ProbeForWrite(UnsafeBuf, cjBuf, 1);
753 RtlCopyMemory(UnsafeBuf, pvBuf, cjBuf);
754 }
755 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
756 {
757 Status = _SEH2_GetExceptionCode();
758 }
759 _SEH2_END
760
761 ExFreePoolWithTag(pvBuf, GDITAG_TEXT);
762 }
763
764 if (pgm)
765 {
766 _SEH2_TRY
767 {
768 ProbeForWrite(pgm, sizeof(GLYPHMETRICS), 1);
769 RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
770 }
771 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
772 {
773 Status = _SEH2_GetExceptionCode();
774 }
775 _SEH2_END
776 }
777
778 if (! NT_SUCCESS(Status))
779 {
780 EngSetLastError(ERROR_INVALID_PARAMETER);
781 Ret = GDI_ERROR;
782 }
783
784 Exit:
785 DC_UnlockDc(dc);
786 return Ret;
787 }
788
789 DWORD
790 APIENTRY
791 NtGdiGetKerningPairs(HDC hDC,
792 ULONG NumPairs,
793 LPKERNINGPAIR krnpair)
794 {
795 PDC dc;
796 PDC_ATTR pdcattr;
797 PTEXTOBJ TextObj;
798 PFONTGDI FontGDI;
799 DWORD Count;
800 KERNINGPAIR *pKP;
801 NTSTATUS Status = STATUS_SUCCESS;
802
803 dc = DC_LockDc(hDC);
804 if (!dc)
805 {
806 EngSetLastError(ERROR_INVALID_HANDLE);
807 return 0;
808 }
809
810 pdcattr = dc->pdcattr;
811 TextObj = RealizeFontInit(pdcattr->hlfntNew);
812 DC_UnlockDc(dc);
813
814 if (!TextObj)
815 {
816 EngSetLastError(ERROR_INVALID_HANDLE);
817 return 0;
818 }
819
820 FontGDI = ObjToGDI(TextObj->Font, FONT);
821 TEXTOBJ_UnlockText(TextObj);
822
823 Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
824
825 if ( Count && krnpair )
826 {
827 if (Count > NumPairs)
828 {
829 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
830 return 0;
831 }
832 pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
833 if (!pKP)
834 {
835 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
836 return 0;
837 }
838 ftGdiGetKerningPairs(FontGDI,Count,pKP);
839 _SEH2_TRY
840 {
841 ProbeForWrite(krnpair, Count * sizeof(KERNINGPAIR), 1);
842 RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
843 }
844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
845 {
846 Status = _SEH2_GetExceptionCode();
847 }
848 _SEH2_END
849 if (!NT_SUCCESS(Status))
850 {
851 EngSetLastError(ERROR_INVALID_PARAMETER);
852 Count = 0;
853 }
854 ExFreePoolWithTag(pKP,GDITAG_TEXT);
855 }
856 return Count;
857 }
858
859 /*
860 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
861 472, this is NtGdiGetOutlineTextMetricsInternalW.
862 */
863 ULONG
864 APIENTRY
865 NtGdiGetOutlineTextMetricsInternalW (HDC hDC,
866 ULONG Data,
867 OUTLINETEXTMETRICW *otm,
868 TMDIFF *Tmd)
869 {
870 PDC dc;
871 PDC_ATTR pdcattr;
872 PTEXTOBJ TextObj;
873 PFONTGDI FontGDI;
874 HFONT hFont = 0;
875 ULONG Size;
876 OUTLINETEXTMETRICW *potm;
877 NTSTATUS Status = STATUS_SUCCESS;
878
879 dc = DC_LockDc(hDC);
880 if (!dc)
881 {
882 EngSetLastError(ERROR_INVALID_HANDLE);
883 return 0;
884 }
885 pdcattr = dc->pdcattr;
886 hFont = pdcattr->hlfntNew;
887 TextObj = RealizeFontInit(hFont);
888 DC_UnlockDc(dc);
889 if (!TextObj)
890 {
891 EngSetLastError(ERROR_INVALID_HANDLE);
892 return 0;
893 }
894 FontGDI = ObjToGDI(TextObj->Font, FONT);
895 TextIntUpdateSize(dc, TextObj, FontGDI, TRUE);
896 TEXTOBJ_UnlockText(TextObj);
897 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
898 if (!otm) return Size;
899 if (Size > Data)
900 {
901 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
902 return 0;
903 }
904 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
905 if (!potm)
906 {
907 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
908 return 0;
909 }
910 IntGetOutlineTextMetrics(FontGDI, Size, potm);
911 if (otm)
912 {
913 _SEH2_TRY
914 {
915 ProbeForWrite(otm, Size, 1);
916 RtlCopyMemory(otm, potm, Size);
917 }
918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
919 {
920 Status = _SEH2_GetExceptionCode();
921 }
922 _SEH2_END
923
924 if (!NT_SUCCESS(Status))
925 {
926 EngSetLastError(ERROR_INVALID_PARAMETER);
927 Size = 0;
928 }
929 }
930 ExFreePoolWithTag(potm,GDITAG_TEXT);
931 return Size;
932 }
933
934 W32KAPI
935 BOOL
936 APIENTRY
937 NtGdiGetFontResourceInfoInternalW(
938 IN LPWSTR pwszFiles,
939 IN ULONG cwc,
940 IN ULONG cFiles,
941 IN UINT cjIn,
942 IN OUT LPDWORD pdwBytes,
943 OUT LPVOID pvBuf,
944 IN DWORD dwType)
945 {
946 NTSTATUS Status = STATUS_SUCCESS;
947 DWORD dwBytes, dwBytesRequested;
948 UNICODE_STRING SafeFileNames;
949 BOOL bRet = FALSE;
950 ULONG cbStringSize;
951 LPVOID Buffer;
952
953 /* FIXME: Handle cFiles > 0 */
954
955 /* Check for valid dwType values */
956 if (dwType > 5)
957 {
958 EngSetLastError(ERROR_INVALID_PARAMETER);
959 return FALSE;
960 }
961
962 /* Allocate a safe unicode string buffer */
963 cbStringSize = cwc * sizeof(WCHAR);
964 SafeFileNames.MaximumLength = SafeFileNames.Length = (USHORT)cbStringSize - sizeof(WCHAR);
965 SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
966 cbStringSize,
967 TAG_USTR);
968 if (!SafeFileNames.Buffer)
969 {
970 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
971 return FALSE;
972 }
973 RtlZeroMemory(SafeFileNames.Buffer, SafeFileNames.MaximumLength);
974
975 /* Check buffers and copy pwszFiles to safe unicode string */
976 _SEH2_TRY
977 {
978 ProbeForRead(pwszFiles, cbStringSize, 1);
979 ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
980 if (pvBuf)
981 ProbeForWrite(pvBuf, cjIn, 1);
982
983 dwBytes = *pdwBytes;
984 dwBytesRequested = dwBytes;
985
986 RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
987 if (dwBytes > 0)
988 {
989 Buffer = ExAllocatePoolWithTag(PagedPool, dwBytes, TAG_FINF);
990 }
991 else
992 {
993 Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(DWORD), TAG_FINF);
994 }
995 }
996 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
997 {
998 Status = _SEH2_GetExceptionCode();
999 }
1000 _SEH2_END
1001
1002 if(!NT_SUCCESS(Status))
1003 {
1004 SetLastNtError(Status);
1005 /* Free the string buffer for the safe filename */
1006 ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
1007 return FALSE;
1008 }
1009
1010 /* Do the actual call */
1011 bRet = IntGdiGetFontResourceInfo(&SafeFileNames,
1012 (pvBuf ? Buffer : NULL),
1013 &dwBytes, dwType);
1014
1015 /* Check if succeeded */
1016 if (bRet)
1017 {
1018 /* Copy the data back to caller */
1019 _SEH2_TRY
1020 {
1021 /* Buffers are already probed */
1022 if (pvBuf && dwBytesRequested > 0)
1023 RtlCopyMemory(pvBuf, Buffer, min(dwBytesRequested, dwBytes));
1024 *pdwBytes = dwBytes;
1025 }
1026 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1027 {
1028 Status = _SEH2_GetExceptionCode();
1029 }
1030 _SEH2_END
1031
1032 if(!NT_SUCCESS(Status))
1033 {
1034 SetLastNtError(Status);
1035 bRet = FALSE;
1036 }
1037 }
1038
1039 ExFreePoolWithTag(Buffer, TAG_FINF);
1040 /* Free the string for the safe filenames */
1041 ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
1042
1043 return bRet;
1044 }
1045
1046 /*
1047 * @unimplemented
1048 */
1049 BOOL
1050 APIENTRY
1051 NtGdiGetRealizationInfo(
1052 IN HDC hdc,
1053 OUT PREALIZATION_INFO pri,
1054 IN HFONT hf)
1055 {
1056 PDC pDc;
1057 PTEXTOBJ pTextObj;
1058 PFONTGDI pFontGdi;
1059 PDC_ATTR pdcattr;
1060 BOOL Ret = FALSE;
1061 INT i = 0;
1062 REALIZATION_INFO ri;
1063
1064 pDc = DC_LockDc(hdc);
1065 if (!pDc)
1066 {
1067 EngSetLastError(ERROR_INVALID_HANDLE);
1068 return 0;
1069 }
1070 pdcattr = pDc->pdcattr;
1071 pTextObj = RealizeFontInit(pdcattr->hlfntNew);
1072 pFontGdi = ObjToGDI(pTextObj->Font, FONT);
1073 TEXTOBJ_UnlockText(pTextObj);
1074 DC_UnlockDc(pDc);
1075
1076 Ret = ftGdiRealizationInfo(pFontGdi, &ri);
1077 if (Ret)
1078 {
1079 if (pri)
1080 {
1081 NTSTATUS Status = STATUS_SUCCESS;
1082 _SEH2_TRY
1083 {
1084 ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
1085 RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
1086 }
1087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1088 {
1089 Status = _SEH2_GetExceptionCode();
1090 }
1091 _SEH2_END
1092
1093 if(!NT_SUCCESS(Status))
1094 {
1095 SetLastNtError(Status);
1096 return FALSE;
1097 }
1098 }
1099 do
1100 {
1101 if (GdiHandleTable->cfPublic[i].hf == hf)
1102 {
1103 GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
1104 GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
1105 GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
1106 GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
1107 GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
1108 }
1109 i++;
1110 }
1111 while ( i < GDI_CFONT_MAX );
1112 }
1113 return Ret;
1114 }
1115
1116
1117 HFONT
1118 APIENTRY
1119 HfontCreate(
1120 IN PENUMLOGFONTEXDVW pelfw,
1121 IN ULONG cjElfw,
1122 IN LFTYPE lft,
1123 IN FLONG fl,
1124 IN PVOID pvCliData )
1125 {
1126 HFONT hNewFont;
1127 PLFONT plfont;
1128
1129 if (!pelfw)
1130 {
1131 return NULL;
1132 }
1133
1134 plfont = LFONT_AllocFontWithHandle();
1135 if (!plfont)
1136 {
1137 return NULL;
1138 }
1139 hNewFont = plfont->BaseObject.hHmgr;
1140
1141 plfont->lft = lft;
1142 plfont->fl = fl;
1143 RtlCopyMemory (&plfont->logfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1144 ExInitializePushLock(&plfont->lock);
1145
1146 if (pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement !=
1147 pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation)
1148 {
1149 /* This should really depend on whether GM_ADVANCED is set */
1150 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
1151 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
1152 }
1153 LFONT_UnlockFont(plfont);
1154
1155 if (pvCliData && hNewFont)
1156 {
1157 // FIXME: Use GDIOBJ_InsertUserData
1158 KeEnterCriticalRegion();
1159 {
1160 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hNewFont);
1161 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
1162 Entry->UserData = pvCliData;
1163 }
1164 KeLeaveCriticalRegion();
1165 }
1166
1167 return hNewFont;
1168 }
1169
1170
1171 HFONT
1172 APIENTRY
1173 NtGdiHfontCreate(
1174 IN PENUMLOGFONTEXDVW pelfw,
1175 IN ULONG cjElfw,
1176 IN LFTYPE lft,
1177 IN FLONG fl,
1178 IN PVOID pvCliData )
1179 {
1180 ENUMLOGFONTEXDVW SafeLogfont;
1181 NTSTATUS Status = STATUS_SUCCESS;
1182
1183 /* Silence GCC warnings */
1184 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement = 0;
1185 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 0;
1186
1187 if (!pelfw)
1188 {
1189 return NULL;
1190 }
1191
1192 _SEH2_TRY
1193 {
1194 ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
1195 RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1196 }
1197 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1198 {
1199 Status = _SEH2_GetExceptionCode();
1200 }
1201 _SEH2_END
1202
1203 if (!NT_SUCCESS(Status))
1204 {
1205 return NULL;
1206 }
1207
1208 return HfontCreate(&SafeLogfont, cjElfw, lft, fl, pvCliData);
1209 }
1210
1211
1212 /* EOF */