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