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