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