Sync with trunk r58033.
[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: 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 ULONG
264 FASTCALL
265 FontGetObject(PTEXTOBJ plfont, ULONG cjBuffer, PVOID pvBuffer)
266 {
267 ULONG cjMaxSize;
268 ENUMLOGFONTEXDVW *plf = &plfont->logfont;
269
270 /* If buffer is NULL, only the size is requested */
271 if (pvBuffer == NULL) return sizeof(LOGFONTW);
272
273 /* Calculate the maximum size according to number of axes */
274 cjMaxSize = FIELD_OFFSET(ENUMLOGFONTEXDVW,
275 elfDesignVector.dvValues[plf->elfDesignVector.dvNumAxes]);
276
277 if (cjBuffer > cjMaxSize) cjBuffer = cjMaxSize;
278
279 RtlCopyMemory(pvBuffer, plf, cjBuffer);
280
281 return cjBuffer;
282 }
283
284 DWORD
285 FASTCALL
286 IntGetCharDimensions(HDC hdc, PTEXTMETRICW ptm, PDWORD height)
287 {
288 PDC pdc;
289 PDC_ATTR pdcattr;
290 PTEXTOBJ TextObj;
291 SIZE sz;
292 TMW_INTERNAL tmwi;
293 BOOL Good;
294
295 static const WCHAR alphabet[] = {
296 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
297 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
298 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
299
300 if(!ftGdiGetTextMetricsW(hdc, &tmwi)) return 0;
301
302 pdc = DC_LockDc(hdc);
303
304 if (!pdc) return 0;
305
306 pdcattr = pdc->pdcattr;
307
308 TextObj = RealizeFontInit(pdcattr->hlfntNew);
309 if ( !TextObj )
310 {
311 DC_UnlockDc(pdc);
312 return 0;
313 }
314 Good = TextIntGetTextExtentPoint(pdc, TextObj, alphabet, 52, 0, NULL, 0, &sz, 0);
315 TEXTOBJ_UnlockText(TextObj);
316 DC_UnlockDc(pdc);
317
318 if (!Good) return 0;
319 if (ptm) *ptm = tmwi.TextMetric;
320 if (height) *height = tmwi.TextMetric.tmHeight;
321
322 return (sz.cx / 26 + 1) / 2;
323 }
324
325
326 DWORD
327 FASTCALL
328 IntGetFontLanguageInfo(PDC Dc)
329 {
330 PDC_ATTR pdcattr;
331 FONTSIGNATURE fontsig;
332 static const DWORD GCP_DBCS_MASK=0x003F0000,
333 GCP_DIACRITIC_MASK=0x00000000,
334 FLI_GLYPHS_MASK=0x00000000,
335 GCP_GLYPHSHAPE_MASK=0x00000040,
336 GCP_KASHIDA_MASK=0x00000000,
337 GCP_LIGATE_MASK=0x00000000,
338 GCP_USEKERNING_MASK=0x00000000,
339 GCP_REORDER_MASK=0x00000060;
340
341 DWORD result=0;
342
343 ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
344
345 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
346 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
347 result|=GCP_DBCS;
348
349 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
350 result|=GCP_DIACRITIC;
351
352 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
353 result|=FLI_GLYPHS;
354
355 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
356 result|=GCP_GLYPHSHAPE;
357
358 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
359 result|=GCP_KASHIDA;
360
361 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
362 result|=GCP_LIGATE;
363
364 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
365 result|=GCP_USEKERNING;
366
367 pdcattr = Dc->pdcattr;
368
369 /* This might need a test for a HEBREW- or ARABIC_CHARSET as well */
370 if ( pdcattr->lTextAlign & TA_RTLREADING )
371 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
372 result|=GCP_REORDER;
373
374 return result;
375 }
376
377 PTEXTOBJ
378 FASTCALL
379 RealizeFontInit(HFONT hFont)
380 {
381 NTSTATUS Status = STATUS_SUCCESS;
382 PTEXTOBJ pTextObj;
383
384 pTextObj = TEXTOBJ_LockText(hFont);
385
386 if ( pTextObj && !(pTextObj->fl & TEXTOBJECT_INIT))
387 {
388 Status = TextIntRealizeFont(hFont, pTextObj);
389 if (!NT_SUCCESS(Status))
390 {
391 TEXTOBJ_UnlockText(pTextObj);
392 return NULL;
393 }
394 }
395 return pTextObj;
396 }
397
398 HFONT
399 FASTCALL
400 GreSelectFont( HDC hDC, HFONT hFont)
401 {
402 PDC pdc;
403 PDC_ATTR pdcattr;
404 PTEXTOBJ pOrgFnt, pNewFnt = NULL;
405 HFONT hOrgFont = NULL;
406
407 if (!hDC || !hFont) return NULL;
408
409 pdc = DC_LockDc(hDC);
410 if (!pdc)
411 {
412 return NULL;
413 }
414
415 if (NT_SUCCESS(TextIntRealizeFont((HFONT)hFont,NULL)))
416 {
417 /* LFONTOBJ use share and locking. */
418 pNewFnt = TEXTOBJ_LockText(hFont);
419 pdcattr = pdc->pdcattr;
420 pOrgFnt = pdc->dclevel.plfnt;
421 if (pOrgFnt)
422 {
423 hOrgFont = pOrgFnt->BaseObject.hHmgr;
424 }
425 else
426 {
427 hOrgFont = pdcattr->hlfntNew;
428 }
429 pdc->dclevel.plfnt = pNewFnt;
430 pdc->hlfntCur = hFont;
431 pdcattr->hlfntNew = hFont;
432 pdcattr->ulDirty_ |= DIRTY_CHARSET;
433 pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
434 }
435
436 if (pNewFnt) TEXTOBJ_UnlockText(pNewFnt);
437 DC_UnlockDc(pdc);
438 return hOrgFont;
439 }
440
441 /** Functions ******************************************************************/
442
443 INT
444 APIENTRY
445 NtGdiAddFontResourceW(
446 IN WCHAR *pwszFiles,
447 IN ULONG cwc,
448 IN ULONG cFiles,
449 IN FLONG fl,
450 IN DWORD dwPidTid,
451 IN OPTIONAL DESIGNVECTOR *pdv)
452 {
453 UNICODE_STRING SafeFileName;
454 PWSTR src;
455 NTSTATUS Status;
456 int Ret;
457
458 /* FIXME: Protect with SEH? */
459 RtlInitUnicodeString(&SafeFileName, pwszFiles);
460
461 /* Reserve for prepending '\??\' */
462 SafeFileName.Length += 4 * sizeof(WCHAR);
463 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
464
465 src = SafeFileName.Buffer;
466 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
467 if(!SafeFileName.Buffer)
468 {
469 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
470 return 0;
471 }
472
473 /* Prepend '\??\' */
474 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
475
476 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
477 if(!NT_SUCCESS(Status))
478 {
479 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
480 SetLastNtError(Status);
481 return 0;
482 }
483
484 Ret = IntGdiAddFontResource(&SafeFileName, (DWORD)fl);
485
486 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
487 return Ret;
488 }
489
490 /*
491 * @unimplemented
492 */
493 DWORD
494 APIENTRY
495 NtGdiGetCharacterPlacementW(
496 IN HDC hdc,
497 IN LPWSTR pwsz,
498 IN INT nCount,
499 IN INT nMaxExtent,
500 IN OUT LPGCP_RESULTSW pgcpw,
501 IN DWORD dwFlags)
502 {
503 UNIMPLEMENTED;
504 return 0;
505 #if 0
506 return GreGetCharacterPlacementW( hdc,
507 pwsz,
508 nCount,
509 nMaxExtent,
510 pgcpw,
511 dwFlags);
512 #endif
513 }
514
515 DWORD
516 APIENTRY
517 NtGdiGetFontData(
518 HDC hDC,
519 DWORD Table,
520 DWORD Offset,
521 LPVOID Buffer,
522 DWORD Size)
523 {
524 PDC Dc;
525 PDC_ATTR pdcattr;
526 HFONT hFont;
527 PTEXTOBJ TextObj;
528 PFONTGDI FontGdi;
529 DWORD Result = GDI_ERROR;
530 NTSTATUS Status = STATUS_SUCCESS;
531
532 if (Buffer && Size)
533 {
534 _SEH2_TRY
535 {
536 ProbeForRead(Buffer, Size, 1);
537 }
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
539 {
540 Status = _SEH2_GetExceptionCode();
541 }
542 _SEH2_END
543 }
544
545 if (!NT_SUCCESS(Status)) return Result;
546
547 Dc = DC_LockDc(hDC);
548 if (Dc == NULL)
549 {
550 EngSetLastError(ERROR_INVALID_HANDLE);
551 return GDI_ERROR;
552 }
553 pdcattr = Dc->pdcattr;
554
555 hFont = pdcattr->hlfntNew;
556 TextObj = RealizeFontInit(hFont);
557 DC_UnlockDc(Dc);
558
559 if (TextObj == NULL)
560 {
561 EngSetLastError(ERROR_INVALID_HANDLE);
562 return GDI_ERROR;
563 }
564
565 FontGdi = ObjToGDI(TextObj->Font, FONT);
566
567 Result = ftGdiGetFontData(FontGdi, Table, Offset, Buffer, Size);
568
569 TEXTOBJ_UnlockText(TextObj);
570
571 return Result;
572 }
573
574 /*
575 * @implemented
576 */
577 DWORD
578 APIENTRY
579 NtGdiGetFontUnicodeRanges(
580 IN HDC hdc,
581 OUT OPTIONAL LPGLYPHSET pgs)
582 {
583 PDC pDc;
584 PDC_ATTR pdcattr;
585 HFONT hFont;
586 PTEXTOBJ TextObj;
587 PFONTGDI FontGdi;
588 DWORD Size = 0;
589 PGLYPHSET pgsSafe;
590 NTSTATUS Status = STATUS_SUCCESS;
591
592 pDc = DC_LockDc(hdc);
593 if (!pDc)
594 {
595 EngSetLastError(ERROR_INVALID_HANDLE);
596 return 0;
597 }
598
599 pdcattr = pDc->pdcattr;
600
601 hFont = pdcattr->hlfntNew;
602 TextObj = RealizeFontInit(hFont);
603
604 if ( TextObj == NULL)
605 {
606 EngSetLastError(ERROR_INVALID_HANDLE);
607 goto Exit;
608 }
609 FontGdi = ObjToGDI(TextObj->Font, FONT);
610
611 Size = ftGetFontUnicodeRanges( FontGdi, NULL);
612
613 if (Size && pgs)
614 {
615 pgsSafe = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
616 if (!pgsSafe)
617 {
618 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
619 Size = 0;
620 goto Exit;
621 }
622
623 Size = ftGetFontUnicodeRanges( FontGdi, pgsSafe);
624
625 if (Size)
626 {
627 _SEH2_TRY
628 {
629 ProbeForWrite(pgs, Size, 1);
630 RtlCopyMemory(pgs, pgsSafe, Size);
631 }
632 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
633 {
634 Status = _SEH2_GetExceptionCode();
635 }
636 _SEH2_END
637
638 if (!NT_SUCCESS(Status)) Size = 0;
639 }
640 ExFreePoolWithTag(pgsSafe, GDITAG_TEXT);
641 }
642 Exit:
643 TEXTOBJ_UnlockText(TextObj);
644 DC_UnlockDc(pDc);
645 return Size;
646 }
647
648 ULONG
649 APIENTRY
650 NtGdiGetGlyphOutline(
651 IN HDC hdc,
652 IN WCHAR wch,
653 IN UINT iFormat,
654 OUT LPGLYPHMETRICS pgm,
655 IN ULONG cjBuf,
656 OUT OPTIONAL PVOID UnsafeBuf,
657 IN LPMAT2 pmat2,
658 IN BOOL bIgnoreRotation)
659 {
660 ULONG Ret = GDI_ERROR;
661 PDC dc;
662 PVOID pvBuf = NULL;
663 GLYPHMETRICS gm;
664 NTSTATUS Status = STATUS_SUCCESS;
665
666 dc = DC_LockDc(hdc);
667 if (!dc)
668 {
669 EngSetLastError(ERROR_INVALID_HANDLE);
670 return GDI_ERROR;
671 }
672
673 if (UnsafeBuf && cjBuf)
674 {
675 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, GDITAG_TEXT);
676 if (!pvBuf)
677 {
678 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
679 goto Exit;
680 }
681 }
682
683 Ret = ftGdiGetGlyphOutline( dc,
684 wch,
685 iFormat,
686 pgm ? &gm : NULL,
687 cjBuf,
688 pvBuf,
689 pmat2,
690 bIgnoreRotation);
691
692 if (pvBuf)
693 {
694 _SEH2_TRY
695 {
696 ProbeForWrite(UnsafeBuf, cjBuf, 1);
697 RtlCopyMemory(UnsafeBuf, pvBuf, cjBuf);
698 }
699 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
700 {
701 Status = _SEH2_GetExceptionCode();
702 }
703 _SEH2_END
704
705 ExFreePoolWithTag(pvBuf, GDITAG_TEXT);
706 }
707
708 if (pgm)
709 {
710 _SEH2_TRY
711 {
712 ProbeForWrite(pgm, sizeof(GLYPHMETRICS), 1);
713 RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
714 }
715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
716 {
717 Status = _SEH2_GetExceptionCode();
718 }
719 _SEH2_END
720 }
721
722 if (! NT_SUCCESS(Status))
723 {
724 EngSetLastError(ERROR_INVALID_PARAMETER);
725 Ret = GDI_ERROR;
726 }
727
728 Exit:
729 DC_UnlockDc(dc);
730 return Ret;
731 }
732
733 DWORD
734 APIENTRY
735 NtGdiGetKerningPairs(HDC hDC,
736 ULONG NumPairs,
737 LPKERNINGPAIR krnpair)
738 {
739 PDC dc;
740 PDC_ATTR pdcattr;
741 PTEXTOBJ TextObj;
742 PFONTGDI FontGDI;
743 DWORD Count;
744 KERNINGPAIR *pKP;
745 NTSTATUS Status = STATUS_SUCCESS;
746
747 dc = DC_LockDc(hDC);
748 if (!dc)
749 {
750 EngSetLastError(ERROR_INVALID_HANDLE);
751 return 0;
752 }
753
754 pdcattr = dc->pdcattr;
755 TextObj = RealizeFontInit(pdcattr->hlfntNew);
756 DC_UnlockDc(dc);
757
758 if (!TextObj)
759 {
760 EngSetLastError(ERROR_INVALID_HANDLE);
761 return 0;
762 }
763
764 FontGDI = ObjToGDI(TextObj->Font, FONT);
765 TEXTOBJ_UnlockText(TextObj);
766
767 Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
768
769 if ( Count && krnpair )
770 {
771 if (Count > NumPairs)
772 {
773 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
774 return 0;
775 }
776 pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
777 if (!pKP)
778 {
779 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
780 return 0;
781 }
782 ftGdiGetKerningPairs(FontGDI,Count,pKP);
783 _SEH2_TRY
784 {
785 ProbeForWrite(krnpair, Count * sizeof(KERNINGPAIR), 1);
786 RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
787 }
788 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
789 {
790 Status = _SEH2_GetExceptionCode();
791 }
792 _SEH2_END
793 if (!NT_SUCCESS(Status))
794 {
795 EngSetLastError(ERROR_INVALID_PARAMETER);
796 Count = 0;
797 }
798 ExFreePoolWithTag(pKP,GDITAG_TEXT);
799 }
800 return Count;
801 }
802
803 /*
804 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
805 472, this is NtGdiGetOutlineTextMetricsInternalW.
806 */
807 ULONG
808 APIENTRY
809 NtGdiGetOutlineTextMetricsInternalW (HDC hDC,
810 ULONG Data,
811 OUTLINETEXTMETRICW *otm,
812 TMDIFF *Tmd)
813 {
814 PDC dc;
815 PDC_ATTR pdcattr;
816 PTEXTOBJ TextObj;
817 PFONTGDI FontGDI;
818 HFONT hFont = 0;
819 ULONG Size;
820 OUTLINETEXTMETRICW *potm;
821 NTSTATUS Status = STATUS_SUCCESS;
822
823 dc = DC_LockDc(hDC);
824 if (!dc)
825 {
826 EngSetLastError(ERROR_INVALID_HANDLE);
827 return 0;
828 }
829 pdcattr = dc->pdcattr;
830 hFont = pdcattr->hlfntNew;
831 TextObj = RealizeFontInit(hFont);
832 DC_UnlockDc(dc);
833 if (!TextObj)
834 {
835 EngSetLastError(ERROR_INVALID_HANDLE);
836 return 0;
837 }
838 FontGDI = ObjToGDI(TextObj->Font, FONT);
839 TEXTOBJ_UnlockText(TextObj);
840 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
841 if (!otm) return Size;
842 if (Size > Data)
843 {
844 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
845 return 0;
846 }
847 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
848 if (!potm)
849 {
850 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
851 return 0;
852 }
853 IntGetOutlineTextMetrics(FontGDI, Size, potm);
854 if (otm)
855 {
856 _SEH2_TRY
857 {
858 ProbeForWrite(otm, Size, 1);
859 RtlCopyMemory(otm, potm, Size);
860 }
861 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
862 {
863 Status = _SEH2_GetExceptionCode();
864 }
865 _SEH2_END
866
867 if (!NT_SUCCESS(Status))
868 {
869 EngSetLastError(ERROR_INVALID_PARAMETER);
870 Size = 0;
871 }
872 }
873 ExFreePoolWithTag(potm,GDITAG_TEXT);
874 return Size;
875 }
876
877 W32KAPI
878 BOOL
879 APIENTRY
880 NtGdiGetFontResourceInfoInternalW(
881 IN LPWSTR pwszFiles,
882 IN ULONG cwc,
883 IN ULONG cFiles,
884 IN UINT cjIn,
885 OUT LPDWORD pdwBytes,
886 OUT LPVOID pvBuf,
887 IN DWORD dwType)
888 {
889 NTSTATUS Status = STATUS_SUCCESS;
890 DWORD dwBytes;
891 UNICODE_STRING SafeFileNames;
892 BOOL bRet = FALSE;
893 ULONG cbStringSize;
894
895 union
896 {
897 LOGFONTW logfontw;
898 WCHAR FullName[LF_FULLFACESIZE];
899 } Buffer;
900
901 /* FIXME: Handle cFiles > 0 */
902
903 /* Check for valid dwType values
904 dwType == 4 seems to be handled by gdi32 only */
905 if (dwType == 4 || dwType > 5)
906 {
907 EngSetLastError(ERROR_INVALID_PARAMETER);
908 return FALSE;
909 }
910
911 /* Allocate a safe unicode string buffer */
912 cbStringSize = cwc * sizeof(WCHAR);
913 SafeFileNames.MaximumLength = SafeFileNames.Length = (USHORT)cbStringSize - sizeof(WCHAR);
914 SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
915 cbStringSize,
916 'RTSU');
917 if (!SafeFileNames.Buffer)
918 {
919 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
920 return FALSE;
921 }
922
923 /* Check buffers and copy pwszFiles to safe unicode string */
924 _SEH2_TRY
925 {
926 ProbeForRead(pwszFiles, cbStringSize, 1);
927 ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
928 ProbeForWrite(pvBuf, cjIn, 1);
929
930 RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
931 }
932 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
933 {
934 Status = _SEH2_GetExceptionCode();
935 }
936 _SEH2_END
937
938 if(!NT_SUCCESS(Status))
939 {
940 SetLastNtError(Status);
941 /* Free the string buffer for the safe filename */
942 ExFreePoolWithTag(SafeFileNames.Buffer,'RTSU');
943 return FALSE;
944 }
945
946 /* Do the actual call */
947 bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType);
948
949 /* Check if succeeded and the buffer is big enough */
950 if (bRet && cjIn >= dwBytes)
951 {
952 /* Copy the data back to caller */
953 _SEH2_TRY
954 {
955 /* Buffers are already probed */
956 RtlCopyMemory(pvBuf, &Buffer, dwBytes);
957 *pdwBytes = dwBytes;
958 }
959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
960 {
961 Status = _SEH2_GetExceptionCode();
962 }
963 _SEH2_END
964
965 if(!NT_SUCCESS(Status))
966 {
967 SetLastNtError(Status);
968 bRet = FALSE;
969 }
970 }
971
972 /* Free the string for the safe filenames */
973 ExFreePoolWithTag(SafeFileNames.Buffer,'RTSU');
974
975 return bRet;
976 }
977
978 /*
979 * @unimplemented
980 */
981 BOOL
982 APIENTRY
983 NtGdiGetRealizationInfo(
984 IN HDC hdc,
985 OUT PREALIZATION_INFO pri,
986 IN HFONT hf)
987 {
988 PDC pDc;
989 PTEXTOBJ pTextObj;
990 PFONTGDI pFontGdi;
991 PDC_ATTR pdcattr;
992 BOOL Ret = FALSE;
993 INT i = 0;
994 REALIZATION_INFO ri;
995
996 pDc = DC_LockDc(hdc);
997 if (!pDc)
998 {
999 EngSetLastError(ERROR_INVALID_HANDLE);
1000 return 0;
1001 }
1002 pdcattr = pDc->pdcattr;
1003 pTextObj = RealizeFontInit(pdcattr->hlfntNew);
1004 pFontGdi = ObjToGDI(pTextObj->Font, FONT);
1005 TEXTOBJ_UnlockText(pTextObj);
1006 DC_UnlockDc(pDc);
1007
1008 Ret = ftGdiRealizationInfo(pFontGdi, &ri);
1009 if (Ret)
1010 {
1011 if (pri)
1012 {
1013 NTSTATUS Status = STATUS_SUCCESS;
1014 _SEH2_TRY
1015 {
1016 ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
1017 RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
1018 }
1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1020 {
1021 Status = _SEH2_GetExceptionCode();
1022 }
1023 _SEH2_END
1024
1025 if(!NT_SUCCESS(Status))
1026 {
1027 SetLastNtError(Status);
1028 return FALSE;
1029 }
1030 }
1031 do
1032 {
1033 if (GdiHandleTable->cfPublic[i].hf == hf)
1034 {
1035 GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
1036 GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
1037 GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
1038 GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
1039 GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
1040 }
1041 i++;
1042 }
1043 while ( i < GDI_CFONT_MAX );
1044 }
1045 return Ret;
1046 }
1047
1048 HFONT
1049 APIENTRY
1050 NtGdiHfontCreate(
1051 IN PENUMLOGFONTEXDVW pelfw,
1052 IN ULONG cjElfw,
1053 IN LFTYPE lft,
1054 IN FLONG fl,
1055 IN PVOID pvCliData )
1056 {
1057 ENUMLOGFONTEXDVW SafeLogfont;
1058 HFONT hNewFont;
1059 PLFONT plfont;
1060 NTSTATUS Status = STATUS_SUCCESS;
1061
1062 /* Silence GCC warnings */
1063 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement = 0;
1064 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 0;
1065
1066 if (!pelfw)
1067 {
1068 return NULL;
1069 }
1070
1071 _SEH2_TRY
1072 {
1073 ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
1074 RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1075 }
1076 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1077 {
1078 Status = _SEH2_GetExceptionCode();
1079 }
1080 _SEH2_END
1081
1082 if (!NT_SUCCESS(Status))
1083 {
1084 return NULL;
1085 }
1086
1087 plfont = LFONT_AllocFontWithHandle();
1088 if (!plfont)
1089 {
1090 return NULL;
1091 }
1092 hNewFont = plfont->BaseObject.hHmgr;
1093
1094 plfont->lft = lft;
1095 plfont->fl = fl;
1096 RtlCopyMemory (&plfont->logfont, &SafeLogfont, sizeof(ENUMLOGFONTEXDVW));
1097 ExInitializePushLock(&plfont->lock);
1098
1099 if (SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement !=
1100 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation)
1101 {
1102 /* This should really depend on whether GM_ADVANCED is set */
1103 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
1104 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
1105 }
1106 LFONT_UnlockFont(plfont);
1107
1108 if (pvCliData && hNewFont)
1109 {
1110 // FIXME: Use GDIOBJ_InsertUserData
1111 KeEnterCriticalRegion();
1112 {
1113 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hNewFont);
1114 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
1115 Entry->UserData = pvCliData;
1116 }
1117 KeLeaveCriticalRegion();
1118 }
1119
1120 return hNewFont;
1121 }
1122
1123 /*
1124 * @implemented
1125 */
1126 HFONT
1127 APIENTRY
1128 NtGdiSelectFont(
1129 IN HDC hDC,
1130 IN HFONT hFont)
1131 {
1132 return GreSelectFont(hDC, hFont);
1133 }
1134
1135
1136 /* EOF */