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.

636 lines
21 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // Module Name : LPK_USER.c //
  4. // //
  5. // Entry points (formal interfaces) for GDI32 to call //
  6. // and route their APIs, so that we can implement our language-specific //
  7. // features. //
  8. // //
  9. // Created : Nov 6, 1996 //
  10. // Author : Mohamed AbdEl Hamid [mhamid] //
  11. // //
  12. // Copyright (c) 1996, Microsoft Corporation. All rights reserved. //
  13. //////////////////////////////////////////////////////////////////////////////
  14. #include "precomp.hxx"
  15. ///// Shared definitions for USER code
  16. #define IS_ALTDC_TYPE(h) (LO_TYPE(h) != LO_DC_TYPE)
  17. ///
  18. #undef TRACE
  19. #define TRACE(a,b)
  20. //////////////////////////////////////////////////////////////////////////////
  21. // USER32 TabbedTextOut will call this function for supporting Multilingual //
  22. // Tabbed Text handling. //
  23. // LpkTabbedTextOut( HDC hdc , int x, int y, LPCWSTR lpstring, UINT nCount, //
  24. // int nTabPositions, LPINT lpTabPositions, int iTabOrigin,//
  25. // BOOL fDrawTheText, int cxCharWidth, int cyCharHeight, //
  26. // int charSet) //
  27. // hDC : Handle of device context //
  28. // x : x-coordinate of text to render //
  29. // y : y-coordinate of text to render //
  30. // lpstring : Input string //
  31. // nCount : Count of characters in input string //
  32. // nTabPositions : Specifies the number of values in the array of //
  33. // tab-stop positions. //
  34. // lpTabPositions : The tab-stop positions array (increasing order)(+/-)//
  35. // iTabOrigin : The X-coordinate position to start expand tabs //
  36. // fDrawTheText : Draw the Text or expand tha tabs only //
  37. // cxCharWidth : Character width to be use to expand the tabs //
  38. // cxCharHeight : Character Height to be use to expand the tabs //
  39. // charSet : Indicates character set of codes. to optimizing the work. ??//
  40. // //
  41. // Return : //
  42. // If the function succeeds, return the string dimensions //
  43. // Else, the return value is 0. //
  44. // And we seted the error by call SetLastError. //
  45. // //
  46. // History : //
  47. // Nov 6, 1996 -by- Mohamed AbdEl Hamid [mhamid] //
  48. //////////////////////////////////////////////////////////////////////////////
  49. LONG LpkTabbedTextOut(
  50. HDC hdc,
  51. int x,
  52. int y,
  53. WCHAR *pwcInChars,
  54. int nCount,
  55. int nTabPositions,
  56. int *pTabPositions,
  57. int iTabOrigin,
  58. BOOL fDrawTheText,
  59. int cxCharWidth,
  60. int cyCharHeight,
  61. int iCharset) {
  62. SIZE textextent;
  63. SIZE viewextent;
  64. SIZE windowextent;
  65. int initialx = x;
  66. int cch;
  67. WCHAR *pwc;
  68. int iOneTab = 0;
  69. RECT rc;
  70. UINT uOpaque;
  71. BOOL fStrStart = TRUE;
  72. BOOL fRTLreading;
  73. int ySign = 1; //Assume y increases in down direction.
  74. UINT OldTextAlign;
  75. HRESULT hr;
  76. DWORD dwObjType;
  77. RECT rcRTL;
  78. STRING_ANALYSIS *psa;
  79. uOpaque = (GetBkMode(hdc) == OPAQUE) ? ETO_OPAQUE : 0;
  80. /*
  81. * If no tabstop positions are specified, then use a default of 8 system
  82. * font ave char widths or use the single fixed tab stop.
  83. */
  84. if (!pTabPositions) {
  85. // no tab stops specified -- default to a tab stop every 8 characters
  86. iOneTab = 8 * cxCharWidth;
  87. } else if (nTabPositions == 1) {
  88. // one tab stop specified -- treat value as the tab increment, one
  89. // tab stop every increment
  90. iOneTab = pTabPositions[0];
  91. if (!iOneTab) {
  92. iOneTab = 1;
  93. }
  94. }
  95. // Calculate if the y increases or decreases in the down direction using
  96. // the ViewPortExtent and WindowExtents.
  97. // If this call fails, hdc must be invalid
  98. if (!GetViewportExtEx(hdc, &viewextent)) {
  99. TRACEMSG(("LpkTabbedTextOut: GetViewportExtEx failed"));
  100. return 0;
  101. }
  102. GetWindowExtEx(hdc, &windowextent);
  103. if ((viewextent.cy ^ windowextent.cy) & 0x80000000) {
  104. ySign = -1;
  105. }
  106. OldTextAlign = GetTextAlign(hdc);
  107. fRTLreading = OldTextAlign & TA_RTLREADING;
  108. SetTextAlign(hdc, (OldTextAlign & ~(TA_CENTER|TA_RIGHT)) | TA_LEFT);
  109. rc.left = initialx;
  110. rc.right= initialx;
  111. rc.top = y;
  112. if (OldTextAlign & TA_BOTTOM) {
  113. rc.bottom = rc.top;
  114. } else {
  115. rc.bottom = rc.top + (ySign * cyCharHeight);
  116. }
  117. while (TRUE) {
  118. // count the number of characters until the next tab character
  119. // this set of characters (substring) will be the working set for
  120. // each iteration of this loop
  121. for (cch = nCount, pwc = pwcInChars; cch && (*pwc != TEXT('\t')); pwc++, cch--) {
  122. }
  123. // Compute the number of characters to be drawn with textout.
  124. cch = nCount - cch;
  125. // Compute the number of characters remaining.
  126. nCount -= cch; // + 1;
  127. // get height and width of substring
  128. if (cch == 0) {
  129. textextent.cx = 0;
  130. textextent.cy = cyCharHeight;
  131. psa = NULL;
  132. } else {
  133. dwObjType = GetObjectType(hdc);
  134. hr = LpkStringAnalyse(
  135. hdc, pwcInChars, cch, 0, -1,
  136. SSA_GLYPHS
  137. | (dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_METAFILE : 0)
  138. | (iCharset==-1 || GdiIsPlayMetafileDC(hdc) ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
  139. | (fRTLreading ? SSA_RTL : 0),
  140. -1, 0,
  141. NULL, NULL, NULL, NULL, NULL,
  142. &psa);
  143. if (FAILED(hr)) {
  144. ASSERTHR(hr, ("LpkTabbedTextOut - LpkStringAnalyse"));
  145. return FALSE;
  146. }
  147. textextent = psa->size;
  148. }
  149. if (fStrStart) {
  150. // first iteration should just spit out the first substring
  151. // no tabbing occurs until the first tab character is encountered
  152. fStrStart = FALSE;
  153. } else {
  154. // not the first iteration -- tab accordingly
  155. int xTab;
  156. int i;
  157. if (!iOneTab) {
  158. // look thru tab stop array for next tab stop after existing
  159. // text to put this substring
  160. for (i = 0; i != nTabPositions; i++) {
  161. xTab = pTabPositions[i];
  162. if (xTab < 0) {
  163. // calc length needed to use this right justified tab
  164. xTab = iTabOrigin - xTab - textextent.cx;
  165. } else {
  166. // calc length needed to use this left justified tab
  167. xTab = iTabOrigin + xTab;
  168. }
  169. if ((xTab - x) > 0) {
  170. // we found a tab with enough room -- let's use it
  171. x = xTab;
  172. break;
  173. }
  174. }
  175. if (i == nTabPositions) {
  176. // we've exhausted all of the given tab positions
  177. // go back to default of a tab stop every 8 characters
  178. iOneTab = 8 * cxCharWidth;
  179. }
  180. }
  181. // we have to recheck iOneTab here (instead of just saying "else")
  182. // because iOneTab will be set if we've run out of tab stops
  183. if (iOneTab) {
  184. if (iOneTab < 0) {
  185. // calc next available right justified tab stop
  186. xTab = x + textextent.cx - iTabOrigin;
  187. xTab = ((xTab / iOneTab) * iOneTab) - iOneTab - textextent.cx + iTabOrigin;
  188. } else {
  189. // calc next available left justified tab stop
  190. xTab = x - iTabOrigin;
  191. xTab = ((xTab / iOneTab) * iOneTab) + iOneTab + iTabOrigin;
  192. }
  193. x = xTab;
  194. }
  195. }
  196. if (fDrawTheText && (cch!=0)) {
  197. /*
  198. * Output all text up to the tab (or end of string) and get its
  199. * extent.
  200. */
  201. rc.right = x + textextent.cx;
  202. // All the calculations are made as if it is LTR and we flip the coordinates
  203. // if we have RTL.
  204. if (fRTLreading) {
  205. rcRTL = rc;
  206. rcRTL.left = (2 * initialx) - rc.right;
  207. rcRTL.right= rcRTL.left + (rc.right - rc.left) ;
  208. ScriptStringOut(psa, rcRTL.left , y, uOpaque, &rcRTL, 0, 0, FALSE);
  209. } else {
  210. ScriptStringOut(psa, x, y, uOpaque, &rc, 0, 0, FALSE);
  211. }
  212. rc.left = rc.right;
  213. }
  214. if (cch) {
  215. ScriptStringFree((void**)&psa);
  216. }
  217. // Skip over the tab and the characters we just drew.
  218. x = x + textextent.cx;
  219. // Skip over the characters we just drew.
  220. pwcInChars += cch;
  221. // See if we have more to draw OR see if this string ends in
  222. // a tab character that needs to be drawn.
  223. if ((nCount > 0) && (*pwcInChars == TEXT('\t'))) {
  224. pwcInChars++; // Skip over the tab
  225. nCount--;
  226. continue;
  227. } else {
  228. break; // Break from the loop.
  229. }
  230. }
  231. // if we have at the end of the text some Tabs then wen need to drae the background
  232. // for it.
  233. if (fDrawTheText && x>rc.right && uOpaque)
  234. {
  235. rc.right = x;
  236. if (fRTLreading) {
  237. rcRTL = rc;
  238. rcRTL.left = (2 * initialx) - rc.right;
  239. rcRTL.right= rcRTL.left + (rc.right - rc.left) ;
  240. ExtTextOutW(hdc, rcRTL.left, y, uOpaque|ETO_IGNORELANGUAGE, &rcRTL, L"", 0, NULL);
  241. } else {
  242. ExtTextOutW(hdc, rc.left, y, uOpaque|ETO_IGNORELANGUAGE, &rc, L"", 0, NULL);
  243. }
  244. }
  245. SetTextAlign(hdc, OldTextAlign);
  246. return MAKELONG((x - initialx), (short)textextent.cy);
  247. }
  248. //////////////////////////////////////////////////////////////////////////////
  249. // USER32 PSMTextOut will call this function for supporting Multilingual //
  250. // Menu handling. //
  251. // LpkPSMTextOut( HDC hdc, int xLeft, int yTop, LPCWSTR lpString, //
  252. // int nCount) //
  253. // hDC : Handle of device context //
  254. // xLeft : x-coordinate of text to render //
  255. // yTop : y-coordinate of text to render //
  256. // lpString : Input string //
  257. // nCount : Count of characters in input string //
  258. // //
  259. // Return : Nothing //
  260. // //
  261. // History : //
  262. // Nov 6, 1996 -by- Mohamed AbdEl Hamid [mhamid] //
  263. //////////////////////////////////////////////////////////////////////////////
  264. ///// LpkInternalPSMtextOut
  265. //
  266. // Called from LPK_USRC.C
  267. int LpkInternalPSMTextOut(
  268. HDC hdc,
  269. int xLeft,
  270. int yTop,
  271. const WCHAR *pwcInChars,
  272. int nCount,
  273. DWORD dwFlags) {
  274. HRESULT hr;
  275. int iTextAlign;
  276. STRING_ANALYSIS *psa;
  277. int iWidth;
  278. DWORD dwObjType;
  279. if (!nCount || !pwcInChars) {
  280. // No action required
  281. TRACE(GDI, ("LpkPSMTextOut: No string: nCount %d, pwcInChars %x",
  282. nCount, pwcInChars));
  283. return 0; // That was easy!
  284. }
  285. dwObjType = GetObjectType(hdc);
  286. hr = LpkStringAnalyse(
  287. hdc, pwcInChars, nCount, 0, -1,
  288. SSA_GLYPHS
  289. | (dwFlags & DT_NOPREFIX ? 0
  290. : (dwFlags & DT_HIDEPREFIX ? SSA_HIDEHOTKEY
  291. : (dwFlags & DT_PREFIXONLY ? SSA_HOTKEYONLY : SSA_HOTKEY)))
  292. | (dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_METAFILE : 0)
  293. | SSA_FALLBACK
  294. | ((((iTextAlign = GetTextAlign(hdc)) & TA_RTLREADING) && (iTextAlign != -1)) ? SSA_RTL : 0),
  295. -1, 0,
  296. NULL, NULL, NULL, NULL, NULL,
  297. &psa);
  298. if (SUCCEEDED(hr)) {
  299. iWidth = psa->size.cx;
  300. ScriptStringOut(psa, xLeft, yTop, 0, NULL, 0, 0, FALSE);
  301. ScriptStringFree((void**)&psa);
  302. } else {
  303. iWidth = 0;
  304. ASSERTHR(hr, ("LpkInternalPSMTextOut - LpkStringAnalyse"));
  305. psa = NULL;
  306. }
  307. return iWidth;
  308. }
  309. #ifdef LPKBREAKAWORD
  310. //////////////////////////////////////////////////////////////////////////////
  311. // //
  312. // LpkBreakAWord : DrawText calls this routine when the length of a word //
  313. // is longer than the line width. //
  314. // //
  315. // return - character position to break a non-breakable word //
  316. // //
  317. //////////////////////////////////////////////////////////////////////////////
  318. ///// LpkBreakAWord
  319. //
  320. // Called from LPK_USRC.C
  321. int LpkBreakAWord(
  322. HDC hdc,
  323. LPCWSTR lpchStr,
  324. int cchStr,
  325. int iMaxWidth) {
  326. if (!lpchStr || cchStr <= 0 || iMaxWidth <= 0)
  327. return 0;
  328. STRING_ANALYSIS* psa;
  329. int cOutChars;
  330. HRESULT hr;
  331. hr = LpkStringAnalyse(
  332. hdc, lpchStr, cchStr, 0, -1,
  333. SSA_GLYPHS | SSA_CLIP,
  334. -1, iMaxWidth,
  335. NULL, NULL, NULL, NULL, NULL,
  336. &psa);
  337. if (FAILED(hr)) {
  338. ASSERTHR(hr, ("LpkBreakAWord - qLpkStringAnalyse"));
  339. return 0;
  340. }
  341. cOutChars = psa->cOutChars;
  342. ScriptStringFree((void**)&psa);
  343. return max(0, cOutChars);
  344. }
  345. #endif
  346. //////////////////////////////////////////////////////////////////////////////
  347. // //
  348. // LpkGetNextWord //
  349. // return - offset to the next word //
  350. // //
  351. //////////////////////////////////////////////////////////////////////////////
  352. #define CR 0x000D
  353. #define LF 0x000A
  354. ///// LpkgetNextWord
  355. //
  356. // Called from LPK_USRC.C
  357. int LpkGetNextWord(
  358. HDC hdc,
  359. LPCWSTR lpchStr,
  360. int cchCount,
  361. int iCharset) {
  362. WCHAR *pRun;
  363. WCHAR *pRunEnd;
  364. int cchRun;
  365. int i=0;
  366. WCHAR wchRun;
  367. HRESULT hr;
  368. STRING_ANALYSIS *psa;
  369. // instantly advance 1 if current char located at whitespaces.
  370. if (*lpchStr == '\t' || *lpchStr == ' ') {
  371. return 1;
  372. }
  373. // try to find the shortest text run that are going to be analysed
  374. cchRun = 0;
  375. pRun = (PWSTR)lpchStr;
  376. pRunEnd = (PWSTR)(lpchStr + cchCount);
  377. while (pRun < pRunEnd) {
  378. wchRun = *pRun;
  379. if (wchRun == CR || wchRun == LF ||
  380. wchRun == '\t' || wchRun == ' ') {
  381. break;
  382. }
  383. pRun++;
  384. cchRun++;
  385. }
  386. if (cchRun == 0) {
  387. return 0;
  388. }
  389. hr = LpkStringAnalyse(
  390. hdc, lpchStr, cchRun, 0, -1,
  391. SSA_BREAK,
  392. -1, 0,
  393. NULL, NULL, NULL, NULL, NULL,
  394. &psa);
  395. if (FAILED(hr)) {
  396. ASSERTHR(hr, ("LpkGetNextWord - qLpkStringAnalyse"));
  397. return 0;
  398. }
  399. // We only return next wordbreak if the first item is a breakable one.
  400. if (g_ppScriptProperties[psa->pItems->a.eScript]->fComplex) {
  401. for (i=1; i < cchRun; i++) {
  402. if (psa->pLogAttr[i].fSoftBreak )
  403. break;
  404. }
  405. }
  406. ScriptStringFree((void**)&psa);
  407. return i;
  408. }
  409. //////////////////////////////////////////////////////////////////////////////
  410. // USER32 DrawTextEx will call this function for supporting Multilingual //
  411. // DrawTextEx handling. //
  412. // LpkDrawTextEx(HDC hdc, int xLeft, int yTop,LPCWSTR pwcInChars, int cchCount//
  413. // , BOOL fDraw, WORD wFormat, LPDRAWTEXTDATA lpDrawInfo, //
  414. // UNIT bAction) //
  415. // hDC : Handle of device context //
  416. // xLeft : x-coordinate of text to render //
  417. // yTop : y-coordinate of text to render //
  418. // lpchStr : Input string //
  419. // cchCount : Count of characters in input string //
  420. // fDraw : Draw the Text or expand tha tabs only //
  421. // wFormat : Same as dwDTFormat options for DrawTextEx //
  422. // lpDrawInfo : Internal Structure //
  423. // bAction : DT_CHARSETDRAW OR DT_GETNEXTWORD //
  424. // //
  425. // Return : Nothing //
  426. // //
  427. // History : //
  428. // Nov 15, 1996 -by- Mohamed AbdEl Hamid [mhamid] //
  429. // Mar 26, 1997 Adding DT_GETNEXTWORD -[wchao] //
  430. //////////////////////////////////////////////////////////////////////////////
  431. ///// LpkCharsetDraw
  432. //
  433. // Called from LPK_USRC.C
  434. //
  435. // Note: Doesn't implement user defined tabstops
  436. int LpkCharsetDraw(
  437. HDC hdc,
  438. int xLeft,
  439. int cxOverhang,
  440. int iTabOrigin,
  441. int iTabLength,
  442. int yTop,
  443. PCWSTR pcwString,
  444. int cchCount,
  445. BOOL fDraw,
  446. DWORD dwFormat,
  447. int iCharset) {
  448. HRESULT hr;
  449. int iTextAlign;
  450. int iWidth;
  451. STRING_ANALYSIS *psa;
  452. SCRIPT_TABDEF std;
  453. DWORD dwObjType;
  454. if (cchCount <= 0) {
  455. return 0; // That was easy!
  456. }
  457. if (dwFormat & DT_EXPANDTABS) {
  458. std.cTabStops = 1;
  459. std.pTabStops = &iTabLength;
  460. std.iTabOrigin = 0;
  461. std.iScale = 4; // Tab stops in pixels (avg ch width already applied in USER)
  462. }
  463. dwObjType = GetObjectType(hdc);
  464. hr = LpkStringAnalyse(
  465. hdc, pcwString, cchCount, 0, -1,
  466. SSA_GLYPHS
  467. | (dwFormat & DT_NOPREFIX ? 0
  468. : (dwFormat & DT_HIDEPREFIX ? SSA_HIDEHOTKEY
  469. : (dwFormat & DT_PREFIXONLY ? SSA_HOTKEYONLY : SSA_HOTKEY)))
  470. | (dwFormat & DT_EXPANDTABS ? SSA_TAB : 0)
  471. | (dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_METAFILE : 0)
  472. | (iCharset==-1 || GdiIsPlayMetafileDC(hdc) ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
  473. | ( dwFormat & DT_RTLREADING
  474. || (((iTextAlign = GetTextAlign(hdc)) & TA_RTLREADING) && (iTextAlign != -1))
  475. ? SSA_RTL : 0),
  476. -1, 0,
  477. NULL, NULL, NULL,
  478. dwFormat & DT_EXPANDTABS ? &std : NULL,
  479. NULL,
  480. &psa);
  481. if (SUCCEEDED(hr)) {
  482. iWidth = psa->size.cx;
  483. if (fDraw && (!(dwFormat & DT_CALCRECT))) {
  484. ScriptStringOut(psa, xLeft, yTop, 0, NULL, 0, 0, FALSE);
  485. }
  486. ScriptStringFree((void**)&psa);
  487. } else {
  488. iWidth = 0;
  489. ASSERTHR(hr, ("LpkCharsetDraw - LpkStringAnalyse"));
  490. psa = NULL;
  491. }
  492. return iWidth;
  493. }