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