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 00013 /***************************************************************************\ 00014 * Define some macros to test the format flags. We won't support them all 00015 * on the kernel-mode side, since they're not all needed there. 00016 \***************************************************************************/ 00017 #ifdef _USERK_ 00018 #define CALCRECT(wFormat) FALSE 00019 #define EDITCONTROL(wFormat) FALSE 00020 #define EXPANDTABS(wFormat) FALSE 00021 #define EXTERNALLEADING(wFormat) FALSE 00022 #define MODIFYSTRING(wFormat) FALSE 00023 #define NOPREFIX(wFormat) TRUE 00024 #define PATHELLIPSIS(wFormat) FALSE 00025 #define SINGLELINE(wFormat) TRUE 00026 #define TABSTOP(wFormat) FALSE 00027 #define WORDBREAK(wFormat) FALSE 00028 #define WORDELLIPSIS(wFormat) FALSE 00029 #define NOFULLWIDTHCHARBREAK(dwFormat) FALSE 00030 #else 00031 #define CALCRECT(wFormat) (wFormat & DT_CALCRECT) 00032 #define EDITCONTROL(wFormat) (wFormat & DT_EDITCONTROL) 00033 #define EXPANDTABS(wFormat) (wFormat & DT_EXPANDTABS) 00034 #define EXTERNALLEADING(wFormat) (wFormat & DT_EXTERNALLEADING) 00035 #define MODIFYSTRING(wFormat) (wFormat & DT_MODIFYSTRING) 00036 #define NOPREFIX(wFormat) (wFormat & DT_NOPREFIX) 00037 #define PATHELLIPSIS(wFormat) (wFormat & DT_PATH_ELLIPSIS) 00038 #define SINGLELINE(wFormat) (wFormat & DT_SINGLELINE) 00039 #define TABSTOP(wFormat) (wFormat & DT_TABSTOP) 00040 #define WORDBREAK(wFormat) (wFormat & DT_WORDBREAK) 00041 #define WORDELLIPSIS(wFormat) (wFormat & DT_WORD_ELLIPSIS) 00042 // Note: DT_NOFULLWIDTHCHARBREAK exceeds WORD limit. Use dwFormat 00043 // rather than wFormat. 00044 #define NOFULLWIDTHCHARBREAK(dwFormat) (dwFormat & DT_NOFULLWIDTHCHARBREAK) 00045 #endif 00046 #define ENDELLIPSIS(wFormat) (wFormat & DT_END_ELLIPSIS) 00047 #define NOCLIP(wFormat) (wFormat & DT_NOCLIP) 00048 #define RTLREADING(wFormat) (wFormat & DT_RTLREADING) 00049 #define HIDEPREFIX(wFormat) (wFormat & DT_HIDEPREFIX) 00050 00051 /***************************************************************************\ 00052 * Stuff used in DrawText code 00053 \***************************************************************************/ 00054 00055 #define CR 13 00056 #define LF 10 00057 #define DT_HFMTMASK 0x03 00058 #define DT_VFMTMASK 0x0C 00059 #define ETO_OPAQUEFGND 0x0A 00060 00061 static CONST WCHAR szEllipsis[CCHELLIPSIS+1] = TEXT("..."); 00062 00063 extern HDC ghdcBits2; 00064 00065 /* Max length of a full path is around 260. But, most of the time, it will 00066 * be less than 128. So, we alloc only this much on stack. If the string is 00067 * longer, we alloc from local heap (which is slower). 00068 * 00069 * BOGUS: For international versions, we need to give some more margin here. 00070 */ 00071 #define MAXBUFFSIZE 128 00072 00073 /***************************************************************************\ 00074 * There are word breaking characters which are compatible with 00075 * Japanese Windows 3.1 and FarEast Windows 95. 00076 * 00077 * SJ - Country Japan , Charset SHIFTJIS, Codepage 932. 00078 * GB - Country PRC , Charset GB2312 , Codepage 936. 00079 * B5 - Country Taiwan, Charset BIG5 , Codepage 950. 00080 * WS - Country Korea , Charset WANGSUNG, Codepage 949. 00081 * JB - Country Korea , Charset JOHAB , Codepage 1361. *** LATER *** 00082 * 00083 * [START BREAK CHARACTERS] 00084 * 00085 * These character should not be the last charatcer of the line. 00086 * 00087 * Unicode Japan PRC Taiwan Korea 00088 * -------+---------+---------+---------+---------+ 00089 * 00090 * + ASCII 00091 * 00092 * U+0024 (SJ+0024) (WS+0024) Dollar sign 00093 * U+0028 (SJ+0028) (WS+0028) Opening parenthesis 00094 * U+003C (SJ+003C) Less-than sign 00095 * U+005C (SJ+005C) Backslash 00096 * U+005B (SJ+005B) (GB+005B) (WS+005B) Opening square bracket 00097 * U+007B (SJ+007B) (GB+007B) (WS+007B) Opening curly bracket 00098 * 00099 * + General punctuation 00100 * 00101 * U+2018 (WS+A1AE) Single Turned Comma Quotation Mark 00102 * U+201C (WS+A1B0) Double Comma Quotation Mark 00103 * 00104 * + CJK symbols and punctuation 00105 * 00106 * U+3008 (WS+A1B4) Opening Angle Bracket 00107 * U+300A (SJ+8173) (WS+A1B6) Opening Double Angle Bracket 00108 * U+300C (SJ+8175) (WS+A1B8) Opening Corner Bracket 00109 * U+300E (SJ+8177) (WS+A1BA) Opening White Corner Bracket 00110 * U+3010 (SJ+9179) (WS+A1BC) Opening Black Lenticular Bracket 00111 * U+3014 (SJ+816B) (WS+A1B2) Opening Tortoise Shell Bracket 00112 * 00113 * + Fullwidth ASCII variants 00114 * 00115 * U+FF04 (WS+A3A4) Fullwidth Dollar Sign 00116 * U+FF08 (SJ+8169) (WS+A3A8) Fullwidth opening parenthesis 00117 * U+FF1C (SJ+8183) Fullwidth less-than sign 00118 * U+FF3B (SJ+816D) (WS+A3DB) Fullwidth opening square bracket 00119 * U+FF5B (SJ+816F) (WS+A3FB) Fullwidth opening curly bracket 00120 * 00121 * + Halfwidth Katakana variants 00122 * 00123 * U+FF62 (SJ+00A2) Halfwidth Opening Corner Bracket 00124 * 00125 * + Fullwidth symbol variants 00126 * 00127 * U+FFE1 (WS+A1CC) Fullwidth Pound Sign 00128 * U+FFE6 (WS+A3DC) Fullwidth Won Sign 00129 * 00130 * [END BREAK CHARACTERS] 00131 * 00132 * These character should not be the top charatcer of the line. 00133 * 00134 * Unicode Japan PRC Taiwan Korea 00135 * -------+---------+---------+---------+---------+ 00136 * 00137 * + ASCII 00138 * 00139 * U+0021 (SJ+0021) (GB+0021) (B5+0021) (WS+0021) Exclamation mark 00140 * U+0025 (WS+0025) Percent Sign 00141 * U+0029 (SJ+0029) (WS+0029) Closing parenthesis 00142 * U+002C (SJ+002C) (GB+002C) (B5+002C) (WS+002C) Comma 00143 * U+002E (SJ+002E) (GB+002E) (B5+002E) (WS+002E) Priod 00144 * U+003A (WS+003A) Colon 00145 * U+003B (WS+003B) Semicolon 00146 * U+003E (SJ+003E) Greater-than sign 00147 * U+003F (SJ+003F) (GB+003F) (B5+003F) (WS+003F) Question mark 00148 * U+005D (SJ+005D) (GB+005D) (B5+005D) (WS+005D) Closing square bracket 00149 * U+007D (SJ+007D) (GB+007D) (B5+007D) (WS+007D) Closing curly bracket 00150 * 00151 * + Latin1 00152 * 00153 * U+00A8 (GB+A1A7) Spacing diaeresis 00154 * U+00B0 (WS+A1C6) Degree Sign 00155 * U+00B7 (B5+A150) Middle Dot 00156 * 00157 * + Modifier letters 00158 * 00159 * U+02C7 (GB+A1A6) Modifier latter hacek 00160 * U+02C9 (GB+A1A5) Modifier letter macron 00161 * 00162 * + General punctuation 00163 * 00164 * U+2013 (B5+A156) En Dash 00165 * U+2014 (b5+A158) Em Dash 00166 * U+2015 (GB+A1AA) Quotation dash 00167 * U+2016 (GB+A1AC) Double vertical bar 00168 * U+2018 (GB+A1AE) Single turned comma quotation mark 00169 * U+2019 (GB+A1AF) (B5+A1A6) (WS+A1AF) Single comma quotation mark 00170 * U+201D (GB+A1B1) (B5+A1A8) (WS+A1B1) Double comma quotation mark 00171 * U+2022 (GB+A1A4) Bullet 00172 * U+2025 (B5+A14C) Two Dot Leader 00173 * U+2026 (GB+A1AD) (B5+A14B) Horizontal ellipsis 00174 * U+2027 (B5+A145) Hyphenation Point 00175 * U+2032 (B5+A1AC) (WS+A1C7) Prime 00176 * U+2033 (WS+A1C8) Double Prime 00177 * 00178 * + Letterlike symbols 00179 * 00180 * U+2103 (WS+A1C9) Degrees Centigrade 00181 * 00182 * + Mathemetical opetartors 00183 * 00184 * U+2236 (GB+A1C3) Ratio 00185 * 00186 * + Form and Chart components 00187 * 00188 * U+2574 (B5+A15A) Forms Light Left 00189 * 00190 * + CJK symbols and punctuation 00191 * 00192 * U+3001 (SJ+8141) (GB+A1A2) (B5+A142) Ideographic comma 00193 * U+3002 (SJ+8142) (GB+A1A3) (B5+A143) Ideographic period 00194 * U+3003 (GB+A1A8) Ditto mark 00195 * U+3005 (GB+A1A9) Ideographic iteration 00196 * U+3009 (GB+A1B5) (B5+A172) (WS+A1B5) Closing angle bracket 00197 * U+300B (SJ+8174) (GB+A1B7) (B5+A16E) (WS+A1B7) Closing double angle bracket 00198 * U+300D (SJ+8176) (GB+A1B9) (B5+A176) (WS+A1B9) Closing corner bracket 00199 * U+300F (SJ+8178) (GB+A1BB) (B5+A17A) (WS+A1BB) Closing white corner bracket 00200 * U+3011 (SJ+817A) (GB+A1BF) (B5+A16A) (WS+A1BD) Closing black lenticular bracket 00201 * U+3015 (SJ+816C) (GB+A1B3) (B5+A166) (WS+A1B3) Closing tortoise shell bracket 00202 * U+3017 (GB+A1BD) Closing white lenticular bracket 00203 * U+301E (B5+A1AA) Double Prime Quotation Mark 00204 * 00205 * + Hiragana 00206 * 00207 * U+309B (SJ+814A) Katakana-Hiragana voiced sound mark 00208 * U+309C (SJ+814B) Katakana-Hiragana semi-voiced sound mark 00209 * 00210 * + CNS 11643 compatibility 00211 * 00212 * U+FE30 (B5+A14A) Glyph for Vertical 2 Dot Leader 00213 * U+FE31 (B5+A157) Glyph For Vertical Em Dash 00214 * U+FE33 (B5+A159) Glyph for Vertical Spacing Underscore 00215 * U+FE34 (B5+A15B) Glyph for Vertical Spacing Wavy Underscore 00216 * U+FE36 (B5+A160) Glyph For Vertical Closing Parenthesis 00217 * U+FE38 (B5+A164) Glyph For Vertical Closing Curly Bracket 00218 * U+FE3A (B5+A168) Glyph For Vertical Closing Tortoise Shell Bracket 00219 * U+FE3C (B5+A16C) Glyph For Vertical Closing Black Lenticular Bracket 00220 * U+FE3E (B5+A16E) Closing Double Angle Bracket 00221 * U+FE40 (B5+A174) Glyph For Vertical Closing Angle Bracket 00222 * U+FE42 (B5+A178) Glyph For Vertical Closing Corner Bracket 00223 * U+FE44 (B5+A17C) Glyph For Vertical Closing White Corner Bracket 00224 * U+FE4F (B5+A15C) Spacing Wavy Underscore 00225 * 00226 * + Small variants 00227 * 00228 * U+FE50 (B5+A14D) Small Comma 00229 * U+FE51 (B5+A14E) Small Ideographic Comma 00230 * U+FE52 (B5+A14F) Small Period 00231 * U+FE54 (B5+A151) Small Semicolon 00232 * U+FE55 (B5+A152) Small Colon 00233 * U+FE56 (B5+A153) Small Question Mark 00234 * U+FE57 (B5+A154) Small Exclamation Mark 00235 * U+FE5A (B5+A17E) Small Closing Parenthesis 00236 * U+FE5C (B5+A1A2) Small Closing Curly Bracket 00237 * U+FE5E (B5+A1A4) Small Closing Tortoise Shell Bracket 00238 * 00239 * + Fullwidth ASCII variants 00240 * 00241 * U+FF01 (SJ+8149) (GB+A3A1) (B5+A149) (WS+A3A1) Fullwidth exclamation mark 00242 * U+FF02 (GB+A3A2) Fullwidth Quotation mark 00243 * U+FF05 (WS+A3A5) Fullwidth Percent Sign 00244 * U+FF07 (GB+A3A7) Fullwidth Apostrophe 00245 * U+FF09 (SJ+816A) (GB+A3A9) (B5+A15E) (WS+A3A9) Fullwidth Closing parenthesis 00246 * U+FF0C (SJ+8143) (GB+A3AC) (B5+A141) (WS+A3AC) Fullwidth comma 00247 * U+FF0D (GB+A3AD) Fullwidth Hyphen-minus 00248 * U+FF0E (SJ+8144) (B5+A144) (WS+A3AE) Fullwidth period 00249 * U+FF1A (GB+A3BA) (B4+A147) (WS+A3BA) Fullwidth colon 00250 * U+FF1B (GB+A3BB) (B5+A146) (WS+A3BB) Fullwidth semicolon 00251 * U+FF1E (SJ+8184) Fullwidth Greater-than sign 00252 * U+FF1F (SJ+8148) (GB+A3BF) (B5+A148) (WS+A3BF) Fullwidth question mark 00253 * U+FF3D (SJ+816E) (GB+A3DD) (WS+A3DD) Fullwidth Closing square bracket 00254 * U+FF5C (B5+A155) Fullwidth Vertical Bar 00255 * U+FF5D (SJ+8170) (B5+A162) (WS+A3FD) Fullwidth Closing curly bracket 00256 * U+FF5E (GB+A1AB) Fullwidth Spacing tilde 00257 * 00258 * + Halfwidth Katakana variants 00259 * 00260 * U+FF61 (SJ+00A1) Halfwidth Ideographic period 00261 * U+FF63 (SJ+00A3) Halfwidth Closing corner bracket 00262 * U+FF64 (SJ+00A4) Halfwidth Ideographic comma 00263 * U+FF9E (SJ+00DE) Halfwidth Katakana voiced sound mark 00264 * U+FF9F (SJ+00DF) Halfwidth Katakana semi-voiced sound mark 00265 * 00266 * + Fullwidth symbol variants 00267 * 00268 * U+FFE0 (WS+A1CB) Fullwidth Cent Sign 00269 * 00270 \***************************************************************************/ 00271 00272 #if 0 // not currently used --- FYI only 00273 /***************************************************************************\ 00274 * Start Break table 00275 * These character should not be the last charatcer of the line. 00276 \***************************************************************************/ 00277 00278 CONST BYTE aASCII_StartBreak[] = { 00279 /* 00 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00280 /* 2X */ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 00281 /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 00282 /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00283 /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 00284 /* 6X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00285 /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 00286 }; 00287 00288 CONST BYTE aCJKSymbol_StartBreak[] = { 00289 /* 30 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00290 /* 0X */ 1, 0, 1, 0, 1, 0, 1, 0, 00291 /* 1X */ 1, 0, 0, 0, 1 00292 }; 00293 00294 CONST BYTE aFullWidthHalfWidthVariants_StartBreak[] = { 00295 /* FF 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00296 /* 0X */ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 00297 /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 00298 /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00299 /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 00300 /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00301 /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 00302 /* 6X */ 0, 0, 1 00303 }; 00304 #endif 00305 00306 /***************************************************************************\ 00307 * End Break table. 00308 * These character should not be the top charatcer of the line. 00309 \***************************************************************************/ 00310 00311 CONST BYTE aASCII_Latin1_EndBreak[] = { 00312 /* 00 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00313 /* 2X */ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 00314 /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 00315 /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00316 /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 00317 /* 6X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00318 /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 00319 /* 8X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00320 /* 9X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00321 /* AX */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 00322 /* BX */ 1, 0, 0, 0, 0, 0, 0, 1 00323 }; 00324 00325 CONST BYTE aGeneralPunctuation_EndBreak[] = { 00326 /* 20 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00327 /* 1X */ 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 00328 /* 2X */ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 00329 /* 3X */ 0, 0, 1, 1 00330 }; 00331 00332 CONST BYTE aCJKSymbol_EndBreak[] = { 00333 /* 30 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00334 /* 0X */ 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 00335 /* 1X */ 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 00336 }; 00337 00338 CONST BYTE aCNS11643_SmallVariants_EndBreak[] = { 00339 /* FE 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00340 /* 3X */ 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 00341 /* 4X */ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 00342 /* 5X */ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1 00343 }; 00344 00345 CONST BYTE aFullWidthHalfWidthVariants_EndBreak[] = { 00346 /* FF 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 00347 /* 0X */ 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 00348 /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 00349 /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00350 /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 00351 /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00352 /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 00353 /* 6X */ 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00354 /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00355 /* 8X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00356 /* 9X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 00357 }; 00358 00359 /***************************************************************************\ 00360 * UserIsFELineBreak() - Detects Far East word breaking characters. * 00361 * * 00362 * History: * 00363 * 10-Mar-1996 HideyukN Created. * 00364 \***************************************************************************/ 00365 00366 #if 0 // not currently used --- FYI only 00367 BOOL UserIsFELineBreakStart(WCHAR wch) 00368 { 00369 switch (wch>>8) { 00370 case 0x00: 00371 // 00372 // Check if word breaking chars in ASCII. 00373 // 00374 if ((wch >= 0x0024) && (wch <= 0x007B)) 00375 return((BOOL)(aASCII_StartBreak[wch - 0x0024])); 00376 else 00377 return(FALSE); 00378 00379 case 0x20: 00380 // 00381 // Check if work breaking chars in "General punctuation" 00382 // 00383 if ((wch == 0x2018) || (wch == 0x201C)) 00384 return(TRUE); 00385 else 00386 return(FALSE); 00387 00388 case 0x30: 00389 // 00390 // Check if word breaking chars in "CJK symbols and punctuation" 00391 // and Hiragana. 00392 // 00393 if ((wch >= 0x3008) && (wch <= 0x3014)) 00394 return((BOOL)(aCJKSymbol_StartBreak[wch - 0x3008])); 00395 else 00396 return(FALSE); 00397 00398 case 0xFF: 00399 // 00400 // Check if word breaking chars in "Fullwidth ASCII variants", 00401 // "Halfwidth Katakana variants" or "Fullwidth Symbol variants". 00402 // 00403 if ((wch >= 0xFF04) && (wch <= 0xFF62)) 00404 return((BOOL)(aFullWidthHalfWidthVariants_StartBreak[wch - 0xFF04])); 00405 else if ((wch == 0xFFE1) || (wch == 0xFFE6)) 00406 return(TRUE); 00407 else 00408 return(FALSE); 00409 00410 default: 00411 return(FALSE); 00412 } 00413 } 00414 #endif 00415 00416 BOOL UserIsFELineBreakEnd(WCHAR wch) 00417 { 00418 switch (wch>>8) { 00419 case 0x00: 00420 // 00421 // Check if word breaking chars in ASCII or Latin1. 00422 // 00423 if ((wch >= 0x0021) && (wch <= 0x00B7)) 00424 return((BOOL)(aASCII_Latin1_EndBreak[wch - 0x0021])); 00425 else 00426 return(FALSE); 00427 00428 case 0x02: 00429 // 00430 // Check if work breaking chars in "Modifier letters" 00431 // 00432 if ((wch == 0x02C7) || (wch == 0x02C9)) 00433 return(TRUE); 00434 else 00435 return(FALSE); 00436 00437 case 0x20: 00438 // 00439 // Check if work breaking chars in "General punctuation" 00440 // 00441 if ((wch >= 0x2013) && (wch <= 0x2033)) 00442 return((BOOL)(aGeneralPunctuation_EndBreak[wch - 0x2013])); 00443 else 00444 return(FALSE); 00445 00446 case 0x21: 00447 // 00448 // Check if work breaking chars in "Letterlike symbols" 00449 // 00450 if (wch == 0x2103) 00451 return(TRUE); 00452 else 00453 return(FALSE); 00454 00455 case 0x22: 00456 // 00457 // Check if work breaking chars in "Mathemetical opetartors" 00458 // 00459 if (wch == 0x2236) 00460 return(TRUE); 00461 else 00462 return(FALSE); 00463 00464 case 0x25: 00465 // 00466 // Check if work breaking chars in "Form and Chart components" 00467 // 00468 if (wch == 0x2574) 00469 return(TRUE); 00470 else 00471 return(FALSE); 00472 00473 case 0x30: 00474 // 00475 // Check if word breaking chars in "CJK symbols and punctuation" 00476 // and Hiragana. 00477 // 00478 if ((wch >= 0x3001) && (wch <= 0x301E)) 00479 return((BOOL)(aCJKSymbol_EndBreak[wch - 0x3001])); 00480 else if ((wch == 0x309B) || (wch == 0x309C)) 00481 return(TRUE); 00482 else 00483 return(FALSE); 00484 00485 case 0xFE: 00486 // 00487 // Check if word breaking chars in "CNS 11643 compatibility" 00488 // or "Small variants". 00489 // 00490 if ((wch >= 0xFE30) && (wch <= 0xFE5E)) 00491 return((BOOL)(aCNS11643_SmallVariants_EndBreak[wch - 0xFE30])); 00492 else 00493 return(FALSE); 00494 00495 case 0xFF: 00496 // 00497 // Check if word breaking chars in "Fullwidth ASCII variants", 00498 // "Halfwidth Katakana variants" or "Fullwidth symbol variants". 00499 // 00500 if ((wch >= 0xFF01) && (wch <= 0xFF9F)) 00501 return((BOOL)(aFullWidthHalfWidthVariants_EndBreak[wch - 0xFF01])); 00502 else if (wch >= 0xFFE0) 00503 return(TRUE); 00504 else 00505 return(FALSE); 00506 00507 default: 00508 return(FALSE); 00509 } 00510 } 00511 00512 #define UserIsFELineBreak(wChar) UserIsFELineBreakEnd(wChar) 00513 00514 /***************************************************************************\ 00515 * UserIsFullWidth() - Detects Far East FullWidth character. * 00516 * * 00517 * History: * 00518 * 10-Mar-1996 HideyukN Created * 00519 \***************************************************************************/ 00520 00521 typedef struct _FULLWIDTH_UNICODE { 00522 WCHAR Start; 00523 WCHAR End; 00524 } FULLWIDTH_UNICODE, *PFULLWIDTH_UNICODE; 00525 00526 #define NUM_FULLWIDTH_UNICODES 4 00527 00528 CONST FULLWIDTH_UNICODE FullWidthUnicodes[] = { 00529 { 0x4E00, 0x9FFF }, // CJK_UNIFIED_IDOGRAPHS 00530 { 0x3040, 0x309F }, // HIRAGANA 00531 { 0x30A0, 0x30FF }, // KATAKANA 00532 { 0xAC00, 0xD7A3 } // HANGUL 00533 }; 00534 00535 BOOL UserIsFullWidth(DWORD dwCodePage,WCHAR wChar) 00536 { 00537 INT index; 00538 INT cChars; 00539 #ifdef _USERK_ 00540 CHAR aChars[2]; 00541 #endif // _USERK_ 00542 00543 // 00544 // Early out for ASCII. 00545 // 00546 if (wChar < 0x0080) { 00547 // 00548 // if the character < 0x0080, it should be a halfwidth character. 00549 // 00550 return (FALSE); 00551 } 00552 // 00553 // Scan FullWdith definition table... most of FullWidth character is 00554 // defined here... this is more faster than call NLS API. 00555 // 00556 for (index = 0; index < NUM_FULLWIDTH_UNICODES; index++) { 00557 if ((wChar >= FullWidthUnicodes[index].Start) && 00558 (wChar <= FullWidthUnicodes[index].End) ) { 00559 return (TRUE); 00560 } 00561 } 00562 // 00563 // if this Unicode character is mapped to Double-Byte character, 00564 // this is also FullWidth character.. 00565 // 00566 #ifdef _USERK_ 00567 cChars = EngWideCharToMultiByte((UINT)dwCodePage,&wChar,sizeof(WCHAR),aChars,sizeof(aChars)); 00568 #else 00569 cChars = WideCharToMultiByte((UINT)dwCodePage,0,&wChar,1,NULL,0,NULL,NULL); 00570 #endif // _USERK_ 00571 00572 return(cChars > 1 ? TRUE : FALSE); 00573 } 00574 /***************************************************************************\ 00575 * UserTextOutWInternal 00576 * Wrapper for UserTextOutW, used to adjust the parameter passed to 00577 * PSMTextOut 00578 * 00579 \***************************************************************************/ 00580 BOOL UserTextOutWInternal( 00581 HDC hdc, 00582 int x, 00583 int y, 00584 LPCWSTR lp, 00585 UINT cc, 00586 DWORD dwFlags) 00587 { 00588 UNREFERENCED_PARAMETER(dwFlags); 00589 return UserTextOutW(hdc, x, y, lp, cc); 00590 } 00591 00592 00593 /*--------------------------------------------------------------------------*/ 00594 /* */ 00595 /* KKGetPrefixWidth() - */ 00596 /* */ 00597 /* Returns total width of prefix character. Japanese Windows has */ 00598 /* three shortcut prefixes, '&',\036 and \037. They may have */ 00599 /* different width. */ 00600 /* */ 00601 /* From Chicago ctlmgr.c HideyukN */ 00602 /*--------------------------------------------------------------------------*/ 00603 00604 int KKGetPrefixWidth(HDC hdc, LPCWSTR lpStr, int cch) 00605 { 00606 SIZE size; 00607 SIZE iPrefix1 = {-1L,-1L}; 00608 SIZE iPrefix2 = {-1L,-1L}; 00609 SIZE iPrefix3 = {-1L,-1L}; 00610 int iTotal = 0; 00611 00612 while (cch-- > 0 && *lpStr) { 00613 switch(*lpStr) { 00614 case CH_PREFIX: 00615 if (lpStr[1] != CH_PREFIX) { 00616 if (iPrefix1.cx == -1) { 00617 UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix1); 00618 } 00619 iTotal += iPrefix1.cx; 00620 } else { 00621 lpStr++; 00622 cch--; 00623 } 00624 break; 00625 case CH_ENGLISHPREFIX: 00626 if (iPrefix2.cx == -1) { 00627 UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix2); 00628 } 00629 iTotal += iPrefix2.cx; 00630 break; 00631 case CH_KANJIPREFIX: 00632 if (iPrefix3.cx == -1) { 00633 UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix3); 00634 } 00635 iTotal += iPrefix3.cx; 00636 // 00637 // In NT, always alpha numeric mode, Then we have to sum 00638 // KANA accel key prefix non visible char width. 00639 // so always add the extent for next char. 00640 // 00641 UserGetTextExtentPointW(hdc, lpStr, 1, &size); 00642 iTotal += size.cx; 00643 break; 00644 default: 00645 // No need to taking care of Double byte since 2nd byte of 00646 // DBC is grater than 0x2f but all shortcut keys are less 00647 // than 0x30. 00648 break; 00649 } 00650 lpStr++; 00651 } 00652 return iTotal; 00653 } 00654 00655 /*--------------------------------------------------------------------------*/ 00656 /* */ 00657 /* GetNextWordbreak() - */ 00658 /* From Chicago ctlmgr.c FritzS */ 00659 /* */ 00660 /*--------------------------------------------------------------------------*/ 00661 00662 LPCWSTR GetNextWordbreak(DWORD dwCodePage, 00663 LPCWSTR lpch, 00664 LPCWSTR lpchEnd, 00665 DWORD dwFormat, 00666 LPDRAWTEXTDATA lpDrawInfo) 00667 00668 { 00669 /* ichNonWhite is used to make sure we always make progress. */ 00670 int ichNonWhite = 1; 00671 int ichComplexBreak = 0; // Breaking opportunity for complex scripts 00672 #if ((DT_WORDBREAK & ~0xff) != 0) 00673 #error cannot use BOOLEAN for DT_WORDBREAK, or you should use "!!" before assigning it 00674 #endif 00675 BOOLEAN fBreakSpace = (BOOLEAN)WORDBREAK(dwFormat); 00676 /* 00677 * If DT_WORDBREAK and DT_NOFULLWIDTHCHARBREAK are both set, we must 00678 * stop assuming FullWidth characters as word as we're doing in 00679 * NT4 and Win95. Instead, CR/LF and/or white space will only be 00680 * a line-break characters. 00681 */ 00682 BOOLEAN fDbcsCharBreak = (fBreakSpace && !NOFULLWIDTHCHARBREAK(dwFormat)); 00683 00684 #ifdef _USERK_ 00685 /* 00686 * Well, we actually should not and do not call GetNextWordBreak() in 00687 * kernel, since only Menu stuff (no word break!) calls DrawText from kernel. 00688 * In reality, thanks to a smart linker, word-break helper 00689 * functions even does not exist in win32k.sys. 00690 * Later, we should explicitly omit to compile those routines when we 00691 * build kernel. 00692 */ 00693 UNREFERENCED_PARAMETER(dwFormat); 00694 #endif 00695 00696 // We must terminate this loop before lpch == lpchEnd, otherwise, we 00697 // may gp fault during *lpch. 00698 while (lpch < lpchEnd) { 00699 switch (*lpch) { 00700 case CR: 00701 case LF: 00702 return lpch; 00703 00704 case '\t': 00705 case ' ': 00706 if (fBreakSpace) 00707 return (lpch + ichNonWhite); 00708 00709 /*** FALL THRU ***/ 00710 00711 default: 00712 /* 00713 * Since most Japanese writing don't use space character 00714 * to separate each word, we define each Kanji character 00715 * as a word. 00716 */ 00717 if (fDbcsCharBreak && UserIsFullWidth(dwCodePage, *lpch)) { 00718 if (!ichNonWhite) 00719 return lpch; 00720 /* 00721 * if the next character is the last character of this string, 00722 * We return the character, even this is a "KINSOKU" charcter... 00723 */ 00724 if ((lpch+1) != lpchEnd) { 00725 /* 00726 * Check next character of FullWidth character. 00727 * if the next character is "KINSOKU" character, the character 00728 * should be handled as a part of previous FullWidth character. 00729 * Never handle is as A character, and should not be a Word also. 00730 */ 00731 if (UserIsFELineBreak(*(lpch+1))) { 00732 /* 00733 * Then if the character is "KINSOKU" character, we return 00734 * the next of this character,... 00735 */ 00736 return (lpch + 1 + 1); 00737 } 00738 } 00739 /* 00740 * Otherwise, we just return the chracter that is next of FullWidth 00741 * Character. Because we treat A FullWidth chacter as A Word. 00742 */ 00743 return (lpch + 1); 00744 } 00745 /* 00746 * If the character is not a FullWidth character and the complex script 00747 * LPK is present. Call it to determine the breaking opportunity for 00748 * script that requires word break such as Thai. Note that if *lpch is 00749 * NOT a complex script character. The LPK will fail the call and return 0 00750 * since currently Uniscribe does not know how to handle FE break. 00751 */ 00752 else if(fBreakSpace && lpDrawInfo->bCharsetDll) { 00753 #ifdef _USERK_ 00754 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00755 if(CALL_LPK(ptiCurrent)) 00756 #endif 00757 ichComplexBreak = (*UserLpkDrawTextEx)(0, 0, 0, lpch, (int)(lpchEnd - lpch), 0, 00758 0, NULL, DT_GETNEXTWORD, -1); 00759 if (ichComplexBreak > 0) 00760 return (lpch + ichComplexBreak); 00761 } 00762 lpch++; 00763 ichNonWhite = 0; 00764 } 00765 } 00766 00767 return lpch; 00768 } 00769 00770 /***************************************************************************\ 00771 * GetPrefixCount 00772 * 00773 * This routine returns the count of accelerator mnemonics and the 00774 * character location (starting at 0) of the character to underline. 00775 * A single CH_PREFIX character will be striped and the following character 00776 * underlined, all double CH_PREFIX character sequences will be replaced by 00777 * a single CH_PREFIX (this is done by PSMTextOut). This routine is used 00778 * to determine the actual character length of the string that will be 00779 * printed, and the location the underline should be placed. Only 00780 * cch characters from the input string will be processed. If the lpstrCopy 00781 * parameter is non-NULL, this routine will make a printable copy of the 00782 * string with all single prefix characters removed and all double prefix 00783 * characters collapsed to a single character. If copying, a maximum 00784 * character count must be specified which will limit the number of 00785 * characters copied. 00786 * 00787 * The location of the single CH_PREFIX is returned in the low order 00788 * word, and the count of CH_PREFIX characters that will be striped 00789 * from the string during printing is in the hi order word. If the 00790 * high order word is 0, the low order word is meaningless. If there 00791 * were no single prefix characters (i.e. nothing to underline), the 00792 * low order word will be -1 (to distinguish from location 0). 00793 * 00794 * These routines assume that there is only one single CH_PREFIX character 00795 * in the string. 00796 * 00797 * WARNING! this rountine returns information in BYTE count not CHAR count 00798 * (so it can easily be passed onto GreExtTextOutW which takes byte 00799 * counts as well) 00800 * 00801 * History: 00802 * 11-13-90 JimA Ported to NT 00803 * 30-Nov-1992 mikeke Client side version 00804 \***************************************************************************/ 00805 00806 LONG GetPrefixCount( 00807 LPCWSTR lpstr, 00808 int cch, 00809 LPWSTR lpstrCopy, 00810 int charcopycount) 00811 { 00812 int chprintpos = 0; /* Num of chars that will be printed */ 00813 int chcount = 0; /* Num of prefix chars that will be removed */ 00814 int chprefixloc = -1; /* Pos (in printed chars) of the prefix */ 00815 WCHAR ch; 00816 00817 /* 00818 * If not copying, use a large bogus count... 00819 */ 00820 if (lpstrCopy == NULL) 00821 charcopycount = 32767; 00822 00823 while ((cch-- > 0) && *lpstr && charcopycount-- != 0) { 00824 00825 /* 00826 * Is this guy a prefix character ? 00827 */ 00828 if ((ch = *lpstr++) == CH_PREFIX) { 00829 00830 /* 00831 * Yup - increment the count of characters removed during print. 00832 */ 00833 chcount++; 00834 00835 /* 00836 * Is the next also a prefix char? 00837 */ 00838 if (*lpstr != CH_PREFIX) { 00839 00840 /* 00841 * Nope - this is a real one, mark its location. 00842 */ 00843 chprefixloc = chprintpos; 00844 00845 } else { 00846 00847 /* 00848 * yup - simply copy it if copying. 00849 */ 00850 if (lpstrCopy != NULL) 00851 *(lpstrCopy++) = CH_PREFIX; 00852 cch--; 00853 lpstr++; 00854 chprintpos++; 00855 } 00856 } else if (ch == CH_ENGLISHPREFIX) { // Still needs to be parsed 00857 /* 00858 * Yup - increment the count of characters removed during print. 00859 */ 00860 chcount++; 00861 00862 /* 00863 * Next character is a real one, mark its location. 00864 */ 00865 chprefixloc = chprintpos; 00866 00867 } else if (ch == CH_KANJIPREFIX) { // Still needs to be parsed 00868 /* 00869 * We only support Alpha Numeric(CH_ENGLISHPREFIX). 00870 * no support for Kana(CH_KANJIPREFIX). 00871 */ 00872 /* 00873 * Yup - increment the count of characters removed during print. 00874 */ 00875 chcount++; 00876 00877 if(cch) { 00878 /* don't copy the character */ 00879 chcount++; 00880 lpstr++; 00881 cch--; 00882 } 00883 } else { 00884 00885 /* 00886 * Nope - just inc count of char. that will be printed 00887 */ 00888 chprintpos++; 00889 if (lpstrCopy != NULL) 00890 *(lpstrCopy++) = ch; 00891 } 00892 } 00893 00894 if (lpstrCopy != NULL) 00895 *lpstrCopy = 0; 00896 00897 /* 00898 * Return the character counts 00899 */ 00900 return MAKELONG(chprefixloc, chcount); 00901 } 00902 00903 /***************************************************************************\ 00904 * DT_GetExtentMinusPrefixes 00905 \***************************************************************************/ 00906 00907 int DT_GetExtentMinusPrefixes(HDC hdc, LPCWSTR lpchStr, int cchCount, UINT wFormat, 00908 int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 00909 { 00910 int iPrefixCount; 00911 int cxPrefixes = 0; 00912 WCHAR PrefixChar = CH_PREFIX; 00913 SIZE size; 00914 PCLIENTINFO pci = GetClientInfo(); 00915 #ifdef _USERK_ 00916 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00917 #endif 00918 UNREFERENCED_PARAMETER(wFormat); 00919 00920 if(!NOPREFIX(wFormat) && 00921 (iPrefixCount = HIWORD(GetPrefixCount(lpchStr, cchCount, NULL, 0)))) { 00922 // 00923 // Kanji Windows has three shortcut prefixes... 00924 // (ported from Win95 ctlmgr.c) 00925 // 00926 if (IS_DBCS_ENABLED() && (pci->dwTIFlags & TIF_16BIT)) { 00927 // 16bit apps compatibility 00928 cxPrefixes = KKGetPrefixWidth(hdc, lpchStr, cchCount) - (iPrefixCount * iOverhang); 00929 } 00930 else { 00931 if(lpDrawInfo->bCharsetDll) { 00932 #ifdef _USERK_ 00933 if(CALL_LPK(ptiCurrent)) 00934 #endif // _USERK_ 00935 { 00936 // Call LPKDrawTextEx with fDraw = FALSE just to get the text extent. 00937 return (*UserLpkDrawTextEx)(hdc, 0, 0, lpchStr, cchCount, FALSE, 00938 wFormat, lpDrawInfo, DT_CHARSETDRAW, iCharSet); 00939 } 00940 } else { 00941 cxPrefixes = UserGetTextExtentPointW(hdc, &PrefixChar, 1, &size); 00942 cxPrefixes = size.cx - iOverhang; 00943 cxPrefixes *= iPrefixCount; 00944 } 00945 } 00946 } 00947 #ifdef _USERK_ 00948 if(CALL_LPK(ptiCurrent)) 00949 xxxClientGetTextExtentPointW(hdc, lpchStr, cchCount, &size); 00950 else 00951 #endif // _USERK_ 00952 UserGetTextExtentPointW(hdc, lpchStr, cchCount, &size); 00953 return (size.cx - cxPrefixes); 00954 } 00955 00956 /***************************************************************************\ 00957 * DT_DrawStr 00958 * This will draw the given string in the given location without worrying 00959 * about the left/right justification. Gets the extent and returns it. 00960 * If fDraw is TRUE and if NOT DT_CALCRECT, this draws the text. 00961 * NOTE: This returns the extent minus Overhang. 00962 * 00963 * From Chicago ctlmgr.c FritzS 00964 \***************************************************************************/ 00965 int DT_DrawStr(HDC hdc, int xLeft, int yTop, LPCWSTR lpchStr, 00966 int cchCount, BOOL fDraw, UINT wFormat, 00967 LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 00968 { 00969 LPCWSTR lpch; 00970 int iLen; 00971 int cxExtent; 00972 int xOldLeft = xLeft; // Save the xLeft given to compute the extent later 00973 int xTabLength = lpDrawInfo->cxTabLength; 00974 int iTabOrigin = lpDrawInfo->rcFormat.left; 00975 00976 #ifdef USE_MIRRORING 00977 // 00978 // Because xLeft and yTop is a point in a rect, and we shift the rect in a mirrored hdc to include 00979 // its most right pixel, then shift this point as well. 00980 // 00981 if (UserGetLayout(hdc) & LAYOUT_RTL) { 00982 --xOldLeft; 00983 --xLeft; 00984 } 00985 #endif 00986 00987 // 00988 // if there is a charset dll, let it draw the text. 00989 // 00990 if(lpDrawInfo->bCharsetDll) { 00991 #ifdef _USERK_ 00992 PTHREADINFO ptiCurrent = PtiCurrentShared(); 00993 00994 // 00995 // Don't perform a callback if in thread cleanup mode. 00996 // 00997 if(!CALL_LPK(ptiCurrent)) 00998 return 0 ; 00999 #endif // _USERK_ 01000 return (*UserLpkDrawTextEx)(hdc, xLeft, yTop, lpchStr, cchCount, fDraw, 01001 wFormat, lpDrawInfo, DT_CHARSETDRAW, iCharSet); 01002 } 01003 01004 // Check if the tabs need to be expanded 01005 if(EXPANDTABS(wFormat)) { 01006 while(cchCount) { 01007 // Look for a tab 01008 for(iLen = 0, lpch = lpchStr; iLen < cchCount; iLen++) 01009 if(*lpch++ == TEXT('\t')) 01010 break; 01011 01012 // Draw text, if any, upto the tab 01013 if (iLen) { 01014 // Draw the substring taking care of the prefixes. 01015 if (fDraw && !CALCRECT(wFormat)) { // Only if we need to draw text 01016 (*(lpDrawInfo->lpfnTextDraw))(hdc, xLeft, yTop, (LPWSTR)lpchStr, iLen, wFormat); 01017 } 01018 // Get the extent of this sub string and add it to xLeft. 01019 xLeft += DT_GetExtentMinusPrefixes(hdc, lpchStr, iLen, wFormat, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet) - lpDrawInfo->cxOverhang; 01020 } 01021 01022 //if a TAB was found earlier, calculate the start of next sub-string. 01023 if (iLen < cchCount) { 01024 iLen++; // Skip the tab 01025 if (xTabLength) // Tab length could be zero 01026 xLeft = (((xLeft - iTabOrigin)/xTabLength) + 1)*xTabLength + iTabOrigin; 01027 } 01028 01029 // Calculate the details of the string that remains to be drawn. 01030 cchCount -= iLen; 01031 lpchStr = lpch; 01032 } 01033 cxExtent = xLeft - xOldLeft; 01034 } else { 01035 // If required, draw the text (with either PSMTextOut or PSTextOut) 01036 if (fDraw && !CALCRECT(wFormat)) { 01037 (*(lpDrawInfo->lpfnTextDraw))(hdc, xLeft, yTop, (LPWSTR)lpchStr, cchCount, wFormat); 01038 } 01039 // Compute the extent of the text. 01040 cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchStr, cchCount, wFormat, 01041 lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet) - lpDrawInfo->cxOverhang; 01042 } 01043 return cxExtent; 01044 } 01045 01046 /***************************************************************************\ 01047 * DT_DrawJustifiedLine 01048 * This function draws one complete line with proper justification 01049 * 01050 * from Chicago ctlmgr.c FritzS 01051 \***************************************************************************/ 01052 01053 void DT_DrawJustifiedLine(HDC hdc, int yTop, LPCWSTR lpchLineSt, 01054 int cchCount, UINT wFormat, 01055 LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 01056 { 01057 LPRECT lprc; 01058 int cxExtent; 01059 int xLeft; 01060 01061 lprc = &(lpDrawInfo->rcFormat); 01062 xLeft = lprc->left; 01063 01064 // Handle the special justifications (right or centered) properly. 01065 if(wFormat & (DT_CENTER | DT_RIGHT)) { 01066 cxExtent = DT_DrawStr(hdc, xLeft, yTop, lpchLineSt, cchCount, FALSE, 01067 wFormat, lpDrawInfo, iCharSet) + lpDrawInfo->cxOverhang; 01068 if(wFormat & DT_CENTER) 01069 xLeft = lprc->left + (((lprc->right - lprc->left) - cxExtent) >> 1); 01070 else 01071 xLeft = lprc->right - cxExtent; 01072 } else 01073 xLeft = lprc->left; 01074 01075 // Draw the whole line. 01076 cxExtent = DT_DrawStr(hdc, xLeft, yTop, lpchLineSt, cchCount, TRUE, wFormat, 01077 lpDrawInfo, iCharSet) +lpDrawInfo->cxOverhang; 01078 if(cxExtent > lpDrawInfo->cxMaxExtent) 01079 lpDrawInfo->cxMaxExtent = cxExtent; 01080 } 01081 01082 /***************************************************************************\ 01083 * DT_InitDrawTextInfo 01084 * This is called at the begining of DrawText(); This initializes the 01085 * DRAWTEXTDATA structure passed to this function with all the required info. 01086 * 01087 * from Chicago ctlmgr.c FritzS 01088 \***************************************************************************/ 01089 01090 BOOL DT_InitDrawTextInfo( 01091 HDC hdc, 01092 LPRECT lprc, 01093 UINT wFormat, 01094 LPDRAWTEXTDATA lpDrawInfo, 01095 LPDRAWTEXTPARAMS lpDTparams) 01096 { 01097 SIZE sizeViewPortExt = {0, 0},sizeWindowExt = {0, 0}; 01098 TEXTMETRICW tm; 01099 LPRECT lprcDest; 01100 int iTabLength = 8; // Default Tab length is 8 characters. 01101 int iLeftMargin; 01102 int iRightMargin; 01103 BOOL fUseSystemFont; 01104 01105 if (lpDTparams) { 01106 /* 01107 * Only if DT_TABSTOP flag is mentioned, we must use the iTabLength field. 01108 */ 01109 if (TABSTOP(wFormat)) 01110 iTabLength = lpDTparams->iTabLength; 01111 iLeftMargin = lpDTparams->iLeftMargin; 01112 iRightMargin = lpDTparams->iRightMargin; 01113 } else { 01114 iLeftMargin = iRightMargin = 0; 01115 } 01116 01117 /* 01118 * Get the View port and Window extents for the given DC 01119 * If this call fails, hdc must be invalid 01120 */ 01121 if (!UserGetViewportExtEx(hdc,&sizeViewPortExt)) { 01122 #ifndef _USERK_ 01123 /* 01124 * This call fails on standard Metafiles. So check 01125 * if the DC is really invalid to be compatible with 01126 * Win9x 01127 */ 01128 if ((hdc == NULL) || !GdiValidateHandle(hdc)) 01129 #endif 01130 return FALSE; 01131 } 01132 UserGetWindowExtEx(hdc, &sizeWindowExt); 01133 01134 /* 01135 * For the current mapping mode, find out the sign of x from left to right. 01136 */ 01137 lpDrawInfo->iXSign = 01138 (((sizeViewPortExt.cx ^ sizeWindowExt.cx) & 0x80000000) ? -1 : 1); 01139 01140 /* 01141 * For the current mapping mode, find out the sign of y from top to bottom. 01142 */ 01143 lpDrawInfo->iYSign = 01144 (((sizeViewPortExt.cy ^ sizeWindowExt.cy) & 0x80000000) ? -1 : 1); 01145 01146 /* 01147 * Calculate the dimensions of the current font in this DC. 01148 * (If it is SysFont AND the mapping mode is MM_TEXT, use system font's data) 01149 */ 01150 fUseSystemFont = ((wFormat & DT_INTERNAL) || IsSysFontAndDefaultMode(hdc)); 01151 if (!fUseSystemFont) { 01152 /* 01153 * Edit controls have their own way of calculating the aveCharWidth. 01154 */ 01155 if (EDITCONTROL(wFormat)) { 01156 tm.tmAveCharWidth = UserGetCharDimensionsW(hdc, &tm, NULL); 01157 tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(hdc, NULL, 0); 01158 if (tm.tmAveCharWidth == 0) { 01159 fUseSystemFont = TRUE; 01160 } 01161 } else if (!UserGetTextMetricsW(hdc, &tm)) { 01162 /* 01163 * This can fail in a hard error popup during logon or logoff 01164 * because UpdatePerUserSystemParameters destroys the server-side 01165 * font handle for the DC, and a repaint occurs before we switch 01166 * desktops (the switch recreates the popup from scratch with the 01167 * new font OK). ChrisWil's changes to move system-wide attributes 01168 * into desktops should take care of this in Kernel-mode. This is 01169 * just a horrible, horrible hack for now. 01170 */ 01171 RIPMSG0(RIP_WARNING, "UserGetTextMetricsW failed: only in logon/off?\n"); 01172 tm.tmOverhang = 0; 01173 01174 /* 01175 * We should probably set fUseSystemFont to TRUE here. But I 01176 * assume that this "horrible hack" works fine plus it has been 01177 * here for good. So I'll leave it alone. 6/3/96 01178 */ 01179 } 01180 } 01181 01182 if (fUseSystemFont) { 01183 /* 01184 * Avoid GetTextMetrics for internal calls since they use sys font. 01185 */ 01186 tm.tmHeight = gpsi->cySysFontChar; 01187 tm.tmExternalLeading = gpsi->tmSysFont.tmExternalLeading; 01188 tm.tmAveCharWidth = gpsi->tmSysFont.tmAveCharWidth; 01189 tm.tmOverhang = gpsi->tmSysFont.tmOverhang; 01190 #ifdef _USERK_ 01191 tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(gpDispInfo->hdcScreen, NULL, 0); 01192 #else 01193 tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(ghdcBits2, NULL, 0); 01194 #endif // _USERK_ 01195 } 01196 01197 01198 // cyLineHeight is in pixels (This will be signed). 01199 lpDrawInfo->cyLineHeight = (tm.tmHeight + 01200 (EXTERNALLEADING(wFormat) ? tm.tmExternalLeading : 0)) * 01201 lpDrawInfo->iYSign; 01202 01203 // cxTabLength is the tab length in pixels (This will not be signed) 01204 lpDrawInfo->cxTabLength = tm.tmAveCharWidth * iTabLength; 01205 01206 // Set the cxOverhang 01207 lpDrawInfo->cxOverhang = tm.tmOverhang; 01208 01209 // Pick up the proper TextOut function based on the prefix processing reqd. 01210 #ifdef _USERK_ 01211 lpDrawInfo->bCharsetDll = PpiCurrent()->dwLpkEntryPoints & LPK_DRAWTEXTEX; 01212 if (lpDrawInfo->bCharsetDll == FALSE) { 01213 lpDrawInfo->lpfnTextDraw = (NOPREFIX(wFormat) ? (LPFNTEXTDRAW)UserTextOutWInternal : xxxPSMTextOut); 01214 } 01215 #else 01216 lpDrawInfo->bCharsetDll = (BOOL)(fpLpkDrawTextEx != (FPLPKDRAWTEXTEX)NULL); 01217 if (lpDrawInfo->bCharsetDll == FALSE) { 01218 lpDrawInfo->lpfnTextDraw = (NOPREFIX(wFormat) ? (LPFNTEXTDRAW)UserTextOutWInternal : PSMTextOut); 01219 } 01220 #endif // _USERK_ 01221 01222 // Set up the format rectangle based on the margins. 01223 // LCopyStruct(lprc, lprcDest = (LPRECT)&(lpDrawInfo->rcFormat), sizeof(RECT)); 01224 lprcDest = &(lpDrawInfo->rcFormat); 01225 *lprcDest = *lprc; 01226 01227 // We need to do the following only if the margins are given 01228 if(iLeftMargin | iRightMargin) { 01229 lprcDest->left += iLeftMargin * lpDrawInfo->iXSign; 01230 lprcDest->right -= (lpDrawInfo->cxRightMargin = iRightMargin * lpDrawInfo->iXSign); 01231 } else 01232 lpDrawInfo->cxRightMargin = 0; // Initialize to zero. 01233 01234 // cxMaxWidth is unsigned. 01235 lpDrawInfo->cxMaxWidth = (lprcDest->right - lprcDest->left) * lpDrawInfo->iXSign; 01236 lpDrawInfo->cxMaxExtent = 0; // Initialize this to zero. 01237 01238 return TRUE; 01239 } 01240 01241 /***************************************************************************\ 01242 * DT_AdjustWhiteSpaces 01243 * In the case of WORDWRAP, we need to treat the white spaces at the 01244 * begining/end of each line specially. This function does that. 01245 * lpStNext = points to the begining of next line. 01246 * lpiCount = points to the count of characters in the current line. 01247 \***************************************************************************/ 01248 01249 LPCWSTR DT_AdjustWhiteSpaces(LPCWSTR lpStNext, LPINT lpiCount, UINT wFormat) 01250 { 01251 switch(wFormat & DT_HFMTMASK) { 01252 case DT_LEFT: 01253 // Prevent a white space at the begining of a left justfied text. 01254 // Is there a white space at the begining of next line...... 01255 if((*lpStNext == TEXT(' ')) || (*lpStNext == TEXT('\t'))) { 01256 // ...then, exclude it from next line. 01257 lpStNext++; 01258 } 01259 break; 01260 01261 case DT_RIGHT: 01262 // Prevent a white space at the end of a RIGHT justified text. 01263 // Is there a white space at the end of current line,....... 01264 if((*(lpStNext-1) == TEXT(' ')) || (*(lpStNext - 1) == TEXT('\t'))) { 01265 // .....then, Skip the white space from the current line. 01266 (*lpiCount)--; 01267 } 01268 break; 01269 01270 case DT_CENTER: 01271 // Exclude white spaces from the begining and end of CENTERed lines. 01272 // If there is a white space at the end of current line....... 01273 if((*(lpStNext-1) == TEXT(' ')) || (*(lpStNext - 1) == TEXT('\t'))) 01274 (*lpiCount)--; //...., don't count it for justification. 01275 // If there is a white space at the begining of next line....... 01276 if((*lpStNext == TEXT(' ')) || (*lpStNext == TEXT('\t'))) 01277 lpStNext++; //...., exclude it from next line. 01278 break; 01279 } 01280 return lpStNext; 01281 } 01282 01283 /***************************************************************************\ 01284 * DT_BreakAWord 01285 * A word needs to be broken across lines and this finds out where to 01286 * break it. 01287 \***************************************************************************/ 01288 LPCWSTR DT_BreakAWord(HDC hdc, LPCWSTR lpchText, 01289 int iLength, int iWidth, UINT wFormat, int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 01290 { 01291 int iLow = 0, iHigh = iLength; 01292 int iNew; 01293 01294 01295 while((iHigh - iLow) > 1) { 01296 iNew = iLow + (iHigh - iLow)/2; 01297 if(DT_GetExtentMinusPrefixes(hdc, lpchText, iNew, wFormat, iOverhang, lpDrawInfo, iCharSet) > iWidth) 01298 iHigh = iNew; 01299 else 01300 iLow = iNew; 01301 } 01302 // If the width is too low, we must print atleast one char per line. 01303 // Else, we will be in an infinite loop. 01304 if(!iLow && iLength) 01305 iLow = 1; 01306 return (lpchText+iLow); 01307 } 01308 01309 /***************************************************************************\ 01310 * DT_GetLineBreak 01311 * This finds out the location where we can break a line. 01312 * Returns LPCSTR to the begining of next line. 01313 * Also returns via lpiLineLength, the length of the current line. 01314 * NOTE: (lpstNextLineStart - lpstCurrentLineStart) is not equal to the 01315 * line length; This is because, we exclude some white spaces at the begining 01316 * and/or end of lines; Also, CR/LF is excluded from the line length. 01317 \***************************************************************************/ 01318 01319 LPWSTR DT_GetLineBreak( 01320 HDC hdc, 01321 LPCWSTR lpchLineStart, 01322 int cchCount, 01323 DWORD dwFormat, 01324 LPINT lpiLineLength, 01325 LPDRAWTEXTDATA lpDrawInfo, 01326 int iCharSet) 01327 { 01328 LPCWSTR lpchText, lpchEnd, lpch, lpchLineEnd; 01329 int cxStart, cxExtent, cxNewExtent; 01330 BOOL fAdjustWhiteSpaces = FALSE; 01331 WCHAR ch; 01332 DWORD dwCodePage = USERGETCODEPAGE(hdc); 01333 01334 cxStart = lpDrawInfo->rcFormat.left; 01335 cxExtent = cxNewExtent = 0; 01336 lpchText = lpchLineStart; 01337 lpchEnd = lpchLineStart + cchCount; 01338 01339 01340 while(lpchText < lpchEnd) { 01341 lpchLineEnd = lpch = GetNextWordbreak(dwCodePage,lpchText, lpchEnd, dwFormat, lpDrawInfo); 01342 // DT_DrawStr does not return the overhang; Otherwise we will end up 01343 // adding one overhang for every word in the string. 01344 01345 // For simulated Bold fonts, the summation of extents of individual 01346 // words in a line is greater than the extent of the whole line. So, 01347 // always calculate extent from the LineStart. 01348 // BUGTAG: #6054 -- Win95B -- SANKAR -- 3/9/95 -- 01349 cxNewExtent = DT_DrawStr(hdc, cxStart, 0, lpchLineStart, (int)(((PBYTE)lpch - (PBYTE)lpchLineStart)/sizeof(WCHAR)), FALSE, 01350 dwFormat, lpDrawInfo, iCharSet); 01351 01352 if (WORDBREAK(dwFormat) && ((cxNewExtent + lpDrawInfo->cxOverhang) > lpDrawInfo->cxMaxWidth)) { 01353 // Are there more than one word in this line? 01354 if (lpchText != lpchLineStart) { 01355 lpchLineEnd = lpch = lpchText; 01356 fAdjustWhiteSpaces = TRUE; 01357 } else { 01358 //One word is longer than the maximum width permissible. 01359 //See if we are allowed to break that single word. 01360 if(EDITCONTROL(dwFormat) && !WORDELLIPSIS(dwFormat)) { 01361 lpchLineEnd = lpch = DT_BreakAWord(hdc, lpchText, (int)(((PBYTE)lpch - (PBYTE)lpchText)/sizeof(WCHAR)), 01362 lpDrawInfo->cxMaxWidth - cxExtent, 01363 dwFormat, 01364 lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet); //Break that word 01365 //Note: Since we broke in the middle of a word, no need to 01366 // adjust for white spaces. 01367 } else { 01368 fAdjustWhiteSpaces = TRUE; 01369 // Check if we need to end this line with ellipsis 01370 if(WORDELLIPSIS(dwFormat)) 01371 { 01372 // Don't do this if already at the end of the string. 01373 if (lpch < lpchEnd) 01374 { 01375 // If there are CR/LF at the end, skip them. 01376 if ((ch = *lpch) == CR || ch == LF) 01377 { 01378 if ((++lpch < lpchEnd) && (*lpch == (WCHAR)(ch ^ (LF ^ CR)))) 01379 lpch++; 01380 fAdjustWhiteSpaces = FALSE; 01381 } 01382 } 01383 } 01384 } 01385 } 01386 // Well! We found a place to break the line. Let us break from this 01387 // loop; 01388 break; 01389 } else { 01390 // Don't do this if already at the end of the string. 01391 if (lpch < lpchEnd) { 01392 if ((ch = *lpch) == CR || ch == LF) { 01393 if ((++lpch < lpchEnd) && (*lpch == (WCHAR)(ch ^ (LF ^ CR)))) 01394 lpch++; 01395 fAdjustWhiteSpaces = FALSE; 01396 break; 01397 } 01398 } 01399 } 01400 01401 // Point at the beginning of the next word. 01402 lpchText = lpch; 01403 cxExtent = cxNewExtent; 01404 } 01405 01406 // Calculate the length of current line. 01407 *lpiLineLength = (INT)((PBYTE)lpchLineEnd - (PBYTE)lpchLineStart)/sizeof(WCHAR); 01408 01409 // Adjust the line length and lpch to take care of spaces. 01410 if(fAdjustWhiteSpaces && (lpch < lpchEnd)) 01411 lpch = DT_AdjustWhiteSpaces(lpch, lpiLineLength, dwFormat); 01412 01413 // return the begining of next line; 01414 return (LPWSTR)lpch; 01415 } 01416 01417 /***************************************************************************\ 01418 * NeedsEndEllipsis() 01419 * This function checks whether the given string fits within the given 01420 * width or we need to add end-ellipse. If it required end-ellipses, it 01421 * returns TRUE and it returns the number of characters that are saved 01422 * in the given string via lpCount. 01423 \***************************************************************************/ 01424 BOOL NeedsEndEllipsis(HDC hdc, 01425 LPCWSTR lpchText, 01426 LPINT lpCount, 01427 LPDRAWTEXTDATA lpDTdata, 01428 UINT wFormat, LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 01429 { 01430 int cchText; 01431 int ichMin, ichMax, ichMid; 01432 int cxMaxWidth; 01433 int iOverhang; 01434 int cxExtent; 01435 SIZE size; 01436 cchText = *lpCount; // Get the current count. 01437 01438 if (cchText == 0) 01439 return FALSE; 01440 01441 cxMaxWidth = lpDTdata->cxMaxWidth; 01442 iOverhang = lpDTdata->cxOverhang; 01443 01444 cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchText, cchText, wFormat, iOverhang, lpDrawInfo, iCharSet); 01445 01446 if (cxExtent <= cxMaxWidth) 01447 return FALSE; 01448 // Reserve room for the "..." ellipses; 01449 // (Assumption: The ellipses don't have any prefixes!) 01450 UserGetTextExtentPointW(hdc, szEllipsis, CCHELLIPSIS, &size); 01451 cxMaxWidth -= size.cx - iOverhang; 01452 01453 // If no room for ellipses, always show first character. 01454 // 01455 ichMax = 1; 01456 if (cxMaxWidth > 0) { 01457 // Binary search to find characters that will fit. 01458 ichMin = 0; 01459 ichMax = cchText; 01460 while (ichMin < ichMax) { 01461 // Be sure to round up, to make sure we make progress in 01462 // the loop if ichMax == ichMin + 1. 01463 // 01464 ichMid = (ichMin + ichMax + 1) / 2; 01465 01466 cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchText, ichMid, wFormat, iOverhang, lpDrawInfo, iCharSet); 01467 01468 if (cxExtent < cxMaxWidth) 01469 ichMin = ichMid; 01470 else { 01471 if (cxExtent > cxMaxWidth) 01472 ichMax = ichMid - 1; 01473 else { 01474 // Exact match up up to ichMid: just exit. 01475 // 01476 ichMax = ichMid; 01477 break; 01478 } 01479 } 01480 } 01481 01482 // Make sure we always show at least the first character... 01483 // 01484 if (ichMax < 1) 01485 ichMax = 1; 01486 } 01487 01488 *lpCount = ichMax; 01489 return TRUE; 01490 } 01491 01492 /***************************************************************************\ 01493 * BOGUS: The same function is available in SHELL2.DLL also. 01494 * We need to remove from one of the places. 01495 \***************************************************************************/ 01496 // Returns a pointer to the last component of a path string. 01497 // 01498 // in: 01499 // path name, either fully qualified or not 01500 // 01501 // returns: 01502 // pointer into the path where the path is. if none is found 01503 // returns a poiter to the start of the path 01504 // 01505 // c:\foo\bar -> bar 01506 // c:\foo -> foo 01507 // c:\foo\ -> c:\foo\ (REVIEW: is this case busted?) 01508 // c:\ -> c:\ (REVIEW: this case is strange) 01509 // c: -> c: 01510 // foo -> foo 01511 /***************************************************************************\ 01512 \***************************************************************************/ 01513 01514 01515 LPWSTR PathFindFileName(LPCWSTR pPath, int cchText) 01516 { 01517 LPCWSTR pT; 01518 01519 for (pT = pPath; cchText > 0 && *pPath; pPath++, cchText--) { 01520 if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1]) 01521 pT = pPath + 1; 01522 } 01523 01524 return (LPWSTR)pT; // REVIEW, should this be const? 01525 } 01526 01527 /***************************************************************************\ 01528 * AddPathEllipse(): 01529 * This adds a path ellipse to the given path name. 01530 * Returns TRUE if the resultant string's extent is less the the 01531 * cxMaxWidth. FALSE, if otherwise. 01532 \***************************************************************************/ 01533 int AddPathEllipsis( 01534 HDC hDC, 01535 LPWSTR lpszPath, 01536 int cchText, 01537 UINT wFormat, 01538 int cxMaxWidth, 01539 int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet) 01540 { 01541 int iLen; 01542 UINT dxFixed, dxEllipsis; 01543 LPWSTR lpEnd; /* end of the unfixed string */ 01544 LPWSTR lpFixed; /* start of text that we always display */ 01545 BOOL bEllipsisIn; 01546 int iLenFixed; 01547 SIZE size; 01548 01549 lpFixed = PathFindFileName(lpszPath, cchText); 01550 if (lpFixed != lpszPath) 01551 lpFixed--; // point at the slash 01552 else 01553 return cchText; 01554 01555 lpEnd = lpFixed; 01556 bEllipsisIn = FALSE; 01557 iLenFixed = cchText - (int)(lpFixed - lpszPath); 01558 dxFixed = DT_GetExtentMinusPrefixes(hDC, lpFixed, iLenFixed, wFormat, iOverhang, lpDrawInfo, iCharSet); 01559 01560 // It is assumed that the "..." string does not have any prefixes ('&'). 01561 UserGetTextExtentPointW(hDC, szEllipsis, CCHELLIPSIS, &size); 01562 dxEllipsis = size.cx - iOverhang; 01563 01564 while (TRUE) { 01565 iLen = dxFixed + DT_GetExtentMinusPrefixes(hDC, lpszPath, (int)((PBYTE)lpEnd - (PBYTE)lpszPath)/sizeof(WCHAR), 01566 wFormat, iOverhang, lpDrawInfo, iCharSet) - iOverhang; 01567 01568 if (bEllipsisIn) 01569 iLen += dxEllipsis; 01570 01571 if (iLen <= cxMaxWidth) 01572 break; 01573 01574 bEllipsisIn = TRUE; 01575 01576 if (lpEnd <= lpszPath) { 01577 /* Things didn't fit. */ 01578 lpEnd = lpszPath; 01579 break; 01580 } 01581 01582 /* Step back a character. */ 01583 lpEnd--; 01584 } 01585 01586 if (bEllipsisIn && (lpEnd + CCHELLIPSIS < lpFixed)) { 01587 // NOTE: the strings could over lap here. So, we use LCopyStruct. 01588 01589 RtlMoveMemory((lpEnd + CCHELLIPSIS), lpFixed, iLenFixed * sizeof(WCHAR)); 01590 RtlCopyMemory(lpEnd, szEllipsis, CCHELLIPSIS * sizeof(WCHAR)); 01591 01592 cchText = (int)(lpEnd - lpszPath) + CCHELLIPSIS + iLenFixed; 01593 01594 // now we can NULL terminate the string 01595 *(lpszPath + cchText) = TEXT('\0'); 01596 } 01597 01598 return cchText; 01599 } 01600 01601 //----------------------------------------------------------------------- 01602 // This function returns the number of characters actually drawn. 01603 //----------------------------------------------------------------------- 01604 int AddEllipsisAndDrawLine( 01605 HDC hdc, 01606 int yLine, 01607 LPCWSTR lpchText, 01608 int cchText, 01609 DWORD dwDTformat, 01610 LPDRAWTEXTDATA lpDrawInfo, 01611 int iCharSet) 01612 { 01613 LPWSTR pEllipsis = NULL; 01614 WCHAR szTempBuff[MAXBUFFSIZE]; 01615 LPWSTR lpDest; 01616 BOOL fAlreadyCopied = FALSE; 01617 01618 // Check if this is a filename with a path AND 01619 // Check if the width is too narrow to hold all the text. 01620 if(PATHELLIPSIS(dwDTformat) && 01621 ((DT_GetExtentMinusPrefixes(hdc, lpchText, cchText, 01622 dwDTformat, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet)) > lpDrawInfo->cxMaxWidth)) { 01623 // We need to add Path-Ellipsis. See if we can do it in-place. 01624 if(!MODIFYSTRING(dwDTformat)) { 01625 // NOTE: When you add Path-Ellipsis, the string could grow by 01626 // CCHELLIPSIS bytes. 01627 if((cchText + CCHELLIPSIS + 1) <= MAXBUFFSIZE) 01628 lpDest = szTempBuff; 01629 else { // Alloc from local heap. 01630 // Alloc the buffer from local heap. 01631 if(!(pEllipsis = (LPWSTR)UserRtlAllocMem( 01632 (cchText+CCHELLIPSIS+1)*sizeof(WCHAR)))) 01633 return 0; 01634 lpDest = (LPWSTR)pEllipsis; 01635 } 01636 // Source String may not be NULL terminated. So, copy just 01637 // the given number of characters. 01638 RtlCopyMemory(lpDest, lpchText, cchText*sizeof(WCHAR)); 01639 lpchText = lpDest; // lpchText points to the copied buff. 01640 fAlreadyCopied = TRUE; // Local copy has been made. 01641 } 01642 // Add the path ellipsis now! 01643 cchText = AddPathEllipsis(hdc, (LPWSTR)lpchText, cchText, dwDTformat, 01644 lpDrawInfo->cxMaxWidth, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet); 01645 } 01646 01647 // Check if end-ellipsis are to be added. 01648 if((ENDELLIPSIS(dwDTformat) || WORDELLIPSIS(dwDTformat)) && 01649 NeedsEndEllipsis(hdc, lpchText, &cchText, lpDrawInfo, dwDTformat, lpDrawInfo, iCharSet)) { 01650 // We need to add end-ellipsis; See if we can do it in-place. 01651 if(!MODIFYSTRING(dwDTformat) && !fAlreadyCopied) { 01652 // See if the string is small enough for the buff on stack. 01653 if((cchText+CCHELLIPSIS+1) <= MAXBUFFSIZE) 01654 lpDest = szTempBuff; // If so, use it. 01655 else { 01656 // Alloc the buffer from local heap. 01657 if(!(pEllipsis = (LPWSTR)UserRtlAllocMem( 01658 (cchText+CCHELLIPSIS+1)*sizeof(WCHAR)))) 01659 return 0; 01660 lpDest = pEllipsis; 01661 } 01662 // Make a copy of the string in the local buff. 01663 RtlCopyMemory(lpDest, lpchText, cchText*sizeof(WCHAR)); 01664 lpchText = lpDest; 01665 } 01666 // Add an end-ellipsis at the proper place. 01667 RtlCopyMemory((LPWSTR)(lpchText+cchText), szEllipsis, (CCHELLIPSIS+1)*sizeof(WCHAR)); 01668 cchText += CCHELLIPSIS; 01669 } 01670 01671 // Draw the line that we just formed. 01672 DT_DrawJustifiedLine(hdc, yLine, lpchText, cchText, dwDTformat, lpDrawInfo, iCharSet); 01673 01674 // Free the block allocated for End-Ellipsis. 01675 if(pEllipsis) 01676 UserRtlFreeMem(pEllipsis); 01677 01678 return cchText; 01679 } 01680 01681 01682 /***************************************************************************\ 01683 * IDrawTextEx 01684 * This is the new DrawText API 01685 \***************************************************************************/ 01686 01687 /***************************************************************************\ 01688 * IDrawTextEx 01689 * This is the new DrawText API 01690 \***************************************************************************/ 01691 01692 int DrawTextExW( 01693 HDC hdc, 01694 LPWSTR lpchText, 01695 int cchText, 01696 LPRECT lprc, 01697 UINT dwDTformat, 01698 LPDRAWTEXTPARAMS lpDTparams) 01699 { 01700 /* 01701 * The LPK requires a charset. The Unicode entry point always passes a -1, 01702 * but the ANSI entry point passes a more interesting value. Both the 01703 * 'W' version and 'A' version of DrawTextEx call this common worker routine. 01704 */ 01705 return DrawTextExWorker(hdc, lpchText, cchText, lprc, dwDTformat, lpDTparams, -1); 01706 } 01707 01708 int DrawTextExWorker( 01709 HDC hdc, 01710 LPWSTR lpchText, 01711 int cchText, 01712 LPRECT lprc, 01713 UINT dwDTformat, 01714 LPDRAWTEXTPARAMS lpDTparams, 01715 int iCharset) 01716 { 01717 DRAWTEXTDATA DrawInfo; 01718 WORD wFormat = LOWORD(dwDTformat); 01719 LPWSTR lpchTextBegin; 01720 LPWSTR lpchEnd; 01721 LPWSTR lpchNextLineSt; 01722 int iLineLength; 01723 int iySign; 01724 int yLine; 01725 int yLastLineHeight; 01726 HRGN hrgnClip; 01727 int iLineCount; 01728 RECT rc; 01729 BOOL fLastLine; 01730 WCHAR ch; 01731 UINT oldAlign; 01732 01733 #if DBG 01734 if (dwDTformat & ~DT_VALID) 01735 RIPMSG0 (RIP_WARNING, "DrawTextExW: Invalid dwDTformat flags"); 01736 #endif 01737 01738 if (lpchText == NULL) { 01739 return 1; 01740 } 01741 01742 if (cchText == 0 && *lpchText) { 01743 /* 01744 * infoview.exe passes lpchText that points to '\0' 01745 * 01746 * "Microsoft Expedia Streets and Trips 2000" and "MS MapPoint 2000" 01747 * tries cchText == 0 to detect if DrawTextW is supported. 01748 */ 01749 01750 /* Added by Chicago: 01751 * Lotus Notes doesn't like getting a zero return here 01752 */ 01753 return 1; 01754 } 01755 01756 if (cchText == -1) 01757 cchText = wcslen(lpchText); 01758 01759 01760 01761 if ((lpDTparams) && (lpDTparams->cbSize != sizeof(DRAWTEXTPARAMS))) { 01762 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "DrawTextEx: cbSize %ld is invalid", 01763 lpDTparams->cbSize); 01764 return 0; 01765 } 01766 01767 01768 #ifdef LATER 01769 /* 01770 * If DT_MODIFYSTRING is specified, then check for read-write pointer. 01771 */ 01772 if (MODIFYSTRING(dwDTformat) && 01773 (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat))) { 01774 if(IsBadWritePtr(lpchText, cchText)) { 01775 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "DrawTextEx: For DT_MODIFYSTRING, lpchText must be read-write"); 01776 return(0); 01777 } 01778 } 01779 #endif 01780 01781 /* 01782 * Initialize the DrawInfo structure. 01783 */ 01784 if (!DT_InitDrawTextInfo(hdc, lprc, dwDTformat, (LPDRAWTEXTDATA)&DrawInfo, lpDTparams)) 01785 return 0; 01786 01787 DrawInfo.iCharset = iCharset; 01788 /* 01789 * If the rect is too narrow or the margins are too wide.....Just forget it! 01790 * 01791 * If wordbreak is specified, the MaxWidth must be a reasonable value. 01792 * This check is sufficient because this will allow CALCRECT and NOCLIP 01793 * cases. --SANKAR. 01794 * 01795 * This also fixed all of our known problems with AppStudio. 01796 */ 01797 if (DrawInfo.cxMaxWidth <= 0) { 01798 01799 /* 01800 * We used to return a non-zero value in win31. 01801 * If the kernel calls this we are always Ver 4.0 or above 01802 */ 01803 #ifdef _USERK_ 01804 if (0) { 01805 #else 01806 if (GETAPPVER() < VER40) { 01807 #endif 01808 if((DrawInfo.cxMaxWidth == 0) && !CALCRECT(wFormat)) { 01809 return(1); 01810 } 01811 } else { 01812 if (WORDBREAK(wFormat)) { 01813 RIPMSG0 (RIP_WARNING, "DrawTextExW: FAILURE DrawInfo.cxMaxWidth <=0"); 01814 return (1); 01815 } 01816 } 01817 } 01818 01819 /* 01820 * if we're not doing the drawing, initialise the lpk-dll 01821 */ 01822 if (RTLREADING(dwDTformat)) { 01823 oldAlign = UserSetTextAlign(hdc, TA_RTLREADING | UserGetTextAlign(hdc)); 01824 } 01825 01826 if (DrawInfo.bCharsetDll) { 01827 #ifdef _USERK_ 01828 PTHREADINFO ptiCurrent = PtiCurrentShared(); 01829 01830 if(CALL_LPK(ptiCurrent)) 01831 #endif // _USERK_ 01832 (*UserLpkDrawTextEx)(hdc, 0, 0, lpchText, cchText, FALSE, dwDTformat, 01833 (LPDRAWTEXTDATA)&DrawInfo, DT_CHARSETINIT, iCharset); 01834 } 01835 01836 /* 01837 * If we need to clip, let us do that. 01838 */ 01839 if (!NOCLIP(wFormat)) { 01840 // 01841 // Save clipping region so we can restore it later. 01842 // 01843 // hrgnSave = SaveClipRgn(hdc); 01844 // IntersectClipRect(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); 01845 01846 hrgnClip = UserCreateRectRgn(0,0,0,0); 01847 if (hrgnClip != NULL) { 01848 if (UserGetClipRgn(hdc, hrgnClip) != 1) { 01849 UserDeleteObject(hrgnClip); 01850 hrgnClip = (HRGN)-1; 01851 } 01852 rc = *lprc; 01853 UserIntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); 01854 } 01855 } else { 01856 hrgnClip = NULL; 01857 } 01858 01859 lpchTextBegin = lpchText; 01860 lpchEnd = lpchText + cchText; 01861 01862 ProcessDrawText: 01863 01864 iLineCount = 0; // Reset number of lines to 1. 01865 yLine = lprc->top; 01866 01867 if (SINGLELINE(wFormat)) { 01868 iLineCount = 1; // It is a single line. 01869 01870 01871 /* 01872 * Process single line DrawText. 01873 */ 01874 switch (wFormat & DT_VFMTMASK) { 01875 case DT_BOTTOM: 01876 yLine = lprc->bottom - DrawInfo.cyLineHeight; 01877 break; 01878 01879 case DT_VCENTER: 01880 yLine = lprc->top + ((lprc->bottom - lprc->top - DrawInfo.cyLineHeight) / 2); 01881 break; 01882 } 01883 01884 cchText = AddEllipsisAndDrawLine(hdc, yLine, lpchText, cchText, dwDTformat, &DrawInfo, iCharset); 01885 yLine += DrawInfo.cyLineHeight; 01886 lpchText += cchText; 01887 } else { 01888 01889 /* 01890 * Multiline 01891 * If the height of the rectangle is not an integral multiple of the 01892 * average char height, then it is possible that the last line drawn 01893 * is only partially visible. However, if DT_EDITCONTROL style is 01894 * specified, then we must make sure that the last line is not drawn if 01895 * it is going to be partially visible. This will help imitate the 01896 * appearance of an edit control. 01897 */ 01898 if (EDITCONTROL(wFormat)) 01899 yLastLineHeight = DrawInfo.cyLineHeight; 01900 else 01901 yLastLineHeight = 0; 01902 01903 iySign = DrawInfo.iYSign; 01904 fLastLine = FALSE; 01905 // Process multiline DrawText. 01906 while ((lpchText < lpchEnd) && (!fLastLine)) { 01907 // Check if the line we are about to draw is the last line that needs 01908 // to be drawn. 01909 // Let us check if the display goes out of the clip rect and if so 01910 // let us stop here, as an optimisation; 01911 if (!CALCRECT(wFormat) && // We don't need to calc rect? 01912 (!NOCLIP(wFormat)) && // Must we clip the display ? 01913 // Are we outside the rect? 01914 ((yLine + DrawInfo.cyLineHeight + yLastLineHeight)*iySign > (lprc->bottom*iySign))) { 01915 fLastLine = TRUE; // Let us quit this loop 01916 } 01917 01918 01919 /* 01920 * We do the Ellipsis processing only for the last line. 01921 */ 01922 if (fLastLine && (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat))) { 01923 lpchText += AddEllipsisAndDrawLine(hdc, yLine, lpchText, cchText, dwDTformat, &DrawInfo, iCharset); 01924 } else { 01925 lpchNextLineSt = (LPWSTR)DT_GetLineBreak(hdc, lpchText, cchText, dwDTformat, &iLineLength, &DrawInfo, iCharset); 01926 01927 /* 01928 * Check if we need to put ellipsis at the end of this line. 01929 * Also check if this is the last line. 01930 */ 01931 if (WORDELLIPSIS(dwDTformat) || 01932 ((lpchNextLineSt >= lpchEnd) && (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat)))) 01933 AddEllipsisAndDrawLine(hdc, yLine, lpchText, iLineLength, dwDTformat, &DrawInfo, iCharset); 01934 else 01935 DT_DrawJustifiedLine(hdc, yLine, lpchText, iLineLength, dwDTformat, &DrawInfo, iCharset); 01936 cchText -= (int)((PBYTE)lpchNextLineSt - (PBYTE)lpchText) / sizeof(WCHAR); 01937 lpchText = lpchNextLineSt; 01938 } 01939 iLineCount++; // We draw one more line. 01940 yLine += DrawInfo.cyLineHeight; 01941 } 01942 01943 01944 /* 01945 * For Win3.1 and NT compatibility, if the last char is a CR or a LF 01946 * then the height returned includes one more line. 01947 */ 01948 if (!EDITCONTROL(dwDTformat) && 01949 (lpchEnd > lpchTextBegin) && // If zero length it will fault. 01950 (((ch = (*(lpchEnd-1))) == CR) || (ch == LF))) 01951 yLine += DrawInfo.cyLineHeight; 01952 } 01953 01954 01955 /* 01956 * If DT_CALCRECT, modify width and height of rectangle to include 01957 * all of the text drawn. 01958 */ 01959 if (CALCRECT(wFormat)) { 01960 DrawInfo.rcFormat.right = DrawInfo.rcFormat.left + DrawInfo.cxMaxExtent * DrawInfo.iXSign; 01961 lprc->right = DrawInfo.rcFormat.right + DrawInfo.cxRightMargin; 01962 01963 // If the Width is more than what was provided, we have to redo all 01964 // the calculations, because, the number of lines can be less now. 01965 // (We need to do this only if we have more than one line). 01966 if((iLineCount > 1) && (DrawInfo.cxMaxExtent > DrawInfo.cxMaxWidth)) { 01967 DrawInfo.cxMaxWidth = DrawInfo.cxMaxExtent; 01968 lpchText = lpchTextBegin; 01969 cchText = (int)((PBYTE)lpchEnd - (PBYTE)lpchTextBegin)/sizeof(WCHAR); 01970 goto ProcessDrawText; // Start all over again! 01971 } 01972 lprc->bottom = yLine; 01973 } 01974 01975 // if (!NOCLIP(wFormat)) 01976 // { 01977 // RestoreClipRgn(hdc, hrgnClip); 01978 // } 01979 01980 if (hrgnClip != NULL) { 01981 if (hrgnClip == (HRGN)-1) { 01982 UserExtSelectClipRgn(hdc, NULL, RGN_COPY); 01983 } else { 01984 UserExtSelectClipRgn(hdc, hrgnClip, RGN_COPY); 01985 UserDeleteObject(hrgnClip); 01986 } 01987 } 01988 01989 if(DrawInfo.bCharsetDll) { 01990 #ifdef _USERK_ 01991 PTHREADINFO ptiCurrent = PtiCurrentShared(); 01992 01993 if(CALL_LPK(ptiCurrent)) 01994 #endif // _USERK_ 01995 (*UserLpkDrawTextEx)(hdc, 0, 0, lpchText, cchText, FALSE, dwDTformat, 01996 (LPDRAWTEXTDATA)&DrawInfo, DT_CHARSETDONE, iCharset); 01997 } 01998 01999 if (RTLREADING(dwDTformat)) 02000 UserSetTextAlign(hdc, oldAlign); 02001 02002 /* 02003 * Copy the number of characters actually drawn 02004 */ 02005 if(lpDTparams != NULL) 02006 lpDTparams->uiLengthDrawn = (UINT)((PBYTE)lpchText - (PBYTE)lpchTextBegin)/sizeof(WCHAR); 02007 02008 if (yLine == lprc->top) 02009 return 1; 02010 02011 return (yLine - lprc->top); 02012 } 02013 02014 /***************************************************************************\ 02015 * 02016 * IsSysFontAndDefaultMode() 02017 * 02018 * Returns TRUE if font selected into DC is the system font AND the current 02019 * mapping mode of the DC is MM_TEXT (Default mode); else returns FALSE. This 02020 * is called by interrupt time code so it needs to be in the fixed code 02021 * segment. 02022 * 02023 * History: 02024 * 07-Jul-95 BradG Ported from Win95 02025 \***************************************************************************/ 02026 02027 BOOL IsSysFontAndDefaultMode(HDC hdc) 02028 { 02029 return((UserGetHFONT(hdc) == ghFontSys) && (UserGetMapMode(hdc) == MM_TEXT)); 02030 }

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