xref: /reactos/win32ss/gdi/ntgdi/font.c (revision 0f9e8897)
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
GreCreateFontIndirectW(LOGFONTW * lplf)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
GreGetKerningPairs(HDC hDC,ULONG NumPairs,LPKERNINGPAIR krnpair)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
FontGetObject(PTEXTOBJ plfont,ULONG cjBuffer,PVOID pvBuffer)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         DPRINT("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
IntGetCharDimensions(HDC hdc,PTEXTMETRICW ptm,PDWORD height)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
IntGetFontLanguageInfo(PDC Dc)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
RealizeFontInit(HFONT hFont)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
NtGdiAddFontResourceW(IN WCHAR * pwcFiles,IN ULONG cwc,IN ULONG cFiles,IN FLONG fl,IN DWORD dwPidTid,IN OPTIONAL DESIGNVECTOR * pdv)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
NtGdiAddFontMemResourceEx(IN PVOID pvBuffer,IN DWORD cjBuffer,IN DESIGNVECTOR * pdv,IN ULONG cjDV,OUT DWORD * pNumFonts)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
NtGdiRemoveFontMemResourceEx(IN HANDLE hMMFont)554 NtGdiRemoveFontMemResourceEx(
555     IN HANDLE hMMFont)
556 {
557     return IntGdiRemoveFontMemResource(hMMFont);
558 }
559 
560 
561  /*
562  * @unimplemented
563  */
564 DWORD
565 APIENTRY
NtGdiGetCharacterPlacementW(IN HDC hdc,IN LPWSTR pwsz,IN INT nCount,IN INT nMaxExtent,IN OUT LPGCP_RESULTSW pgcpw,IN DWORD dwFlags)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
NtGdiGetFontData(HDC hDC,DWORD Table,DWORD Offset,LPVOID Buffer,DWORD Size)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
NtGdiGetFontUnicodeRanges(IN HDC hdc,OUT OPTIONAL LPGLYPHSET pgs)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
NtGdiGetGlyphOutline(IN HDC hdc,IN WCHAR wch,IN UINT iFormat,OUT LPGLYPHMETRICS pgm,IN ULONG cjBuf,OUT OPTIONAL PVOID UnsafeBuf,IN LPMAT2 pmat2,IN BOOL bIgnoreRotation)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 = ExAllocatePoolZero(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
NtGdiGetKerningPairs(HDC hDC,ULONG NumPairs,LPKERNINGPAIR krnpair)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
NtGdiGetOutlineTextMetricsInternalW(HDC hDC,ULONG Data,OUTLINETEXTMETRICW * otm,TMDIFF * Tmd)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, FALSE);
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   RtlZeroMemory(potm, Size);
931   IntGetOutlineTextMetrics(FontGDI, Size, potm, FALSE);
932 
933   _SEH2_TRY
934   {
935       ProbeForWrite(otm, Size, 1);
936       RtlCopyMemory(otm, potm, Size);
937   }
938   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
939   {
940       Status = _SEH2_GetExceptionCode();
941   }
942   _SEH2_END
943 
944   if (!NT_SUCCESS(Status))
945   {
946      EngSetLastError(ERROR_INVALID_PARAMETER);
947      Size = 0;
948   }
949 
950   ExFreePoolWithTag(potm,GDITAG_TEXT);
951   return Size;
952 }
953 
954 W32KAPI
955 BOOL
956 APIENTRY
NtGdiGetFontResourceInfoInternalW(IN LPWSTR pwszFiles,IN ULONG cwc,IN ULONG cFiles,IN UINT cjIn,IN OUT LPDWORD pdwBytes,OUT LPVOID pvBuf,IN DWORD dwType)957 NtGdiGetFontResourceInfoInternalW(
958     IN LPWSTR       pwszFiles,
959     IN ULONG        cwc,
960     IN ULONG        cFiles,
961     IN UINT         cjIn,
962     IN OUT LPDWORD  pdwBytes,
963     OUT LPVOID      pvBuf,
964     IN DWORD        dwType)
965 {
966     NTSTATUS Status = STATUS_SUCCESS;
967     DWORD dwBytes, dwBytesRequested;
968     UNICODE_STRING SafeFileNames;
969     BOOL bRet = FALSE;
970     ULONG cbStringSize;
971     LPVOID Buffer;
972 
973     /* FIXME: Handle cFiles > 0 */
974 
975     /* Check for valid dwType values */
976     if (dwType > 5)
977     {
978         EngSetLastError(ERROR_INVALID_PARAMETER);
979         return FALSE;
980     }
981 
982     /* Allocate a safe unicode string buffer */
983     cbStringSize = cwc * sizeof(WCHAR);
984     SafeFileNames.MaximumLength = SafeFileNames.Length = (USHORT)cbStringSize - sizeof(WCHAR);
985     SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
986                                                  cbStringSize,
987                                                  TAG_USTR);
988     if (!SafeFileNames.Buffer)
989     {
990         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
991         return FALSE;
992     }
993     RtlZeroMemory(SafeFileNames.Buffer, SafeFileNames.MaximumLength);
994 
995     /* Check buffers and copy pwszFiles to safe unicode string */
996     _SEH2_TRY
997     {
998         ProbeForRead(pwszFiles, cbStringSize, 1);
999         ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
1000         if (pvBuf)
1001             ProbeForWrite(pvBuf, cjIn, 1);
1002 
1003         dwBytes = *pdwBytes;
1004         dwBytesRequested = dwBytes;
1005 
1006         RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
1007         if (dwBytes > 0)
1008         {
1009             Buffer = ExAllocatePoolWithTag(PagedPool, dwBytes, TAG_FINF);
1010         }
1011         else
1012         {
1013             Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(DWORD), TAG_FINF);
1014         }
1015     }
1016     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1017     {
1018         Status = _SEH2_GetExceptionCode();
1019     }
1020     _SEH2_END
1021 
1022     if(!NT_SUCCESS(Status))
1023     {
1024         SetLastNtError(Status);
1025         /* Free the string buffer for the safe filename */
1026         ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
1027         return FALSE;
1028     }
1029 
1030     /* Do the actual call */
1031     bRet = IntGdiGetFontResourceInfo(&SafeFileNames,
1032                                      (pvBuf ? Buffer : NULL),
1033                                      &dwBytes, dwType);
1034 
1035     /* Check if succeeded */
1036     if (bRet)
1037     {
1038         /* Copy the data back to caller */
1039         _SEH2_TRY
1040         {
1041             /* Buffers are already probed */
1042             if (pvBuf && dwBytesRequested > 0)
1043                 RtlCopyMemory(pvBuf, Buffer, min(dwBytesRequested, dwBytes));
1044             *pdwBytes = dwBytes;
1045         }
1046         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1047         {
1048             Status = _SEH2_GetExceptionCode();
1049         }
1050         _SEH2_END
1051 
1052         if(!NT_SUCCESS(Status))
1053         {
1054             SetLastNtError(Status);
1055             bRet = FALSE;
1056         }
1057     }
1058 
1059     ExFreePoolWithTag(Buffer, TAG_FINF);
1060     /* Free the string for the safe filenames */
1061     ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
1062 
1063     return bRet;
1064 }
1065 
1066  /*
1067  * @unimplemented
1068  */
1069 BOOL
1070 APIENTRY
NtGdiGetRealizationInfo(IN HDC hdc,OUT PREALIZATION_INFO pri,IN HFONT hf)1071 NtGdiGetRealizationInfo(
1072     IN HDC hdc,
1073     OUT PREALIZATION_INFO pri,
1074     IN HFONT hf)
1075 {
1076   PDC pDc;
1077   PTEXTOBJ pTextObj;
1078   PFONTGDI pFontGdi;
1079   PDC_ATTR pdcattr;
1080   BOOL Ret = FALSE;
1081   INT i = 0;
1082   REALIZATION_INFO ri;
1083 
1084   pDc = DC_LockDc(hdc);
1085   if (!pDc)
1086   {
1087      EngSetLastError(ERROR_INVALID_HANDLE);
1088      return 0;
1089   }
1090   pdcattr = pDc->pdcattr;
1091   pTextObj = RealizeFontInit(pdcattr->hlfntNew);
1092   ASSERT(pTextObj != NULL);
1093   pFontGdi = ObjToGDI(pTextObj->Font, FONT);
1094   TEXTOBJ_UnlockText(pTextObj);
1095   DC_UnlockDc(pDc);
1096 
1097   Ret = ftGdiRealizationInfo(pFontGdi, &ri);
1098   if (Ret)
1099   {
1100      if (pri)
1101      {
1102         NTSTATUS Status = STATUS_SUCCESS;
1103         _SEH2_TRY
1104         {
1105             ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
1106             RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
1107         }
1108         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1109         {
1110             Status = _SEH2_GetExceptionCode();
1111         }
1112         _SEH2_END
1113 
1114         if(!NT_SUCCESS(Status))
1115         {
1116             SetLastNtError(Status);
1117             return FALSE;
1118         }
1119      }
1120      do
1121      {
1122         if (GdiHandleTable->cfPublic[i].hf == hf)
1123         {
1124            GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
1125            GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
1126            GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
1127            GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
1128            GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
1129         }
1130         i++;
1131      }
1132      while ( i < GDI_CFONT_MAX );
1133   }
1134   return Ret;
1135 }
1136 
1137 
1138 HFONT
1139 APIENTRY
HfontCreate(IN PENUMLOGFONTEXDVW pelfw,IN ULONG cjElfw,IN LFTYPE lft,IN FLONG fl,IN PVOID pvCliData)1140 HfontCreate(
1141   IN PENUMLOGFONTEXDVW pelfw,
1142   IN ULONG cjElfw,
1143   IN LFTYPE lft,
1144   IN FLONG  fl,
1145   IN PVOID pvCliData )
1146 {
1147   HFONT hNewFont;
1148   PLFONT plfont;
1149 
1150   if (!pelfw)
1151   {
1152       return NULL;
1153   }
1154 
1155   plfont = LFONT_AllocFontWithHandle();
1156   if (!plfont)
1157   {
1158       return NULL;
1159   }
1160   hNewFont = plfont->BaseObject.hHmgr;
1161 
1162   plfont->lft = lft;
1163   plfont->fl  = fl;
1164   RtlCopyMemory (&plfont->logfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1165   ExInitializePushLock(&plfont->lock);
1166 
1167   if (pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement !=
1168       pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation)
1169   {
1170     /* This should really depend on whether GM_ADVANCED is set */
1171     plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
1172     plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
1173   }
1174   LFONT_UnlockFont(plfont);
1175 
1176   if (pvCliData && hNewFont)
1177   {
1178     // FIXME: Use GDIOBJ_InsertUserData
1179     KeEnterCriticalRegion();
1180     {
1181        INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hNewFont);
1182        PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
1183        Entry->UserData = pvCliData;
1184     }
1185     KeLeaveCriticalRegion();
1186   }
1187 
1188   return hNewFont;
1189 }
1190 
1191 
1192 HFONT
1193 APIENTRY
NtGdiHfontCreate(IN PENUMLOGFONTEXDVW pelfw,IN ULONG cjElfw,IN LFTYPE lft,IN FLONG fl,IN PVOID pvCliData)1194 NtGdiHfontCreate(
1195   IN PENUMLOGFONTEXDVW pelfw,
1196   IN ULONG cjElfw,
1197   IN LFTYPE lft,
1198   IN FLONG  fl,
1199   IN PVOID pvCliData )
1200 {
1201   ENUMLOGFONTEXDVW SafeLogfont;
1202   NTSTATUS Status = STATUS_SUCCESS;
1203 
1204   /* Silence GCC warnings */
1205   SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement = 0;
1206   SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 0;
1207 
1208   if (!pelfw)
1209   {
1210       return NULL;
1211   }
1212 
1213   _SEH2_TRY
1214   {
1215       ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
1216       RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
1217   }
1218   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1219   {
1220       Status = _SEH2_GetExceptionCode();
1221   }
1222   _SEH2_END
1223 
1224   if (!NT_SUCCESS(Status))
1225   {
1226       return NULL;
1227   }
1228 
1229   return HfontCreate(&SafeLogfont, cjElfw, lft, fl, pvCliData);
1230 }
1231 
1232 
1233 /* EOF */
1234