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