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.

1278 lines
42 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // Module Name : LPK_GDI.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 : Oct 24, 1996 //
  10. // Author : Mohamed AbdEl Hamid [mhamid] //
  11. // //
  12. // Copyright (c) 1996, Microsoft Corporation. All rights reserved. //
  13. //////////////////////////////////////////////////////////////////////////////
  14. #include "precomp.hxx"
  15. //// FontHasWesternScript
  16. //
  17. // Detect if the current selected font in the hdc has Western script or not by using
  18. // the cached data g_FontIDCache. and also add the selected font to the cache it it is
  19. // not cached before.
  20. // All calles used inside this function is Client-mode calls except if the font will be
  21. // cached then calling GetGlyphIndices (Kernel-mode call) will take place.
  22. // This function used in the optimization checking for ExtTextOut and GetTextExtent.
  23. //
  24. // entry hdc - Device context
  25. //
  26. // return value: TRUE if font has western script. FALSE otherwise.
  27. //
  28. BOOL FontHasWesternScript(HDC hdc)
  29. {
  30. REALIZATION_INFO ri;
  31. int i;
  32. WORD Glyphs[4];
  33. BOOL fRet;
  34. if (!GdiRealizationInfo(hdc, &ri)) {
  35. return FALSE;
  36. }
  37. EnterCriticalSection(&csFontIdCache);
  38. if (g_cCachedFontsID > 0) {
  39. for (i=0 ; i<g_cCachedFontsID ; i++) {
  40. if (ri.uFontFileID == g_FontIDCache[i].uFontFileID) {
  41. fRet = g_FontIDCache[i].bHasWestern;
  42. LeaveCriticalSection(&csFontIdCache);
  43. return (fRet);
  44. }
  45. }
  46. }
  47. if ((GetGlyphIndicesW(hdc , L"dMr\"" , 4 , Glyphs , GGI_MARK_NONEXISTING_GLYPHS) == 4) &&
  48. (Glyphs[0] != 0xFFFF && Glyphs[1] != 0xFFFF && Glyphs[2] != 0xFFFF && Glyphs[3] != 0xFFFF)) {
  49. g_FontIDCache[g_pCurrentAvailablePos].bHasWestern = fRet = TRUE;
  50. } else {
  51. g_FontIDCache[g_pCurrentAvailablePos].bHasWestern = fRet = FALSE;
  52. }
  53. g_FontIDCache[g_pCurrentAvailablePos].uFontFileID = ri.uFontFileID ;
  54. g_pCurrentAvailablePos++;
  55. if (g_pCurrentAvailablePos >= MAX_FONT_ID_CACHE) {
  56. g_pCurrentAvailablePos = 0;
  57. }
  58. if (g_cCachedFontsID < MAX_FONT_ID_CACHE) {
  59. g_cCachedFontsID++;
  60. }
  61. LeaveCriticalSection(&csFontIdCache);
  62. return (fRet);
  63. }
  64. //// InternalTextOut
  65. //
  66. // Display text with possible font association
  67. //
  68. // entry hdc - Device context
  69. // x,y - Starting coords (Unless TA_UPDATECP)
  70. // uOptions - Flags (see below)
  71. // prc - Pointer to clipping rectangle
  72. // pString - Unicode string
  73. // cbCount - String length in unicode characters
  74. // pdx - Overriding logical dx array
  75. // iCharset - Original ANSI iCharset, or -1 if unicode
  76. //
  77. // exit TRUE if string drawn OK
  78. //
  79. // options ETO_CLIPPED - Clip to clipping rectangle
  80. // ETO_OPAQUE - Extend background colour to bounds of clipping rectangle
  81. // ETO_RTLREADING - Render text with right to left reading order
  82. // ETO_NUMERICSLOCAL
  83. // ETO_NUMERICSLATIN
  84. // ETO_PDY - lpdx array contains DX,DY pairs - causes LPK to be bypassed
  85. //
  86. // note LpkExtTextOut also obeys options set by SetTextAlign:
  87. // TA_LEFT - x,y is position of left edge of displayed glyphs
  88. // TA_CENTRE - x,y is position at centre of diplayed glyphs
  89. // TA_RIGHT - x,y is position at right edge of displayed glyphs
  90. // TA_RTLREADING - Render text with right to left reading order
  91. // TA_UPDATECP - Get x,y from current position, ignoring x,y parameters,
  92. // update current position following textout.
  93. //
  94. // history Oct 22, 1996 -by- Samer Arafeh [samera]
  95. // Oct 24, 1996 -by- Mohamed AbdEl Hamid [mhamid]
  96. // Feb 18, 1887 dbrown - Support font association
  97. ///// InternalTextOut
  98. //
  99. //
  100. BOOL InternalTextOut(
  101. HDC hdc,
  102. int x,
  103. int y,
  104. UINT uOptions,
  105. const RECT *prc,
  106. const WCHAR *pStr,
  107. UINT cbCount,
  108. const int *piDX,
  109. int iCharset,
  110. int *piWidth,
  111. int iRequiredWidth) {
  112. BOOL fRTLreading;
  113. int iDigitSubstitute;
  114. int iTextAlign;
  115. HRESULT hr;
  116. DWORD dwObjType;
  117. DWORD dwSicFlags; // Flags for ScriptIsComplex
  118. int iCurrentCharSet;
  119. STRING_ANALYSIS *psa;
  120. UNREFERENCED_PARAMETER(iRequiredWidth) ;
  121. if (!cbCount || !pStr) {
  122. // Empty string - no glyph processing required. Optimise ...
  123. return ExtTextOutW(hdc, x, y, uOptions|ETO_GLYPH_INDEX, prc,
  124. pStr, cbCount, piDX);
  125. }
  126. // ETO_PDY is not relevant for complex script strings. Let GDI
  127. // handle it. (APps wanting to adjust the y coordinate of glyphs in
  128. // complex script strings should use Uniscribe and manipulate the
  129. // pGoffset parameter to ScriptTextOut.
  130. if (uOptions & ETO_PDY) {
  131. return ExtTextOutW(hdc, x, y, uOptions | ETO_IGNORELANGUAGE, prc,
  132. pStr, cbCount, piDX);
  133. }
  134. // Establish Bidi reading order.
  135. //
  136. // Note, it is possible for us to be passed an hdc that does not
  137. // support GetTextAlign, in which case GetTextAlign will return -1.
  138. // Treat this as left to right reading order.
  139. fRTLreading = ((uOptions & ETO_RTLREADING)
  140. || (((iTextAlign = GetTextAlign(hdc)) & TA_RTLREADING) && (iTextAlign != -1)))
  141. ? TRUE : FALSE;
  142. // Interpret ETO_NUMERICS* flags:
  143. // If both bits are set, the digit substitute = context. This is a win95
  144. // compatability issue and is used mainly by Access.
  145. if ((uOptions&(ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN)) == (ETO_NUMERICSLOCAL|ETO_NUMERICSLATIN)) {
  146. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
  147. } else if (uOptions & ETO_NUMERICSLOCAL) {
  148. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
  149. } else if (uOptions & ETO_NUMERICSLATIN) {
  150. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
  151. } else {
  152. iDigitSubstitute = -1;
  153. }
  154. uOptions = uOptions & ~(ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN);
  155. // Check for plain text that can bypass the LPK entirely
  156. dwSicFlags = SIC_COMPLEX;
  157. if ( iDigitSubstitute == SCRIPT_DIGITSUBSTITUTE_CONTEXT
  158. || iDigitSubstitute == SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
  159. || g_DigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE) {
  160. dwSicFlags |= SIC_ASCIIDIGIT;
  161. }
  162. if (fRTLreading != !!(GetLayout(hdc) & LAYOUT_RTL)) {
  163. dwSicFlags |= SIC_NEUTRAL;
  164. }
  165. if (( ScriptIsComplex(pStr,cbCount,dwSicFlags) == S_FALSE
  166. && FontHasWesternScript(hdc))
  167. || GetTextCharacterExtra(hdc) != 0)
  168. {
  169. // No complex script processing required
  170. return ExtTextOutW(hdc, x, y, uOptions | ETO_IGNORELANGUAGE, prc,
  171. pStr, cbCount, piDX);
  172. }
  173. dwObjType = GetObjectType(hdc);
  174. // Analyse the string
  175. hr = LpkStringAnalyse(
  176. hdc, pStr, cbCount, 0, -1,
  177. SSA_GLYPHS
  178. | (dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_DONTGLYPH : 0)
  179. | (iCharset==-1 || GdiIsPlayMetafileDC(hdc) ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
  180. | (fRTLreading ? SSA_RTL : 0),
  181. iDigitSubstitute, iRequiredWidth,
  182. NULL, NULL,
  183. piDX,
  184. NULL, NULL,
  185. &psa);
  186. if (FAILED(hr)) {
  187. ASSERTHR(hr, ("InternalTextOut - LpkStringAnalyse"));
  188. return FALSE;
  189. }
  190. // Return string width if required (for DrawText)
  191. if (piWidth) {
  192. *piWidth = psa->size.cx;
  193. }
  194. hr = ScriptStringOut(psa, x, y, uOptions, prc, 0, 0, FALSE);
  195. ScriptStringFree((void**)&psa);
  196. if (SUCCEEDED(hr)) {
  197. return TRUE;
  198. } else {
  199. ASSERTHR(hr, ("InternalTextOut - ScriptStringOut"));
  200. return FALSE;
  201. }
  202. }
  203. BOOL LpkExtTextOut(
  204. HDC hdc,
  205. int x,
  206. int y,
  207. UINT uOptions,
  208. CONST RECT *prc,
  209. PCWSTR pStr,
  210. UINT cbCount,
  211. CONST INT *pDx,
  212. int iCharset) {
  213. return InternalTextOut(hdc, x, y, uOptions, prc, pStr, cbCount, pDx, iCharset, NULL, -1);
  214. }
  215. //////////////////////////////////////////////////////////////////////////////
  216. // GDI32 GetTextExtentExPoint will call this function for supporting //
  217. // Multilingual Text handling. //
  218. // //
  219. // LpkGetTextExtentExPoint( HDC hdc, PWSTR pStr, int cchString, //
  220. // int nMaxExtent, PINT pnFit, PINT pDx, PSIZE pSize, int iCharset) //
  221. // //
  222. // hDC Identifies the device context //
  223. // pStr Points to string for which extents are to be retrieved. //
  224. // cchString Count of characters in input string //
  225. // nMaxExtent Specifies the maximum allowable width, in logical units, //
  226. // of the formatted string. //
  227. // pnFit Maximum characters that fit in the formatted string //
  228. // When the pnFit parameter is NULL, the nMaxExtent parameter //
  229. // is ignored. //
  230. // //
  231. // pDx address of array for partial string widths //
  232. // pSize Address for string dimension //
  233. // fl ???? //
  234. // iCharset Indicates character set of codes. to optimizing the work. ??//
  235. // //
  236. // Return //
  237. // If the function succeeds, the return value is TRUE. //
  238. // If the function fails, the return value is FALSE. //
  239. // And we seted the error by call SetLastError. //
  240. // To get extended error information, call GetLastError. //
  241. // //
  242. // History //
  243. // Oct 22, 1996 -by- Samer Arafeh [samera] //
  244. // Oct 25, 1996 -by- MOhammed Abdul Hammed [mhamid] //
  245. //////////////////////////////////////////////////////////////////////////////
  246. BOOL LpkGetTextExtentExPoint(
  247. HDC hdc,
  248. PCWSTR pStr,
  249. int cchString,
  250. int nMaxExtent,
  251. PINT pnFit,
  252. PINT pDx,
  253. PSIZE pSize,
  254. FLONG fl,
  255. int iCharset)
  256. {
  257. int iTextAlign;
  258. BOOL fRTLreading;
  259. int i;
  260. HRESULT hr;
  261. DWORD dwObjType;
  262. DWORD dwSicFlags; // Flags for ScriptIsComplex
  263. int iCurrentCharSet;
  264. STRING_ANALYSIS *psa;
  265. STRING_ANALYSIS *psaFit;
  266. UNREFERENCED_PARAMETER(fl) ;
  267. // Check required parameters
  268. if (!hdc || !pSize) {
  269. ASSERTS(hdc, ("LpkGetTextExtentPoint - required parameter hdc is NULL"));
  270. ASSERTS(pSize, ("LpkGetTextExtentPoint - required parameter pSize is NULL"));
  271. return FALSE;
  272. }
  273. //Do we have a string
  274. if (!cchString || !pStr) {
  275. //no then go away
  276. pSize->cx = 0;
  277. pSize->cy = 0;
  278. if (pnFit) {
  279. *pnFit = 0;
  280. }
  281. return TRUE;
  282. }
  283. iTextAlign = GetTextAlign(hdc);
  284. fRTLreading = (iTextAlign & TA_RTLREADING) && (iTextAlign != -1);
  285. // Check for plain text that can bypass the LPK entirely
  286. dwSicFlags = SIC_COMPLEX;
  287. if (g_DigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE) {
  288. dwSicFlags |= SIC_ASCIIDIGIT;
  289. }
  290. if (fRTLreading != !!(GetLayout(hdc) & LAYOUT_RTL)) {
  291. dwSicFlags |= SIC_NEUTRAL;
  292. }
  293. if (( ScriptIsComplex(pStr, cchString, dwSicFlags) == S_FALSE
  294. && FontHasWesternScript(hdc))
  295. || GetTextCharacterExtra(hdc) != 0)
  296. {
  297. // No complex script processing required
  298. return GetTextExtentExPointWPri(hdc, pStr, cchString, nMaxExtent, pnFit, pDx, pSize);
  299. }
  300. dwObjType = GetObjectType(hdc);
  301. // Analyse the string
  302. hr = LpkStringAnalyse(
  303. hdc, pStr, cchString, 0, -1,
  304. SSA_GLYPHS
  305. // if the DC is Meta-File DC, we should enable the FallBack because it is enabled for ETOA while playing any Meta-File.
  306. | (iCharset==-1 || dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
  307. | (fRTLreading ? SSA_RTL : 0)
  308. | (pnFit ? SSA_FULLMEASURE : 0),
  309. -1, nMaxExtent,
  310. NULL, NULL, NULL, NULL, NULL,
  311. &psa);
  312. if (FAILED(hr)) {
  313. ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
  314. return FALSE;
  315. }
  316. if (pDx) {
  317. // if we have pnFit and psa->cOutChars>=cchString so we should fill lpDx.
  318. if (!pnFit || psa->cOutChars>=cchString) {
  319. ScriptStringGetLogicalWidths(psa, pDx);
  320. }
  321. // we need to update the width of last fit glyph.
  322. if (pnFit && psa->cOutChars<cchString && psa->cOutChars>0) {
  323. hr = LpkStringAnalyse(
  324. hdc, pStr, psa->cOutChars, 0, -1,
  325. SSA_GLYPHS
  326. // if the DC is Meta-File DC, we should enable the FallBack because it is enabled for ETOA while playing any Meta-File.
  327. | (iCharset==-1 || dwObjType == OBJ_METADC || dwObjType == OBJ_ENHMETADC ? SSA_FALLBACK : SSA_LPKANSIFALLBACK)
  328. | (fRTLreading ? SSA_RTL : 0),
  329. -1, 0,
  330. NULL, NULL, NULL, NULL, NULL,
  331. &psaFit);
  332. if (FAILED(hr)) {
  333. ScriptStringFree((void**)&psa);
  334. ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
  335. return FALSE;
  336. }
  337. ScriptStringGetLogicalWidths(psaFit, pDx);
  338. ScriptStringFree((void**)&psaFit);
  339. }
  340. // Accumulate extents
  341. for (i=1; i<(pnFit==NULL?cchString:psa->cOutChars); i++) {
  342. pDx[i] += pDx[i-1];
  343. }
  344. }
  345. if (pnFit) {
  346. *pnFit = psa->cOutChars;
  347. }
  348. *pSize = psa->size;
  349. ScriptStringFree((void**)&psa);
  350. return TRUE;
  351. }
  352. //// GetCharacterPlacement support
  353. //
  354. //
  355. //// GCPgenerateOutString
  356. //
  357. // Creates a reordered copy of the input string
  358. void GCPgenerateOutString(
  359. STRING_ANALYSIS *psa,
  360. WCHAR *pwOutString) {
  361. int i,j;
  362. int iItem;
  363. int iStart;
  364. int iLen;
  365. WCHAR *pwch;
  366. // Copy items one by one in visual order
  367. for (i=0; i<psa->cItems; i++) {
  368. iItem = psa->piVisToLog[i];
  369. iStart = psa->pItems[iItem].iCharPos;
  370. iLen = psa->pItems[iItem+1].iCharPos - iStart;
  371. if (psa->pItems[iItem].a.fRTL) {
  372. // Right to left item
  373. pwch = psa->pwInChars + iStart + iLen - 1;
  374. for (j=0; j<iLen; j++) {
  375. *pwOutString++ = *pwch--;
  376. }
  377. } else {
  378. // Left to right item
  379. memcpy(pwOutString, psa->pwInChars+iStart, sizeof(WCHAR) * iLen);
  380. pwOutString += iLen;
  381. }
  382. }
  383. }
  384. //// GCPgenerateClass
  385. //
  386. // Creates an array of character classifications using
  387. // GetCharacterPlacement legacy definitons
  388. void GCPgenerateClass(
  389. STRING_ANALYSIS *psa,
  390. BYTE *pbClass) {
  391. int iItem;
  392. int iStart;
  393. int iLen;
  394. int iClass;
  395. int iChar;
  396. // Map LogClust entries item by item in logical order
  397. for (iItem=0; iItem<psa->cItems; iItem++) {
  398. iStart = psa->pItems[iItem].iCharPos;
  399. iLen = psa->pItems[iItem+1].iCharPos - iStart;
  400. if (g_ppScriptProperties[psa->pItems[iItem].a.eScript]->fNumeric) {
  401. if (psa->pItems[iItem].a.fLayoutRTL) {
  402. iClass = GCPCLASS_LOCALNUMBER;
  403. } else {
  404. iClass = GCPCLASS_LATINNUMBER;
  405. }
  406. } else {
  407. if (psa->pItems[iItem].a.fLayoutRTL) {
  408. iClass = GCPCLASS_ARABIC; // (Same constant as GCPCLASS_HEBREW)
  409. } else {
  410. iClass = GCPCLASS_LATIN;
  411. }
  412. }
  413. memset(pbClass, iClass, iLen);
  414. pbClass += iLen;
  415. }
  416. }
  417. /******************************Public*Routine******************************\
  418. * GCPJustification
  419. *
  420. * Justifies text according to piJustify and returns proper pwgi and piDx
  421. * arrays.
  422. *
  423. * IMPORTANT : Caller should free (USPFREE(*ppwgi)) allocated buffer if
  424. * the fn succeeds (SUCCEEDED(hr)) and return code isn't S_FALSE.
  425. * S_FALSE means no justification is to be applied here since the piJustify and
  426. * piDx are either identical or the total width to justify for is less than the
  427. * min kashida width.
  428. *
  429. * All param are DWORD aligned.
  430. *
  431. * History :
  432. *
  433. * Mar 23, 1998 -by- Samer Arafeh [samera]
  434. * wrote it
  435. \**************************************************************************/
  436. #define BlankPriority 10
  437. HRESULT GCPJustification( WORD **ppwgi, // Out Output buffer width justified glyphs
  438. int **ppiJustifyDx, // Out Newly generated piDx buffer
  439. WORD *pwgi, // In Incoming GIs
  440. const int *piAdvWidth, // In Advance wdiths
  441. const SCRIPT_VISATTR *pVisAttr, // In Visual attributes
  442. int *piJustify, // In Justification advanced widths
  443. int cGlyphs, // In number of glyphs
  444. int iKashidaWidth, // In Minimum width of kashida
  445. int *pcJustifiedGlyphs, // Out Receives the total # of glyphs in output buf
  446. DWORD dwgKashida, // In Kashida GI
  447. DWORD dwgSpace) // In Space GI
  448. {
  449. DWORD dwSize;
  450. int iInsert=0L, iGlyph, iAmount, iJustDx;
  451. int cNewGlyphs = cGlyphs;
  452. WORD *pwNewGlyph;
  453. int *piNewAdvWidth;
  454. int cMaxGlyphs = *pcJustifiedGlyphs;
  455. int cNonArabicGlyph;
  456. int cNonBlank;
  457. int iDelta;
  458. HRESULT hr;
  459. INT iPartialKashida;
  460. //
  461. // Point to caller's data initially
  462. //
  463. *ppwgi = pwgi;
  464. *ppiJustifyDx = (INT *)piJustify;
  465. *pcJustifiedGlyphs = cGlyphs;
  466. //
  467. // If Kashida width is less than or equal 0, then justify with spaces only.
  468. //
  469. if(iKashidaWidth <= 0L) {
  470. iKashidaWidth = -1;
  471. }
  472. //
  473. // 1- Analyze input buffer to see how many kashida to insert, If Kashida is used.
  474. //
  475. if (iKashidaWidth != -1 ) {
  476. cNonArabicGlyph = 0;
  477. cNonBlank = 0;
  478. iDelta = 0;
  479. for( iGlyph=cGlyphs-1 ; iGlyph >= 0L ; iGlyph-- )
  480. {
  481. if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_NONE) ||
  482. (pVisAttr[iGlyph].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL)) {
  483. iAmount = piJustify[iGlyph]-piAdvWidth[iGlyph];
  484. if (iAmount > 0 && cNewGlyphs < cMaxGlyphs){
  485. iPartialKashida = iAmount % iKashidaWidth;
  486. iAmount /= iKashidaWidth;
  487. if (iPartialKashida > 0 && iAmount>0)
  488. {
  489. iAmount++;
  490. }
  491. if (cNewGlyphs + iAmount > cMaxGlyphs) {
  492. iAmount = (cMaxGlyphs - cNewGlyphs) * iKashidaWidth;
  493. cNewGlyphs = cMaxGlyphs;
  494. iDelta += piJustify[iGlyph] - piAdvWidth[iGlyph] - iAmount;
  495. piJustify[iGlyph] = piAdvWidth[iGlyph] + iAmount;
  496. } else {
  497. cNewGlyphs += iAmount;
  498. }
  499. } else {
  500. iDelta += iAmount;
  501. piJustify[iGlyph] = piAdvWidth[iGlyph];
  502. }
  503. } else {
  504. if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK) ||
  505. (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_BLANK)) {
  506. cNonBlank++;
  507. } else {
  508. cNonArabicGlyph++;
  509. }
  510. }
  511. }
  512. if (iDelta > 0 && cNonArabicGlyph+cNonBlank>0) {
  513. // The Space has 10-times higher priority than Latin characters.
  514. iAmount = iDelta / (cNonArabicGlyph + (cNonBlank * BlankPriority));
  515. for( iGlyph=0 ; iGlyph < cGlyphs ; iGlyph++ )
  516. {
  517. if( (pVisAttr[iGlyph].uJustification != SCRIPT_JUSTIFY_NONE) &&
  518. (pVisAttr[iGlyph].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL)) {
  519. if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK) ||
  520. (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_BLANK)) {
  521. piJustify[iGlyph] += BlankPriority * iAmount;
  522. iDelta -= BlankPriority * iAmount;
  523. } else {
  524. piJustify[iGlyph] += iAmount;
  525. iDelta -= iAmount;
  526. }
  527. cNonArabicGlyph = iGlyph;
  528. }
  529. }
  530. if (iDelta > 0) {
  531. piJustify[cNonArabicGlyph] += iDelta;
  532. }
  533. }
  534. }
  535. //
  536. // 2- Allocate for new glyphs and piDx
  537. //
  538. dwSize = (cNewGlyphs * (sizeof(INT)+sizeof(WORD)));
  539. hr = USPALLOCTEMP( dwSize , (void **)&pwNewGlyph );
  540. if(FAILED(hr))
  541. {
  542. ASSERTHR(hr, ("Not ennough memory for JustifiyArabicStringWithKashida()"));
  543. return hr;
  544. }
  545. piNewAdvWidth = (INT *)(pwNewGlyph+cNewGlyphs);
  546. //
  547. // 3- Begin inserting and formulating the justified buffer
  548. //
  549. int iJustReminder = 0;
  550. for( iGlyph=cGlyphs-1, iInsert=cNewGlyphs-1; iGlyph >= 0L && iInsert>=0; iGlyph-- )
  551. {
  552. iJustDx = (piJustify[iGlyph] - piAdvWidth[iGlyph]) + iJustReminder;
  553. iJustReminder = 0;
  554. if( iJustDx > 0)
  555. {
  556. if( (pVisAttr[iGlyph].uJustification == SCRIPT_JUSTIFY_NONE) ||
  557. (pVisAttr[iGlyph].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL))
  558. {
  559. //Arabic glyph then justify with kashida
  560. if(( iJustDx >= iKashidaWidth ) && (iKashidaWidth != -1))
  561. {
  562. pwNewGlyph[iInsert] = pwgi[iGlyph];
  563. piNewAdvWidth[iInsert] = piAdvWidth[iGlyph];
  564. iInsert--;
  565. while( (iJustDx >= iKashidaWidth) && (iInsert >= 0L) )
  566. {
  567. pwNewGlyph[iInsert] = (WORD)dwgKashida;
  568. piNewAdvWidth[iInsert] = iKashidaWidth;
  569. iInsert--;
  570. iJustDx -= iKashidaWidth;
  571. }
  572. if(( iJustDx > 0L ) && (iInsert >= 0L))
  573. {
  574. pwNewGlyph[iInsert] = (WORD)dwgKashida;
  575. piNewAdvWidth[iInsert] = iJustDx;
  576. iInsert--;
  577. iJustDx = 0L;
  578. }
  579. }
  580. else
  581. {
  582. pwNewGlyph[iInsert] = pwgi[iGlyph];
  583. piNewAdvWidth[iInsert] = piAdvWidth[iGlyph];
  584. iJustReminder = iJustDx;
  585. iInsert--;
  586. }
  587. }
  588. else
  589. {
  590. pwNewGlyph[iInsert] = pwgi[iGlyph];
  591. piNewAdvWidth[iInsert] = piAdvWidth[iGlyph] + iJustDx;
  592. iInsert--;
  593. }
  594. }
  595. else
  596. {
  597. pwNewGlyph[iInsert] = pwgi[iGlyph];
  598. piNewAdvWidth[iInsert] = piJustify[iGlyph];
  599. iInsert--;
  600. }
  601. }
  602. //
  603. // In case there is a space glyph, it will be expanded in locatio rather
  604. // than inserting kashida GIs
  605. //
  606. while( iInsert >= 0L )
  607. {
  608. piNewAdvWidth[iInsert] = 0L;
  609. pwNewGlyph[iInsert] = (WORD)dwgSpace;
  610. iInsert--;
  611. }
  612. //
  613. // 4- Update results
  614. //
  615. *ppwgi = pwNewGlyph;
  616. *ppiJustifyDx = piNewAdvWidth;
  617. *pcJustifiedGlyphs = cNewGlyphs;
  618. return S_OK;
  619. }
  620. //////////////////////////////////////////////////////////////////////////////
  621. // GDI32 GetCharacterPlacement will call this function for //
  622. // supporting Multilingual Text handling. //
  623. // //
  624. // LpkGetCharacterPlacement( HDC hdc, PWSTR pStr, int nCount, //
  625. // int nMaxExtent, LPGCP_RESULTSW pResults, DWORD dwFlags, //
  626. // int iCharset) //
  627. // //
  628. // hDC : Handle to device context //
  629. // pStr : Input string //
  630. // nCount : Count of characters in input string //
  631. // nMaxExtent : Maximum width for formatting string //
  632. // pResults : Pointer to GCP_RESULTS strucutre for output //
  633. // dwFlags : GCP Processing Flags //
  634. // iCharset : Origianl character set of pStr //
  635. // //
  636. // Return //
  637. // If the function succeeds, the return value is Width an the Height //
  638. // of the string //
  639. // If the function fails, the return value is 0. //
  640. // And we seted the error by call SetLastError. //
  641. // To get extended error information, call GetLastError. //
  642. // //
  643. // History : //
  644. // Oct 22, 1996 -by- Samer Arafeh [samera] //
  645. // Oct 29, 1996 -by- MOhammed Abdul Hammed [mhamid] //
  646. // Jan 13, 1997 -by- David C Brown (dbrown) //
  647. // New justification widths buffer //
  648. // ANALYSE field name changes //
  649. //////////////////////////////////////////////////////////////////////////////
  650. DWORD LpkGetCharacterPlacement(
  651. HDC hdc,
  652. const WCHAR *pwcInChars,
  653. int cInChars,
  654. int nMaxExtent,
  655. GCP_RESULTSW *pResults,
  656. DWORD dwFlags,
  657. int iCharset) {
  658. UINT uBufferOptions;
  659. int iDigitSubstitute, i, cMaxGlyphs;
  660. int *pLocalDX;
  661. DWORD dwRet = 0;
  662. HRESULT hr;
  663. DWORD dwSSAflags;
  664. SCRIPT_CONTROL scriptControl = {0}; // Analysis control
  665. SCRIPT_STATE scriptState = {0}; // Initial state
  666. STRING_ANALYSIS *psa;
  667. SCRIPT_FONTPROPERTIES sfp;
  668. WORD *pwLocalGlyphs;
  669. TRACE(GDI, ("LpkGetCharacterPlacement begins"));
  670. //////////////////////////////////////////////////////////////////////////
  671. // 1-Check parameters //
  672. //////////////////////////////////////////////////////////////////////////
  673. // Check required parameters
  674. ASSERTS(hdc, ("LpkGetCharacterPlacement - required parameter hdc is NULL"));
  675. //GCP_MAXEXTENT and no nMaxExtent
  676. if ((dwFlags & GCP_MAXEXTENT) && (nMaxExtent < 0)) {
  677. TRACEMSG(("LpkGetCharacterPlacement: Invalid parameter - GCP_MAXEXTENT and no nMaxExtent"));
  678. GdiSetLastError(ERROR_INVALID_PARAMETER);
  679. return 0;
  680. }
  681. //GCP_CLASSIN set and no pClass
  682. if ((dwFlags & GCP_CLASSIN) && !(pResults->lpClass)) {
  683. TRACEMSG(("LpkGetCharacterPlacement: Invalid parameter - GCP_CLASSIN set and no pClass"));
  684. GdiSetLastError(ERROR_INVALID_PARAMETER);
  685. return 0;
  686. }
  687. //////////////////////////////////////////////////////////////////////////
  688. // 2 - Interpret control flags //
  689. //////////////////////////////////////////////////////////////////////////
  690. switch (dwFlags & (GCP_NUMERICSLOCAL|GCP_NUMERICSLATIN)) {
  691. case GCP_NUMERICSLOCAL:
  692. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
  693. break;
  694. case GCP_NUMERICSLOCAL|GCP_NUMERICSLATIN:
  695. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
  696. break;
  697. case GCP_NUMERICSLATIN:
  698. iDigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
  699. break;
  700. default:
  701. iDigitSubstitute = -1;
  702. }
  703. dwSSAflags = 0;
  704. if (dwFlags & GCP_REORDER) {
  705. if (GetTextAlign(hdc) & TA_RTLREADING ? 1 : 0) {
  706. dwSSAflags |= SSA_RTL;
  707. }
  708. } else {
  709. scriptState.fOverrideDirection = TRUE;
  710. }
  711. if (dwFlags & GCP_DISPLAYZWG) scriptState.fDisplayZWG = TRUE;
  712. if (!(dwFlags & GCP_LIGATE)) scriptState.fInhibitLigate = TRUE;
  713. if (dwFlags & GCP_SYMSWAPOFF) scriptState.fInhibitSymSwap = TRUE;
  714. if (dwFlags & GCP_NEUTRALOVERRIDE) scriptControl.fNeutralOverride = TRUE;
  715. if (dwFlags & GCP_NUMERICOVERRIDE) scriptControl.fNumericOverride = TRUE;
  716. if (pResults->lpGlyphs) {
  717. scriptControl.fLinkStringBefore = pResults->lpGlyphs[0] & GCPGLYPH_LINKBEFORE ? TRUE : FALSE;
  718. scriptControl.fLinkStringAfter = pResults->lpGlyphs[0] & GCPGLYPH_LINKAFTER ? TRUE : FALSE;
  719. }
  720. if (dwFlags & GCP_MAXEXTENT) {
  721. dwSSAflags |= SSA_CLIP;
  722. if (dwFlags & GCP_JUSTIFY) {
  723. dwSSAflags |= SSA_FIT;
  724. if (!(dwFlags & GCP_KASHIDA) || !(dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE))) {
  725. dwSSAflags |= SSA_NOKASHIDA;
  726. }
  727. }
  728. }
  729. if (dwFlags & GCP_CLASSIN) {
  730. if (((const BYTE *)pResults->lpClass)[0] & (GCPCLASS_PREBOUNDLTR | GCPCLASS_PREBOUNDRTL)) {
  731. scriptControl.fInvertPreBoundDir = (((const BYTE *)pResults->lpClass)[0] & GCPCLASS_PREBOUNDRTL ? 1 : 0)
  732. ^ (dwSSAflags & SSA_RTL ? 1 : 0);
  733. }
  734. if (((const BYTE *)pResults->lpClass)[0] & (GCPCLASS_POSTBOUNDLTR | GCPCLASS_POSTBOUNDRTL)) {
  735. scriptControl.fInvertPostBoundDir = (((const BYTE *)pResults->lpClass)[0] & GCPCLASS_POSTBOUNDRTL ? 1 : 0)
  736. ^ (dwSSAflags & SSA_RTL ? 1 : 0);
  737. }
  738. }
  739. //////////////////////////////////////////////////////////////////////////
  740. // 3-Call LPK_ANA to do Layout and Shaping //
  741. //////////////////////////////////////////////////////////////////////////
  742. if (dwFlags & GCP_CLASSIN) {
  743. hr = LpkStringAnalyse(
  744. hdc, pwcInChars, cInChars, pResults->nGlyphs, -1,
  745. dwSSAflags | SSA_GLYPHS | SSA_GCP,
  746. iDigitSubstitute, nMaxExtent,
  747. &scriptControl, &scriptState,
  748. NULL,
  749. NULL,
  750. (BYTE*)pResults->lpClass,
  751. &psa);
  752. } else {
  753. hr = LpkStringAnalyse(
  754. hdc, pwcInChars, cInChars, pResults->nGlyphs, -1,
  755. dwSSAflags | SSA_GLYPHS | SSA_GCP,
  756. iDigitSubstitute, nMaxExtent,
  757. &scriptControl, &scriptState,
  758. NULL,
  759. NULL,
  760. NULL,
  761. &psa);
  762. }
  763. if (FAILED(hr)) {
  764. ASSERTHR(hr, ("LpkGetTextExtentExPoint - LpkStringAnalyse"));
  765. return FALSE;
  766. }
  767. //
  768. // If the user's suppled buffer isn't sufficient to hold the
  769. // output, then let's truncate it.
  770. //
  771. if (pResults->nGlyphs < (UINT) psa->cOutGlyphs) {
  772. psa->cOutGlyphs = (UINT) pResults->nGlyphs;
  773. }
  774. if (pResults->lpOutString) {
  775. GCPgenerateOutString(psa, pResults->lpOutString);
  776. }
  777. if (pResults->lpOrder) {
  778. ScriptStringGetOrder(psa, pResults->lpOrder);
  779. }
  780. if (pResults->lpClass) {
  781. GCPgenerateClass(psa, (PBYTE) pResults->lpClass);
  782. }
  783. BOOL bGlyphsCopied = FALSE;
  784. if (pResults->lpDx) {
  785. if (psa->piJustify && (dwFlags & GCP_JUSTIFY)) {
  786. sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
  787. hr = ScriptGetFontProperties(hdc,
  788. &psa->sc[0],
  789. &sfp);
  790. if(SUCCEEDED(hr)) {
  791. if (!(dwFlags & GCP_KASHIDA) || !(dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE)))
  792. sfp.iKashidaWidth = -1;
  793. else {
  794. ASSERTS(sfp.wgKashida, ("LpkGetCharacterPlacement - ther is no Kashida glyph"));
  795. }
  796. cMaxGlyphs = pResults->nGlyphs;
  797. hr = GCPJustification( (WORD **)&pwLocalGlyphs,
  798. (int **)&pLocalDX,
  799. (WORD *)psa->pwGlyphs,
  800. (int *)psa->piAdvance,
  801. psa->pVisAttr,
  802. psa->piJustify,
  803. psa->cOutGlyphs,
  804. sfp.iKashidaWidth,
  805. &cMaxGlyphs,
  806. sfp.wgKashida,
  807. sfp.wgBlank);
  808. if(SUCCEEDED(hr)) {
  809. int iOffset = 0;
  810. if (cMaxGlyphs > (int)pResults->nGlyphs) {
  811. iOffset = cMaxGlyphs - pResults->nGlyphs;
  812. cMaxGlyphs = pResults->nGlyphs;
  813. }
  814. psa->cOutGlyphs = cMaxGlyphs;
  815. if (pResults->lpGlyphs) {
  816. memcpy (pResults->lpGlyphs, (LPVOID)(pwLocalGlyphs+iOffset), sizeof(WORD) * cMaxGlyphs);
  817. bGlyphsCopied = TRUE;
  818. }
  819. psa->size.cx = 0;
  820. for (i=0; i<cMaxGlyphs; i++) {
  821. pResults->lpDx[i] = pLocalDX[i+iOffset];
  822. psa->size.cx += pLocalDX[i+iOffset];
  823. }
  824. USPFREE((LPVOID)pwLocalGlyphs);
  825. }
  826. }
  827. } else {
  828. memcpy(pResults->lpDx, psa->piAdvance, sizeof(int) * psa->cOutGlyphs);
  829. }
  830. }
  831. if (!bGlyphsCopied && pResults->lpGlyphs) {
  832. memcpy(pResults->lpGlyphs, psa->pwGlyphs, sizeof(WORD) * psa->cOutGlyphs);
  833. }
  834. if (dwFlags & (GCP_GLYPHSHAPE | GCP_LIGATE))
  835. pResults->nGlyphs = psa->cOutGlyphs;
  836. else
  837. pResults->nGlyphs = cInChars;
  838. pResults->nMaxFit = psa->cOutChars;
  839. // If there was justification we may have zero glyphs
  840. if (!psa->cOutGlyphs) {
  841. pResults->nGlyphs = 0;
  842. ScriptStringFree((void**)&psa);
  843. // Weird Middle East Win95 compatability rules
  844. if ( (dwFlags & GCP_MAXEXTENT)
  845. || !(dwFlags & GCP_GLYPHSHAPE)
  846. || !pResults->lpGlyphs) {
  847. return 1;
  848. } else {
  849. return 0;
  850. }
  851. }
  852. //////////////////////////////////////////////////////////////////////////
  853. // 4-Generate lpCaretPos //
  854. //////////////////////////////////////////////////////////////////////////
  855. if (pResults->lpCaretPos) {
  856. char *pbClass = NULL;
  857. INT *piAdvance = pResults->lpDx ? pResults->lpDx : psa->piAdvance;
  858. UINT *puiOrder = NULL;
  859. INT *pCaretCalc;
  860. INT iWidth = 0;
  861. UINT j, uOrder;
  862. hr = USPALLOC(sizeof(INT)*pResults->nGlyphs, (void **)&pCaretCalc);
  863. if(FAILED(hr)) {
  864. ScriptStringFree((void**)&psa);
  865. return 0;
  866. }
  867. // Allocate for pbClass if pResults->lpClass is NULL otherwise us it.
  868. if (pResults->lpClass == NULL) {
  869. hr = USPALLOC(sizeof(char)*cInChars, (void **)&pbClass);
  870. if(FAILED(hr)) {
  871. USPFREE(pCaretCalc);
  872. ScriptStringFree((void**)&psa);
  873. return 0;
  874. }
  875. GCPgenerateClass(psa, (PBYTE) pbClass);
  876. } else {
  877. pbClass = pResults->lpClass;
  878. }
  879. // Allocate for puiOrder if pResults->lpOrder is NULL otherwise us it.
  880. if (pResults->lpOrder == NULL) {
  881. hr = USPALLOC(sizeof(UINT)*cInChars, (void **)&puiOrder);
  882. if(FAILED(hr)) {
  883. if (pResults->lpClass == NULL) {
  884. USPFREE(pbClass);
  885. }
  886. USPFREE(pCaretCalc);
  887. ScriptStringFree((void**)&psa);
  888. return 0;
  889. }
  890. ScriptStringGetOrder(psa, puiOrder);
  891. } else {
  892. puiOrder = pResults->lpOrder;
  893. }
  894. // simple-minded loop used to generate glyph-offsets
  895. // as the same code used in NT4/MET.
  896. UINT caretPosCount = min(pResults->nGlyphs, (UINT)cInChars);
  897. for( j=0 ; j<caretPosCount ; j++ ) {
  898. if (pbClass[j] == GCPCLASS_ARABIC) {
  899. iWidth += piAdvance[j];
  900. pCaretCalc[j] = iWidth - 1;
  901. if (iWidth == 0) {
  902. pCaretCalc[j] = 0;
  903. }
  904. } else {
  905. pCaretCalc[j] = iWidth;
  906. iWidth += piAdvance[j];
  907. }
  908. }
  909. if (pResults->nGlyphs > (UINT)cInChars)
  910. {
  911. for( j=cInChars ; j<pResults->nGlyphs ; j++)
  912. {
  913. pCaretCalc[j] = iWidth;
  914. iWidth += piAdvance[j];
  915. }
  916. }
  917. // Convert to char-indexing. We need to take care if the
  918. // user supplied in sufficient visual buffers
  919. for( j=0 ; j<(UINT)cInChars ; j++ ) {
  920. uOrder = puiOrder[j];
  921. if ((uOrder+1) > (UINT)psa->cOutGlyphs) {
  922. uOrder = 0;
  923. }
  924. pResults->lpCaretPos[j] = pCaretCalc[uOrder];
  925. }
  926. if (pResults->lpOrder == NULL) {
  927. USPFREE(puiOrder);
  928. }
  929. if (pResults->lpClass == NULL) {
  930. USPFREE(pbClass);
  931. }
  932. USPFREE(pCaretCalc);
  933. }
  934. //////////////////////////////////////////////////////////////////////////
  935. // 5 - Return width and height //
  936. //////////////////////////////////////////////////////////////////////////
  937. dwRet = (psa->size.cx & 0xffff) + (psa->size.cy << 16);
  938. //////////////////////////////////////////////////////////////////////////
  939. // 6 - Free allocated memory and exit //
  940. //////////////////////////////////////////////////////////////////////////
  941. ScriptStringFree((void**)&psa);
  942. return dwRet;
  943. }
  944. /******************************Public*Routine******************************\
  945. *
  946. * BOOL LpkUseGDIWidthCache( HDC hDC , LPCSTR psz , int count ,
  947. * LONG fl , BOOL fUnicode)
  948. *
  949. * Checks whether the LPK can use GDI cached widths for the ASCII (0<=x<=127)
  950. * by inspecting the following variables :
  951. * - System numeric shape setting
  952. * - DC Align state
  953. * - The selected font has Western script
  954. * - The string code points in range 0<=x<=127 with Ansi calls
  955. *
  956. * Returns TRUE if it is OK to use GDI width cache, otherwise FALSE
  957. *
  958. * History:
  959. * 28-Aug-1997 -by- Samer Arafeh [SamerA]
  960. * Wrote it.
  961. \**************************************************************************/
  962. BOOL LpkUseGDIWidthCache( HDC hDC , LPCSTR psz , int count , LONG fl , BOOL fUnicode)
  963. {
  964. BOOL bRet;
  965. int i;
  966. BYTE cTest;
  967. LPSTR pstr;
  968. //
  969. // Let's make sure that :
  970. // 1- Text is LTR Reading
  971. // 2- Digits shape setting is Arabic
  972. // 3- if Unicode call, make sure the font has Western script
  973. // if Ansi call check if all code points less than 0x80 and font has Wetern script.
  974. bRet = (!!(fl & TA_RTLREADING) == !!(GetLayout(hDC) & LAYOUT_RTL))
  975. && g_DigitSubstitute.DigitSubstitute == SCRIPT_DIGITSUBSTITUTE_NONE;
  976. TRACE( GDI, ("LpkUseGDIWidthCache: g_DigitSubstitute.DigitSubstitute=%x, bRet=%x",
  977. g_DigitSubstitute.DigitSubstitute, bRet));
  978. if (bRet) {
  979. // We don't need this check for Unicdoe calls because it is done in GDI.
  980. if (!fUnicode) {
  981. cTest = 0;
  982. i = count;
  983. pstr = (LPSTR) psz;
  984. unroll_here:
  985. switch(i)
  986. {
  987. default:
  988. cTest |= pstr[9];
  989. case 9:
  990. cTest |= pstr[8];
  991. case 8:
  992. cTest |= pstr[7];
  993. case 7:
  994. cTest |= pstr[6];
  995. case 6:
  996. cTest |= pstr[5];
  997. case 5:
  998. cTest |= pstr[4];
  999. case 4:
  1000. cTest |= pstr[3];
  1001. case 3:
  1002. cTest |= pstr[2];
  1003. case 2:
  1004. cTest |= pstr[1];
  1005. case 1:
  1006. cTest |= pstr[0];
  1007. }
  1008. if ((i > 10) && !(cTest & 0x80))
  1009. {
  1010. i -= 10;
  1011. pstr += 10;
  1012. goto unroll_here;
  1013. }
  1014. bRet = !(cTest & 0x80);
  1015. }
  1016. return (bRet && FontHasWesternScript(hDC));
  1017. }
  1018. return bRet ;
  1019. }