Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2021 lines
76 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: drawtext.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains common text drawing functions.
  7. *
  8. * History:
  9. * 02-12-92 mikeke Moved Drawtext to the client side
  10. \***************************************************************************/
  11. /***************************************************************************\
  12. * Define some macros to test the format flags. We won't support them all
  13. * on the kernel-mode side, since they're not all needed there.
  14. \***************************************************************************/
  15. #ifdef _USERK_
  16. #define CALCRECT(wFormat) FALSE
  17. #define EDITCONTROL(wFormat) FALSE
  18. #define EXPANDTABS(wFormat) FALSE
  19. #define EXTERNALLEADING(wFormat) FALSE
  20. #define MODIFYSTRING(wFormat) FALSE
  21. #define NOPREFIX(wFormat) TRUE
  22. #define PATHELLIPSIS(wFormat) FALSE
  23. #define SINGLELINE(wFormat) TRUE
  24. #define TABSTOP(wFormat) FALSE
  25. #define WORDBREAK(wFormat) FALSE
  26. #define WORDELLIPSIS(wFormat) FALSE
  27. #define NOFULLWIDTHCHARBREAK(dwFormat) FALSE
  28. #else
  29. #define CALCRECT(wFormat) (wFormat & DT_CALCRECT)
  30. #define EDITCONTROL(wFormat) (wFormat & DT_EDITCONTROL)
  31. #define EXPANDTABS(wFormat) (wFormat & DT_EXPANDTABS)
  32. #define EXTERNALLEADING(wFormat) (wFormat & DT_EXTERNALLEADING)
  33. #define MODIFYSTRING(wFormat) (wFormat & DT_MODIFYSTRING)
  34. #define NOPREFIX(wFormat) (wFormat & DT_NOPREFIX)
  35. #define PATHELLIPSIS(wFormat) (wFormat & DT_PATH_ELLIPSIS)
  36. #define SINGLELINE(wFormat) (wFormat & DT_SINGLELINE)
  37. #define TABSTOP(wFormat) (wFormat & DT_TABSTOP)
  38. #define WORDBREAK(wFormat) (wFormat & DT_WORDBREAK)
  39. #define WORDELLIPSIS(wFormat) (wFormat & DT_WORD_ELLIPSIS)
  40. // Note: DT_NOFULLWIDTHCHARBREAK exceeds WORD limit. Use dwFormat
  41. // rather than wFormat.
  42. #define NOFULLWIDTHCHARBREAK(dwFormat) (dwFormat & DT_NOFULLWIDTHCHARBREAK)
  43. #endif
  44. #define ENDELLIPSIS(wFormat) (wFormat & DT_END_ELLIPSIS)
  45. #define NOCLIP(wFormat) (wFormat & DT_NOCLIP)
  46. #define RTLREADING(wFormat) (wFormat & DT_RTLREADING)
  47. #define HIDEPREFIX(wFormat) (wFormat & DT_HIDEPREFIX)
  48. /***************************************************************************\
  49. * Stuff used in DrawText code
  50. \***************************************************************************/
  51. #define CR 13
  52. #define LF 10
  53. #define SYM_SP 0xf020
  54. #define DT_HFMTMASK 0x03
  55. #define DT_VFMTMASK 0x0C
  56. #define ETO_OPAQUEFGND 0x0A
  57. static CONST WCHAR szEllipsis[CCHELLIPSIS+1] = TEXT("...");
  58. extern HDC ghdcBits2;
  59. /* Max length of a full path is around 260. But, most of the time, it will
  60. * be less than 128. So, we alloc only this much on stack. If the string is
  61. * longer, we alloc from local heap (which is slower).
  62. *
  63. * BOGUS: For international versions, we need to give some more margin here.
  64. */
  65. #define MAXBUFFSIZE 128
  66. /***************************************************************************\
  67. * There are word breaking characters which are compatible with
  68. * Japanese Windows 3.1 and FarEast Windows 95.
  69. *
  70. * SJ - Country Japan , Charset SHIFTJIS, Codepage 932.
  71. * GB - Country PRC , Charset GB2312 , Codepage 936.
  72. * B5 - Country Taiwan, Charset BIG5 , Codepage 950.
  73. * WS - Country Korea , Charset WANGSUNG, Codepage 949.
  74. * JB - Country Korea , Charset JOHAB , Codepage 1361. *** LATER ***
  75. *
  76. * [START BREAK CHARACTERS]
  77. *
  78. * These character should not be the last charatcer of the line.
  79. *
  80. * Unicode Japan PRC Taiwan Korea
  81. * -------+---------+---------+---------+---------+
  82. *
  83. * + ASCII
  84. *
  85. * U+0024 (SJ+0024) (WS+0024) Dollar sign
  86. * U+0028 (SJ+0028) (WS+0028) Opening parenthesis
  87. * U+003C (SJ+003C) Less-than sign
  88. * U+005C (SJ+005C) Backslash
  89. * U+005B (SJ+005B) (GB+005B) (WS+005B) Opening square bracket
  90. * U+007B (SJ+007B) (GB+007B) (WS+007B) Opening curly bracket
  91. *
  92. * + General punctuation
  93. *
  94. * U+2018 (WS+A1AE) Single Turned Comma Quotation Mark
  95. * U+201C (WS+A1B0) Double Comma Quotation Mark
  96. *
  97. * + CJK symbols and punctuation
  98. *
  99. * U+3008 (WS+A1B4) Opening Angle Bracket
  100. * U+300A (SJ+8173) (WS+A1B6) Opening Double Angle Bracket
  101. * U+300C (SJ+8175) (WS+A1B8) Opening Corner Bracket
  102. * U+300E (SJ+8177) (WS+A1BA) Opening White Corner Bracket
  103. * U+3010 (SJ+9179) (WS+A1BC) Opening Black Lenticular Bracket
  104. * U+3014 (SJ+816B) (WS+A1B2) Opening Tortoise Shell Bracket
  105. *
  106. * + Fullwidth ASCII variants
  107. *
  108. * U+FF04 (WS+A3A4) Fullwidth Dollar Sign
  109. * U+FF08 (SJ+8169) (WS+A3A8) Fullwidth opening parenthesis
  110. * U+FF1C (SJ+8183) Fullwidth less-than sign
  111. * U+FF3B (SJ+816D) (WS+A3DB) Fullwidth opening square bracket
  112. * U+FF5B (SJ+816F) (WS+A3FB) Fullwidth opening curly bracket
  113. *
  114. * + Halfwidth Katakana variants
  115. *
  116. * U+FF62 (SJ+00A2) Halfwidth Opening Corner Bracket
  117. *
  118. * + Fullwidth symbol variants
  119. *
  120. * U+FFE1 (WS+A1CC) Fullwidth Pound Sign
  121. * U+FFE6 (WS+A3DC) Fullwidth Won Sign
  122. *
  123. * [END BREAK CHARACTERS]
  124. *
  125. * These character should not be the top charatcer of the line.
  126. *
  127. * Unicode Japan PRC Taiwan Korea
  128. * -------+---------+---------+---------+---------+
  129. *
  130. * + ASCII
  131. *
  132. * U+0021 (SJ+0021) (GB+0021) (B5+0021) (WS+0021) Exclamation mark
  133. * U+0025 (WS+0025) Percent Sign
  134. * U+0029 (SJ+0029) (WS+0029) Closing parenthesis
  135. * U+002C (SJ+002C) (GB+002C) (B5+002C) (WS+002C) Comma
  136. * U+002E (SJ+002E) (GB+002E) (B5+002E) (WS+002E) Priod
  137. * U+003A (WS+003A) Colon
  138. * U+003B (WS+003B) Semicolon
  139. * U+003E (SJ+003E) Greater-than sign
  140. * U+003F (SJ+003F) (GB+003F) (B5+003F) (WS+003F) Question mark
  141. * U+005D (SJ+005D) (GB+005D) (B5+005D) (WS+005D) Closing square bracket
  142. * U+007D (SJ+007D) (GB+007D) (B5+007D) (WS+007D) Closing curly bracket
  143. *
  144. * + Latin1
  145. *
  146. * U+00A8 (GB+A1A7) Spacing diaeresis
  147. * U+00B0 (WS+A1C6) Degree Sign
  148. * U+00B7 (B5+A150) Middle Dot
  149. *
  150. * + Modifier letters
  151. *
  152. * U+02C7 (GB+A1A6) Modifier latter hacek
  153. * U+02C9 (GB+A1A5) Modifier letter macron
  154. *
  155. * + General punctuation
  156. *
  157. * U+2013 (B5+A156) En Dash
  158. * U+2014 (b5+A158) Em Dash
  159. * U+2015 (GB+A1AA) Quotation dash
  160. * U+2016 (GB+A1AC) Double vertical bar
  161. * U+2018 (GB+A1AE) Single turned comma quotation mark
  162. * U+2019 (GB+A1AF) (B5+A1A6) (WS+A1AF) Single comma quotation mark
  163. * U+201D (GB+A1B1) (B5+A1A8) (WS+A1B1) Double comma quotation mark
  164. * U+2022 (GB+A1A4) Bullet
  165. * U+2025 (B5+A14C) Two Dot Leader
  166. * U+2026 (GB+A1AD) (B5+A14B) Horizontal ellipsis
  167. * U+2027 (B5+A145) Hyphenation Point
  168. * U+2032 (B5+A1AC) (WS+A1C7) Prime
  169. * U+2033 (WS+A1C8) Double Prime
  170. *
  171. * + Letterlike symbols
  172. *
  173. * U+2103 (WS+A1C9) Degrees Centigrade
  174. *
  175. * + Mathemetical opetartors
  176. *
  177. * U+2236 (GB+A1C3) Ratio
  178. *
  179. * + Form and Chart components
  180. *
  181. * U+2574 (B5+A15A) Forms Light Left
  182. *
  183. * + CJK symbols and punctuation
  184. *
  185. * U+3001 (SJ+8141) (GB+A1A2) (B5+A142) Ideographic comma
  186. * U+3002 (SJ+8142) (GB+A1A3) (B5+A143) Ideographic period
  187. * U+3003 (GB+A1A8) Ditto mark
  188. * U+3005 (GB+A1A9) Ideographic iteration
  189. * U+3009 (GB+A1B5) (B5+A172) (WS+A1B5) Closing angle bracket
  190. * U+300B (SJ+8174) (GB+A1B7) (B5+A16E) (WS+A1B7) Closing double angle bracket
  191. * U+300D (SJ+8176) (GB+A1B9) (B5+A176) (WS+A1B9) Closing corner bracket
  192. * U+300F (SJ+8178) (GB+A1BB) (B5+A17A) (WS+A1BB) Closing white corner bracket
  193. * U+3011 (SJ+817A) (GB+A1BF) (B5+A16A) (WS+A1BD) Closing black lenticular bracket
  194. * U+3015 (SJ+816C) (GB+A1B3) (B5+A166) (WS+A1B3) Closing tortoise shell bracket
  195. * U+3017 (GB+A1BD) Closing white lenticular bracket
  196. * U+301E (B5+A1AA) Double Prime Quotation Mark
  197. *
  198. * + Hiragana
  199. *
  200. * U+309B (SJ+814A) Katakana-Hiragana voiced sound mark
  201. * U+309C (SJ+814B) Katakana-Hiragana semi-voiced sound mark
  202. *
  203. * + CNS 11643 compatibility
  204. *
  205. * U+FE30 (B5+A14A) Glyph for Vertical 2 Dot Leader
  206. * U+FE31 (B5+A157) Glyph For Vertical Em Dash
  207. * U+FE33 (B5+A159) Glyph for Vertical Spacing Underscore
  208. * U+FE34 (B5+A15B) Glyph for Vertical Spacing Wavy Underscore
  209. * U+FE36 (B5+A160) Glyph For Vertical Closing Parenthesis
  210. * U+FE38 (B5+A164) Glyph For Vertical Closing Curly Bracket
  211. * U+FE3A (B5+A168) Glyph For Vertical Closing Tortoise Shell Bracket
  212. * U+FE3C (B5+A16C) Glyph For Vertical Closing Black Lenticular Bracket
  213. * U+FE3E (B5+A16E) Closing Double Angle Bracket
  214. * U+FE40 (B5+A174) Glyph For Vertical Closing Angle Bracket
  215. * U+FE42 (B5+A178) Glyph For Vertical Closing Corner Bracket
  216. * U+FE44 (B5+A17C) Glyph For Vertical Closing White Corner Bracket
  217. * U+FE4F (B5+A15C) Spacing Wavy Underscore
  218. *
  219. * + Small variants
  220. *
  221. * U+FE50 (B5+A14D) Small Comma
  222. * U+FE51 (B5+A14E) Small Ideographic Comma
  223. * U+FE52 (B5+A14F) Small Period
  224. * U+FE54 (B5+A151) Small Semicolon
  225. * U+FE55 (B5+A152) Small Colon
  226. * U+FE56 (B5+A153) Small Question Mark
  227. * U+FE57 (B5+A154) Small Exclamation Mark
  228. * U+FE5A (B5+A17E) Small Closing Parenthesis
  229. * U+FE5C (B5+A1A2) Small Closing Curly Bracket
  230. * U+FE5E (B5+A1A4) Small Closing Tortoise Shell Bracket
  231. *
  232. * + Fullwidth ASCII variants
  233. *
  234. * U+FF01 (SJ+8149) (GB+A3A1) (B5+A149) (WS+A3A1) Fullwidth exclamation mark
  235. * U+FF02 (GB+A3A2) Fullwidth Quotation mark
  236. * U+FF05 (WS+A3A5) Fullwidth Percent Sign
  237. * U+FF07 (GB+A3A7) Fullwidth Apostrophe
  238. * U+FF09 (SJ+816A) (GB+A3A9) (B5+A15E) (WS+A3A9) Fullwidth Closing parenthesis
  239. * U+FF0C (SJ+8143) (GB+A3AC) (B5+A141) (WS+A3AC) Fullwidth comma
  240. * U+FF0D (GB+A3AD) Fullwidth Hyphen-minus
  241. * U+FF0E (SJ+8144) (B5+A144) (WS+A3AE) Fullwidth period
  242. * U+FF1A (GB+A3BA) (B4+A147) (WS+A3BA) Fullwidth colon
  243. * U+FF1B (GB+A3BB) (B5+A146) (WS+A3BB) Fullwidth semicolon
  244. * U+FF1E (SJ+8184) Fullwidth Greater-than sign
  245. * U+FF1F (SJ+8148) (GB+A3BF) (B5+A148) (WS+A3BF) Fullwidth question mark
  246. * U+FF3D (SJ+816E) (GB+A3DD) (WS+A3DD) Fullwidth Closing square bracket
  247. * U+FF5C (B5+A155) Fullwidth Vertical Bar
  248. * U+FF5D (SJ+8170) (B5+A162) (WS+A3FD) Fullwidth Closing curly bracket
  249. * U+FF5E (GB+A1AB) Fullwidth Spacing tilde
  250. *
  251. * + Halfwidth Katakana variants
  252. *
  253. * U+FF61 (SJ+00A1) Halfwidth Ideographic period
  254. * U+FF63 (SJ+00A3) Halfwidth Closing corner bracket
  255. * U+FF64 (SJ+00A4) Halfwidth Ideographic comma
  256. * U+FF9E (SJ+00DE) Halfwidth Katakana voiced sound mark
  257. * U+FF9F (SJ+00DF) Halfwidth Katakana semi-voiced sound mark
  258. *
  259. * + Fullwidth symbol variants
  260. *
  261. * U+FFE0 (WS+A1CB) Fullwidth Cent Sign
  262. *
  263. \***************************************************************************/
  264. #if 0 // not currently used --- FYI only
  265. /***************************************************************************\
  266. * Start Break table
  267. * These character should not be the last charatcer of the line.
  268. \***************************************************************************/
  269. CONST BYTE aASCII_StartBreak[] = {
  270. /* 00 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  271. /* 2X */ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
  272. /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
  273. /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  274. /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
  275. /* 6X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  276. /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  277. };
  278. CONST BYTE aCJKSymbol_StartBreak[] = {
  279. /* 30 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  280. /* 0X */ 1, 0, 1, 0, 1, 0, 1, 0,
  281. /* 1X */ 1, 0, 0, 0, 1
  282. };
  283. CONST BYTE aFullWidthHalfWidthVariants_StartBreak[] = {
  284. /* FF 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  285. /* 0X */ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
  286. /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
  287. /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  288. /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
  289. /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  290. /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
  291. /* 6X */ 0, 0, 1
  292. };
  293. #endif
  294. /***************************************************************************\
  295. * End Break table.
  296. * These character should not be the top charatcer of the line.
  297. \***************************************************************************/
  298. CONST BYTE aASCII_Latin1_EndBreak[] = {
  299. /* 00 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  300. /* 2X */ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0,
  301. /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
  302. /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  303. /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
  304. /* 6X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  305. /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
  306. /* 8X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  307. /* 9X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  308. /* AX */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
  309. /* BX */ 1, 0, 0, 0, 0, 0, 0, 1
  310. };
  311. CONST BYTE aGeneralPunctuation_EndBreak[] = {
  312. /* 20 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  313. /* 1X */ 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0,
  314. /* 2X */ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  315. /* 3X */ 0, 0, 1, 1
  316. };
  317. CONST BYTE aCJKSymbol_EndBreak[] = {
  318. /* 30 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  319. /* 0X */ 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
  320. /* 1X */ 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1
  321. };
  322. CONST BYTE aCNS11643_SmallVariants_EndBreak[] = {
  323. /* FE 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  324. /* 3X */ 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
  325. /* 4X */ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
  326. /* 5X */ 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1
  327. };
  328. CONST BYTE aFullWidthHalfWidthVariants_EndBreak[] = {
  329. /* FF 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  330. /* 0X */ 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0,
  331. /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
  332. /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  333. /* 3X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
  334. /* 4X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  335. /* 5X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
  336. /* 6X */ 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  337. /* 7X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  338. /* 8X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  339. /* 9X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
  340. };
  341. /***************************************************************************\
  342. * UserIsFELineBreak() - Detects East Asia word breaking characters. *
  343. * *
  344. * History: *
  345. * 10-Mar-1996 HideyukN Created. *
  346. \***************************************************************************/
  347. #if 0 // not currently used --- FYI only
  348. BOOL UserIsFELineBreakStart(WCHAR wch)
  349. {
  350. switch (wch>>8) {
  351. case 0x00:
  352. //
  353. // Check if word breaking chars in ASCII.
  354. //
  355. if ((wch >= 0x0024) && (wch <= 0x007B))
  356. return((BOOL)(aASCII_StartBreak[wch - 0x0024]));
  357. else
  358. return(FALSE);
  359. case 0x20:
  360. //
  361. // Check if work breaking chars in "General punctuation"
  362. //
  363. if ((wch == 0x2018) || (wch == 0x201C))
  364. return(TRUE);
  365. else
  366. return(FALSE);
  367. case 0x30:
  368. //
  369. // Check if word breaking chars in "CJK symbols and punctuation"
  370. // and Hiragana.
  371. //
  372. if ((wch >= 0x3008) && (wch <= 0x3014))
  373. return((BOOL)(aCJKSymbol_StartBreak[wch - 0x3008]));
  374. else
  375. return(FALSE);
  376. case 0xFF:
  377. //
  378. // Check if word breaking chars in "Fullwidth ASCII variants",
  379. // "Halfwidth Katakana variants" or "Fullwidth Symbol variants".
  380. //
  381. if ((wch >= 0xFF04) && (wch <= 0xFF62))
  382. return((BOOL)(aFullWidthHalfWidthVariants_StartBreak[wch - 0xFF04]));
  383. else if ((wch == 0xFFE1) || (wch == 0xFFE6))
  384. return(TRUE);
  385. else
  386. return(FALSE);
  387. default:
  388. return(FALSE);
  389. }
  390. }
  391. #endif
  392. BOOL UserIsFELineBreakEnd(WCHAR wch)
  393. {
  394. switch (wch>>8) {
  395. case 0x00:
  396. //
  397. // Check if word breaking chars in ASCII or Latin1.
  398. //
  399. if ((wch >= 0x0021) && (wch <= 0x00B7))
  400. return((BOOL)(aASCII_Latin1_EndBreak[wch - 0x0021]));
  401. else
  402. return(FALSE);
  403. case 0x02:
  404. //
  405. // Check if work breaking chars in "Modifier letters"
  406. //
  407. if ((wch == 0x02C7) || (wch == 0x02C9))
  408. return(TRUE);
  409. else
  410. return(FALSE);
  411. case 0x20:
  412. //
  413. // Check if work breaking chars in "General punctuation"
  414. //
  415. if ((wch >= 0x2013) && (wch <= 0x2033))
  416. return((BOOL)(aGeneralPunctuation_EndBreak[wch - 0x2013]));
  417. else
  418. return(FALSE);
  419. case 0x21:
  420. //
  421. // Check if work breaking chars in "Letterlike symbols"
  422. //
  423. if (wch == 0x2103)
  424. return(TRUE);
  425. else
  426. return(FALSE);
  427. case 0x22:
  428. //
  429. // Check if work breaking chars in "Mathemetical opetartors"
  430. //
  431. if (wch == 0x2236)
  432. return(TRUE);
  433. else
  434. return(FALSE);
  435. case 0x25:
  436. //
  437. // Check if work breaking chars in "Form and Chart components"
  438. //
  439. if (wch == 0x2574)
  440. return(TRUE);
  441. else
  442. return(FALSE);
  443. case 0x30:
  444. //
  445. // Check if word breaking chars in "CJK symbols and punctuation"
  446. // and Hiragana.
  447. //
  448. if ((wch >= 0x3001) && (wch <= 0x301E))
  449. return((BOOL)(aCJKSymbol_EndBreak[wch - 0x3001]));
  450. else if ((wch == 0x309B) || (wch == 0x309C))
  451. return(TRUE);
  452. else
  453. return(FALSE);
  454. case 0xFE:
  455. //
  456. // Check if word breaking chars in "CNS 11643 compatibility"
  457. // or "Small variants".
  458. //
  459. if ((wch >= 0xFE30) && (wch <= 0xFE5E))
  460. return((BOOL)(aCNS11643_SmallVariants_EndBreak[wch - 0xFE30]));
  461. else
  462. return(FALSE);
  463. case 0xFF:
  464. //
  465. // Check if word breaking chars in "Fullwidth ASCII variants",
  466. // "Halfwidth Katakana variants" or "Fullwidth symbol variants".
  467. //
  468. if ((wch >= 0xFF01) && (wch <= 0xFF9F))
  469. return((BOOL)(aFullWidthHalfWidthVariants_EndBreak[wch - 0xFF01]));
  470. else if (wch >= 0xFFE0)
  471. return(TRUE);
  472. else
  473. return(FALSE);
  474. default:
  475. return(FALSE);
  476. }
  477. }
  478. #define UserIsFELineBreak(wChar) UserIsFELineBreakEnd(wChar)
  479. /***************************************************************************\
  480. * UserIsFullWidth() - Detects East Asia FullWidth character. *
  481. * *
  482. * History: *
  483. * 10-Mar-1996 HideyukN Created *
  484. \***************************************************************************/
  485. typedef struct _FULLWIDTH_UNICODE {
  486. WCHAR Start;
  487. WCHAR End;
  488. } FULLWIDTH_UNICODE, *PFULLWIDTH_UNICODE;
  489. #define NUM_FULLWIDTH_UNICODES 4
  490. CONST FULLWIDTH_UNICODE FullWidthUnicodes[] = {
  491. { 0x4E00, 0x9FFF }, // CJK_UNIFIED_IDOGRAPHS
  492. { 0x3040, 0x309F }, // HIRAGANA
  493. { 0x30A0, 0x30FF }, // KATAKANA
  494. { 0xAC00, 0xD7A3 } // HANGUL
  495. };
  496. BOOL UserIsFullWidth(DWORD dwCodePage,WCHAR wChar)
  497. {
  498. INT index;
  499. INT cChars;
  500. #ifdef _USERK_
  501. CHAR aChars[2];
  502. #endif // _USERK_
  503. //
  504. // Early out for ASCII.
  505. //
  506. if (wChar < 0x0080) {
  507. //
  508. // if the character < 0x0080, it should be a halfwidth character.
  509. //
  510. return (FALSE);
  511. }
  512. //
  513. // Scan FullWdith definition table... most of FullWidth character is
  514. // defined here... this is more faster than call NLS API.
  515. //
  516. for (index = 0; index < NUM_FULLWIDTH_UNICODES; index++) {
  517. if ((wChar >= FullWidthUnicodes[index].Start) &&
  518. (wChar <= FullWidthUnicodes[index].End) ) {
  519. return (TRUE);
  520. }
  521. }
  522. //
  523. // if this Unicode character is mapped to Double-Byte character,
  524. // this is also FullWidth character..
  525. //
  526. #ifdef _USERK_
  527. cChars = EngWideCharToMultiByte((UINT)dwCodePage,&wChar,sizeof(WCHAR),aChars,sizeof(aChars));
  528. #else
  529. cChars = WideCharToMultiByte((UINT)dwCodePage,0,&wChar,1,NULL,0,NULL,NULL);
  530. #endif // _USERK_
  531. return(cChars > 1 ? TRUE : FALSE);
  532. }
  533. /***************************************************************************\
  534. * UserTextOutWInternal
  535. * Wrapper for UserTextOutW, used to adjust the parameter passed to
  536. * PSMTextOut
  537. *
  538. \***************************************************************************/
  539. BOOL UserTextOutWInternal(
  540. HDC hdc,
  541. int x,
  542. int y,
  543. LPCWSTR lp,
  544. UINT cc,
  545. DWORD dwFlags)
  546. {
  547. UNREFERENCED_PARAMETER(dwFlags);
  548. return UserTextOutW(hdc, x, y, lp, cc);
  549. }
  550. /*--------------------------------------------------------------------------*/
  551. /* */
  552. /* KKGetPrefixWidth() - */
  553. /* */
  554. /* Returns total width of prefix character. Japanese Windows has */
  555. /* three shortcut prefixes, '&',\036 and \037. They may have */
  556. /* different width. */
  557. /* */
  558. /* From Chicago ctlmgr.c HideyukN */
  559. /*--------------------------------------------------------------------------*/
  560. int KKGetPrefixWidth(HDC hdc, LPCWSTR lpStr, int cch)
  561. {
  562. SIZE size;
  563. SIZE iPrefix1 = {-1L,-1L};
  564. SIZE iPrefix2 = {-1L,-1L};
  565. SIZE iPrefix3 = {-1L,-1L};
  566. int iTotal = 0;
  567. while (cch-- > 0 && *lpStr) {
  568. switch(*lpStr) {
  569. case CH_PREFIX:
  570. if (lpStr[1] != CH_PREFIX) {
  571. if (iPrefix1.cx == -1) {
  572. UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix1);
  573. }
  574. iTotal += iPrefix1.cx;
  575. } else {
  576. lpStr++;
  577. cch--;
  578. }
  579. break;
  580. case CH_ENGLISHPREFIX:
  581. if (iPrefix2.cx == -1) {
  582. UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix2);
  583. }
  584. iTotal += iPrefix2.cx;
  585. break;
  586. case CH_KANJIPREFIX:
  587. if (iPrefix3.cx == -1) {
  588. UserGetTextExtentPointW(hdc, lpStr, 1, &iPrefix3);
  589. }
  590. iTotal += iPrefix3.cx;
  591. //
  592. // In NT, always alpha numeric mode, Then we have to sum
  593. // KANA accel key prefix non visible char width.
  594. // so always add the extent for next char.
  595. //
  596. UserGetTextExtentPointW(hdc, lpStr, 1, &size);
  597. iTotal += size.cx;
  598. break;
  599. default:
  600. // No need to taking care of Double byte since 2nd byte of
  601. // DBC is grater than 0x2f but all shortcut keys are less
  602. // than 0x30.
  603. break;
  604. }
  605. lpStr++;
  606. }
  607. return iTotal;
  608. }
  609. #if ((DT_WORDBREAK & ~0xff) != 0)
  610. #error cannot use BOOLEAN for DT_WORDBREAK, or you should use "!!" before assigning it
  611. #endif
  612. /*--------------------------------------------------------------------------*/
  613. /* */
  614. /* GetNextWordbreak() - */
  615. /* From Chicago ctlmgr.c FritzS */
  616. /* */
  617. /*--------------------------------------------------------------------------*/
  618. LPCWSTR GetNextWordbreak(DWORD dwCodePage,
  619. LPCWSTR lpch,
  620. LPCWSTR lpchEnd,
  621. DWORD dwFormat,
  622. LPDRAWTEXTDATA lpDrawInfo)
  623. {
  624. /* ichNonWhite is used to make sure we always make progress. */
  625. int ichNonWhite = 1;
  626. int ichComplexBreak = 0; // Breaking opportunity for complex scripts
  627. BOOLEAN fBreakSpace = (BOOLEAN)WORDBREAK(dwFormat);
  628. /*
  629. * If DT_WORDBREAK and DT_NOFULLWIDTHCHARBREAK are both set, we must
  630. * stop assuming FullWidth characters as word as we're doing in
  631. * NT4 and Win95. Instead, CR/LF and/or white space will only be
  632. * a line-break characters.
  633. */
  634. BOOLEAN fDbcsCharBreak = (fBreakSpace && !NOFULLWIDTHCHARBREAK(dwFormat));
  635. #ifdef _USERK_
  636. /*
  637. * Well, we actually should not and do not call GetNextWordBreak() in
  638. * kernel, since only Menu stuff (no word break!) calls DrawText from kernel.
  639. * In reality, thanks to a smart linker, word-break helper
  640. * functions even does not exist in win32k.sys.
  641. * Later, we should explicitly omit to compile those routines when we
  642. * build kernel.
  643. */
  644. UNREFERENCED_PARAMETER(dwFormat);
  645. #endif
  646. // We must terminate this loop before lpch == lpchEnd, otherwise, we
  647. // may gp fault during *lpch.
  648. while (lpch < lpchEnd) {
  649. switch (*lpch) {
  650. case CR:
  651. case LF:
  652. return lpch;
  653. case '\t':
  654. case ' ':
  655. case SYM_SP:
  656. if (fBreakSpace)
  657. return (lpch + ichNonWhite);
  658. /*** FALL THRU ***/
  659. default:
  660. /*
  661. * Since most Japanese writing don't use space character
  662. * to separate each word, we define each Kanji character
  663. * as a word.
  664. */
  665. if (fDbcsCharBreak && UserIsFullWidth(dwCodePage, *lpch)) {
  666. if (!ichNonWhite)
  667. return lpch;
  668. /*
  669. * if the next character is the last character of this string,
  670. * We return the character, even this is a "KINSOKU" charcter...
  671. */
  672. if ((lpch+1) != lpchEnd) {
  673. /*
  674. * Check next character of FullWidth character.
  675. * if the next character is "KINSOKU" character, the character
  676. * should be handled as a part of previous FullWidth character.
  677. * Never handle is as A character, and should not be a Word also.
  678. */
  679. if (UserIsFELineBreak(*(lpch+1))) {
  680. /*
  681. * Then if the character is "KINSOKU" character, we return
  682. * the next of this character,...
  683. */
  684. return (lpch + 1 + 1);
  685. }
  686. }
  687. /*
  688. * Otherwise, we just return the chracter that is next of FullWidth
  689. * Character. Because we treat A FullWidth chacter as A Word.
  690. */
  691. return (lpch + 1);
  692. }
  693. /*
  694. * If the character is not a FullWidth character and the complex script
  695. * LPK is present. Call it to determine the breaking opportunity for
  696. * script that requires word break such as Thai. Note that if *lpch is
  697. * NOT a complex script character. The LPK will fail the call and return 0
  698. * since currently Uniscribe does not know how to handle FE break.
  699. */
  700. else if(fBreakSpace && lpDrawInfo->bCharsetDll) {
  701. #ifdef _USERK_
  702. PTHREADINFO ptiCurrent = PtiCurrentShared();
  703. if(CALL_LPK(ptiCurrent))
  704. #endif
  705. ichComplexBreak = (*UserLpkDrawTextEx)(0, 0, 0, lpch, (int)(lpchEnd - lpch), 0,
  706. 0, NULL, DT_GETNEXTWORD, -1);
  707. if (ichComplexBreak > 0)
  708. return (lpch + ichComplexBreak);
  709. }
  710. lpch++;
  711. ichNonWhite = 0;
  712. }
  713. }
  714. return lpch;
  715. }
  716. /***************************************************************************\
  717. * GetPrefixCount
  718. *
  719. * This routine returns the count of accelerator mnemonics and the
  720. * character location (starting at 0) of the character to underline.
  721. * A single CH_PREFIX character will be striped and the following character
  722. * underlined, all double CH_PREFIX character sequences will be replaced by
  723. * a single CH_PREFIX (this is done by PSMTextOut). This routine is used
  724. * to determine the actual character length of the string that will be
  725. * printed, and the location the underline should be placed. Only
  726. * cch characters from the input string will be processed. If the lpstrCopy
  727. * parameter is non-NULL, this routine will make a printable copy of the
  728. * string with all single prefix characters removed and all double prefix
  729. * characters collapsed to a single character. If copying, a maximum
  730. * character count must be specified which will limit the number of
  731. * characters copied.
  732. *
  733. * The location of the single CH_PREFIX is returned in the low order
  734. * word, and the count of CH_PREFIX characters that will be striped
  735. * from the string during printing is in the hi order word. If the
  736. * high order word is 0, the low order word is meaningless. If there
  737. * were no single prefix characters (i.e. nothing to underline), the
  738. * low order word will be -1 (to distinguish from location 0).
  739. *
  740. * These routines assume that there is only one single CH_PREFIX character
  741. * in the string.
  742. *
  743. * WARNING! this rountine returns information in BYTE count not CHAR count
  744. * (so it can easily be passed onto GreExtTextOutW which takes byte
  745. * counts as well)
  746. *
  747. * History:
  748. * 11-13-90 JimA Ported to NT
  749. * 30-Nov-1992 mikeke Client side version
  750. \***************************************************************************/
  751. LONG GetPrefixCount(
  752. LPCWSTR lpstr,
  753. int cch,
  754. LPWSTR lpstrCopy,
  755. int charcopycount)
  756. {
  757. int chprintpos = 0; /* Num of chars that will be printed */
  758. int chcount = 0; /* Num of prefix chars that will be removed */
  759. int chprefixloc = -1; /* Pos (in printed chars) of the prefix */
  760. WCHAR ch;
  761. /*
  762. * If not copying, use a large bogus count...
  763. */
  764. if (lpstrCopy == NULL)
  765. charcopycount = 32767;
  766. while ((cch-- > 0) && *lpstr && charcopycount-- != 0) {
  767. /*
  768. * Is this guy a prefix character ?
  769. */
  770. if ((ch = *lpstr++) == CH_PREFIX) {
  771. /*
  772. * Yup - increment the count of characters removed during print.
  773. */
  774. chcount++;
  775. /*
  776. * Is the next also a prefix char?
  777. */
  778. if (*lpstr != CH_PREFIX) {
  779. /*
  780. * Nope - this is a real one, mark its location.
  781. */
  782. chprefixloc = chprintpos;
  783. } else {
  784. /*
  785. * yup - simply copy it if copying.
  786. */
  787. if (lpstrCopy != NULL)
  788. *(lpstrCopy++) = CH_PREFIX;
  789. cch--;
  790. lpstr++;
  791. chprintpos++;
  792. }
  793. } else if (ch == CH_ENGLISHPREFIX) { // Still needs to be parsed
  794. /*
  795. * Yup - increment the count of characters removed during print.
  796. */
  797. chcount++;
  798. /*
  799. * Next character is a real one, mark its location.
  800. */
  801. chprefixloc = chprintpos;
  802. } else if (ch == CH_KANJIPREFIX) { // Still needs to be parsed
  803. /*
  804. * We only support Alpha Numeric(CH_ENGLISHPREFIX).
  805. * no support for Kana(CH_KANJIPREFIX).
  806. */
  807. /*
  808. * Yup - increment the count of characters removed during print.
  809. */
  810. chcount++;
  811. if(cch) {
  812. /* don't copy the character */
  813. chcount++;
  814. lpstr++;
  815. cch--;
  816. }
  817. } else {
  818. /*
  819. * Nope - just inc count of char. that will be printed
  820. */
  821. chprintpos++;
  822. if (lpstrCopy != NULL)
  823. *(lpstrCopy++) = ch;
  824. }
  825. }
  826. if (lpstrCopy != NULL)
  827. *lpstrCopy = 0;
  828. /*
  829. * Return the character counts
  830. */
  831. return MAKELONG(chprefixloc, chcount);
  832. }
  833. /***************************************************************************\
  834. * DT_GetExtentMinusPrefixes
  835. \***************************************************************************/
  836. int DT_GetExtentMinusPrefixes(HDC hdc, LPCWSTR lpchStr, int cchCount, UINT wFormat,
  837. int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  838. {
  839. int iPrefixCount;
  840. int cxPrefixes = 0;
  841. WCHAR PrefixChar = CH_PREFIX;
  842. SIZE size;
  843. PCLIENTINFO pci = GetClientInfo();
  844. #ifdef _USERK_
  845. PTHREADINFO ptiCurrent = PtiCurrentShared();
  846. #endif
  847. UNREFERENCED_PARAMETER(wFormat);
  848. if(!NOPREFIX(wFormat) &&
  849. (iPrefixCount = HIWORD(GetPrefixCount(lpchStr, cchCount, NULL, 0)))) {
  850. //
  851. // Kanji Windows has three shortcut prefixes...
  852. // (ported from Win95 ctlmgr.c)
  853. //
  854. BOOL b16Bit;
  855. #ifdef _USERK_
  856. try {
  857. b16Bit = pci->dwTIFlags & TIF_16BIT;
  858. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  859. b16Bit = FALSE;
  860. }
  861. #else
  862. b16Bit = pci->dwTIFlags & TIF_16BIT;
  863. #endif
  864. if (IS_DBCS_ENABLED() && b16Bit) {
  865. // 16bit apps compatibility
  866. cxPrefixes = KKGetPrefixWidth(hdc, lpchStr, cchCount) - (iPrefixCount * iOverhang);
  867. }
  868. else {
  869. if(lpDrawInfo->bCharsetDll) {
  870. #ifdef _USERK_
  871. if(CALL_LPK(ptiCurrent))
  872. #endif // _USERK_
  873. {
  874. // Call LPKDrawTextEx with fDraw = FALSE just to get the text extent.
  875. return (*UserLpkDrawTextEx)(hdc, 0, 0, lpchStr, cchCount, FALSE,
  876. wFormat, lpDrawInfo, DT_CHARSETDRAW, iCharSet);
  877. }
  878. } else {
  879. cxPrefixes = UserGetTextExtentPointW(hdc, &PrefixChar, 1, &size);
  880. cxPrefixes = size.cx - iOverhang;
  881. cxPrefixes *= iPrefixCount;
  882. }
  883. }
  884. }
  885. #ifdef _USERK_
  886. if(CALL_LPK(ptiCurrent))
  887. xxxClientGetTextExtentPointW(hdc, lpchStr, cchCount, &size);
  888. else
  889. #endif // _USERK_
  890. UserGetTextExtentPointW(hdc, lpchStr, cchCount, &size);
  891. return (size.cx - cxPrefixes);
  892. }
  893. /***************************************************************************\
  894. * DT_DrawStr
  895. * This will draw the given string in the given location without worrying
  896. * about the left/right justification. Gets the extent and returns it.
  897. * If fDraw is TRUE and if NOT DT_CALCRECT, this draws the text.
  898. * NOTE: This returns the extent minus Overhang.
  899. *
  900. * From Chicago ctlmgr.c FritzS
  901. \***************************************************************************/
  902. int DT_DrawStr(HDC hdc, int xLeft, int yTop, LPCWSTR lpchStr,
  903. int cchCount, BOOL fDraw, UINT wFormat,
  904. LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  905. {
  906. LPCWSTR lpch;
  907. int iLen;
  908. int cxExtent;
  909. int xOldLeft = xLeft; // Save the xLeft given to compute the extent later
  910. int xTabLength = lpDrawInfo->cxTabLength;
  911. int iTabOrigin = lpDrawInfo->rcFormat.left;
  912. //
  913. // Because xLeft and yTop is a point in a rect, and we shift the rect in a mirrored hdc to include
  914. // its most right pixel, then shift this point as well.
  915. //
  916. if (UserGetLayout(hdc) & LAYOUT_RTL) {
  917. --xOldLeft;
  918. --xLeft;
  919. }
  920. //
  921. // if there is a charset dll, let it draw the text.
  922. //
  923. if(lpDrawInfo->bCharsetDll) {
  924. #ifdef _USERK_
  925. PTHREADINFO ptiCurrent = PtiCurrentShared();
  926. //
  927. // Don't perform a callback if in thread cleanup mode.
  928. //
  929. if(!CALL_LPK(ptiCurrent))
  930. return 0 ;
  931. #endif // _USERK_
  932. return (*UserLpkDrawTextEx)(hdc, xLeft, yTop, lpchStr, cchCount, fDraw,
  933. wFormat, lpDrawInfo, DT_CHARSETDRAW, iCharSet);
  934. }
  935. // Check if the tabs need to be expanded
  936. if(EXPANDTABS(wFormat)) {
  937. while(cchCount) {
  938. // Look for a tab
  939. for(iLen = 0, lpch = lpchStr; iLen < cchCount; iLen++)
  940. if(*lpch++ == TEXT('\t'))
  941. break;
  942. // Draw text, if any, upto the tab
  943. if (iLen) {
  944. // Draw the substring taking care of the prefixes.
  945. if (fDraw && !CALCRECT(wFormat)) { // Only if we need to draw text
  946. (*(lpDrawInfo->lpfnTextDraw))(hdc, xLeft, yTop, (LPWSTR)lpchStr, iLen, wFormat);
  947. }
  948. // Get the extent of this sub string and add it to xLeft.
  949. xLeft += DT_GetExtentMinusPrefixes(hdc, lpchStr, iLen, wFormat, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet) - lpDrawInfo->cxOverhang;
  950. }
  951. //if a TAB was found earlier, calculate the start of next sub-string.
  952. if (iLen < cchCount) {
  953. iLen++; // Skip the tab
  954. if (xTabLength) // Tab length could be zero
  955. xLeft = (((xLeft - iTabOrigin)/xTabLength) + 1)*xTabLength + iTabOrigin;
  956. }
  957. // Calculate the details of the string that remains to be drawn.
  958. cchCount -= iLen;
  959. lpchStr = lpch;
  960. }
  961. cxExtent = xLeft - xOldLeft;
  962. } else {
  963. // If required, draw the text (with either PSMTextOut or PSTextOut)
  964. if (fDraw && !CALCRECT(wFormat)) {
  965. (*(lpDrawInfo->lpfnTextDraw))(hdc, xLeft, yTop, (LPWSTR)lpchStr, cchCount, wFormat);
  966. }
  967. // Compute the extent of the text.
  968. cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchStr, cchCount, wFormat,
  969. lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet) - lpDrawInfo->cxOverhang;
  970. }
  971. return cxExtent;
  972. }
  973. /***************************************************************************\
  974. * DT_DrawJustifiedLine
  975. * This function draws one complete line with proper justification
  976. *
  977. * from Chicago ctlmgr.c FritzS
  978. \***************************************************************************/
  979. void DT_DrawJustifiedLine(HDC hdc, int yTop, LPCWSTR lpchLineSt,
  980. int cchCount, UINT wFormat,
  981. LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  982. {
  983. LPRECT lprc;
  984. int cxExtent;
  985. int xLeft;
  986. lprc = &(lpDrawInfo->rcFormat);
  987. xLeft = lprc->left;
  988. // Handle the special justifications (right or centered) properly.
  989. if(wFormat & (DT_CENTER | DT_RIGHT)) {
  990. cxExtent = DT_DrawStr(hdc, xLeft, yTop, lpchLineSt, cchCount, FALSE,
  991. wFormat, lpDrawInfo, iCharSet) + lpDrawInfo->cxOverhang;
  992. if(wFormat & DT_CENTER)
  993. xLeft = lprc->left + (((lprc->right - lprc->left) - cxExtent) >> 1);
  994. else
  995. xLeft = lprc->right - cxExtent;
  996. } else
  997. xLeft = lprc->left;
  998. // Draw the whole line.
  999. cxExtent = DT_DrawStr(hdc, xLeft, yTop, lpchLineSt, cchCount, TRUE, wFormat,
  1000. lpDrawInfo, iCharSet) +lpDrawInfo->cxOverhang;
  1001. if(cxExtent > lpDrawInfo->cxMaxExtent)
  1002. lpDrawInfo->cxMaxExtent = cxExtent;
  1003. }
  1004. /***************************************************************************\
  1005. * DT_InitDrawTextInfo
  1006. * This is called at the begining of DrawText(); This initializes the
  1007. * DRAWTEXTDATA structure passed to this function with all the required info.
  1008. *
  1009. * from Chicago ctlmgr.c FritzS
  1010. \***************************************************************************/
  1011. BOOL DT_InitDrawTextInfo(
  1012. HDC hdc,
  1013. LPRECT lprc,
  1014. UINT wFormat,
  1015. LPDRAWTEXTDATA lpDrawInfo,
  1016. LPDRAWTEXTPARAMS lpDTparams)
  1017. {
  1018. SIZE sizeViewPortExt = {0, 0},sizeWindowExt = {0, 0};
  1019. TEXTMETRICW tm;
  1020. LPRECT lprcDest;
  1021. int iTabLength = 8; // Default Tab length is 8 characters.
  1022. int iLeftMargin;
  1023. int iRightMargin;
  1024. BOOL fUseSystemFont;
  1025. if (lpDTparams) {
  1026. /*
  1027. * Only if DT_TABSTOP flag is mentioned, we must use the iTabLength field.
  1028. */
  1029. if (TABSTOP(wFormat))
  1030. iTabLength = lpDTparams->iTabLength;
  1031. iLeftMargin = lpDTparams->iLeftMargin;
  1032. iRightMargin = lpDTparams->iRightMargin;
  1033. } else {
  1034. iLeftMargin = iRightMargin = 0;
  1035. }
  1036. /*
  1037. * Get the View port and Window extents for the given DC
  1038. * If this call fails, hdc must be invalid
  1039. */
  1040. if (!UserGetViewportExtEx(hdc,&sizeViewPortExt)) {
  1041. #ifndef _USERK_
  1042. /*
  1043. * This call fails on standard Metafiles. So check
  1044. * if the DC is really invalid to be compatible with
  1045. * Win9x
  1046. */
  1047. if ((hdc == NULL) || !GdiValidateHandle(hdc))
  1048. #endif
  1049. return FALSE;
  1050. }
  1051. UserGetWindowExtEx(hdc, &sizeWindowExt);
  1052. /*
  1053. * For the current mapping mode, find out the sign of x from left to right.
  1054. */
  1055. lpDrawInfo->iXSign =
  1056. (((sizeViewPortExt.cx ^ sizeWindowExt.cx) & 0x80000000) ? -1 : 1);
  1057. /*
  1058. * For the current mapping mode, find out the sign of y from top to bottom.
  1059. */
  1060. lpDrawInfo->iYSign =
  1061. (((sizeViewPortExt.cy ^ sizeWindowExt.cy) & 0x80000000) ? -1 : 1);
  1062. /*
  1063. * Calculate the dimensions of the current font in this DC.
  1064. * (If it is SysFont AND the mapping mode is MM_TEXT, use system font's data)
  1065. */
  1066. fUseSystemFont = ((wFormat & DT_INTERNAL) || IsSysFontAndDefaultMode(hdc));
  1067. if (!fUseSystemFont) {
  1068. /*
  1069. * Edit controls have their own way of calculating the aveCharWidth.
  1070. */
  1071. if (EDITCONTROL(wFormat)) {
  1072. tm.tmAveCharWidth = UserGetCharDimensionsW(hdc, &tm, NULL);
  1073. tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(hdc, NULL, 0);
  1074. if (tm.tmAveCharWidth == 0) {
  1075. fUseSystemFont = TRUE;
  1076. }
  1077. } else if (!UserGetTextMetricsW(hdc, &tm)) {
  1078. /*
  1079. * This can fail in a hard error popup during logon or logoff
  1080. * because UpdatePerUserSystemParameters destroys the server-side
  1081. * font handle for the DC, and a repaint occurs before we switch
  1082. * desktops (the switch recreates the popup from scratch with the
  1083. * new font OK). ChrisWil's changes to move system-wide attributes
  1084. * into desktops should take care of this in Kernel-mode. This is
  1085. * just a horrible, horrible hack for now.
  1086. */
  1087. RIPMSG0(RIP_WARNING, "UserGetTextMetricsW failed: only in logon/off?\n");
  1088. tm.tmOverhang = 0;
  1089. /*
  1090. * We should probably set fUseSystemFont to TRUE here. But I
  1091. * assume that this "horrible hack" works fine plus it has been
  1092. * here for good. So I'll leave it alone. 6/3/96
  1093. */
  1094. }
  1095. }
  1096. if (fUseSystemFont) {
  1097. /*
  1098. * Avoid GetTextMetrics for internal calls since they use sys font.
  1099. */
  1100. tm.tmHeight = gpsi->cySysFontChar;
  1101. tm.tmExternalLeading = gpsi->tmSysFont.tmExternalLeading;
  1102. tm.tmAveCharWidth = gpsi->tmSysFont.tmAveCharWidth;
  1103. tm.tmOverhang = gpsi->tmSysFont.tmOverhang;
  1104. #ifdef _USERK_
  1105. tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(gpDispInfo->hdcScreen, NULL, 0);
  1106. #else
  1107. tm.tmCharSet = (BYTE)UserGetTextCharsetInfo(ghdcBits2, NULL, 0);
  1108. #endif // _USERK_
  1109. }
  1110. // cyLineHeight is in pixels (This will be signed).
  1111. lpDrawInfo->cyLineHeight = (tm.tmHeight +
  1112. (EXTERNALLEADING(wFormat) ? tm.tmExternalLeading : 0)) *
  1113. lpDrawInfo->iYSign;
  1114. // cxTabLength is the tab length in pixels (This will not be signed)
  1115. lpDrawInfo->cxTabLength = tm.tmAveCharWidth * iTabLength;
  1116. // Set the cxOverhang
  1117. lpDrawInfo->cxOverhang = tm.tmOverhang;
  1118. // Pick up the proper TextOut function based on the prefix processing reqd.
  1119. #ifdef _USERK_
  1120. lpDrawInfo->bCharsetDll = PpiCurrent()->dwLpkEntryPoints & LPK_DRAWTEXTEX;
  1121. if (lpDrawInfo->bCharsetDll == FALSE) {
  1122. lpDrawInfo->lpfnTextDraw = (NOPREFIX(wFormat) ? (LPFNTEXTDRAW)UserTextOutWInternal : xxxPSMTextOut);
  1123. }
  1124. #else
  1125. lpDrawInfo->bCharsetDll = (BOOL)(fpLpkDrawTextEx != (FPLPKDRAWTEXTEX)NULL);
  1126. if (lpDrawInfo->bCharsetDll == FALSE) {
  1127. lpDrawInfo->lpfnTextDraw = (NOPREFIX(wFormat) ? (LPFNTEXTDRAW)UserTextOutWInternal : PSMTextOut);
  1128. }
  1129. #endif // _USERK_
  1130. // Set up the format rectangle based on the margins.
  1131. // LCopyStruct(lprc, lprcDest = (LPRECT)&(lpDrawInfo->rcFormat), sizeof(RECT));
  1132. lprcDest = &(lpDrawInfo->rcFormat);
  1133. *lprcDest = *lprc;
  1134. // We need to do the following only if the margins are given
  1135. if(iLeftMargin | iRightMargin) {
  1136. lprcDest->left += iLeftMargin * lpDrawInfo->iXSign;
  1137. lprcDest->right -= (lpDrawInfo->cxRightMargin = iRightMargin * lpDrawInfo->iXSign);
  1138. } else
  1139. lpDrawInfo->cxRightMargin = 0; // Initialize to zero.
  1140. // cxMaxWidth is unsigned.
  1141. lpDrawInfo->cxMaxWidth = (lprcDest->right - lprcDest->left) * lpDrawInfo->iXSign;
  1142. lpDrawInfo->cxMaxExtent = 0; // Initialize this to zero.
  1143. return TRUE;
  1144. }
  1145. /***************************************************************************\
  1146. * DT_AdjustWhiteSpaces
  1147. * In the case of WORDWRAP, we need to treat the white spaces at the
  1148. * begining/end of each line specially. This function does that.
  1149. * lpStNext = points to the begining of next line.
  1150. * lpiCount = points to the count of characters in the current line.
  1151. \***************************************************************************/
  1152. LPCWSTR DT_AdjustWhiteSpaces(LPCWSTR lpStNext, LPINT lpiCount, UINT wFormat)
  1153. {
  1154. switch(wFormat & DT_HFMTMASK) {
  1155. case DT_LEFT:
  1156. // Prevent a white space at the begining of a left justfied text.
  1157. // Is there a white space at the begining of next line......
  1158. if((*lpStNext == TEXT(' ')) || (*lpStNext == TEXT('\t'))) {
  1159. // ...then, exclude it from next line.
  1160. lpStNext++;
  1161. }
  1162. break;
  1163. case DT_RIGHT:
  1164. // Prevent a white space at the end of a RIGHT justified text.
  1165. // Is there a white space at the end of current line,.......
  1166. if((*(lpStNext-1) == TEXT(' ')) || (*(lpStNext - 1) == TEXT('\t'))) {
  1167. // .....then, Skip the white space from the current line.
  1168. (*lpiCount)--;
  1169. }
  1170. break;
  1171. case DT_CENTER:
  1172. // Exclude white spaces from the begining and end of CENTERed lines.
  1173. // If there is a white space at the end of current line.......
  1174. if((*(lpStNext-1) == TEXT(' ')) || (*(lpStNext - 1) == TEXT('\t')))
  1175. (*lpiCount)--; //...., don't count it for justification.
  1176. // If there is a white space at the begining of next line.......
  1177. if((*lpStNext == TEXT(' ')) || (*lpStNext == TEXT('\t')))
  1178. lpStNext++; //...., exclude it from next line.
  1179. break;
  1180. }
  1181. return lpStNext;
  1182. }
  1183. /***************************************************************************\
  1184. * DT_BreakAWord
  1185. * A word needs to be broken across lines and this finds out where to
  1186. * break it.
  1187. \***************************************************************************/
  1188. LPCWSTR DT_BreakAWord(HDC hdc, LPCWSTR lpchText,
  1189. int iLength, int iWidth, UINT wFormat, int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  1190. {
  1191. int iLow = 0, iHigh = iLength;
  1192. int iNew;
  1193. while((iHigh - iLow) > 1) {
  1194. iNew = iLow + (iHigh - iLow)/2;
  1195. if(DT_GetExtentMinusPrefixes(hdc, lpchText, iNew, wFormat, iOverhang, lpDrawInfo, iCharSet) > iWidth)
  1196. iHigh = iNew;
  1197. else
  1198. iLow = iNew;
  1199. }
  1200. // If the width is too low, we must print atleast one char per line.
  1201. // Else, we will be in an infinite loop.
  1202. if(!iLow && iLength)
  1203. iLow = 1;
  1204. return (lpchText+iLow);
  1205. }
  1206. /***************************************************************************\
  1207. * DT_GetLineBreak
  1208. * This finds out the location where we can break a line.
  1209. * Returns LPCSTR to the begining of next line.
  1210. * Also returns via lpiLineLength, the length of the current line.
  1211. * NOTE: (lpstNextLineStart - lpstCurrentLineStart) is not equal to the
  1212. * line length; This is because, we exclude some white spaces at the begining
  1213. * and/or end of lines; Also, CR/LF is excluded from the line length.
  1214. \***************************************************************************/
  1215. LPWSTR DT_GetLineBreak(
  1216. HDC hdc,
  1217. LPCWSTR lpchLineStart,
  1218. int cchCount,
  1219. DWORD dwFormat,
  1220. LPINT lpiLineLength,
  1221. LPDRAWTEXTDATA lpDrawInfo,
  1222. int iCharSet)
  1223. {
  1224. LPCWSTR lpchText, lpchEnd, lpch, lpchLineEnd;
  1225. int cxStart, cxExtent, cxNewExtent;
  1226. BOOL fAdjustWhiteSpaces = FALSE;
  1227. WCHAR ch;
  1228. DWORD dwCodePage = USERGETCODEPAGE(hdc);
  1229. cxStart = lpDrawInfo->rcFormat.left;
  1230. cxExtent = cxNewExtent = 0;
  1231. lpchText = lpchLineStart;
  1232. lpchEnd = lpchLineStart + cchCount;
  1233. while(lpchText < lpchEnd) {
  1234. lpchLineEnd = lpch = GetNextWordbreak(dwCodePage,lpchText, lpchEnd, dwFormat, lpDrawInfo);
  1235. // DT_DrawStr does not return the overhang; Otherwise we will end up
  1236. // adding one overhang for every word in the string.
  1237. // For simulated Bold fonts, the summation of extents of individual
  1238. // words in a line is greater than the extent of the whole line. So,
  1239. // always calculate extent from the LineStart.
  1240. // BUGTAG: #6054 -- Win95B -- SANKAR -- 3/9/95 --
  1241. cxNewExtent = DT_DrawStr(hdc, cxStart, 0, lpchLineStart, (int)(((PBYTE)lpch - (PBYTE)lpchLineStart)/sizeof(WCHAR)), FALSE,
  1242. dwFormat, lpDrawInfo, iCharSet);
  1243. if (WORDBREAK(dwFormat) && ((cxNewExtent + lpDrawInfo->cxOverhang) > lpDrawInfo->cxMaxWidth)) {
  1244. // Are there more than one word in this line?
  1245. if (lpchText != lpchLineStart) {
  1246. lpchLineEnd = lpch = lpchText;
  1247. fAdjustWhiteSpaces = TRUE;
  1248. } else {
  1249. //One word is longer than the maximum width permissible.
  1250. //See if we are allowed to break that single word.
  1251. if(EDITCONTROL(dwFormat) && !WORDELLIPSIS(dwFormat)) {
  1252. lpchLineEnd = lpch = DT_BreakAWord(hdc, lpchText, (int)(((PBYTE)lpch - (PBYTE)lpchText)/sizeof(WCHAR)),
  1253. lpDrawInfo->cxMaxWidth - cxExtent,
  1254. dwFormat,
  1255. lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet); //Break that word
  1256. //Note: Since we broke in the middle of a word, no need to
  1257. // adjust for white spaces.
  1258. } else {
  1259. fAdjustWhiteSpaces = TRUE;
  1260. // Check if we need to end this line with ellipsis
  1261. if(WORDELLIPSIS(dwFormat))
  1262. {
  1263. // Don't do this if already at the end of the string.
  1264. if (lpch < lpchEnd)
  1265. {
  1266. // If there are CR/LF at the end, skip them.
  1267. if ((ch = *lpch) == CR || ch == LF)
  1268. {
  1269. if ((++lpch < lpchEnd) && (*lpch == (WCHAR)(ch ^ (LF ^ CR))))
  1270. lpch++;
  1271. fAdjustWhiteSpaces = FALSE;
  1272. }
  1273. }
  1274. }
  1275. }
  1276. }
  1277. // Well! We found a place to break the line. Let us break from this
  1278. // loop;
  1279. break;
  1280. } else {
  1281. // Don't do this if already at the end of the string.
  1282. if (lpch < lpchEnd) {
  1283. if ((ch = *lpch) == CR || ch == LF) {
  1284. if ((++lpch < lpchEnd) && (*lpch == (WCHAR)(ch ^ (LF ^ CR))))
  1285. lpch++;
  1286. fAdjustWhiteSpaces = FALSE;
  1287. break;
  1288. }
  1289. }
  1290. }
  1291. // Point at the beginning of the next word.
  1292. lpchText = lpch;
  1293. cxExtent = cxNewExtent;
  1294. }
  1295. // Calculate the length of current line.
  1296. *lpiLineLength = (INT)((PBYTE)lpchLineEnd - (PBYTE)lpchLineStart)/sizeof(WCHAR);
  1297. // Adjust the line length and lpch to take care of spaces.
  1298. if(fAdjustWhiteSpaces && (lpch < lpchEnd))
  1299. lpch = DT_AdjustWhiteSpaces(lpch, lpiLineLength, dwFormat);
  1300. // return the begining of next line;
  1301. return (LPWSTR)lpch;
  1302. }
  1303. /***************************************************************************\
  1304. * NeedsEndEllipsis()
  1305. * This function checks whether the given string fits within the given
  1306. * width or we need to add end-ellipse. If it required end-ellipses, it
  1307. * returns TRUE and it returns the number of characters that are saved
  1308. * in the given string via lpCount.
  1309. \***************************************************************************/
  1310. BOOL NeedsEndEllipsis(HDC hdc,
  1311. LPCWSTR lpchText,
  1312. LPINT lpCount,
  1313. LPDRAWTEXTDATA lpDTdata,
  1314. UINT wFormat, LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  1315. {
  1316. int cchText;
  1317. int ichMin, ichMax, ichMid;
  1318. int cxMaxWidth;
  1319. int iOverhang;
  1320. int cxExtent;
  1321. SIZE size;
  1322. cchText = *lpCount; // Get the current count.
  1323. if (cchText == 0)
  1324. return FALSE;
  1325. cxMaxWidth = lpDTdata->cxMaxWidth;
  1326. iOverhang = lpDTdata->cxOverhang;
  1327. cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchText, cchText, wFormat, iOverhang, lpDrawInfo, iCharSet);
  1328. if (cxExtent <= cxMaxWidth)
  1329. return FALSE;
  1330. // Reserve room for the "..." ellipses;
  1331. // (Assumption: The ellipses don't have any prefixes!)
  1332. UserGetTextExtentPointW(hdc, szEllipsis, CCHELLIPSIS, &size);
  1333. cxMaxWidth -= size.cx - iOverhang;
  1334. // If no room for ellipses, always show first character.
  1335. //
  1336. ichMax = 1;
  1337. if (cxMaxWidth > 0) {
  1338. // Binary search to find characters that will fit.
  1339. ichMin = 0;
  1340. ichMax = cchText;
  1341. while (ichMin < ichMax) {
  1342. // Be sure to round up, to make sure we make progress in
  1343. // the loop if ichMax == ichMin + 1.
  1344. //
  1345. ichMid = (ichMin + ichMax + 1) / 2;
  1346. cxExtent = DT_GetExtentMinusPrefixes(hdc, lpchText, ichMid, wFormat, iOverhang, lpDrawInfo, iCharSet);
  1347. if (cxExtent < cxMaxWidth)
  1348. ichMin = ichMid;
  1349. else {
  1350. if (cxExtent > cxMaxWidth)
  1351. ichMax = ichMid - 1;
  1352. else {
  1353. // Exact match up up to ichMid: just exit.
  1354. //
  1355. ichMax = ichMid;
  1356. break;
  1357. }
  1358. }
  1359. }
  1360. // Make sure we always show at least the first character...
  1361. //
  1362. if (ichMax < 1)
  1363. ichMax = 1;
  1364. }
  1365. *lpCount = ichMax;
  1366. return TRUE;
  1367. }
  1368. /***************************************************************************\
  1369. * BOGUS: The same function is available in SHELL2.DLL also.
  1370. * We need to remove from one of the places.
  1371. \***************************************************************************/
  1372. // Returns a pointer to the last component of a path string.
  1373. //
  1374. // in:
  1375. // path name, either fully qualified or not
  1376. //
  1377. // returns:
  1378. // pointer into the path where the path is. if none is found
  1379. // returns a poiter to the start of the path
  1380. //
  1381. // c:\foo\bar -> bar
  1382. // c:\foo -> foo
  1383. // c:\foo\ -> c:\foo\ (REVIEW: is this case busted?)
  1384. // c:\ -> c:\ (REVIEW: this case is strange)
  1385. // c: -> c:
  1386. // foo -> foo
  1387. /***************************************************************************\
  1388. \***************************************************************************/
  1389. LPWSTR PathFindFileName(LPCWSTR pPath, int cchText)
  1390. {
  1391. LPCWSTR pT;
  1392. for (pT = pPath; cchText > 0 && *pPath; pPath++, cchText--) {
  1393. if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1])
  1394. pT = pPath + 1;
  1395. }
  1396. return (LPWSTR)pT; // REVIEW, should this be const?
  1397. }
  1398. /***************************************************************************\
  1399. * AddPathEllipse():
  1400. * This adds a path ellipse to the given path name.
  1401. * Returns TRUE if the resultant string's extent is less the the
  1402. * cxMaxWidth. FALSE, if otherwise.
  1403. \***************************************************************************/
  1404. int AddPathEllipsis(
  1405. HDC hDC,
  1406. LPWSTR lpszPath,
  1407. int cchText,
  1408. UINT wFormat,
  1409. int cxMaxWidth,
  1410. int iOverhang, LPDRAWTEXTDATA lpDrawInfo, int iCharSet)
  1411. {
  1412. int iLen;
  1413. UINT dxFixed, dxEllipsis;
  1414. LPWSTR lpEnd; /* end of the unfixed string */
  1415. LPWSTR lpFixed; /* start of text that we always display */
  1416. BOOL bEllipsisIn;
  1417. int iLenFixed;
  1418. SIZE size;
  1419. lpFixed = PathFindFileName(lpszPath, cchText);
  1420. if (lpFixed != lpszPath)
  1421. lpFixed--; // point at the slash
  1422. else
  1423. return cchText;
  1424. lpEnd = lpFixed;
  1425. bEllipsisIn = FALSE;
  1426. iLenFixed = cchText - (int)(lpFixed - lpszPath);
  1427. dxFixed = DT_GetExtentMinusPrefixes(hDC, lpFixed, iLenFixed, wFormat, iOverhang, lpDrawInfo, iCharSet);
  1428. // It is assumed that the "..." string does not have any prefixes ('&').
  1429. UserGetTextExtentPointW(hDC, szEllipsis, CCHELLIPSIS, &size);
  1430. dxEllipsis = size.cx - iOverhang;
  1431. while (TRUE) {
  1432. iLen = dxFixed + DT_GetExtentMinusPrefixes(hDC, lpszPath, (int)((PBYTE)lpEnd - (PBYTE)lpszPath)/sizeof(WCHAR),
  1433. wFormat, iOverhang, lpDrawInfo, iCharSet) - iOverhang;
  1434. if (bEllipsisIn)
  1435. iLen += dxEllipsis;
  1436. if (iLen <= cxMaxWidth)
  1437. break;
  1438. bEllipsisIn = TRUE;
  1439. if (lpEnd <= lpszPath) {
  1440. /* Things didn't fit. */
  1441. lpEnd = lpszPath;
  1442. break;
  1443. }
  1444. /* Step back a character. */
  1445. lpEnd--;
  1446. }
  1447. if (bEllipsisIn && (lpEnd + CCHELLIPSIS < lpFixed)) {
  1448. // NOTE: the strings could over lap here. So, we use LCopyStruct.
  1449. RtlMoveMemory((lpEnd + CCHELLIPSIS), lpFixed, iLenFixed * sizeof(WCHAR));
  1450. RtlCopyMemory(lpEnd, szEllipsis, CCHELLIPSIS * sizeof(WCHAR));
  1451. cchText = (int)(lpEnd - lpszPath) + CCHELLIPSIS + iLenFixed;
  1452. // now we can NULL terminate the string
  1453. *(lpszPath + cchText) = TEXT('\0');
  1454. }
  1455. return cchText;
  1456. }
  1457. //-----------------------------------------------------------------------
  1458. // This function returns the number of characters actually drawn.
  1459. //-----------------------------------------------------------------------
  1460. int AddEllipsisAndDrawLine(
  1461. HDC hdc,
  1462. int yLine,
  1463. LPCWSTR lpchText,
  1464. int cchText,
  1465. DWORD dwDTformat,
  1466. LPDRAWTEXTDATA lpDrawInfo,
  1467. int iCharSet)
  1468. {
  1469. LPWSTR pEllipsis = NULL;
  1470. WCHAR szTempBuff[MAXBUFFSIZE];
  1471. LPWSTR lpDest;
  1472. BOOL fAlreadyCopied = FALSE;
  1473. // Check if this is a filename with a path AND
  1474. // Check if the width is too narrow to hold all the text.
  1475. if(PATHELLIPSIS(dwDTformat) &&
  1476. ((DT_GetExtentMinusPrefixes(hdc, lpchText, cchText,
  1477. dwDTformat, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet)) > lpDrawInfo->cxMaxWidth)) {
  1478. // We need to add Path-Ellipsis. See if we can do it in-place.
  1479. if(!MODIFYSTRING(dwDTformat)) {
  1480. // NOTE: When you add Path-Ellipsis, the string could grow by
  1481. // CCHELLIPSIS bytes.
  1482. if((cchText + CCHELLIPSIS + 1) <= MAXBUFFSIZE)
  1483. lpDest = szTempBuff;
  1484. else { // Alloc from local heap.
  1485. // Alloc the buffer from local heap.
  1486. if(!(pEllipsis = (LPWSTR)UserRtlAllocMem(
  1487. (cchText+CCHELLIPSIS+1)*sizeof(WCHAR))))
  1488. return 0;
  1489. lpDest = (LPWSTR)pEllipsis;
  1490. }
  1491. // Source String may not be NULL terminated. So, copy just
  1492. // the given number of characters.
  1493. RtlCopyMemory(lpDest, lpchText, cchText*sizeof(WCHAR));
  1494. lpchText = lpDest; // lpchText points to the copied buff.
  1495. fAlreadyCopied = TRUE; // Local copy has been made.
  1496. }
  1497. // Add the path ellipsis now!
  1498. cchText = AddPathEllipsis(hdc, (LPWSTR)lpchText, cchText, dwDTformat,
  1499. lpDrawInfo->cxMaxWidth, lpDrawInfo->cxOverhang, lpDrawInfo, iCharSet);
  1500. }
  1501. // Check if end-ellipsis are to be added.
  1502. if((ENDELLIPSIS(dwDTformat) || WORDELLIPSIS(dwDTformat)) &&
  1503. NeedsEndEllipsis(hdc, lpchText, &cchText, lpDrawInfo, dwDTformat, lpDrawInfo, iCharSet)) {
  1504. // We need to add end-ellipsis; See if we can do it in-place.
  1505. if(!MODIFYSTRING(dwDTformat) && !fAlreadyCopied) {
  1506. // See if the string is small enough for the buff on stack.
  1507. if((cchText+CCHELLIPSIS+1) <= MAXBUFFSIZE)
  1508. lpDest = szTempBuff; // If so, use it.
  1509. else {
  1510. // Alloc the buffer from local heap.
  1511. if(!(pEllipsis = (LPWSTR)UserRtlAllocMem(
  1512. (cchText+CCHELLIPSIS+1)*sizeof(WCHAR))))
  1513. return 0;
  1514. lpDest = pEllipsis;
  1515. }
  1516. // Make a copy of the string in the local buff.
  1517. RtlCopyMemory(lpDest, lpchText, cchText*sizeof(WCHAR));
  1518. lpchText = lpDest;
  1519. }
  1520. // Add an end-ellipsis at the proper place.
  1521. RtlCopyMemory((LPWSTR)(lpchText+cchText), szEllipsis, (CCHELLIPSIS+1)*sizeof(WCHAR));
  1522. cchText += CCHELLIPSIS;
  1523. }
  1524. // Draw the line that we just formed.
  1525. DT_DrawJustifiedLine(hdc, yLine, lpchText, cchText, dwDTformat, lpDrawInfo, iCharSet);
  1526. // Free the block allocated for End-Ellipsis.
  1527. if(pEllipsis)
  1528. UserRtlFreeMem(pEllipsis);
  1529. return cchText;
  1530. }
  1531. /***************************************************************************\
  1532. * IDrawTextEx
  1533. * This is the new DrawText API
  1534. \***************************************************************************/
  1535. /***************************************************************************\
  1536. * IDrawTextEx
  1537. * This is the new DrawText API
  1538. \***************************************************************************/
  1539. int DrawTextExW(
  1540. HDC hdc,
  1541. LPWSTR lpchText,
  1542. int cchText,
  1543. LPRECT lprc,
  1544. UINT dwDTformat,
  1545. LPDRAWTEXTPARAMS lpDTparams)
  1546. {
  1547. /*
  1548. * The LPK requires a charset. The Unicode entry point always passes a -1,
  1549. * but the ANSI entry point passes a more interesting value. Both the
  1550. * 'W' version and 'A' version of DrawTextEx call this common worker routine.
  1551. */
  1552. return DrawTextExWorker(hdc, lpchText, cchText, lprc, dwDTformat, lpDTparams, -1);
  1553. }
  1554. int DrawTextExWorker(
  1555. HDC hdc,
  1556. LPWSTR lpchText,
  1557. int cchText,
  1558. LPRECT lprc,
  1559. UINT dwDTformat,
  1560. LPDRAWTEXTPARAMS lpDTparams,
  1561. int iCharset)
  1562. {
  1563. DRAWTEXTDATA DrawInfo;
  1564. WORD wFormat = LOWORD(dwDTformat);
  1565. LPWSTR lpchTextBegin;
  1566. LPWSTR lpchEnd;
  1567. LPWSTR lpchNextLineSt;
  1568. int iLineLength;
  1569. int iySign;
  1570. int yLine;
  1571. int yLastLineHeight;
  1572. HRGN hrgnClip;
  1573. int iLineCount;
  1574. RECT rc;
  1575. BOOL fLastLine;
  1576. WCHAR ch;
  1577. UINT oldAlign;
  1578. #if DBG
  1579. if (dwDTformat & ~DT_VALID)
  1580. RIPMSG0 (RIP_WARNING, "DrawTextExW: Invalid dwDTformat flags");
  1581. #endif
  1582. if (lpchText == NULL) {
  1583. return 0;
  1584. }
  1585. if (cchText == 0 && *lpchText) {
  1586. /*
  1587. * infoview.exe passes lpchText that points to '\0'
  1588. *
  1589. * "Microsoft Expedia Streets and Trips 2000" and "MS MapPoint 2000"
  1590. * tries cchText == 0 to detect if DrawTextW is supported.
  1591. */
  1592. /* Added by Chicago:
  1593. * Lotus Notes doesn't like getting a zero return here
  1594. */
  1595. return 1;
  1596. }
  1597. if (cchText == -1)
  1598. cchText = wcslen(lpchText);
  1599. if ((lpDTparams) && (lpDTparams->cbSize != sizeof(DRAWTEXTPARAMS))) {
  1600. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "DrawTextEx: cbSize %ld is invalid",
  1601. lpDTparams->cbSize);
  1602. return 0;
  1603. }
  1604. #ifdef LATER
  1605. /*
  1606. * If DT_MODIFYSTRING is specified, then check for read-write pointer.
  1607. */
  1608. if (MODIFYSTRING(dwDTformat) &&
  1609. (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat))) {
  1610. if(IsBadWritePtr(lpchText, cchText)) {
  1611. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "DrawTextEx: For DT_MODIFYSTRING, lpchText must be read-write");
  1612. return(0);
  1613. }
  1614. }
  1615. #endif
  1616. /*
  1617. * Initialize the DrawInfo structure.
  1618. */
  1619. if (!DT_InitDrawTextInfo(hdc, lprc, dwDTformat, (LPDRAWTEXTDATA)&DrawInfo, lpDTparams))
  1620. return 0;
  1621. DrawInfo.iCharset = iCharset;
  1622. /*
  1623. * If the rect is too narrow or the margins are too wide.....Just forget it!
  1624. *
  1625. * If wordbreak is specified, the MaxWidth must be a reasonable value.
  1626. * This check is sufficient because this will allow CALCRECT and NOCLIP
  1627. * cases. --SANKAR.
  1628. *
  1629. * This also fixed all of our known problems with AppStudio.
  1630. */
  1631. if (DrawInfo.cxMaxWidth <= 0) {
  1632. /*
  1633. * We used to return a non-zero value in win31.
  1634. * If the kernel calls this we are always Ver 4.0 or above
  1635. */
  1636. #ifdef _USERK_
  1637. if (0) {
  1638. #else
  1639. if (GETAPPVER() < VER40) {
  1640. #endif
  1641. if((DrawInfo.cxMaxWidth == 0) && !CALCRECT(wFormat)) {
  1642. return(1);
  1643. }
  1644. } else {
  1645. if (WORDBREAK(wFormat)) {
  1646. RIPMSG0 (RIP_WARNING, "DrawTextExW: FAILURE DrawInfo.cxMaxWidth <=0");
  1647. return (1);
  1648. }
  1649. }
  1650. }
  1651. /*
  1652. * if we're not doing the drawing, initialise the lpk-dll
  1653. */
  1654. if (RTLREADING(dwDTformat)) {
  1655. oldAlign = UserSetTextAlign(hdc, TA_RTLREADING | UserGetTextAlign(hdc));
  1656. }
  1657. /*
  1658. * If we need to clip, let us do that.
  1659. */
  1660. if (!NOCLIP(wFormat)) {
  1661. //
  1662. // Save clipping region so we can restore it later.
  1663. //
  1664. // hrgnSave = SaveClipRgn(hdc);
  1665. // IntersectClipRect(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
  1666. hrgnClip = UserCreateRectRgn(0,0,0,0);
  1667. if (hrgnClip != NULL) {
  1668. if (UserGetClipRgn(hdc, hrgnClip) != 1) {
  1669. UserDeleteObject(hrgnClip);
  1670. hrgnClip = (HRGN)-1;
  1671. }
  1672. rc = *lprc;
  1673. UserIntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  1674. }
  1675. } else {
  1676. hrgnClip = NULL;
  1677. }
  1678. lpchTextBegin = lpchText;
  1679. lpchEnd = lpchText + cchText;
  1680. ProcessDrawText:
  1681. iLineCount = 0; // Reset number of lines to 1.
  1682. yLine = lprc->top;
  1683. if (SINGLELINE(wFormat)) {
  1684. iLineCount = 1; // It is a single line.
  1685. /*
  1686. * Process single line DrawText.
  1687. */
  1688. switch (wFormat & DT_VFMTMASK) {
  1689. case DT_BOTTOM:
  1690. yLine = lprc->bottom - DrawInfo.cyLineHeight;
  1691. break;
  1692. case DT_VCENTER:
  1693. yLine = lprc->top + ((lprc->bottom - lprc->top - DrawInfo.cyLineHeight) / 2);
  1694. break;
  1695. }
  1696. cchText = AddEllipsisAndDrawLine(hdc, yLine, lpchText, cchText, dwDTformat, &DrawInfo, iCharset);
  1697. yLine += DrawInfo.cyLineHeight;
  1698. lpchText += cchText;
  1699. } else {
  1700. /*
  1701. * Multiline
  1702. * If the height of the rectangle is not an integral multiple of the
  1703. * average char height, then it is possible that the last line drawn
  1704. * is only partially visible. However, if DT_EDITCONTROL style is
  1705. * specified, then we must make sure that the last line is not drawn if
  1706. * it is going to be partially visible. This will help imitate the
  1707. * appearance of an edit control.
  1708. */
  1709. if (EDITCONTROL(wFormat))
  1710. yLastLineHeight = DrawInfo.cyLineHeight;
  1711. else
  1712. yLastLineHeight = 0;
  1713. iySign = DrawInfo.iYSign;
  1714. fLastLine = FALSE;
  1715. // Process multiline DrawText.
  1716. while ((lpchText < lpchEnd) && (!fLastLine)) {
  1717. // Check if the line we are about to draw is the last line that needs
  1718. // to be drawn.
  1719. // Let us check if the display goes out of the clip rect and if so
  1720. // let us stop here, as an optimisation;
  1721. if (!CALCRECT(wFormat) && // We don't need to calc rect?
  1722. (!NOCLIP(wFormat)) && // Must we clip the display ?
  1723. // Are we outside the rect?
  1724. ((yLine + DrawInfo.cyLineHeight + yLastLineHeight)*iySign > (lprc->bottom*iySign))) {
  1725. fLastLine = TRUE; // Let us quit this loop
  1726. }
  1727. /*
  1728. * We do the Ellipsis processing only for the last line.
  1729. */
  1730. if (fLastLine && (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat))) {
  1731. lpchText += AddEllipsisAndDrawLine(hdc, yLine, lpchText, cchText, dwDTformat, &DrawInfo, iCharset);
  1732. } else {
  1733. lpchNextLineSt = (LPWSTR)DT_GetLineBreak(hdc, lpchText, cchText, dwDTformat, &iLineLength, &DrawInfo, iCharset);
  1734. /*
  1735. * Check if we need to put ellipsis at the end of this line.
  1736. * Also check if this is the last line.
  1737. */
  1738. if (WORDELLIPSIS(dwDTformat) ||
  1739. ((lpchNextLineSt >= lpchEnd) && (ENDELLIPSIS(dwDTformat) || PATHELLIPSIS(dwDTformat))))
  1740. AddEllipsisAndDrawLine(hdc, yLine, lpchText, iLineLength, dwDTformat, &DrawInfo, iCharset);
  1741. else
  1742. DT_DrawJustifiedLine(hdc, yLine, lpchText, iLineLength, dwDTformat, &DrawInfo, iCharset);
  1743. cchText -= (int)((PBYTE)lpchNextLineSt - (PBYTE)lpchText) / sizeof(WCHAR);
  1744. lpchText = lpchNextLineSt;
  1745. }
  1746. iLineCount++; // We draw one more line.
  1747. yLine += DrawInfo.cyLineHeight;
  1748. }
  1749. /*
  1750. * For Win3.1 and NT compatibility, if the last char is a CR or a LF
  1751. * then the height returned includes one more line.
  1752. */
  1753. if (!EDITCONTROL(dwDTformat) &&
  1754. (lpchEnd > lpchTextBegin) && // If zero length it will fault.
  1755. (((ch = (*(lpchEnd-1))) == CR) || (ch == LF)))
  1756. yLine += DrawInfo.cyLineHeight;
  1757. }
  1758. /*
  1759. * If DT_CALCRECT, modify width and height of rectangle to include
  1760. * all of the text drawn.
  1761. */
  1762. if (CALCRECT(wFormat)) {
  1763. DrawInfo.rcFormat.right = DrawInfo.rcFormat.left + DrawInfo.cxMaxExtent * DrawInfo.iXSign;
  1764. lprc->right = DrawInfo.rcFormat.right + DrawInfo.cxRightMargin;
  1765. // If the Width is more than what was provided, we have to redo all
  1766. // the calculations, because, the number of lines can be less now.
  1767. // (We need to do this only if we have more than one line).
  1768. if((iLineCount > 1) && (DrawInfo.cxMaxExtent > DrawInfo.cxMaxWidth)) {
  1769. DrawInfo.cxMaxWidth = DrawInfo.cxMaxExtent;
  1770. lpchText = lpchTextBegin;
  1771. cchText = (int)((PBYTE)lpchEnd - (PBYTE)lpchTextBegin)/sizeof(WCHAR);
  1772. goto ProcessDrawText; // Start all over again!
  1773. }
  1774. lprc->bottom = yLine;
  1775. }
  1776. // if (!NOCLIP(wFormat))
  1777. // {
  1778. // RestoreClipRgn(hdc, hrgnClip);
  1779. // }
  1780. if (hrgnClip != NULL) {
  1781. if (hrgnClip == (HRGN)-1) {
  1782. UserExtSelectClipRgn(hdc, NULL, RGN_COPY);
  1783. } else {
  1784. UserExtSelectClipRgn(hdc, hrgnClip, RGN_COPY);
  1785. UserDeleteObject(hrgnClip);
  1786. }
  1787. }
  1788. if (RTLREADING(dwDTformat))
  1789. UserSetTextAlign(hdc, oldAlign);
  1790. /*
  1791. * Copy the number of characters actually drawn
  1792. */
  1793. if(lpDTparams != NULL)
  1794. lpDTparams->uiLengthDrawn = (UINT)((PBYTE)lpchText - (PBYTE)lpchTextBegin)/sizeof(WCHAR);
  1795. if (yLine == lprc->top)
  1796. return 1;
  1797. return (yLine - lprc->top);
  1798. }
  1799. /***************************************************************************\
  1800. *
  1801. * IsSysFontAndDefaultMode()
  1802. *
  1803. * Returns TRUE if font selected into DC is the system font AND the current
  1804. * mapping mode of the DC is MM_TEXT (Default mode); else returns FALSE. This
  1805. * is called by interrupt time code so it needs to be in the fixed code
  1806. * segment.
  1807. *
  1808. * History:
  1809. * 07-Jul-95 BradG Ported from Win95
  1810. \***************************************************************************/
  1811. BOOL IsSysFontAndDefaultMode(HDC hdc)
  1812. {
  1813. return((UserGetHFONT(hdc) == ghFontSys) && (UserGetMapMode(hdc) == MM_TEXT));
  1814. }