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