xref: /reactos/win32ss/gdi/ntgdi/text.c (revision e4930be4)
1 /*
2  * PROJECT:         ReactOS win32 kernel mode subsystem
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            win32ss/gdi/ntgdi/text.c
5  * PURPOSE:         Text/Font
6  * PROGRAMMER:
7  */
8 
9 /** Includes ******************************************************************/
10 
11 #include <win32k.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 
17 /*
18    This is a hack. See CORE-1091.
19 
20    It is needed because ReactOS does not support raster fonts now.
21    After Raster Font support is added, then it can be removed.
22    Find the current font's logfont for testing its lf.lfFaceName.
23 
24    The ftGdiGetTextMetricsW function currently in ReactOS will always return a Truetype font
25    because we cannot yet handle raster fonts. So it will return flags
26    TMPF_VECTOR and TMPF_TRUETYPE, which can cause problems in edit boxes.
27  */
28 
29 VOID FASTCALL
IntTMWFixUp(HDC hDC,TMW_INTERNAL * ptm)30 IntTMWFixUp(
31    HDC hDC,
32    TMW_INTERNAL *ptm)
33 {
34     LOGFONTW lf;
35     HFONT hCurrentFont;
36 
37     hCurrentFont = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_FONT);
38     GreGetObject(hCurrentFont, sizeof(LOGFONTW), &lf);
39 
40     /* To compensate for the GetTextMetricsW call changing the PitchAndFamily
41      * to a TrueType one when we have a 'Raster' font as our input we filter
42      * out the problematic TrueType and Vector bits.
43      * Our list below checks for Raster Font Facenames. */
44     DPRINT("Font Facename is '%S'.\n", lf.lfFaceName);
45     if ((_wcsicmp(lf.lfFaceName, L"Courier") == 0) ||
46         (_wcsicmp(lf.lfFaceName, L"FixedSys") == 0) ||
47         (_wcsicmp(lf.lfFaceName, L"Helv") == 0) ||
48         (_wcsicmp(lf.lfFaceName, L"MS Sans Serif") == 0) ||
49         (_wcsicmp(lf.lfFaceName, L"MS Serif") == 0) ||
50         (_wcsicmp(lf.lfFaceName, L"System") == 0) ||
51         (_wcsicmp(lf.lfFaceName, L"Terminal") == 0) ||
52         (_wcsicmp(lf.lfFaceName, L"Tms Rmn") == 0))
53     {
54         ptm->TextMetric.tmPitchAndFamily &= ~(TMPF_TRUETYPE | TMPF_VECTOR);
55     }
56 }
57 
58 /** Functions *****************************************************************/
59 
60 BOOL FASTCALL
GreTextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpString,int cchString)61 GreTextOutW(
62     HDC  hdc,
63     int  nXStart,
64     int  nYStart,
65     LPCWSTR  lpString,
66     int  cchString)
67 {
68     return GreExtTextOutW(hdc, nXStart, nYStart, 0, NULL, lpString, cchString, NULL, 0);
69 }
70 
71 /*
72    flOpts :
73    GetTextExtentPoint32W = 0
74    GetTextExtentPointW   = 1
75  */
76 BOOL
77 FASTCALL
GreGetTextExtentW(HDC hDC,LPCWSTR lpwsz,INT cwc,LPSIZE psize,UINT flOpts)78 GreGetTextExtentW(
79     HDC hDC,
80     LPCWSTR lpwsz,
81     INT cwc,
82     LPSIZE psize,
83     UINT flOpts)
84 {
85     PDC pdc;
86     PDC_ATTR pdcattr;
87     BOOL Result;
88     PTEXTOBJ TextObj;
89 
90     if (!cwc)
91     {
92         psize->cx = 0;
93         psize->cy = 0;
94         return TRUE;
95     }
96 
97     pdc = DC_LockDc(hDC);
98     if (!pdc)
99     {
100         EngSetLastError(ERROR_INVALID_HANDLE);
101         return FALSE;
102     }
103 
104     pdcattr = pdc->pdcattr;
105 
106     TextObj = RealizeFontInit(pdcattr->hlfntNew);
107     if ( TextObj )
108     {
109         Result = TextIntGetTextExtentPoint( pdc,
110                                             TextObj,
111                                             lpwsz,
112                                             cwc,
113                                             0,
114                                             NULL,
115                                             0,
116                                             psize,
117                                             flOpts);
118         TEXTOBJ_UnlockText(TextObj);
119     }
120     else
121         Result = FALSE;
122 
123     DC_UnlockDc(pdc);
124     return Result;
125 }
126 
127 
128 /*
129    fl :
130    GetTextExtentExPointW = 0 and everything else that uses this.
131    GetTextExtentExPointI = 1
132  */
133 BOOL
134 FASTCALL
GreGetTextExtentExW(HDC hDC,LPCWSTR String,ULONG Count,ULONG MaxExtent,PULONG Fit,PULONG Dx,LPSIZE pSize,FLONG fl)135 GreGetTextExtentExW(
136     HDC hDC,
137     LPCWSTR String,
138     ULONG Count,
139     ULONG MaxExtent,
140     PULONG Fit,
141     PULONG Dx,
142     LPSIZE pSize,
143     FLONG fl)
144 {
145     PDC pdc;
146     PDC_ATTR pdcattr;
147     BOOL Result;
148     PTEXTOBJ TextObj;
149 
150     if ( (!String && Count ) || !pSize )
151     {
152         EngSetLastError(ERROR_INVALID_PARAMETER);
153         return FALSE;
154     }
155 
156     if ( !Count )
157     {
158         if ( Fit ) Fit = 0;
159         return TRUE;
160     }
161 
162     pdc = DC_LockDc(hDC);
163     if (NULL == pdc)
164     {
165         EngSetLastError(ERROR_INVALID_HANDLE);
166         return FALSE;
167     }
168     pdcattr = pdc->pdcattr;
169 
170     TextObj = RealizeFontInit(pdcattr->hlfntNew);
171     if ( TextObj )
172     {
173         Result = TextIntGetTextExtentPoint( pdc,
174                                             TextObj,
175                                             String,
176                                             Count,
177                                             MaxExtent,
178                                             (LPINT)Fit,
179                                             (LPINT)Dx,
180                                             pSize,
181                                             fl);
182         TEXTOBJ_UnlockText(TextObj);
183     }
184     else
185         Result = FALSE;
186 
187     DC_UnlockDc(pdc);
188     return Result;
189 }
190 
191 BOOL
192 WINAPI
GreGetTextMetricsW(_In_ HDC hdc,_Out_ LPTEXTMETRICW lptm)193 GreGetTextMetricsW(
194     _In_  HDC hdc,
195     _Out_ LPTEXTMETRICW lptm)
196 {
197    TMW_INTERNAL tmwi;
198    if (!ftGdiGetTextMetricsW(hdc, &tmwi)) return FALSE;
199    IntTMWFixUp(hdc, &tmwi);
200    *lptm = tmwi.TextMetric;
201    return TRUE;
202 }
203 
204 DWORD
205 APIENTRY
NtGdiGetCharSet(HDC hDC)206 NtGdiGetCharSet(HDC hDC)
207 {
208     PDC Dc;
209     PDC_ATTR pdcattr;
210     DWORD cscp;
211     // If here, update everything!
212     Dc = DC_LockDc(hDC);
213     if (!Dc)
214     {
215         EngSetLastError(ERROR_INVALID_HANDLE);
216         return 0;
217     }
218     cscp = ftGdiGetTextCharsetInfo(Dc, NULL, 0);
219     pdcattr = Dc->pdcattr;
220     pdcattr->iCS_CP = cscp;
221     pdcattr->ulDirty_ &= ~DIRTY_CHARSET;
222     DC_UnlockDc( Dc );
223     return cscp;
224 }
225 
226 BOOL
227 APIENTRY
NtGdiGetRasterizerCaps(OUT LPRASTERIZER_STATUS praststat,IN ULONG cjBytes)228 NtGdiGetRasterizerCaps(
229     OUT LPRASTERIZER_STATUS praststat,
230     IN ULONG cjBytes)
231 {
232     NTSTATUS Status = STATUS_SUCCESS;
233     RASTERIZER_STATUS rsSafe;
234 
235     if (praststat && cjBytes)
236     {
237         if ( cjBytes >= sizeof(RASTERIZER_STATUS) ) cjBytes = sizeof(RASTERIZER_STATUS);
238         if ( ftGdiGetRasterizerCaps(&rsSafe))
239         {
240             _SEH2_TRY
241             {
242                 ProbeForWrite( praststat,
243                 sizeof(RASTERIZER_STATUS),
244                 1);
245                 RtlCopyMemory(praststat, &rsSafe, cjBytes );
246             }
247             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
248             {
249                 Status = _SEH2_GetExceptionCode();
250             }
251             _SEH2_END;
252 
253             if (!NT_SUCCESS(Status))
254             {
255                 SetLastNtError(Status);
256                 return FALSE;
257             }
258 
259             return TRUE;
260         }
261     }
262     return FALSE;
263 }
264 
265 INT
266 APIENTRY
NtGdiGetTextCharsetInfo(IN HDC hdc,OUT OPTIONAL LPFONTSIGNATURE lpSig,IN DWORD dwFlags)267 NtGdiGetTextCharsetInfo(
268     IN HDC hdc,
269     OUT OPTIONAL LPFONTSIGNATURE lpSig,
270     IN DWORD dwFlags)
271 {
272     PDC Dc;
273     INT Ret;
274     FONTSIGNATURE fsSafe;
275     PFONTSIGNATURE pfsSafe = &fsSafe;
276     NTSTATUS Status = STATUS_SUCCESS;
277 
278     Dc = DC_LockDc(hdc);
279     if (!Dc)
280     {
281         EngSetLastError(ERROR_INVALID_HANDLE);
282         return DEFAULT_CHARSET;
283     }
284 
285     if (!lpSig) pfsSafe = NULL;
286 
287     Ret = HIWORD(ftGdiGetTextCharsetInfo( Dc, pfsSafe, dwFlags));
288 
289     if (lpSig)
290     {
291         if (Ret == DEFAULT_CHARSET)
292             RtlZeroMemory(pfsSafe, sizeof(FONTSIGNATURE));
293 
294         _SEH2_TRY
295         {
296             ProbeForWrite( lpSig,
297             sizeof(FONTSIGNATURE),
298             1);
299             RtlCopyMemory(lpSig, pfsSafe, sizeof(FONTSIGNATURE));
300         }
301         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
302         {
303             Status = _SEH2_GetExceptionCode();
304         }
305         _SEH2_END;
306 
307         if (!NT_SUCCESS(Status))
308         {
309             SetLastNtError(Status);
310             return DEFAULT_CHARSET;
311         }
312     }
313     DC_UnlockDc(Dc);
314     return Ret;
315 }
316 
317 
318 /*
319    fl :
320    GetTextExtentExPointW = 0 and everything else that uses this.
321    GetTextExtentExPointI = 1
322  */
323 W32KAPI
324 BOOL
325 APIENTRY
NtGdiGetTextExtentExW(IN HDC hDC,IN OPTIONAL LPWSTR UnsafeString,IN ULONG Count,IN ULONG MaxExtent,OUT OPTIONAL PULONG UnsafeFit,OUT OPTIONAL PULONG UnsafeDx,OUT LPSIZE UnsafeSize,IN FLONG fl)326 NtGdiGetTextExtentExW(
327     IN HDC hDC,
328     IN OPTIONAL LPWSTR UnsafeString,
329     IN ULONG Count,
330     IN ULONG MaxExtent,
331     OUT OPTIONAL PULONG UnsafeFit,
332     OUT OPTIONAL PULONG UnsafeDx,
333     OUT LPSIZE UnsafeSize,
334     IN FLONG fl
335 )
336 {
337     PDC dc;
338     PDC_ATTR pdcattr;
339     LPWSTR String;
340     SIZE Size;
341     NTSTATUS Status;
342     BOOLEAN Result;
343     INT Fit;
344     LPINT Dx;
345     PTEXTOBJ TextObj;
346 
347     if ((LONG)Count < 0)
348     {
349         EngSetLastError(ERROR_INVALID_PARAMETER);
350         return FALSE;
351     }
352 
353     /* FIXME: Handle fl */
354 
355     if (0 == Count)
356     {
357         Size.cx = 0;
358         Size.cy = 0;
359         Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
360         if (! NT_SUCCESS(Status))
361         {
362             SetLastNtError(Status);
363             return FALSE;
364         }
365         return TRUE;
366     }
367 
368     String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), GDITAG_TEXT);
369     if (NULL == String)
370     {
371         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
372         return FALSE;
373     }
374 
375     if (NULL != UnsafeDx)
376     {
377         Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), GDITAG_TEXT);
378         if (NULL == Dx)
379         {
380             ExFreePoolWithTag(String, GDITAG_TEXT);
381             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
382             return FALSE;
383         }
384     }
385     else
386     {
387         Dx = NULL;
388     }
389 
390     Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
391     if (! NT_SUCCESS(Status))
392     {
393         if (NULL != Dx)
394         {
395             ExFreePoolWithTag(Dx, GDITAG_TEXT);
396         }
397         ExFreePoolWithTag(String, GDITAG_TEXT);
398         SetLastNtError(Status);
399         return FALSE;
400     }
401 
402     dc = DC_LockDc(hDC);
403     if (NULL == dc)
404     {
405         if (NULL != Dx)
406         {
407             ExFreePoolWithTag(Dx, GDITAG_TEXT);
408         }
409         ExFreePoolWithTag(String, GDITAG_TEXT);
410         EngSetLastError(ERROR_INVALID_HANDLE);
411         return FALSE;
412     }
413     pdcattr = dc->pdcattr;
414     TextObj = RealizeFontInit(pdcattr->hlfntNew);
415     if ( TextObj )
416     {
417         Result = TextIntGetTextExtentPoint( dc,
418                                             TextObj,
419                                             String,
420                                             Count,
421                                             MaxExtent,
422                                             NULL == UnsafeFit ? NULL : &Fit,
423                                             Dx,
424                                             &Size,
425                                             fl);
426         TEXTOBJ_UnlockText(TextObj);
427     }
428     else
429         Result = FALSE;
430     DC_UnlockDc(dc);
431 
432     ExFreePoolWithTag(String, GDITAG_TEXT);
433     if (! Result)
434     {
435         if (NULL != Dx)
436         {
437             ExFreePoolWithTag(Dx, GDITAG_TEXT);
438         }
439         return FALSE;
440     }
441 
442     if (NULL != UnsafeFit)
443     {
444         Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
445         if (! NT_SUCCESS(Status))
446         {
447             if (NULL != Dx)
448             {
449                 ExFreePoolWithTag(Dx, GDITAG_TEXT);
450             }
451             SetLastNtError(Status);
452             return FALSE;
453         }
454     }
455 
456     if (NULL != UnsafeDx)
457     {
458         Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
459         if (! NT_SUCCESS(Status))
460         {
461             if (NULL != Dx)
462             {
463                 ExFreePoolWithTag(Dx, GDITAG_TEXT);
464             }
465             SetLastNtError(Status);
466             return FALSE;
467         }
468     }
469     if (NULL != Dx)
470     {
471         ExFreePoolWithTag(Dx, GDITAG_TEXT);
472     }
473 
474     Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
475     if (! NT_SUCCESS(Status))
476     {
477         SetLastNtError(Status);
478         return FALSE;
479     }
480 
481     return TRUE;
482 }
483 
484 
485 /*
486    flOpts :
487    GetTextExtentPoint32W = 0
488    GetTextExtentPointW   = 1
489  */
490 BOOL
491 APIENTRY
NtGdiGetTextExtent(HDC hdc,LPWSTR lpwsz,INT cwc,LPSIZE psize,UINT flOpts)492 NtGdiGetTextExtent(HDC hdc,
493                    LPWSTR lpwsz,
494                    INT cwc,
495                    LPSIZE psize,
496                    UINT flOpts)
497 {
498     return NtGdiGetTextExtentExW(hdc, lpwsz, cwc, 0, NULL, NULL, psize, flOpts);
499 }
500 
501 BOOL
502 APIENTRY
NtGdiSetTextJustification(HDC hDC,int BreakExtra,int BreakCount)503 NtGdiSetTextJustification(HDC  hDC,
504                           int  BreakExtra,
505                           int  BreakCount)
506 {
507     PDC pDc;
508     PDC_ATTR pdcattr;
509 
510     pDc = DC_LockDc(hDC);
511     if (!pDc)
512     {
513         EngSetLastError(ERROR_INVALID_HANDLE);
514         return FALSE;
515     }
516 
517     pdcattr = pDc->pdcattr;
518 
519     pdcattr->lBreakExtra = BreakExtra;
520     pdcattr->cBreak = BreakCount;
521 
522     DC_UnlockDc(pDc);
523     return TRUE;
524 }
525 
526 
527 W32KAPI
528 INT
529 APIENTRY
NtGdiGetTextFaceW(IN HDC hDC,IN INT Count,OUT OPTIONAL LPWSTR FaceName,IN BOOL bAliasName)530 NtGdiGetTextFaceW(
531     IN HDC hDC,
532     IN INT Count,
533     OUT OPTIONAL LPWSTR FaceName,
534     IN BOOL bAliasName
535 )
536 {
537     PDC Dc;
538     PDC_ATTR pdcattr;
539     HFONT hFont;
540     PTEXTOBJ TextObj;
541     NTSTATUS Status;
542     SIZE_T fLen;
543     INT ret;
544 
545     /* FIXME: Handle bAliasName */
546 
547     Dc = DC_LockDc(hDC);
548     if (Dc == NULL)
549     {
550         EngSetLastError(ERROR_INVALID_HANDLE);
551         return FALSE;
552     }
553     pdcattr = Dc->pdcattr;
554     hFont = pdcattr->hlfntNew;
555     DC_UnlockDc(Dc);
556 
557     TextObj = RealizeFontInit(hFont);
558     ASSERT(TextObj != NULL);
559     fLen = wcslen(TextObj->TextFace) + 1;
560 
561     if (FaceName != NULL)
562     {
563         Count = min(Count, fLen);
564         Status = MmCopyToCaller(FaceName, TextObj->TextFace, Count * sizeof(WCHAR));
565         if (!NT_SUCCESS(Status))
566         {
567             TEXTOBJ_UnlockText(TextObj);
568             SetLastNtError(Status);
569             return 0;
570         }
571         /* Terminate if we copied only part of the font name */
572         if (Count > 0 && Count < fLen)
573         {
574             FaceName[Count - 1] = '\0';
575         }
576         ret = Count;
577     }
578     else
579     {
580         ret = fLen;
581     }
582 
583     TEXTOBJ_UnlockText(TextObj);
584     return ret;
585 }
586 
587 W32KAPI
588 BOOL
589 APIENTRY
NtGdiGetTextMetricsW(IN HDC hDC,OUT TMW_INTERNAL * pUnsafeTmwi,IN ULONG cj)590 NtGdiGetTextMetricsW(
591     IN HDC hDC,
592     OUT TMW_INTERNAL * pUnsafeTmwi,
593     IN ULONG cj)
594 {
595     TMW_INTERNAL Tmwi;
596 
597     if ( cj <= sizeof(TMW_INTERNAL) )
598     {
599         if (ftGdiGetTextMetricsW(hDC, &Tmwi))
600         {
601             IntTMWFixUp(hDC, &Tmwi);
602             _SEH2_TRY
603             {
604                 ProbeForWrite(pUnsafeTmwi, cj, 1);
605                 RtlCopyMemory(pUnsafeTmwi, &Tmwi, cj);
606             }
607             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
608             {
609                 SetLastNtError(_SEH2_GetExceptionCode());
610                 _SEH2_YIELD(return FALSE);
611             }
612             _SEH2_END
613 
614             return TRUE;
615         }
616     }
617     return FALSE;
618 }
619 
620 /* EOF */
621