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