- Separate NtGdiHfontCreate to allow calling it direct without SEH.
[reactos.git] / reactos / 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
399 /** Functions ******************************************************************/
400
401 INT
402 APIENTRY
403 NtGdiAddFontResourceW(
404 IN WCHAR *pwszFiles,
405 IN ULONG cwc,
406 IN ULONG cFiles,
407 IN FLONG fl,
408 IN DWORD dwPidTid,
409 IN OPTIONAL DESIGNVECTOR *pdv)
410 {
411 UNICODE_STRING SafeFileName;
412 PWSTR src;
413 NTSTATUS Status;
414 int Ret;
415
416 /* FIXME: Protect with SEH? */
417 RtlInitUnicodeString(&SafeFileName, pwszFiles);
418
419 /* Reserve for prepending '\??\' */
420 SafeFileName.Length += 4 * sizeof(WCHAR);
421 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
422
423 src = SafeFileName.Buffer;
424 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
425 if(!SafeFileName.Buffer)
426 {
427 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
428 return 0;
429 }
430
431 /* Prepend '\??\' */
432 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
433
434 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
435 if(!NT_SUCCESS(Status))
436 {
437 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
438 SetLastNtError(Status);
439 return 0;
440 }
441
442 Ret = IntGdiAddFontResource(&SafeFileName, (DWORD)fl);
443
444 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
445 return Ret;
446 }
447
448 /*
449 * @unimplemented
450 */
451 DWORD
452 APIENTRY
453 NtGdiGetCharacterPlacementW(
454 IN HDC hdc,
455 IN LPWSTR pwsz,
456 IN INT nCount,
457 IN INT nMaxExtent,
458 IN OUT LPGCP_RESULTSW pgcpw,
459 IN DWORD dwFlags)
460 {
461 UNIMPLEMENTED;
462 return 0;
463 #if 0
464 return GreGetCharacterPlacementW( hdc,
465 pwsz,
466 nCount,
467 nMaxExtent,
468 pgcpw,
469 dwFlags);
470 #endif
471 }
472
473 DWORD
474 APIENTRY
475 NtGdiGetFontData(
476 HDC hDC,
477 DWORD Table,
478 DWORD Offset,
479 LPVOID Buffer,
480 DWORD Size)
481 {
482 PDC Dc;
483 PDC_ATTR pdcattr;
484 HFONT hFont;
485 PTEXTOBJ TextObj;
486 PFONTGDI FontGdi;
487 DWORD Result = GDI_ERROR;
488 NTSTATUS Status = STATUS_SUCCESS;
489
490 if (Buffer && Size)
491 {
492 _SEH2_TRY
493 {
494 ProbeForRead(Buffer, Size, 1);
495 }
496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
497 {
498 Status = _SEH2_GetExceptionCode();
499 }
500 _SEH2_END
501 }
502
503 if (!NT_SUCCESS(Status)) return Result;
504
505 Dc = DC_LockDc(hDC);
506 if (Dc == NULL)
507 {
508 EngSetLastError(ERROR_INVALID_HANDLE);
509 return GDI_ERROR;
510 }
511 pdcattr = Dc->pdcattr;
512
513 hFont = pdcattr->hlfntNew;
514 TextObj = RealizeFontInit(hFont);
515 DC_UnlockDc(Dc);
516
517 if (TextObj == NULL)
518 {
519 EngSetLastError(ERROR_INVALID_HANDLE);
520 return GDI_ERROR;
521 }
522
523 FontGdi = ObjToGDI(TextObj->Font, FONT);
524
525 Result = ftGdiGetFontData(FontGdi, Table, Offset, Buffer, Size);
526
527 TEXTOBJ_UnlockText(TextObj);
528
529 return Result;
530 }
531
532 /*
533 * @implemented
534 */
535 DWORD
536 APIENTRY
537 NtGdiGetFontUnicodeRanges(
538 IN HDC hdc,
539 OUT OPTIONAL LPGLYPHSET pgs)
540 {
541 PDC pDc;
542 PDC_ATTR pdcattr;
543 HFONT hFont;
544 PTEXTOBJ TextObj;
545 PFONTGDI FontGdi;
546 DWORD Size = 0;
547 PGLYPHSET pgsSafe;
548 NTSTATUS Status = STATUS_SUCCESS;
549
550 pDc = DC_LockDc(hdc);
551 if (!pDc)
552 {
553 EngSetLastError(ERROR_INVALID_HANDLE);
554 return 0;
555 }
556
557 pdcattr = pDc->pdcattr;
558
559 hFont = pdcattr->hlfntNew;
560 TextObj = RealizeFontInit(hFont);
561
562 if ( TextObj == NULL)
563 {
564 EngSetLastError(ERROR_INVALID_HANDLE);
565 goto Exit;
566 }
567 FontGdi = ObjToGDI(TextObj->Font, FONT);
568
569 Size = ftGetFontUnicodeRanges( FontGdi, NULL);
570
571 if (Size && pgs)
572 {
573 pgsSafe = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
574 if (!pgsSafe)
575 {
576 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
577 Size = 0;
578 goto Exit;
579 }
580
581 Size = ftGetFontUnicodeRanges( FontGdi, pgsSafe);
582
583 if (Size)
584 {
585 _SEH2_TRY
586 {
587 ProbeForWrite(pgs, Size, 1);
588 RtlCopyMemory(pgs, pgsSafe, Size);
589 }
590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
591 {
592 Status = _SEH2_GetExceptionCode();
593 }
594 _SEH2_END
595
596 if (!NT_SUCCESS(Status)) Size = 0;
597 }
598 ExFreePoolWithTag(pgsSafe, GDITAG_TEXT);
599 }
600 Exit:
601 TEXTOBJ_UnlockText(TextObj);
602 DC_UnlockDc(pDc);
603 return Size;
604 }
605
606 ULONG
607 APIENTRY
608 NtGdiGetGlyphOutline(
609 IN HDC hdc,
610 IN WCHAR wch,
611 IN UINT iFormat,
612 OUT LPGLYPHMETRICS pgm,
613 IN ULONG cjBuf,
614 OUT OPTIONAL PVOID UnsafeBuf,
615 IN LPMAT2 pmat2,
616 IN BOOL bIgnoreRotation)
617 {
618 ULONG Ret = GDI_ERROR;
619 PDC dc;
620 PVOID pvBuf = NULL;
621 GLYPHMETRICS gm;
622 NTSTATUS Status = STATUS_SUCCESS;
623
624 dc = DC_LockDc(hdc);
625 if (!dc)
626 {
627 EngSetLastError(ERROR_INVALID_HANDLE);
628 return GDI_ERROR;
629 }
630
631 if (UnsafeBuf && cjBuf)
632 {
633 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, GDITAG_TEXT);
634 if (!pvBuf)
635 {
636 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
637 goto Exit;
638 }
639 }
640
641 Ret = ftGdiGetGlyphOutline( dc,
642 wch,
643 iFormat,
644 pgm ? &gm : NULL,
645 cjBuf,
646 pvBuf,
647 pmat2,
648 bIgnoreRotation);
649
650 if (pvBuf)
651 {
652 _SEH2_TRY
653 {
654 ProbeForWrite(UnsafeBuf, cjBuf, 1);
655 RtlCopyMemory(UnsafeBuf, pvBuf, cjBuf);
656 }
657 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
658 {
659 Status = _SEH2_GetExceptionCode();
660 }
661 _SEH2_END
662
663 ExFreePoolWithTag(pvBuf, GDITAG_TEXT);
664 }
665
666 if (pgm)
667 {
668 _SEH2_TRY
669 {
670 ProbeForWrite(pgm, sizeof(GLYPHMETRICS), 1);
671 RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
672 }
673 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
674 {
675 Status = _SEH2_GetExceptionCode();
676 }
677 _SEH2_END
678 }
679
680 if (! NT_SUCCESS(Status))
681 {
682 EngSetLastError(ERROR_INVALID_PARAMETER);
683 Ret = GDI_ERROR;
684 }
685
686 Exit:
687 DC_UnlockDc(dc);
688 return Ret;
689 }
690
691 DWORD
692 APIENTRY
693 NtGdiGetKerningPairs(HDC hDC,
694 ULONG NumPairs,
695 LPKERNINGPAIR krnpair)
696 {
697 PDC dc;
698 PDC_ATTR pdcattr;
699 PTEXTOBJ TextObj;
700 PFONTGDI FontGDI;
701 DWORD Count;
702 KERNINGPAIR *pKP;
703 NTSTATUS Status = STATUS_SUCCESS;
704
705 dc = DC_LockDc(hDC);
706 if (!dc)
707 {
708 EngSetLastError(ERROR_INVALID_HANDLE);
709 return 0;
710 }
711
712 pdcattr = dc->pdcattr;
713 TextObj = RealizeFontInit(pdcattr->hlfntNew);
714 DC_UnlockDc(dc);
715
716 if (!TextObj)
717 {
718 EngSetLastError(ERROR_INVALID_HANDLE);
719 return 0;
720 }
721
722 FontGDI = ObjToGDI(TextObj->Font, FONT);
723 TEXTOBJ_UnlockText(TextObj);
724
725 Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
726
727 if ( Count && krnpair )
728 {
729 if (Count > NumPairs)
730 {
731 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
732 return 0;
733 }
734 pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
735 if (!pKP)
736 {
737 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
738 return 0;
739 }
740 ftGdiGetKerningPairs(FontGDI,Count,pKP);
741 _SEH2_TRY
742 {
743 ProbeForWrite(krnpair, Count * sizeof(KERNINGPAIR), 1);
744 RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
745 }
746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
747 {
748 Status = _SEH2_GetExceptionCode();
749 }
750 _SEH2_END
751 if (!NT_SUCCESS(Status))
752 {
753 EngSetLastError(ERROR_INVALID_PARAMETER);
754 Count = 0;
755 }
756 ExFreePoolWithTag(pKP,GDITAG_TEXT);
757 }
758 return Count;
759 }
760
761 /*
762 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
763 472, this is NtGdiGetOutlineTextMetricsInternalW.
764 */
765 ULONG
766 APIENTRY
767 NtGdiGetOutlineTextMetricsInternalW (HDC hDC,
768 ULONG Data,
769 OUTLINETEXTMETRICW *otm,
770 TMDIFF *Tmd)
771 {
772 PDC dc;
773 PDC_ATTR pdcattr;
774 PTEXTOBJ TextObj;
775 PFONTGDI FontGDI;
776 HFONT hFont = 0;
777 ULONG Size;
778 OUTLINETEXTMETRICW *potm;
779 NTSTATUS Status = STATUS_SUCCESS;
780
781 dc = DC_LockDc(hDC);
782 if (!dc)
783 {
784 EngSetLastError(ERROR_INVALID_HANDLE);
785 return 0;
786 }
787 pdcattr = dc->pdcattr;
788 hFont = pdcattr->hlfntNew;
789 TextObj = RealizeFontInit(hFont);
790 DC_UnlockDc(dc);
791 if (!TextObj)
792 {
793 EngSetLastError(ERROR_INVALID_HANDLE);
794 return 0;
795 }
796 FontGDI = ObjToGDI(TextObj->Font, FONT);
797 TEXTOBJ_UnlockText(TextObj);
798 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
799 if (!otm) return Size;
800 if (Size > Data)
801 {
802 EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
803 return 0;
804 }
805 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
806 if (!potm)
807 {
808 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
809 return 0;
810 }
811 IntGetOutlineTextMetrics(FontGDI, Size, potm);
812 if (otm)
813 {
814 _SEH2_TRY
815 {
816 ProbeForWrite(otm, Size, 1);
817 RtlCopyMemory(otm, potm, Size);
818 }
819 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
820 {
821 Status = _SEH2_GetExceptionCode();
822 }
823 _SEH2_END
824
825 if (!NT_SUCCESS(Status))
826 {
827 EngSetLastError(ERROR_INVALID_PARAMETER);
828 Size = 0;
829 }
830 }
831 ExFreePoolWithTag(potm,GDITAG_TEXT);
832 return Size;
833 }
834
835 W32KAPI
836 BOOL
837 APIENTRY
838 NtGdiGetFontResourceInfoInternalW(
839 IN LPWSTR pwszFiles,
840 IN ULONG cwc,
841 IN ULONG cFiles,
842 IN UINT cjIn,
843 OUT LPDWORD pdwBytes,
844 OUT LPVOID pvBuf,
845 IN DWORD dwType)
846 {
847 NTSTATUS Status = STATUS_SUCCESS;
848 DWORD dwBytes;
849 UNICODE_STRING SafeFileNames;
850 BOOL bRet = FALSE;
851 ULONG cbStringSize;
852
853 union
854 {
855 LOGFONTW logfontw;
856 WCHAR FullName[LF_FULLFACESIZE];
857 } Buffer;
858
859 /* FIXME: Handle cFiles > 0 */
860
861 /* Check for valid dwType values
862 dwType == 4 seems to be handled by gdi32 only */
863 if (dwType == 4 || dwType > 5)
864 {
865 EngSetLastError(ERROR_INVALID_PARAMETER);
866 return FALSE;
867 }
868
869 /* Allocate a safe unicode string buffer */
870 cbStringSize = cwc * sizeof(WCHAR);
871 SafeFileNames.MaximumLength = SafeFileNames.Length = (USHORT)cbStringSize - sizeof(WCHAR);
872 SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
873 cbStringSize,
874 'RTSU');
875 if (!SafeFileNames.Buffer)
876 {
877 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
878 return FALSE;
879 }
880
881 /* Check buffers and copy pwszFiles to safe unicode string */
882 _SEH2_TRY
883 {
884 ProbeForRead(pwszFiles, cbStringSize, 1);
885 ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
886 ProbeForWrite(pvBuf, cjIn, 1);
887
888 RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
889 }
890 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
891 {
892 Status = _SEH2_GetExceptionCode();
893 }
894 _SEH2_END
895
896 if(!NT_SUCCESS(Status))
897 {
898 SetLastNtError(Status);
899 /* Free the string buffer for the safe filename */
900 ExFreePoolWithTag(SafeFileNames.Buffer,'RTSU');
901 return FALSE;
902 }
903
904 /* Do the actual call */
905 bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType);
906
907 /* Check if succeeded and the buffer is big enough */
908 if (bRet && cjIn >= dwBytes)
909 {
910 /* Copy the data back to caller */
911 _SEH2_TRY
912 {
913 /* Buffers are already probed */
914 RtlCopyMemory(pvBuf, &Buffer, dwBytes);
915 *pdwBytes = dwBytes;
916 }
917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
918 {
919 Status = _SEH2_GetExceptionCode();
920 }
921 _SEH2_END
922
923 if(!NT_SUCCESS(Status))
924 {
925 SetLastNtError(Status);
926 bRet = FALSE;
927 }
928 }
929
930 /* Free the string for the safe filenames */
931 ExFreePoolWithTag(SafeFileNames.Buffer,'RTSU');
932
933 return bRet;
934 }
935
936 /*
937 * @unimplemented
938 */
939 BOOL
940 APIENTRY
941 NtGdiGetRealizationInfo(
942 IN HDC hdc,
943 OUT PREALIZATION_INFO pri,
944 IN HFONT hf)
945 {
946 PDC pDc;
947 PTEXTOBJ pTextObj;
948 PFONTGDI pFontGdi;
949 PDC_ATTR pdcattr;
950 BOOL Ret = FALSE;
951 INT i = 0;
952 REALIZATION_INFO ri;
953
954 pDc = DC_LockDc(hdc);
955 if (!pDc)
956 {
957 EngSetLastError(ERROR_INVALID_HANDLE);
958 return 0;
959 }
960 pdcattr = pDc->pdcattr;
961 pTextObj = RealizeFontInit(pdcattr->hlfntNew);
962 pFontGdi = ObjToGDI(pTextObj->Font, FONT);
963 TEXTOBJ_UnlockText(pTextObj);
964 DC_UnlockDc(pDc);
965
966 Ret = ftGdiRealizationInfo(pFontGdi, &ri);
967 if (Ret)
968 {
969 if (pri)
970 {
971 NTSTATUS Status = STATUS_SUCCESS;
972 _SEH2_TRY
973 {
974 ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
975 RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
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 return FALSE;
987 }
988 }
989 do
990 {
991 if (GdiHandleTable->cfPublic[i].hf == hf)
992 {
993 GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
994 GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
995 GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
996 GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
997 GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
998 }
999 i++;
1000 }
1001 while ( i < GDI_CFONT_MAX );
1002 }
1003 return Ret;
1004 }
1005
1006
1007 HFONT
1008 APIENTRY
1009 HfontCreate(
1010 IN PENUMLOGFONTEXDVW pelfw,
1011 IN ULONG cjElfw,
1012 IN LFTYPE lft,
1013 IN FLONG fl,
1014 IN PVOID pvCliData )
1015 {
1016 HFONT hNewFont;
1017 PLFONT plfont;
1018
1019 if (!pelfw)
1020 {
1021 return NULL;
1022 }
1023
1024 plfont = LFONT_AllocFontWithHandle();
1025 if (!plfont)
1026 {
1027 return NULL;
1028 }
1029 hNewFont = plfont->BaseObject.hHmgr;
1030
1031 plfont->lft = lft;
1032 plfont->fl = fl;
1033 RtlCopyMemory (&plfont->logfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1034 ExInitializePushLock(&plfont->lock);
1035
1036 if (pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement !=
1037 pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation)
1038 {
1039 /* This should really depend on whether GM_ADVANCED is set */
1040 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
1041 plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
1042 }
1043 LFONT_UnlockFont(plfont);
1044
1045 if (pvCliData && hNewFont)
1046 {
1047 // FIXME: Use GDIOBJ_InsertUserData
1048 KeEnterCriticalRegion();
1049 {
1050 INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hNewFont);
1051 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
1052 Entry->UserData = pvCliData;
1053 }
1054 KeLeaveCriticalRegion();
1055 }
1056
1057 return hNewFont;
1058 }
1059
1060
1061 HFONT
1062 APIENTRY
1063 NtGdiHfontCreate(
1064 IN PENUMLOGFONTEXDVW pelfw,
1065 IN ULONG cjElfw,
1066 IN LFTYPE lft,
1067 IN FLONG fl,
1068 IN PVOID pvCliData )
1069 {
1070 ENUMLOGFONTEXDVW SafeLogfont;
1071 NTSTATUS Status = STATUS_SUCCESS;
1072
1073 /* Silence GCC warnings */
1074 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement = 0;
1075 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 0;
1076
1077 if (!pelfw)
1078 {
1079 return NULL;
1080 }
1081
1082 _SEH2_TRY
1083 {
1084 ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
1085 RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1086 }
1087 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1088 {
1089 Status = _SEH2_GetExceptionCode();
1090 }
1091 _SEH2_END
1092
1093 if (!NT_SUCCESS(Status))
1094 {
1095 return NULL;
1096 }
1097
1098 return HfontCreate(&SafeLogfont, cjElfw, lft, fl, pvCliData);
1099 }
1100
1101
1102 /* EOF */