Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

drawtext.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: drawtext.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains common text drawing functions. 00007 * 00008 * History: 00009 * 02-12-92 mikeke Moved Drawtext to the client side 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 #define CR 13 00016 #define LF 10 00017 00018 #define DT_HFMTMASK 0x03 00019 00020 /***************************************************************************\ 00021 * IsMetaFile 00022 * 00023 * History: 00024 * 30-Nov-1992 mikeke Created 00025 \***************************************************************************/ 00026 00027 BOOL IsMetaFile( 00028 HDC hdc) 00029 { 00030 DWORD dwType = GetObjectType(hdc); 00031 return (dwType == OBJ_METAFILE || 00032 dwType == OBJ_METADC || 00033 dwType == OBJ_ENHMETAFILE || 00034 dwType == OBJ_ENHMETADC); 00035 } 00036 00037 /***************************************************************************\ 00038 * DrawTextA (API) 00039 * 00040 * History: 00041 * 30-11-92 mikeke Created 00042 \***************************************************************************/ 00043 00044 00045 CONST WCHAR gwszNullStr[] = L""; 00046 00047 int DrawTextExA( 00048 HDC hdc, 00049 LPSTR lpchText, 00050 int cchText, 00051 LPRECT lprc, 00052 UINT format, 00053 LPDRAWTEXTPARAMS lpdtp) 00054 { 00055 LPWSTR lpwstr; 00056 int iRet; 00057 int iUniString; 00058 WORD wCodePage = (WORD)GdiGetCodePage(hdc); 00059 00060 if (cchText == -1) { 00061 // USER_AWCONV_COUNTSTRINGSZ does not count/convert trailing \0. 00062 cchText = USER_AWCONV_COUNTSTRINGSZ; 00063 } else if (cchText < -1) { 00064 return 0; 00065 } 00066 00067 if ((iUniString = MBToWCSEx(wCodePage, lpchText, cchText, &lpwstr, -1, TRUE)) == 0) { 00068 if (cchText == USER_AWCONV_COUNTSTRINGSZ) { 00069 lpwstr = (LPWSTR)gwszNullStr; 00070 format &= ~DT_MODIFYSTRING; 00071 } else { 00072 return 0; 00073 } 00074 } 00075 00076 /* 00077 * Grow the buffer to accomodate the ellipsis (see AddEllipsisAndDrawLine) 00078 */ 00079 if (format & DT_MODIFYSTRING) { 00080 int iNewLen = (iUniString + CCHELLIPSIS + 1) * sizeof(*lpwstr); 00081 LPWSTR lpwstrNew = UserLocalReAlloc(lpwstr, iNewLen, HEAP_ZERO_MEMORY); 00082 if (lpwstrNew == NULL) { 00083 UserLocalFree((HANDLE)lpwstr); 00084 return FALSE; 00085 } 00086 lpwstr = lpwstrNew; 00087 } 00088 00089 iRet = DrawTextExWorker(hdc, lpwstr, iUniString, lprc, format, lpdtp, GetTextCharset(hdc)); 00090 00091 if (format & DT_MODIFYSTRING) { 00092 /* 00093 * Note that if the buffer grew and the caller provided the string size, 00094 * then we won't return the additional characters... fixing this 00095 * might break some apps so let's leave it alone until some one complains 00096 */ 00097 if (cchText < 0) { 00098 UserAssert(cchText == USER_AWCONV_COUNTSTRINGSZ); 00099 // Guess how many bytes we can put in the buffer... 00100 // We can safely assume the maximum bytes available. 00101 // At worst, even for DBCS, the buffer size required 00102 // will be smaller than or equal to the orignal size, 00103 // because some DBCS characters would be substituted 00104 // to SBC ".", which is one byte each. 00105 // On the other hand, the number of characters converted 00106 // is limited by both iUniString and cchText. 00107 // 00108 if (IS_DBCS_ENABLED()) { 00109 cchText = iUniString * DBCS_CHARSIZE; 00110 } else { 00111 cchText = iUniString * sizeof(CHAR); 00112 } 00113 } 00114 WCSToMBEx(wCodePage, lpwstr, iUniString, &lpchText, cchText, FALSE); 00115 } 00116 00117 if (lpwstr != gwszNullStr) { 00118 UserLocalFree((HANDLE)lpwstr); 00119 } 00120 00121 return iRet; 00122 } 00123 00124 /***************************************************************************\ 00125 * DrawTextW (API) 00126 * 00127 * History: 00128 * 30-11-92 mikeke Created 00129 \***************************************************************************/ 00130 00131 int DrawTextW( 00132 HDC hdc, 00133 LPCWSTR lpchText, 00134 int cchText, 00135 LPRECT lprc, 00136 UINT format) 00137 { 00138 DRAWTEXTPARAMS DTparams; 00139 LPDRAWTEXTPARAMS lpDTparams = NULL; 00140 00141 /* v-ronaar: fix bug #24985 00142 * Disallow negative string lengths, except -1 (which has special meaning). 00143 */ 00144 if (cchText < -1) 00145 return(0); 00146 00147 if (format & DT_TABSTOP) 00148 { 00149 DTparams.cbSize = sizeof(DRAWTEXTPARAMS); 00150 DTparams.iLeftMargin = DTparams.iRightMargin = 0; 00151 DTparams.iTabLength = (format & 0xff00) >> 8; 00152 lpDTparams = &DTparams; 00153 format &= 0xffff00ff; 00154 } 00155 00156 return DrawTextExW(hdc, (LPWSTR)lpchText, cchText, lprc, format, lpDTparams); 00157 } 00158 00159 /***************************************************************************\ 00160 * DrawTextA (API) 00161 * 00162 * History: 00163 * 30-11-92 mikeke Created 00164 \***************************************************************************/ 00165 00166 int DrawTextA( 00167 HDC hdc, 00168 LPCSTR lpchText, 00169 int cchText, 00170 LPRECT lprc, 00171 UINT format) 00172 { 00173 DRAWTEXTPARAMS DTparams; 00174 LPDRAWTEXTPARAMS lpDTparams = NULL; 00175 00176 /* v-ronaar: fix bug #24985 00177 * Disallow negative string lengths, except -1 (which has special meaning). 00178 */ 00179 if (cchText < -1) 00180 return(0); 00181 00182 if (format & DT_TABSTOP) { 00183 DTparams.cbSize = sizeof(DRAWTEXTPARAMS); 00184 DTparams.iLeftMargin = DTparams.iRightMargin = 0; 00185 DTparams.iTabLength = (format & 0xff00) >> 8; 00186 lpDTparams = &DTparams; 00187 format &= 0xffff00ff; 00188 } 00189 00190 return DrawTextExA(hdc, (LPSTR)lpchText, cchText, lprc, format, lpDTparams); 00191 } 00192 00193 /***************************************************************************\ 00194 * ClientTabTheTextOutForWimps 00195 * 00196 * effects: Outputs the tabbed text if fDrawTheText is TRUE and returns the 00197 * textextent of the tabbed text. 00198 * 00199 * nCount Count of bytes in string 00200 * nTabPositions Count of tabstops in tabstop array 00201 * lpintTabStopPositions Tab stop positions in pixels 00202 * iTabOrigin Tab stops are with respect to this 00203 * 00204 * History: 00205 * 19-Jan-1993 mikeke Client side 00206 * 13-Sep-1996 GregoryW This routine now calls the LPK(s) to handle text out. 00207 * If no LPKs are installed, this defaults to calling 00208 * UserLpkTabbedTextOut (identical behavior to what we 00209 * had before supporting LPKs). 00210 \***************************************************************************/ 00211 00212 LONG TabTextOut( 00213 HDC hdc, 00214 int x, 00215 int y, 00216 LPCWSTR lpstring, 00217 int nCount, 00218 int nTabPositions, 00219 CONST INT *lpTabPositions, 00220 int iTabOrigin, 00221 BOOL fDrawTheText, 00222 int iCharset) 00223 { 00224 int cxCharWidth; 00225 int cyCharHeight = 0; 00226 00227 if (nCount == -1 && lpstring) { 00228 nCount = wcslen(lpstring); 00229 } 00230 if (!lpstring || nCount < 0 || nTabPositions < 0) 00231 return 0; 00232 00233 00234 // Check if it is SysFont AND the mapping mode is MM_TEXT; 00235 // Fix made in connection with Bug #8717 --02-01-90 --SANKAR-- 00236 if (IsSysFontAndDefaultMode(hdc)) 00237 { 00238 cxCharWidth = gpsi->cxSysFontChar; 00239 cyCharHeight = gpsi->cySysFontChar; 00240 } else { 00241 cxCharWidth = GdiGetCharDimensions(hdc, NULL, &cyCharHeight); 00242 if (cxCharWidth == 0) { 00243 RIPMSG0(RIP_WARNING, "TabTextOut: GdiGetCharDimensions failed"); 00244 return 0; 00245 } 00246 } 00247 00248 return (*fpLpkTabbedTextOut)(hdc, x, y, lpstring, nCount, nTabPositions, 00249 lpTabPositions, iTabOrigin, fDrawTheText, 00250 cxCharWidth, cyCharHeight, iCharset); 00251 } 00252 00253 LONG UserLpkTabbedTextOut( 00254 HDC hdc, 00255 int x, 00256 int y, 00257 LPCWSTR lpstring, 00258 int nCount, 00259 int nTabPositions, 00260 CONST INT *lpTabPositions, 00261 int iTabOrigin, 00262 BOOL fDrawTheText, 00263 int cxCharWidth, 00264 int cyCharHeight, 00265 int iCharset) 00266 { 00267 SIZE textextent, viewextent, windowextent; 00268 int initialx = x; 00269 int cch; 00270 LPCWSTR lp; 00271 int iOneTab = 0; 00272 RECT rc; 00273 UINT uOpaque = (GetBkMode(hdc) == OPAQUE) ? ETO_OPAQUE : 0; 00274 BOOL fStrStart = TRUE; 00275 int ySign = 1; //Assume y increases in down direction. 00276 00277 UNREFERENCED_PARAMETER(iCharset); //Needed by lpk, but not us 00278 /* 00279 * If no tabstop positions are specified, then use a default of 8 system 00280 * font ave char widths or use the single fixed tab stop. 00281 */ 00282 if (!lpTabPositions) { 00283 // no tab stops specified -- default to a tab stop every 8 characters 00284 iOneTab = 8 * cxCharWidth; 00285 } else if (nTabPositions == 1) { 00286 // one tab stop specified -- treat value as the tab increment, one 00287 // tab stop every increment 00288 iOneTab = lpTabPositions[0]; 00289 00290 if (!iOneTab) 00291 iOneTab = 1; 00292 } 00293 00294 // Calculate if the y increases or decreases in the down direction using 00295 // the ViewPortExtent and WindowExtents. 00296 // If this call fails, hdc must be invalid 00297 if (!GetViewportExtEx(hdc, &viewextent)) 00298 return 0; 00299 GetWindowExtEx(hdc, &windowextent); 00300 if ((viewextent.cy ^ windowextent.cy) & 0x80000000) 00301 ySign = -1; 00302 00303 rc.left = initialx; 00304 rc.top = y; 00305 rc.bottom = rc.top + (ySign * cyCharHeight); 00306 00307 while (TRUE) { 00308 // count the number of characters until the next tab character 00309 // this set of characters (substring) will be the working set for 00310 // each iteration of this loop 00311 for (cch = nCount, lp = lpstring; cch && (*lp != TEXT('\t')); lp++, cch--) 00312 { 00313 } 00314 00315 // Compute the number of characters to be drawn with textout. 00316 cch = nCount - cch; 00317 00318 // Compute the number of characters remaining. 00319 nCount -= cch + 1; 00320 00321 // get height and width of substring 00322 if (cch == 0) { 00323 textextent.cx = 0; 00324 textextent.cy = cyCharHeight; 00325 } else 00326 GetTextExtentPointW(hdc, lpstring, cch, &textextent); 00327 00328 if (fStrStart) 00329 // first iteration should just spit out the first substring 00330 // no tabbing occurs until the first tab character is encountered 00331 fStrStart = FALSE; 00332 else 00333 { 00334 // not the first iteration -- tab accordingly 00335 00336 int xTab; 00337 int i; 00338 00339 if (!iOneTab) 00340 { 00341 // look thru tab stop array for next tab stop after existing 00342 // text to put this substring 00343 for (i = 0; i < nTabPositions; i++) 00344 { 00345 xTab = lpTabPositions[i]; 00346 00347 if (xTab < 0) 00348 // calc length needed to use this right justified tab 00349 xTab = (iTabOrigin - xTab) - textextent.cx; 00350 else 00351 // calc length needed to use this left justified tab 00352 xTab = iTabOrigin + xTab; 00353 00354 if (x < xTab) 00355 { 00356 // we found a tab with enough room -- let's use it 00357 x = xTab; 00358 break; 00359 } 00360 } 00361 00362 if (i == nTabPositions) 00363 // we've exhausted all of the given tab positions 00364 // go back to default of a tab stop every 8 characters 00365 iOneTab = 8 * cxCharWidth; 00366 } 00367 00368 // we have to recheck iOneTab here (instead of just saying "else") 00369 // because iOneTab will be set if we've run out of tab stops 00370 if (iOneTab) 00371 { 00372 if (iOneTab < 0) 00373 { 00374 // calc next available right justified tab stop 00375 xTab = x + textextent.cx - iTabOrigin; 00376 xTab = ((xTab / iOneTab) * iOneTab) - iOneTab - textextent.cx + iTabOrigin; 00377 } 00378 else 00379 { 00380 // calc next available left justified tab stop 00381 xTab = x - iTabOrigin; 00382 xTab = ((xTab / iOneTab) * iOneTab) + iOneTab + iTabOrigin; 00383 } 00384 x = xTab; 00385 } 00386 } 00387 00388 if (fDrawTheText) { 00389 00390 /* 00391 * Output all text up to the tab (or end of string) and get its 00392 * extent. 00393 */ 00394 rc.right = x + textextent.cx; 00395 ExtTextOutW( 00396 hdc, x, y, uOpaque, &rc, (LPWSTR)lpstring, 00397 cch, NULL); 00398 rc.left = rc.right; 00399 } 00400 00401 // Skip over the tab and the characters we just drew. 00402 x += textextent.cx; 00403 00404 // Skip over the characters we just drew. 00405 lpstring += cch; 00406 00407 // See if we have more to draw OR see if this string ends in 00408 // a tab character that needs to be drawn. 00409 if((nCount > 0) || ((nCount == 0) && (*lpstring == TEXT('\t')))) 00410 { 00411 00412 lpstring++; // Skip over the tab 00413 continue; 00414 } 00415 else 00416 break; // Break from the loop. 00417 } 00418 return MAKELONG((x - initialx), (short)textextent.cy); 00419 } 00420 00421 00422 00423 /***************************************************************************\ 00424 * TabbedTextOutW 00425 * 00426 * effects: Outputs the tabbed text and returns the 00427 * textextent of the tabbed text. 00428 * 00429 * nCount Count of bytes in string 00430 * nTabPositions Count of tabstops in tabstop array 00431 * lpintTabStopPositions Tab stop positions in pixels 00432 * iTabOrigin Tab stops are with respect to this 00433 * 00434 * History: 00435 * 19-Jan-1993 mikeke Client side 00436 \***************************************************************************/ 00437 00438 LONG TabbedTextOutW( 00439 HDC hdc, 00440 int x, 00441 int y, 00442 LPCWSTR lpstring, 00443 int cchChars, 00444 int nTabPositions, 00445 CONST INT *lpintTabStopPositions, 00446 int iTabOrigin) 00447 { 00448 return TabTextOut(hdc, x, y, lpstring, cchChars, 00449 nTabPositions, lpintTabStopPositions, iTabOrigin, TRUE, -1); 00450 } 00451 00452 /***************************************************************************\ 00453 * TabbedTextOutA (API) 00454 * 00455 * History: 00456 * 30-11-92 mikeke Created 00457 \***************************************************************************/ 00458 00459 LONG TabbedTextOutA( 00460 HDC hdc, 00461 int x, 00462 int y, 00463 LPCSTR pString, 00464 int chCount, 00465 int nTabPositions, 00466 CONST INT *pnTabStopPositions, 00467 int nTabOrigin) 00468 { 00469 LPWSTR lpwstr; 00470 BOOL bRet; 00471 WORD wCodePage = (WORD)GdiGetCodePage(hdc); 00472 int iUniString; 00473 00474 if (chCount == -1) { 00475 chCount = USER_AWCONV_COUNTSTRINGSZ; 00476 } 00477 00478 if ((iUniString = MBToWCSEx(wCodePage, pString, chCount, &lpwstr, -1, TRUE)) == 0) { 00479 if (chCount == USER_AWCONV_COUNTSTRINGSZ) { 00480 lpwstr = (LPWSTR)gwszNullStr; 00481 } else { 00482 return FALSE; 00483 } 00484 } 00485 00486 bRet = TabTextOut( 00487 hdc, x, y, lpwstr, iUniString, nTabPositions, 00488 pnTabStopPositions, nTabOrigin, TRUE, GetTextCharset(hdc)); 00489 00490 if (lpwstr != gwszNullStr) { 00491 UserLocalFree((HANDLE)lpwstr); 00492 } 00493 00494 return bRet; 00495 } 00496 00497 DWORD GetTabbedTextExtentW( 00498 HDC hdc, 00499 LPCWSTR pString, 00500 int chCount, 00501 int nTabPositions, 00502 CONST INT *pnTabStopPositions) 00503 { 00504 return TabTextOut(hdc, 0, 0, pString, chCount, 00505 nTabPositions, pnTabStopPositions, 0, FALSE, -1); 00506 } 00507 00508 DWORD GetTabbedTextExtentA( 00509 HDC hdc, 00510 LPCSTR pString, 00511 int chCount, 00512 int nTabPositions, 00513 CONST INT *pnTabStopPositions) 00514 { 00515 LPWSTR lpwstr; 00516 BOOL bRet; 00517 WORD wCodePage = (WORD)GdiGetCodePage(hdc); 00518 int iUniString; 00519 00520 if (chCount == -1) { 00521 chCount = USER_AWCONV_COUNTSTRINGSZ; 00522 } 00523 if ((iUniString = MBToWCSEx(wCodePage, pString, chCount, &lpwstr, -1, TRUE)) == 0) { 00524 if (chCount == USER_AWCONV_COUNTSTRINGSZ) { 00525 lpwstr = (LPWSTR)gwszNullStr; 00526 } else { 00527 return FALSE; 00528 } 00529 } 00530 00531 bRet = TabTextOut(hdc, 0, 0, lpwstr, iUniString, 00532 nTabPositions, pnTabStopPositions, 0, FALSE, GetTextCharset(hdc)); 00533 00534 if (lpwstr != gwszNullStr) { 00535 UserLocalFree((HANDLE)lpwstr); 00536 } 00537 00538 return bRet; 00539 } 00540 00541 00542 /***************************************************************************\ 00543 * PSMTextOut 00544 * 00545 * Outputs the text and puts and _ below the character with an & 00546 * before it. Note that this routine isn't used for menus since menus 00547 * have their own special one so that it is specialized and faster... 00548 * 00549 * History: 00550 * 11-13-90 JimA Ported to NT. 00551 * 30-Nov-1992 mikeke Client side version 00552 * 7-Apr-1998 MCostea Added dwFlags 00553 \***************************************************************************/ 00554 00555 void PSMTextOut( 00556 HDC hdc, 00557 int xLeft, 00558 int yTop, 00559 LPWSTR lpsz, 00560 int cch, 00561 DWORD dwFlags) 00562 { 00563 /* 00564 * By default this is just a call to UserLpkPSMTextOut. If an 00565 * LPK is installed, this calls out to the LPK. The LPK calls 00566 * UserLpkPSMTextOut, if necessary. 00567 */ 00568 (*fpLpkPSMTextOut)(hdc, xLeft, yTop, lpsz, cch, dwFlags); 00569 return; 00570 } 00571 00572 /***************************************************************************\ 00573 * UserLpkPSMTextOut 00574 * 00575 * NOTE: A very similar routine (xxxPSMTextOut) exists on the kernel 00576 * side in text.c. Any changes to this routine most likely need 00577 * to be made in xxxPSMTextOut as well. 00578 * 00579 \***************************************************************************/ 00580 void UserLpkPSMTextOut( 00581 HDC hdc, 00582 int xLeft, 00583 int yTop, 00584 LPWSTR lpsz, 00585 int cch, 00586 DWORD dwFlags) 00587 { 00588 int cx; 00589 LONG textsize, result; 00590 WCHAR achWorkBuffer[255]; 00591 WCHAR *pchOut = achWorkBuffer; 00592 TEXTMETRICW textMetric; 00593 SIZE size; 00594 RECT rc; 00595 COLORREF color; 00596 00597 if (cch > sizeof(achWorkBuffer)/sizeof(WCHAR)) { 00598 pchOut = (WCHAR*)UserLocalAlloc(HEAP_ZERO_MEMORY, (cch+1) * sizeof(WCHAR)); 00599 if (pchOut == NULL) 00600 return; 00601 } 00602 00603 result = GetPrefixCount(lpsz, cch, pchOut, cch); 00604 /* 00605 * DT_PREFIXONLY is a new 5.0 option used when switching from keyboard cues off 00606 * to on. 00607 */ 00608 if (!(dwFlags & DT_PREFIXONLY)) { 00609 TextOutW(hdc, xLeft, yTop, pchOut, cch - HIWORD(result)); 00610 } 00611 00612 /* 00613 * Any true prefix characters to underline? 00614 */ 00615 if (LOWORD(result) == 0xFFFF || dwFlags & DT_HIDEPREFIX) { 00616 if (pchOut != achWorkBuffer) 00617 UserLocalFree(pchOut); 00618 return; 00619 } 00620 00621 if (!GetTextMetricsW(hdc, &textMetric)) { 00622 textMetric.tmOverhang = 0; 00623 textMetric.tmAscent = 0; 00624 } 00625 00626 /* 00627 * For proportional fonts, find starting point of underline. 00628 */ 00629 if (LOWORD(result) != 0) { 00630 00631 /* 00632 * How far in does underline start (if not at 0th byte.). 00633 */ 00634 GetTextExtentPointW(hdc, pchOut, LOWORD(result), &size); 00635 xLeft += size.cx; 00636 00637 /* 00638 * Adjust starting point of underline if not at first char and there is 00639 * an overhang. (Italics or bold fonts.) 00640 */ 00641 xLeft = xLeft - textMetric.tmOverhang; 00642 } 00643 00644 /* 00645 * Adjust for proportional font when setting the length of the underline and 00646 * height of text. 00647 */ 00648 GetTextExtentPointW(hdc, pchOut + LOWORD(result), 1, &size); 00649 textsize = size.cx; 00650 00651 /* 00652 * Find the width of the underline character. Just subtract out the overhang 00653 * divided by two so that we look better with italic fonts. This is not 00654 * going to effect embolded fonts since their overhang is 1. 00655 */ 00656 cx = LOWORD(textsize) - textMetric.tmOverhang / 2; 00657 00658 /* 00659 * Get height of text so that underline is at bottom. 00660 */ 00661 yTop += textMetric.tmAscent + 1; 00662 00663 /* 00664 * Draw the underline using the foreground color. 00665 */ 00666 SetRect(&rc, xLeft, yTop, xLeft+cx, yTop+1); 00667 color = SetBkColor(hdc, GetTextColor(hdc)); 00668 ExtTextOutW(hdc, xLeft, yTop, ETO_OPAQUE, &rc, TEXT(""), 0, NULL); 00669 SetBkColor(hdc, color); 00670 00671 if (pchOut != achWorkBuffer) { 00672 UserLocalFree(pchOut); 00673 } 00674 }

Generated on Sat May 15 19:39:46 2004 for test by doxygen 1.3.7