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