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 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 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 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 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 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 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 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 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 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 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 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 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 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