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.

1106 lines
28 KiB

  1. /*
  2. * Uniscribe interface (& related classes) class implementation
  3. *
  4. * File: uspi.cpp
  5. * Create: Jan 10, 1998
  6. * Author: Worachai Chaoweeraprasit (wchao)
  7. *
  8. * Copyright (c) 1998-2000, Microsoft Corporation. All rights reserved.
  9. */
  10. #include "_common.h"
  11. #ifndef NOCOMPLEXSCRIPTS
  12. #include "_font.h"
  13. #include "_edit.h"
  14. #include "_frunptr.h"
  15. #include "_select.h"
  16. #include "_measure.h"
  17. #include "_uspi.h"
  18. CUniscribe* g_pusp = NULL;
  19. int g_cMaxScript = 0x100;
  20. // initial dummy script properties (= SCRIPT_UNDEFINED)
  21. static const SCRIPT_PROPERTIES g_propUndef = { LANG_NEUTRAL, FALSE, FALSE, FALSE, FALSE, 0 };
  22. static const SCRIPT_PROPERTIES* g_pPropUndef[1] = { &g_propUndef };
  23. CUniscribe::CUniscribe ()
  24. {
  25. // Initialize digit substitution info
  26. ApplyDigitSubstitution(W32->GetDigitSubstitutionMode());
  27. // Get maximum number of scripts supported
  28. ScriptGetProperties(NULL, &g_cMaxScript);
  29. }
  30. // Test the OS if it does any complex script.
  31. // REVIEW (keithcu) What if it only supports indic, but not the other ones?
  32. BOOL IsSupportedOS()
  33. {
  34. BOOL fSupport = !OnWin95FE();
  35. int rguCodePage[] = {1255, 1256, 874};
  36. BYTE rgbch[] = {0xe0, 0xd3, 0xa1};
  37. WCHAR rgwch[] = {0x05d0, 0x0633, 0x0e01};
  38. WCHAR wch;
  39. int i = 0;
  40. if (fSupport)
  41. {
  42. for (;i < 3; i++)
  43. {
  44. if (MBTWC(rguCodePage[i], 0, (LPCSTR)&rgbch[i], 1, (LPWSTR)&wch, 1, NULL) > 0 &&
  45. wch == rgwch[i])
  46. break; // support either Arabic, Hebrew or Thai
  47. }
  48. }
  49. return fSupport && i < 3;
  50. }
  51. // Prepare information for digit substitution
  52. // return: Native digit script (shapine engine) ID.
  53. //
  54. WORD CUniscribe::ApplyDigitSubstitution(BYTE bDigitSubstMode)
  55. {
  56. _wesNationalDigit = 0;
  57. // Remember national digits script ID if substitution mode is not None
  58. if (bDigitSubstMode != DIGITS_NOTIMPL && bDigitSubstMode != DIGITS_NONE)
  59. {
  60. WCHAR chZero = 0x0030;
  61. int cItems;
  62. SCRIPT_ITEM si[2];
  63. SCRIPT_CONTROL sc = {0};
  64. SCRIPT_STATE ss = {0};
  65. // force national digit mode
  66. sc.uDefaultLanguage = GetNationalDigitLanguage(GetThreadLocale());
  67. ss.fDigitSubstitute = TRUE;
  68. sc.fContextDigits = FALSE;
  69. if (SUCCEEDED(ScriptItemize(&chZero, 1, 2, &sc, &ss, (SCRIPT_ITEM*)&si, (int*)&cItems)))
  70. _wesNationalDigit = si[0].a.eScript;
  71. }
  72. return _wesNationalDigit;
  73. }
  74. // Some locales may have its own traditional (native) digit and national standard digit
  75. // recognised by a standard body and adopted by NLSAPI. The example is that Nepali(India)
  76. // has its own digit but the India standard uses Hindi digit as the national digit.
  77. //
  78. DWORD CUniscribe::GetNationalDigitLanguage(LCID lcid)
  79. {
  80. DWORD dwDigitLang = PRIMARYLANGID(LANGIDFROMLCID(lcid));
  81. if (W32->OnWinNT5())
  82. {
  83. WCHAR rgwstrDigit[20];
  84. if (GetLocaleInfoW(lcid, LOCALE_SNATIVEDIGITS, rgwstrDigit, ARRAY_SIZE(rgwstrDigit)))
  85. {
  86. // Steal this from Uniscribe (build 0231)
  87. switch (rgwstrDigit[1])
  88. {
  89. case 0x0661: dwDigitLang = LANG_ARABIC; break;
  90. case 0x06F1: dwDigitLang = LANG_FARSI; break;
  91. case 0x0e51: dwDigitLang = LANG_THAI; break;
  92. case 0x0967: dwDigitLang = LANG_HINDI; break;
  93. case 0x09e7: dwDigitLang = LANG_BENGALI; break;
  94. case 0x0a67: dwDigitLang = LANG_PUNJABI; break;
  95. case 0x0ae7: dwDigitLang = LANG_GUJARATI; break;
  96. case 0x0b67: dwDigitLang = LANG_ORIYA; break;
  97. case 0x0be7: dwDigitLang = LANG_TAMIL; break;
  98. case 0x0c67: dwDigitLang = LANG_TELUGU; break;
  99. case 0x0ce7: dwDigitLang = LANG_KANNADA; break;
  100. case 0x0d67: dwDigitLang = LANG_MALAYALAM; break;
  101. case 0x0f21: dwDigitLang = LANG_TIBETAN; break;
  102. case 0x0ed1: dwDigitLang = LANG_LAO; break;
  103. }
  104. }
  105. }
  106. return dwDigitLang;
  107. }
  108. CUniscribe::~CUniscribe ()
  109. {
  110. if (_pFSM)
  111. {
  112. delete _pFSM;
  113. }
  114. }
  115. /***** High level services *****/
  116. // Tokenize string and run Unicode Bidi algorithm if requested.
  117. // return : =<0 - error
  118. // >0 - number of complex script tokens
  119. //
  120. int CUniscribe::ItemizeString (
  121. USP_CLIENT* pc, // in: Working structure
  122. WORD uInitLevel, // in: Initial Bidi level
  123. int* pcItems, // out: Count of items generated
  124. WCHAR* pwchString, // in: Input string
  125. int cch, // in: Number of character to itemize
  126. BOOL fUnicodeBiDi, // in: TRUE - Use UnicodeBidi
  127. WORD wLangId) // in: (optional) Dominant language preference
  128. {
  129. Assert (pc && pc->si && pcItems && pwchString && cch > 0 && cch <= pc->si->cchString);
  130. USP_CLIENT_SI* pc_si = pc->si;
  131. SCRIPT_ITEM* psi = pc_si->psi;
  132. SCRIPT_CONTROL sc = {0};
  133. SCRIPT_STATE ss = {0};
  134. SCRIPT_CONTROL* psc;
  135. SCRIPT_STATE* pss;
  136. HRESULT hr;
  137. int cItems = 0;
  138. if (fUnicodeBiDi)
  139. {
  140. psc = &sc;
  141. pss = &ss;
  142. if (wLangId == LANG_NEUTRAL)
  143. wLangId = PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale()));
  144. // (preitemize:) set up initial state
  145. psc->uDefaultLanguage = wLangId;
  146. // Classify + - and / in Win9x legacy manner
  147. psc->fLegacyBidiClass = TRUE;
  148. // For Arabic Office's compatibility.
  149. // We enable fArabicNumContext if the dominant language is Arabic.
  150. //
  151. if (psc->uDefaultLanguage == LANG_ARABIC)
  152. pss->fArabicNumContext = uInitLevel & 1;
  153. pss->uBidiLevel = uInitLevel;
  154. // Leave digit substitution to None since we do it ourself.
  155. // pss->fDigitSubstitute = FALSE;
  156. // psc->fContextDigits = FALSE;
  157. }
  158. else
  159. {
  160. psc = NULL;
  161. pss = NULL;
  162. }
  163. // begin real work
  164. hr = ScriptItemize(pwchString, cch, cch+1, psc, pss, psi, (int*)&cItems);
  165. return SUCCEEDED(hr) ? *pcItems = cItems : 0;
  166. }
  167. // Produce a shaped string (glyph array), taking care of font association and measurer's CF update
  168. //
  169. // Success can require 3 calls to Shape():
  170. // 1. Returns E_PENDING (script cache doesn't contain the glyphing information)
  171. // 2. Return USP_E_SCRIPT_NOT_IN_FONT --the HFONT doesn't contain the script needed to do the glyphing
  172. // 3. Hopefully success, but may return again if the fallback font doesn't exist, but we quit anyway.
  173. int CUniscribe::ShapeString (
  174. PLSRUN plsrun, // in: The first run to be shaped
  175. SCRIPT_ANALYSIS* psa, // in: Analysis of the run to be shaped
  176. CMeasurer* pme, // in: Measurer points to start cp of the run
  177. const WCHAR* pwch, // in: String to be shaped
  178. int cch, // in: Count of chars
  179. WORD*& pwgi, // out: Reference to glyph indices array
  180. WORD* pwlc, // out: Logical cluster array
  181. SCRIPT_VISATTR*& psva) // out: Reference to glyph's attribute array
  182. {
  183. AssertSz (plsrun && psa && pme && pwch, "ShapeString failed: Invalid params");
  184. HRESULT hr = S_OK;
  185. HRESULT hrLastError = S_OK;
  186. HDC hdc = NULL;
  187. HFONT hOrgFont = NULL;
  188. int cGlyphs;
  189. int cchAdd = 0;
  190. CCcs *pccsSave = pme->Check_pccs();
  191. int nAttempt = 8; // Maximum attempt to realloc glyph buffer to shape a string
  192. // make sure that we have proper font cache ready to use
  193. if (!pme->_pccs)
  194. return 0;
  195. if (psa->fNoGlyphIndex)
  196. // If no glyph processing, hdc must be around.
  197. hdc = PrepareShapeDC(plsrun, pme, E_PENDING, hOrgFont);
  198. // prepare glyph buffer
  199. if (!CacheAllocGlyphBuffers(cch, cGlyphs, pwgi, psva))
  200. return 0;
  201. do
  202. {
  203. hr = ScriptShape(hdc, &pme->_pccs->_sc, pwch, cch, cGlyphs, psa, pwgi, pwlc, psva, &cGlyphs);
  204. if (SUCCEEDED(hr))
  205. break;
  206. // Error handling...
  207. switch (hr)
  208. {
  209. case E_PENDING:
  210. case USP_E_SCRIPT_NOT_IN_FONT:
  211. if (hr == hrLastError)
  212. nAttempt = 0; // We encounter the same error twice.
  213. else
  214. {
  215. hdc = PrepareShapeDC(plsrun, pme, hr, hOrgFont);
  216. hrLastError = hr;
  217. }
  218. break;
  219. case E_OUTOFMEMORY:
  220. // (#6773)Indic shaping engine could produce glyphs more than we could hold.
  221. //
  222. cchAdd += 16;
  223. if (CacheAllocGlyphBuffers(cch + cchAdd, cGlyphs, pwgi, psva))
  224. {
  225. nAttempt--;
  226. break;
  227. }
  228. default:
  229. nAttempt = 0;
  230. //AssertSz(FALSE, "Shaping fails with invalid error or we run out of memory.");
  231. break;
  232. }
  233. } while (nAttempt > 0);
  234. // restore hdc's original font
  235. if (hdc && hOrgFont)
  236. SelectObject(hdc, hOrgFont);
  237. if (pme->_pccs != pccsSave)
  238. plsrun->SetFallback(SUCCEEDED(hr));
  239. return SUCCEEDED(hr) ? cGlyphs : 0;
  240. }
  241. // Place a string and take care of font association and measurer's CF update
  242. //
  243. // This is called right after ShapeString.
  244. int CUniscribe::PlaceString(
  245. PLSRUN plsrun, // in: The first run to be shaped
  246. SCRIPT_ANALYSIS* psa, // in: Analysis of the run to be shaped
  247. CMeasurer* pme, // in: Measurer points to start cp of the run
  248. const WORD* pcwgi, // in: Glyph indices array
  249. int cgi, // in: Count of input glyphs
  250. const SCRIPT_VISATTR* psva, // in: Glyph's attribute array
  251. int* pgdx, // out: Glyph's advanced width array
  252. GOFFSET* pgduv, // out: Glyph's offset array
  253. ABC* pABC) // out: Run's dimension
  254. {
  255. AssertSz (plsrun && psa && pme && pcwgi, "PlaceString failed: Invalid params");
  256. HRESULT hr = S_OK;
  257. HRESULT hrLastError = S_OK;
  258. HDC hdc = NULL;
  259. HFONT hOrgFont = NULL;
  260. int nAttempt = 1;
  261. pme->Check_pccs();
  262. pme->ApplyFontCache(plsrun->IsFallback(), plsrun->_a.eScript);
  263. // make sure that we have proper font cache ready to use
  264. if (!pme->_pccs)
  265. return 0;
  266. if (psa->fNoGlyphIndex)
  267. // If no glyph processing, hdc must be around.
  268. hdc = PrepareShapeDC(plsrun, pme, E_PENDING, hOrgFont);
  269. do
  270. {
  271. hr = ScriptPlace(hdc, &pme->_pccs->_sc, pcwgi, cgi, psva, psa, pgdx, pgduv, pABC);
  272. if (SUCCEEDED(hr))
  273. break;
  274. // Error handling...
  275. switch (hr)
  276. {
  277. case E_PENDING:
  278. if (hr == hrLastError)
  279. nAttempt = 0; // We encounter the same error twice.
  280. else
  281. {
  282. hdc = PrepareShapeDC(plsrun, pme, hr, hOrgFont);
  283. hrLastError = hr;
  284. }
  285. break;
  286. default:
  287. nAttempt = 0;
  288. //AssertSz(FALSE, "Placing fails with invalid error.");
  289. break;
  290. }
  291. } while (nAttempt > 0);
  292. // restore hdc's original font
  293. if (hdc && hOrgFont)
  294. SelectObject(hdc, hOrgFont);
  295. return SUCCEEDED(hr) ? cgi : 0;
  296. }
  297. // Placing given string results in logical width array,
  298. // the result array would be used to record WMF metafile.
  299. //
  300. int CUniscribe::PlaceMetafileString (
  301. PLSRUN plsrun, // in: The first run to be shaped
  302. CMeasurer* pme, // in: Measurer points to start cp of the run
  303. const WCHAR* pwch, // in: Input codepoint string
  304. int cch, // in: Character count
  305. PINT* ppiDx) // out: Pointer to logical widths array
  306. {
  307. AssertSz (pme && pwch && ppiDx, "PlaceMetafileString failed: Invalid params");
  308. if (W32->OnWinNT4() || W32->OnWin9xThai())
  309. {
  310. // MET NT40 has bug in lpdx justification so i doesnt playback the lpdx very nicely.
  311. // Thai Win9x simply cannot handle fancy lpdx values generated by Uniscribe.
  312. // We workaround both cases here by metafiling no lpdx and let the system reconstructs
  313. // it from scratch during playback time.
  314. // =FUTURE= If we do line justification. We need more sophisticated work here
  315. // basically to reconstruct the OS preferred type of lpdx.
  316. //
  317. *ppiDx = NULL;
  318. return cch;
  319. }
  320. HRESULT hr = E_FAIL;
  321. PUSP_CLIENT pc = NULL;
  322. int* piLogDx; // logical width array
  323. int* piVisDx; // visual width array
  324. GOFFSET* pGoffset; // glyph offset array
  325. WORD* pwgi; // glyph array
  326. SCRIPT_VISATTR* psva; // glyph properties array
  327. int cgi = 0;
  328. BYTE pbBufIn[MAX_CLIENT_BUF];
  329. SCRIPT_ANALYSIS sa = plsrun->_a;
  330. BOOL fVisualGlyphDx = sa.fRTL && W32->OnWin9x() && W32->OnBiDiOS();
  331. CreateClientStruc(pbBufIn, MAX_CLIENT_BUF, &pc, cch, cli_pcluster);
  332. if (!pc)
  333. return 0;
  334. PUSP_CLIENT_SSP pcssp = pc->ssp;
  335. if (fVisualGlyphDx)
  336. sa.fLogicalOrder = FALSE; // shaping result in visual order
  337. // Shape string
  338. if (cgi = ShapeString(plsrun, &sa, pme, pwch, (int)cch, pwgi, pcssp->pcluster, psva))
  339. {
  340. // Get static buffer for logical and visual width arrays
  341. //
  342. if ( (piLogDx = GetWidthBuffer(cgi + cch)) &&
  343. (pGoffset = GetGoffsetBuffer(cgi)) )
  344. {
  345. piVisDx = &piLogDx[cch];
  346. // then place it...
  347. if (cgi == PlaceString(plsrun, &sa, pme, pwgi, cgi, psva, piVisDx, pGoffset, NULL))
  348. {
  349. if (fVisualGlyphDx)
  350. {
  351. // Workaround BiDi Win9x's lpdx handling
  352. // It assumes ExtTextOut's dx array is glyph width in visual order
  353. Assert (cgi <= cch); // glyph count never exceeds character count in BiDi
  354. CopyMemory (piLogDx, piVisDx, min(cgi, cch)*sizeof(int));
  355. }
  356. else
  357. {
  358. // Map visual glyph widths to logical widths
  359. hr = ScriptGetLogicalWidths(&sa, cch, cgi, piVisDx, pcssp->pcluster, psva, piLogDx);
  360. }
  361. }
  362. // result
  363. *ppiDx = piLogDx;
  364. }
  365. }
  366. if (pc && pbBufIn != (BYTE*)pc)
  367. FreePv(pc);
  368. return SUCCEEDED(hr) ? cgi : 0;
  369. }
  370. /***** Helper functions *****/
  371. // Retrieve the BidiLevel FSM
  372. const CBiDiFSM* CUniscribe::GetFSM ()
  373. {
  374. if (!_pFSM)
  375. {
  376. _pFSM = new CBiDiFSM(this);
  377. if (_pFSM && !_pFSM->Init())
  378. {
  379. delete _pFSM;
  380. }
  381. }
  382. return _pFSM;
  383. }
  384. // Prepare the shapeable font ready to dc for a given script
  385. //
  386. // USP_E_SCRIPT_NOT_IN_FONT - complex scripts font association
  387. // E_PENDING - prepare dc with current font selected
  388. //
  389. HDC CUniscribe::PrepareShapeDC (
  390. PLSRUN plsrun, // in: The first run to be shaped
  391. CMeasurer* pme, // in: Measurer points to start cp of the run
  392. HRESULT hrReq, // in: Error code to react
  393. HFONT& hOrgFont) // in/out: Original font of the shape DC
  394. {
  395. Assert (pme);
  396. HDC hdc = NULL;
  397. HFONT hOldFont;
  398. switch (hrReq)
  399. {
  400. case USP_E_SCRIPT_NOT_IN_FONT:
  401. {
  402. pme->ApplyFontCache(fTrue, plsrun->_a.eScript);
  403. #ifdef DEBUG
  404. if (pme->_pccs)
  405. Tracef(TRCSEVWARN, "USP_E_SCRIPT_NOT_IN_FONT: charset %d applied", pme->_pccs->_bCharSet);
  406. #endif
  407. }
  408. default:
  409. if (pme->_pccs)
  410. {
  411. hdc = pme->_pccs->_hdc;
  412. hOldFont = (HFONT)SelectObject(hdc, pme->_pccs->_hfont);
  413. if (!hOrgFont)
  414. hOrgFont = hOldFont;
  415. }
  416. }
  417. return hdc;
  418. }
  419. const SCRIPT_PROPERTIES* CUniscribe::GeteProp (WORD eScript)
  420. {
  421. if (!_ppProp)
  422. {
  423. if (!SUCCEEDED(ScriptGetProperties(&_ppProp, NULL)) || !_ppProp)
  424. _ppProp = g_pPropUndef;
  425. }
  426. if (_ppProp == g_pPropUndef || eScript >= (WORD)g_cMaxScript)
  427. eScript = 0;
  428. return _ppProp[eScript];
  429. }
  430. // Figure proper charset to use for complex script.
  431. // The resulted charset can be either actual or virtual (internal) GDI charset used by given script
  432. BOOL CUniscribe::GetComplexCharRep(
  433. const SCRIPT_PROPERTIES* psp, // Uniscribe script's properties
  434. BYTE iCharRepDefault, // -1 format's charset
  435. BYTE& iCharRepOut) // out: Charset to use
  436. {
  437. Assert(psp);
  438. BYTE iCharRep = !psp->fCDM
  439. ? CharRepFromCharSet(psp->bCharSet)
  440. : GetCDMCharRep(iCharRepDefault);
  441. BOOL fr = psp->fComplex && !psp->fControl;
  442. if (fr)
  443. {
  444. if (iCharRep == ANSI_INDEX || iCharRep == DEFAULT_INDEX)
  445. iCharRep = CharRepFromLID(psp->langid);
  446. if (IsBiDiCharRep(iCharRep))
  447. _iCharRepRtl = iCharRep; // Cache the last found BiDi charset
  448. iCharRepOut = iCharRep;
  449. }
  450. return fr;
  451. }
  452. // Figure out the charset to use for CDM run
  453. //
  454. BYTE CUniscribe::GetCDMCharRep(
  455. BYTE iCharRepDefault)
  456. {
  457. if (!_iCharRepCDM)
  458. {
  459. _iCharRepCDM = (iCharRepDefault == VIET_INDEX ||
  460. W32->GetPreferredKbd(VIET_INDEX) ||
  461. GetLocaleCharRep() == VIET_INDEX || GetACP() == 1258)
  462. ? VIET_INDEX : DEFAULT_INDEX;
  463. }
  464. return _iCharRepCDM;
  465. }
  466. BYTE CUniscribe::GetRtlCharRep(
  467. CTxtEdit* ped,
  468. CRchTxtPtr* prtp) // ptr to the numeric run
  469. {
  470. CFormatRunPtr rp(prtp->_rpCF);
  471. rp.AdjustBackward();
  472. BYTE iCharRep = ped->GetCharFormat(rp.GetFormat())->_iCharRep;
  473. if (!IsBiDiCharRep(iCharRep))
  474. {
  475. iCharRep = _iCharRepRtl; // Use the last found BiDi charset
  476. if (!IsBiDiCharRep(iCharRep))
  477. {
  478. // try default charset
  479. DWORD dwCharFlags;
  480. iCharRep = ped->GetCharFormat(-1)->_iCharRep;
  481. if (!IsBiDiCharRep(iCharRep))
  482. {
  483. // Then the system charset
  484. iCharRep = CharRepFromCodePage(GetACP());
  485. if (!IsBiDiCharRep(iCharRep))
  486. {
  487. // Then the content
  488. dwCharFlags = ped->GetCharFlags() & (FARABIC | FHEBREW);
  489. if (dwCharFlags == FARABIC)
  490. iCharRep = ARABIC_INDEX;
  491. else if(dwCharFlags == FHEBREW)
  492. iCharRep = HEBREW_INDEX;
  493. else
  494. {
  495. // And last chance with the first found loaded BiDi kbd
  496. if (W32->GetPreferredKbd(HEBREW_INDEX))
  497. iCharRep = HEBREW_INDEX;
  498. else
  499. // Even if we can't find Arabic, we have to assume it here.
  500. iCharRep = ARABIC_INDEX;
  501. }
  502. }
  503. }
  504. }
  505. }
  506. Assert(IsBiDiCharRep(iCharRep));
  507. return iCharRep;
  508. }
  509. // Substitute digit shaper in plsrun if needed
  510. //
  511. void CUniscribe::SubstituteDigitShaper (
  512. PLSRUN plsrun,
  513. CMeasurer* pme)
  514. {
  515. Assert(plsrun && pme);
  516. CTxtEdit* ped = pme->GetPed();
  517. WORD wScript;
  518. if (GeteProp(plsrun->_a.eScript)->fNumeric)
  519. {
  520. wScript = plsrun->_pCF->_wScript; // reset it before
  521. switch (W32->GetDigitSubstitutionMode())
  522. {
  523. case DIGITS_CTX:
  524. {
  525. if (ped->IsRich())
  526. {
  527. // Context mode simply means the charset of the kbd for richtext.
  528. if (!IsBiDiCharRep(ped->GetCharFormat(pme->_rpCF.GetFormat())->_iCharRep))
  529. break;
  530. }
  531. else
  532. {
  533. // Digit follows directionality of preceding run for plain text
  534. CFormatRunPtr rp(pme->_rpCF);
  535. Assert(rp.IsValid());
  536. if (rp.PrevRun())
  537. {
  538. if (!IsBiDiCharRep(ped->GetCharFormat(rp.GetFormat())->_iCharRep))
  539. break;
  540. }
  541. else
  542. {
  543. // No preceding run, looking for the paragraph direction
  544. if (!pme->Get_pPF()->IsRtl())
  545. break;
  546. }
  547. }
  548. // otherwise, fall thru...
  549. }
  550. case DIGITS_NATIONAL:
  551. wScript = _wesNationalDigit;
  552. default:
  553. break;
  554. }
  555. // Update all linked runs
  556. while (plsrun)
  557. {
  558. plsrun->_a.eScript = wScript; // assign proper shaping engine to digits
  559. plsrun = plsrun->_pNext;
  560. }
  561. }
  562. }
  563. /***** Uniscribe entry point *****/
  564. // memory allocator
  565. //
  566. BOOL CUniscribe::CreateClientStruc (
  567. BYTE* pbBufIn,
  568. LONG cbBufIn,
  569. PUSP_CLIENT* ppc,
  570. LONG cchString,
  571. DWORD dwMask)
  572. {
  573. Assert(ppc && pbBufIn);
  574. if (!ppc)
  575. return FALSE;
  576. *ppc = NULL;
  577. if (cchString == 0)
  578. cchString = 1; // simplify caller's logic
  579. LONG i;
  580. LONG cbSize;
  581. PBYTE pbBlock;
  582. // ScriptItemize's
  583. //
  584. PVOID pvString;
  585. PVOID pvsi;
  586. // ScriptBreak's
  587. //
  588. PVOID pvsla;
  589. // ScriptShape & Place's
  590. //
  591. PVOID pvwgi;
  592. PVOID pvsva;
  593. PVOID pvcluster;
  594. PVOID pvidx;
  595. PVOID pvgoffset;
  596. // subtable ptrs
  597. //
  598. PUSP_CLIENT_SI pc_si;
  599. PUSP_CLIENT_SB pc_sb;
  600. PUSP_CLIENT_SSP pc_ssp;
  601. #define RQ_COUNT 12
  602. BUF_REQ brq[RQ_COUNT] =
  603. {
  604. // table and subtable blocks
  605. //
  606. { sizeof(USP_CLIENT), 1, (void**)ppc},
  607. { sizeof(USP_CLIENT_SI), dwMask & cli_Itemize ? 1 : 0, (void**)&pc_si},
  608. { sizeof(USP_CLIENT_SB), dwMask & cli_Break ? 1 : 0, (void**)&pc_sb},
  609. { sizeof(USP_CLIENT_SSP), dwMask & cli_ShapePlace ? 1 : 0, (void**)&pc_ssp},
  610. // data blocks
  611. //
  612. { sizeof(WCHAR), dwMask & cli_string ? cchString + 1 : 0, &pvString},
  613. { sizeof(SCRIPT_ITEM), dwMask & cli_psi ? cchString + 1 : 0, &pvsi},
  614. { sizeof(SCRIPT_LOGATTR), dwMask & cli_psla ? cchString + 1 : 0, &pvsla},
  615. { sizeof(WORD), dwMask & cli_pwgi ? GLYPH_COUNT(cchString+1) : 0, &pvwgi},
  616. { sizeof(SCRIPT_VISATTR), dwMask & cli_psva ? GLYPH_COUNT(cchString+1) : 0, &pvsva},
  617. { sizeof(WORD), dwMask & cli_pcluster ? cchString + 1 : 0, &pvcluster},
  618. { sizeof(int), dwMask & cli_pidx ? GLYPH_COUNT(cchString+1) : 0, &pvidx},
  619. { sizeof(GOFFSET), dwMask & cli_pgoffset ? GLYPH_COUNT(cchString+1) : 0, &pvgoffset},
  620. };
  621. // count total buffer size in byte (WORD aligned)
  622. //
  623. for (i=0, cbSize=0; i < RQ_COUNT; i++)
  624. {
  625. cbSize += ALIGN(brq[i].size * brq[i].c);
  626. }
  627. // allocate the whole buffer at once
  628. //
  629. if (cbSize > cbBufIn)
  630. {
  631. pbBlock = (PBYTE)PvAlloc(cbSize, 0);
  632. }
  633. else
  634. {
  635. pbBlock = pbBufIn;
  636. }
  637. if (!pbBlock)
  638. {
  639. //
  640. // memory management failed!
  641. //
  642. TRACEERRORSZ("Allocation failed in CreateClientStruc!\n");
  643. *ppc = NULL;
  644. return FALSE;
  645. }
  646. // clear the main table
  647. ZeroMemory (pbBlock, sizeof(USP_CLIENT));
  648. // assign ptrs in buffer request structure
  649. //
  650. for (i=0; i < RQ_COUNT; i++)
  651. {
  652. if (brq[i].c > 0)
  653. {
  654. *brq[i].ppv = pbBlock;
  655. pbBlock += ALIGN(brq[i].size * brq[i].c);
  656. }
  657. else
  658. {
  659. *brq[i].ppv = NULL;
  660. }
  661. }
  662. Assert(((PBYTE)(*ppc)+cbSize == pbBlock));
  663. // fill in data block ptrs in subtable
  664. //
  665. if (pc_si)
  666. {
  667. pc_si->pwchString = (WCHAR*) pvString;
  668. pc_si->cchString = cchString;
  669. pc_si->psi = (SCRIPT_ITEM*) pvsi;
  670. }
  671. if (pc_sb)
  672. {
  673. pc_sb->psla = (SCRIPT_LOGATTR*) pvsla;
  674. }
  675. if (pc_ssp)
  676. {
  677. pc_ssp->pwgi = (WORD*) pvwgi;
  678. pc_ssp->psva = (SCRIPT_VISATTR*) pvsva;
  679. pc_ssp->pcluster = (WORD*) pvcluster;
  680. pc_ssp->pidx = (int*) pvidx;
  681. pc_ssp->pgoffset = (GOFFSET*) pvgoffset;
  682. }
  683. // fill in subtable ptrs in header table
  684. //
  685. (*ppc)->si = (PUSP_CLIENT_SI) pc_si;
  686. (*ppc)->sb = (PUSP_CLIENT_SB) pc_sb;
  687. (*ppc)->ssp = (PUSP_CLIENT_SSP) pc_ssp;
  688. return TRUE;
  689. }
  690. /////// CBidiFSM class implementation
  691. //
  692. // Create: Worachai Chaoweeraprasit(wchao), Jan 29, 1998
  693. //
  694. CBiDiFSM::~CBiDiFSM ()
  695. {
  696. FreePv(_pStart);
  697. }
  698. INPUT_CLASS CBiDiFSM::InputClass (
  699. const CCharFormat* pCF,
  700. CTxtPtr* ptp,
  701. LONG cchRun) const
  702. {
  703. if (!_pusp->IsValid() || !pCF || pCF->_wScript == SCRIPT_WHITE)
  704. return chGround;
  705. const SCRIPT_PROPERTIES* psp = _pusp->GeteProp(pCF->_wScript);
  706. BYTE iCharRep = pCF->_iCharRep;
  707. if (psp->fControl)
  708. {
  709. if (cchRun == 1)
  710. switch (ptp->GetChar()) // single-char run
  711. {
  712. case LTRMARK: return chLTR; // \ltrmark
  713. case RTLMARK: return chRTL; // \rtlmark
  714. }
  715. return chGround;
  716. }
  717. if(IsSymbolOrOEMCharRep(iCharRep) || IsFECharRep(iCharRep) || pCF->_dwEffects & CFE_RUNISDBCS)
  718. return chLTR;
  719. BOOL fBiDiCharSet = IsBiDiCharSet(psp->bCharSet);
  720. if (psp->fNumeric)
  721. // Numeric digits
  722. return (fBiDiCharSet || IsBiDiCharRep(iCharRep)) ? digitRTL : digitLTR;
  723. // RTL if it's RTL script or its format charset is RTL and NOT a simplified script
  724. return (fBiDiCharSet || pCF->_wScript && IsBiDiCharRep(iCharRep)) ? chRTL : chLTR;
  725. }
  726. // The FSM generates run's embedding level based on given base level and puts it
  727. // in CFormatRun. LsFetchRun is the client using this result.
  728. //
  729. #ifdef DEBUG
  730. //#define DEBUG_LEVEL
  731. #endif
  732. #ifdef DEBUG_LEVEL
  733. void DebugLevel (CBiDiFSMCell* pCell)
  734. {
  735. Tracef(TRCSEVNONE, "%d,", pCell->_level._value);
  736. }
  737. #else
  738. #define DebugLevel(x)
  739. #endif
  740. HRESULT CBiDiFSM::RunFSM (
  741. CRchTxtPtr* prtp, // in: text pointer to start run
  742. LONG cRuns, // in: number of FSM run
  743. LONG cRunsStart, // in: number of start run
  744. BYTE bBaseLevel) const // in: base level
  745. {
  746. Assert (prtp->_rpCF.IsValid() && cRuns > 0);
  747. CRchTxtPtr rtp(*prtp);
  748. const CCharFormat* pCF;
  749. LONG cchRun;
  750. LONG cRunsAll = cRuns + cRunsStart;
  751. CBiDiFSMCell* pCell;
  752. USHORT ucState = bBaseLevel ? S_X * NUM_FSM_INPUTS : 0;
  753. BOOL fNext = TRUE;
  754. // loop thru FSM
  755. for (; fNext && cRunsAll > 0; cRunsAll--, fNext = !!rtp.Move(cchRun))
  756. {
  757. cchRun = rtp.GetCchLeftRunCF();
  758. pCF = rtp.GetPed()->GetCharFormat(rtp._rpCF.GetFormat());
  759. ucState += InputClass(pCF, &rtp._rpTX, cchRun);
  760. pCell = &_pStart[ucState];
  761. // set level to FSM runs
  762. if (cRunsAll <= cRuns)
  763. rtp._rpCF.SetLevel (pCell->_level);
  764. DebugLevel(pCell);
  765. ucState = pCell->_uNext; // next state
  766. }
  767. return S_OK;
  768. }
  769. // Construct the BiDi embedding level FSM (FSM details see bidifsm2.html)
  770. // :FSM's size = NUM_FSM_INPUTS * NUM_FSM_STATES * sizeof(CBiDiFSMCell) = 6*5*4 = 120 bytes
  771. //
  772. BOOL CBiDiFSM::Init()
  773. {
  774. CBiDiFSMCell* pCell;
  775. int i;
  776. // Build the Bidi FSM
  777. _nState = NUM_FSM_STATES;
  778. _nInput = NUM_FSM_INPUTS;
  779. pCell = (CBiDiFSMCell*)PvAlloc(NUM_FSM_STATES * NUM_FSM_INPUTS * sizeof(CBiDiFSMCell), 0);
  780. if (!pCell)
  781. return FALSE; // unable to create FSM!
  782. _pStart = pCell;
  783. CBiDiLevel lvlZero = {0,0};
  784. CBiDiLevel lvlOne = {1,0};
  785. CBiDiLevel lvlTwo = {2,0};
  786. CBiDiLevel lvlTwoStart = {2,1};
  787. // State A(0): LTR char in LTR para
  788. //
  789. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  790. {
  791. switch (i)
  792. {
  793. case chLTR:
  794. SetFSMCell(pCell, &lvlZero, 0); break;
  795. case chRTL:
  796. SetFSMCell(pCell, &lvlOne, S_B * NUM_FSM_INPUTS); break;
  797. case digitLTR:
  798. SetFSMCell(pCell, &lvlZero, 0); break;
  799. case digitRTL:
  800. SetFSMCell(pCell, &lvlTwo, S_C * NUM_FSM_INPUTS); break;
  801. case chGround:
  802. SetFSMCell(pCell, &lvlZero, 0); break;
  803. }
  804. }
  805. // State B(1): RTL char in LTR para
  806. //
  807. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  808. {
  809. switch (i)
  810. {
  811. case chLTR:
  812. SetFSMCell(pCell, &lvlZero, 0); break;
  813. case chRTL:
  814. SetFSMCell(pCell, &lvlOne, S_B * NUM_FSM_INPUTS); break;
  815. case digitLTR:
  816. SetFSMCell(pCell, &lvlZero, 0); break;
  817. case digitRTL:
  818. SetFSMCell(pCell, &lvlTwo, S_C * NUM_FSM_INPUTS); break;
  819. case chGround:
  820. SetFSMCell(pCell, &lvlZero, 0); break;
  821. }
  822. }
  823. // State C(2): RTL number run in LTR para
  824. //
  825. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  826. {
  827. switch (i)
  828. {
  829. case chLTR:
  830. SetFSMCell(pCell, &lvlZero, 0); break;
  831. case chRTL:
  832. SetFSMCell(pCell, &lvlOne, S_B * NUM_FSM_INPUTS); break;
  833. case digitLTR:
  834. SetFSMCell(pCell, &lvlZero, 0); break;
  835. case digitRTL:
  836. SetFSMCell(pCell, &lvlTwo, S_C * NUM_FSM_INPUTS); break;
  837. case chGround:
  838. SetFSMCell(pCell, &lvlZero, 0); break;
  839. }
  840. }
  841. // State X(1): RTL char in RTL para
  842. //
  843. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  844. {
  845. switch (i)
  846. {
  847. case chLTR:
  848. SetFSMCell(pCell, &lvlTwo, S_Y * NUM_FSM_INPUTS); break;
  849. case chRTL:
  850. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  851. case digitLTR:
  852. SetFSMCell(pCell, &lvlTwo, S_Y * NUM_FSM_INPUTS); break;
  853. case digitRTL:
  854. SetFSMCell(pCell, &lvlTwo, S_Z * NUM_FSM_INPUTS); break;
  855. case chGround:
  856. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  857. }
  858. }
  859. // State Y(2): LTR char in RTL para
  860. //
  861. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  862. {
  863. switch (i)
  864. {
  865. case chLTR:
  866. SetFSMCell(pCell, &lvlTwo, S_Y * NUM_FSM_INPUTS); break;
  867. case chRTL:
  868. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  869. case digitLTR:
  870. SetFSMCell(pCell, &lvlTwo, S_Y * NUM_FSM_INPUTS); break;
  871. case digitRTL:
  872. SetFSMCell(pCell, &lvlTwoStart, S_Z * NUM_FSM_INPUTS); break;
  873. case chGround:
  874. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  875. }
  876. }
  877. // State Z(2): RTL number in RTL para
  878. //
  879. for (i=0; i < NUM_FSM_INPUTS; i++, pCell++)
  880. {
  881. switch (i)
  882. {
  883. case chLTR:
  884. SetFSMCell(pCell, &lvlTwoStart, S_Y * NUM_FSM_INPUTS); break;
  885. case chRTL:
  886. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  887. case digitLTR:
  888. SetFSMCell(pCell, &lvlTwoStart, S_Y * NUM_FSM_INPUTS); break;
  889. case digitRTL:
  890. SetFSMCell(pCell, &lvlTwo, S_Z * NUM_FSM_INPUTS); break;
  891. case chGround:
  892. SetFSMCell(pCell, &lvlOne, S_X * NUM_FSM_INPUTS); break;
  893. }
  894. }
  895. AssertSz(&pCell[-(NUM_FSM_STATES * NUM_FSM_INPUTS)] == _pStart, "Bidi FSM incomplete constructed!");
  896. return TRUE;
  897. }
  898. /////// CCallbackBufferBase class implementation
  899. //
  900. void* CBufferBase::GetPtr(int cel)
  901. {
  902. if (_cElem < cel)
  903. {
  904. cel += celAdvance;
  905. _p = PvReAlloc(_p, cel * _cbElem);
  906. if (!_p)
  907. return NULL;
  908. ZeroMemory(_p, cel * _cbElem);
  909. _cElem = cel;
  910. }
  911. return _p;
  912. }
  913. void CBufferBase::Release()
  914. {
  915. if (_p)
  916. FreePv(_p);
  917. }
  918. #endif // NOCOMPLEXSCRIPTS