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