- Fix RealizationInfo, it should use DC font not cFont if 0.
[reactos.git] / reactos / subsystems / win32 / win32k / objects / font.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/font.c
5 * PURPOSE: Font
6 * PROGRAMMER:
7 */
8
9 /** Includes ******************************************************************/
10
11 #include <w32k.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /** Internal ******************************************************************/
17
18 INT
19 FASTCALL
20 FontGetObject(PTEXTOBJ TFont, INT Count, PVOID Buffer)
21 {
22 if( Buffer == NULL ) return sizeof(LOGFONTW);
23
24 switch (Count)
25 {
26 case sizeof(ENUMLOGFONTEXDVW):
27 RtlCopyMemory( (LPENUMLOGFONTEXDVW) Buffer,
28 &TFont->logfont,
29 sizeof(ENUMLOGFONTEXDVW));
30 break;
31 case sizeof(ENUMLOGFONTEXW):
32 RtlCopyMemory( (LPENUMLOGFONTEXW) Buffer,
33 &TFont->logfont.elfEnumLogfontEx,
34 sizeof(ENUMLOGFONTEXW));
35 break;
36
37 case sizeof(EXTLOGFONTW):
38 case sizeof(ENUMLOGFONTW):
39 RtlCopyMemory((LPENUMLOGFONTW) Buffer,
40 &TFont->logfont.elfEnumLogfontEx.elfLogFont,
41 sizeof(ENUMLOGFONTW));
42 break;
43
44 case sizeof(LOGFONTW):
45 RtlCopyMemory((LPLOGFONTW) Buffer,
46 &TFont->logfont.elfEnumLogfontEx.elfLogFont,
47 sizeof(LOGFONTW));
48 break;
49
50 default:
51 SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
52 return 0;
53 }
54 return Count;
55 }
56
57 DWORD
58 FASTCALL
59 IntGetFontLanguageInfo(PDC Dc)
60 {
61 PDC_ATTR Dc_Attr;
62 FONTSIGNATURE fontsig;
63 static const DWORD GCP_DBCS_MASK=0x003F0000,
64 GCP_DIACRITIC_MASK=0x00000000,
65 FLI_GLYPHS_MASK=0x00000000,
66 GCP_GLYPHSHAPE_MASK=0x00000040,
67 GCP_KASHIDA_MASK=0x00000000,
68 GCP_LIGATE_MASK=0x00000000,
69 GCP_USEKERNING_MASK=0x00000000,
70 GCP_REORDER_MASK=0x00000060;
71
72 DWORD result=0;
73
74 ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
75
76 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
77 if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
78 result|=GCP_DBCS;
79
80 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
81 result|=GCP_DIACRITIC;
82
83 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
84 result|=FLI_GLYPHS;
85
86 if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
87 result|=GCP_GLYPHSHAPE;
88
89 if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
90 result|=GCP_KASHIDA;
91
92 if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
93 result|=GCP_LIGATE;
94
95 if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
96 result|=GCP_USEKERNING;
97
98 Dc_Attr = Dc->pDc_Attr;
99 if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
100
101 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
102 if ( Dc_Attr->lTextAlign & TA_RTLREADING )
103 if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
104 result|=GCP_REORDER;
105
106 return result;
107 }
108
109 PTEXTOBJ
110 FASTCALL
111 RealizeFontInit(HFONT hFont)
112 {
113 NTSTATUS Status = STATUS_SUCCESS;
114 PTEXTOBJ pTextObj;
115
116 pTextObj = TEXTOBJ_LockText(hFont);
117
118 if ( pTextObj && !(pTextObj->fl & TEXTOBJECT_INIT))
119 {
120 Status = TextIntRealizeFont(hFont, pTextObj);
121 if (!NT_SUCCESS(Status))
122 {
123 TEXTOBJ_UnlockText(pTextObj);
124 return NULL;
125 }
126 }
127 return pTextObj;
128 }
129
130 /** Functions ******************************************************************/
131
132 INT
133 APIENTRY
134 NtGdiAddFontResourceW(
135 IN WCHAR *pwszFiles,
136 IN ULONG cwc,
137 IN ULONG cFiles,
138 IN FLONG fl,
139 IN DWORD dwPidTid,
140 IN OPTIONAL DESIGNVECTOR *pdv)
141 {
142 UNICODE_STRING SafeFileName;
143 PWSTR src;
144 NTSTATUS Status;
145 int Ret;
146
147 /* FIXME - Protect with SEH? */
148 RtlInitUnicodeString(&SafeFileName, pwszFiles);
149
150 /* Reserve for prepending '\??\' */
151 SafeFileName.Length += 4 * sizeof(WCHAR);
152 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
153
154 src = SafeFileName.Buffer;
155 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
156 if(!SafeFileName.Buffer)
157 {
158 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
159 return 0;
160 }
161
162 /* Prepend '\??\' */
163 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
164
165 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
166 if(!NT_SUCCESS(Status))
167 {
168 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
169 SetLastNtError(Status);
170 return 0;
171 }
172
173 Ret = IntGdiAddFontResource(&SafeFileName, (DWORD)fl);
174
175 ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
176 return Ret;
177 }
178
179 DWORD
180 STDCALL
181 NtGdiGetFontData(
182 HDC hDC,
183 DWORD Table,
184 DWORD Offset,
185 LPVOID Buffer,
186 DWORD Size)
187 {
188 PDC Dc;
189 PDC_ATTR Dc_Attr;
190 HFONT hFont;
191 PTEXTOBJ TextObj;
192 PFONTGDI FontGdi;
193 DWORD Result = GDI_ERROR;
194 NTSTATUS Status = STATUS_SUCCESS;
195
196 if (Buffer && Size)
197 {
198 _SEH_TRY
199 {
200 ProbeForRead(Buffer, Size, 1);
201 }
202 _SEH_HANDLE
203 {
204 Status = _SEH_GetExceptionCode();
205 }
206 _SEH_END
207 }
208
209 if (!NT_SUCCESS(Status)) return Result;
210
211 Dc = DC_LockDc(hDC);
212 if (Dc == NULL)
213 {
214 SetLastWin32Error(ERROR_INVALID_HANDLE);
215 return GDI_ERROR;
216 }
217 Dc_Attr = Dc->pDc_Attr;
218 if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
219
220 hFont = Dc_Attr->hlfntNew;
221 TextObj = RealizeFontInit(hFont);
222 DC_UnlockDc(Dc);
223
224 if (TextObj == NULL)
225 {
226 SetLastWin32Error(ERROR_INVALID_HANDLE);
227 return GDI_ERROR;
228 }
229
230 FontGdi = ObjToGDI(TextObj->Font, FONT);
231
232 Result = ftGdiGetFontData(FontGdi, Table, Offset, Buffer, Size);
233
234 TEXTOBJ_UnlockText(TextObj);
235
236 return Result;
237 }
238
239 /*
240 * @implemented
241 */
242 DWORD
243 APIENTRY
244 NtGdiGetFontUnicodeRanges(
245 IN HDC hdc,
246 OUT OPTIONAL LPGLYPHSET pgs)
247 {
248 PDC pDc;
249 PDC_ATTR Dc_Attr;
250 HFONT hFont;
251 PTEXTOBJ TextObj;
252 PFONTGDI FontGdi;
253 DWORD Size = 0;
254 PGLYPHSET pgsSafe;
255 NTSTATUS Status = STATUS_SUCCESS;
256
257 pDc = DC_LockDc(hdc);
258 if (!pDc)
259 {
260 SetLastWin32Error(ERROR_INVALID_HANDLE);
261 return 0;
262 }
263
264 Dc_Attr = pDc->pDc_Attr;
265 if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
266
267 hFont = Dc_Attr->hlfntNew;
268 TextObj = RealizeFontInit(hFont);
269
270 if ( TextObj == NULL)
271 {
272 SetLastWin32Error(ERROR_INVALID_HANDLE);
273 goto Exit;
274 }
275 FontGdi = ObjToGDI(TextObj->Font, FONT);
276
277 Size = ftGetFontUnicodeRanges( FontGdi, NULL);
278
279 if (Size && pgs)
280 {
281 pgsSafe = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
282 if (!pgsSafe)
283 {
284 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
285 Size = 0;
286 goto Exit;
287 }
288
289 Size = ftGetFontUnicodeRanges( FontGdi, pgsSafe);
290
291 if (Size)
292 {
293 _SEH_TRY
294 {
295 ProbeForWrite(pgsSafe, Size, 1);
296 RtlCopyMemory(pgs, pgsSafe, Size);
297 }
298 _SEH_HANDLE
299 {
300 Status = _SEH_GetExceptionCode();
301 }
302 _SEH_END
303
304 if (!NT_SUCCESS(Status)) Size = 0;
305 }
306 ExFreePoolWithTag(pgsSafe, TAG_GDITEXT);
307 }
308 Exit:
309 TEXTOBJ_UnlockText(TextObj);
310 DC_UnlockDc(pDc);
311 return Size;
312 }
313
314 ULONG
315 APIENTRY
316 NtGdiGetGlyphOutline(
317 IN HDC hdc,
318 IN WCHAR wch,
319 IN UINT iFormat,
320 OUT LPGLYPHMETRICS pgm,
321 IN ULONG cjBuf,
322 OUT OPTIONAL PVOID UnsafeBuf,
323 IN LPMAT2 pmat2,
324 IN BOOL bIgnoreRotation)
325 {
326 ULONG Ret = GDI_ERROR;
327 PDC dc;
328 PVOID pvBuf = NULL;
329 GLYPHMETRICS gm;
330 NTSTATUS Status = STATUS_SUCCESS;
331
332 dc = DC_LockDc(hdc);
333 if (!dc)
334 {
335 SetLastWin32Error(ERROR_INVALID_HANDLE);
336 return GDI_ERROR;
337 }
338
339 if (UnsafeBuf && cjBuf)
340 {
341 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, TAG_GDITEXT);
342 if (!pvBuf)
343 {
344 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
345 goto Exit;
346 }
347 }
348
349 Ret = ftGdiGetGlyphOutline( dc,
350 wch,
351 iFormat,
352 pgm ? &gm : NULL,
353 cjBuf,
354 pvBuf,
355 pmat2,
356 bIgnoreRotation);
357
358 if (pvBuf)
359 {
360 _SEH_TRY
361 {
362 ProbeForWrite(UnsafeBuf, cjBuf, 1);
363 RtlCopyMemory(UnsafeBuf, pvBuf, cjBuf);
364 }
365 _SEH_HANDLE
366 {
367 Status = _SEH_GetExceptionCode();
368 }
369 _SEH_END
370
371 ExFreePoolWithTag(pvBuf, TAG_GDITEXT);
372 }
373
374 if (pgm)
375 {
376 _SEH_TRY
377 {
378 ProbeForWrite(pgm, sizeof(GLYPHMETRICS), 1);
379 RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
380 }
381 _SEH_HANDLE
382 {
383 Status = _SEH_GetExceptionCode();
384 }
385 _SEH_END
386 }
387
388 if (! NT_SUCCESS(Status))
389 {
390 SetLastWin32Error(ERROR_INVALID_PARAMETER);
391 Ret = GDI_ERROR;
392 }
393
394 Exit:
395 DC_UnlockDc(dc);
396 return Ret;
397 }
398
399 DWORD
400 STDCALL
401 NtGdiGetKerningPairs(HDC hDC,
402 ULONG NumPairs,
403 LPKERNINGPAIR krnpair)
404 {
405 UNIMPLEMENTED;
406 return 0;
407 }
408
409 /*
410 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
411 472, this is NtGdiGetOutlineTextMetricsInternalW.
412 */
413 ULONG
414 STDCALL
415 NtGdiGetOutlineTextMetricsInternalW (HDC hDC,
416 ULONG Data,
417 OUTLINETEXTMETRICW *otm,
418 TMDIFF *Tmd)
419 {
420 PDC dc;
421 PDC_ATTR Dc_Attr;
422 PTEXTOBJ TextObj;
423 PFONTGDI FontGDI;
424 HFONT hFont = 0;
425 ULONG Size;
426 OUTLINETEXTMETRICW *potm;
427 NTSTATUS Status;
428
429 dc = DC_LockDc(hDC);
430 if (!dc)
431 {
432 SetLastWin32Error(ERROR_INVALID_HANDLE);
433 return 0;
434 }
435 Dc_Attr = dc->pDc_Attr;
436 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
437 hFont = Dc_Attr->hlfntNew;
438 TextObj = RealizeFontInit(hFont);
439 DC_UnlockDc(dc);
440 if (!TextObj)
441 {
442 SetLastWin32Error(ERROR_INVALID_HANDLE);
443 return 0;
444 }
445 FontGDI = ObjToGDI(TextObj->Font, FONT);
446 TEXTOBJ_UnlockText(TextObj);
447 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
448 if (!otm) return Size;
449 if (Size > Data)
450 {
451 SetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
452 return 0;
453 }
454 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
455 if (!potm)
456 {
457 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
458 return 0;
459 }
460 IntGetOutlineTextMetrics(FontGDI, Size, potm);
461 if (otm)
462 {
463 Status = MmCopyToCaller(otm, potm, Size);
464 if (! NT_SUCCESS(Status))
465 {
466 SetLastWin32Error(ERROR_INVALID_PARAMETER);
467 ExFreePoolWithTag(potm,TAG_GDITEXT);
468 return 0;
469 }
470 }
471 ExFreePoolWithTag(potm,TAG_GDITEXT);
472 return Size;
473 }
474
475 W32KAPI
476 BOOL
477 APIENTRY
478 NtGdiGetFontResourceInfoInternalW(
479 IN LPWSTR pwszFiles,
480 IN ULONG cwc,
481 IN ULONG cFiles,
482 IN UINT cjIn,
483 OUT LPDWORD pdwBytes,
484 OUT LPVOID pvBuf,
485 IN DWORD dwType)
486 {
487 NTSTATUS Status = STATUS_SUCCESS;
488 DWORD dwBytes;
489 UNICODE_STRING SafeFileNames;
490 BOOL bRet = FALSE;
491 ULONG cbStringSize;
492
493 union
494 {
495 LOGFONTW logfontw;
496 WCHAR FullName[LF_FULLFACESIZE];
497 } Buffer;
498
499 /* FIXME: handle cFiles > 0 */
500
501 /* Check for valid dwType values
502 dwType == 4 seems to be handled by gdi32 only */
503 if (dwType == 4 || dwType > 5)
504 {
505 SetLastWin32Error(ERROR_INVALID_PARAMETER);
506 return FALSE;
507 }
508
509 /* Allocate a safe unicode string buffer */
510 cbStringSize = cwc * sizeof(WCHAR);
511 SafeFileNames.MaximumLength = SafeFileNames.Length = cbStringSize - sizeof(WCHAR);
512 SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
513 cbStringSize,
514 TAG('R','T','S','U'));
515 if (!SafeFileNames.Buffer)
516 {
517 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
518 return FALSE;
519 }
520
521 /* Check buffers and copy pwszFiles to safe unicode string */
522 _SEH_TRY
523 {
524 ProbeForRead(pwszFiles, cbStringSize, 1);
525 ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
526 ProbeForWrite(pvBuf, cjIn, 1);
527
528 RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
529 }
530 _SEH_HANDLE
531 {
532 Status = _SEH_GetExceptionCode();
533 }
534 _SEH_END
535
536 if(!NT_SUCCESS(Status))
537 {
538 SetLastNtError(Status);
539 /* Free the string buffer for the safe filename */
540 ExFreePoolWithTag(SafeFileNames.Buffer,TAG('R','T','S','U'));
541 return FALSE;
542 }
543
544 /* Do the actual call */
545 bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType);
546
547 /* Check if succeeded and the buffer is big enough */
548 if (bRet && cjIn >= dwBytes)
549 {
550 /* Copy the data back to caller */
551 _SEH_TRY
552 {
553 /* Buffers are already probed */
554 RtlCopyMemory(pvBuf, &Buffer, dwBytes);
555 *pdwBytes = dwBytes;
556 }
557 _SEH_HANDLE
558 {
559 Status = _SEH_GetExceptionCode();
560 }
561 _SEH_END
562
563 if(!NT_SUCCESS(Status))
564 {
565 SetLastNtError(Status);
566 bRet = FALSE;
567 }
568 }
569
570 /* Free the string for the safe filenames */
571 ExFreePoolWithTag(SafeFileNames.Buffer,TAG('R','T','S','U'));
572
573 return bRet;
574 }
575
576 /*
577 * @unimplemented
578 */
579 BOOL
580 APIENTRY
581 NtGdiGetRealizationInfo(
582 IN HDC hdc,
583 OUT PREALIZATION_INFO pri,
584 IN HFONT hf)
585 {
586 PDC pDc;
587 PTEXTOBJ pTextObj;
588 PFONTGDI pFontGdi;
589 PDC_ATTR Dc_Attr;
590 BOOL Ret = FALSE;
591 INT i = 0;
592 REALIZATION_INFO ri;
593
594 pDc = DC_LockDc(hdc);
595 if (!pDc)
596 {
597 SetLastWin32Error(ERROR_INVALID_HANDLE);
598 return 0;
599 }
600 Dc_Attr = pDc->pDc_Attr;
601 if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
602 pTextObj = RealizeFontInit(Dc_Attr->hlfntNew);
603 pFontGdi = ObjToGDI(pTextObj->Font, FONT);
604 TEXTOBJ_UnlockText(pTextObj);
605 DC_UnlockDc(pDc);
606
607 Ret = ftGdiRealizationInfo(pFontGdi, &ri);
608 if (Ret)
609 {
610 if (pri)
611 {
612 NTSTATUS Status = STATUS_SUCCESS;
613 _SEH_TRY
614 {
615 ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
616 RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
617 }
618 _SEH_HANDLE
619 {
620 Status = _SEH_GetExceptionCode();
621 }
622 _SEH_END
623
624 if(!NT_SUCCESS(Status))
625 {
626 SetLastNtError(Status);
627 return FALSE;
628 }
629 }
630 do
631 {
632 if (GdiHandleTable->cfPublic[i].hf == hf)
633 {
634 GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
635 GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
636 GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
637 GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
638 GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
639 }
640 i++;
641 }
642 while ( i < GDI_CFONT_MAX );
643 }
644 return Ret;
645 }
646
647 HFONT
648 STDCALL
649 NtGdiHfontCreate(
650 IN PENUMLOGFONTEXDVW pelfw,
651 IN ULONG cjElfw,
652 IN LFTYPE lft,
653 IN FLONG fl,
654 IN PVOID pvCliData )
655 {
656 ENUMLOGFONTEXDVW SafeLogfont;
657 HFONT hNewFont;
658 PTEXTOBJ TextObj;
659 NTSTATUS Status = STATUS_SUCCESS;
660
661 if (!pelfw)
662 {
663 return NULL;
664 }
665
666 _SEH_TRY
667 {
668 ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
669 RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
670 }
671 _SEH_HANDLE
672 {
673 Status = _SEH_GetExceptionCode();
674 }
675 _SEH_END
676
677 if (!NT_SUCCESS(Status))
678 {
679 return NULL;
680 }
681
682 TextObj = TEXTOBJ_AllocTextWithHandle();
683 if (!TextObj)
684 {
685 return NULL;
686 }
687 hNewFont = TextObj->BaseObject.hHmgr;
688
689 TextObj->lft = lft;
690 TextObj->fl = fl;
691 RtlCopyMemory (&TextObj->logfont, &SafeLogfont, sizeof(ENUMLOGFONTEXDVW));
692
693 if (SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement !=
694 SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation)
695 {
696 /* this should really depend on whether GM_ADVANCED is set */
697 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
698 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
699 }
700 TEXTOBJ_UnlockText(TextObj);
701
702 return hNewFont;
703 }
704
705
706 /* EOF */