Source code of Windows XP (NT5)
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.

820 lines
17 KiB

  1. /*
  2. * Text Breaker & Bit stream break array class implementation
  3. *
  4. * File: txtbrk.cpp
  5. * Create: Mar 29, 1998
  6. * Author: Worachai Chaoweeraprasit (wchao)
  7. *
  8. * Copyright (c) 1998-1999, Microsoft Corporation. All rights reserved.
  9. */
  10. //#include "stdafx.h"
  11. //#include "Array.h"
  12. #include "_common.h"
  13. #ifndef NOCOMPLEXSCRIPTS
  14. #ifndef BITVIEW
  15. #include "_edit.h"
  16. #include "_frunptr.h"
  17. #include "_range.h"
  18. #include "_notmgr.h"
  19. #endif
  20. #include "_txtbrk.h"
  21. CBreakArray::CBreakArray()
  22. {
  23. _ibGap = 0;
  24. _cbGap = 0;
  25. _cbSize = 0;
  26. _cbBreak = 0;
  27. }
  28. void CBreakArray::CheckArray ()
  29. {
  30. if (!IsValid())
  31. {
  32. // Add the first element. This is required to be a sentinel.
  33. Add(1, NULL);
  34. }
  35. }
  36. // Remove <cchOld> and insert <cchNew> break items at <cp>
  37. LONG CBreakArray::ReplaceBreak (
  38. LONG cp, // insertion cp
  39. LONG cchOld, // number of break item to be deleted
  40. LONG cchNew) // number of break item to be inserted
  41. {
  42. PUSH_STATE(cp, cchNew, REPLACER);
  43. if (!cchOld && cchNew)
  44. return VALIDATE(InsertBreak (cp, cchNew));
  45. if (cchOld && !cchNew)
  46. return VALIDATE(RemoveBreak (cp, cchOld));
  47. LONG cRep = 0; // number of new break inserted after replacing
  48. if (cchOld > cchNew)
  49. {
  50. cRep = RemoveBreak(cp+cchNew, cchOld-cchNew);
  51. ClearBreak(cp, cchNew);
  52. }
  53. else if (cchOld < cchNew)
  54. {
  55. cRep = InsertBreak(cp+cchOld, cchNew-cchOld);
  56. ClearBreak(cp, cchOld);
  57. }
  58. else if (cchNew)
  59. {
  60. ClearBreak(cp, cchNew);
  61. }
  62. return VALIDATE(cRep);
  63. }
  64. // Add <cch> break items at <cp>
  65. // note: This routine assumes there is no gap left in the bit array
  66. LONG CBreakArray::AddBreak(
  67. LONG cp,
  68. LONG cch)
  69. {
  70. Assert (cp == _cbBreak);
  71. LONG cchAdd = min(cch, _cbSize - _cbBreak);
  72. LONG c;
  73. _cbBreak += cchAdd;
  74. cch -= cchAdd;
  75. if (cch > 0)
  76. {
  77. cp += cchAdd;
  78. c = (cch + RSIZE-1)/RSIZE;
  79. Insert (cp / RSIZE, c);
  80. _cbSize += c * RSIZE;
  81. _cbBreak += cch;
  82. cchAdd += cch;
  83. }
  84. return cchAdd;
  85. }
  86. // Insert <cch> break items at <cp>
  87. // <detail see: bitrun.html>
  88. LONG CBreakArray::InsertBreak (
  89. LONG cp, // insertion point cp
  90. LONG cch) // number of break item to be inserted
  91. {
  92. LONG cIns = 0; // number of break inserted
  93. ITEM *peli, *pelj;
  94. LONG cchSave = cch;
  95. PUSH_STATE(cp, cch, INSERTER);
  96. // Make sure we establish the array
  97. CheckArray();
  98. if (cp == _ibGap)
  99. {
  100. // The insertion takes place at the gap,
  101. // reposition and shrink the gap down
  102. for (cIns=0 ; cch > 0 && cIns < _cbGap; cIns++, cch--, cp++)
  103. {
  104. peli = Elem(cp / RSIZE);
  105. *peli &= ~(1<<(cp % RSIZE));
  106. }
  107. _cbGap -= cIns;
  108. _ibGap += cIns;
  109. _cbBreak += cIns;
  110. }
  111. else
  112. {
  113. // The insertion point is outside the gap,
  114. // Collapse the gap and go as normal.
  115. CollapseGap();
  116. }
  117. if (cch <= 0)
  118. return VALIDATE(cIns);
  119. if (cp == _cbBreak)
  120. return VALIDATE(cIns + AddBreak(cp, cch));
  121. Assert (_cbGap == 0 && cp < _cbBreak);
  122. LONG cit = (cch+RSIZE-1) / RSIZE;
  123. LONG i = cp / RSIZE;
  124. LONG j;
  125. ITEM uh, ul; // H: high-mask after cp, L: low-mask before cp
  126. // Insert items
  127. Insert (i+1, cit);
  128. cIns += (cit * RSIZE);
  129. // Get the [i]
  130. peli = Elem(i);
  131. // Create the high/low mask & keep the masked values
  132. ul = MASK_LOW (-1, cp % RSIZE);
  133. uh = ~ul;
  134. ul &= *peli;
  135. uh &= *peli;
  136. // Reference the [j]
  137. j = i + cit;
  138. // Move L to [i]; move H to [j]
  139. *peli = ul;
  140. pelj = Elem(j);
  141. Assert (pelj);
  142. *pelj = uh;
  143. // Calculate gap position
  144. _ibGap = cp + (cch / RSIZE) * RSIZE;
  145. _cbGap = cit*RSIZE - cch;
  146. Assert(_cbGap < RSIZE && cIns - _cbGap == cchSave);
  147. _cbSize += (cIns - cchSave + cch);
  148. _cbBreak += cch;
  149. return VALIDATE(cIns - _cbGap);
  150. }
  151. // Remove <cch> break items at <cp>
  152. // <detail see: bitrun.html>
  153. LONG CBreakArray::RemoveBreak (
  154. LONG cp, // deletion point cp
  155. LONG cch) // number of break item to be deleted
  156. {
  157. Assert (IsValid() && cp + cch <= _cbBreak);
  158. PUSH_STATE(cp, cch, REMOVER);
  159. LONG i = cp / RSIZE;
  160. LONG j;
  161. LONG cDel = 0; // number of break deleted
  162. if (cp == _ibGap)
  163. {
  164. // The deletion takes place at the gap,
  165. // reposition and expand the gap
  166. cDel = cch;
  167. _cbGap += cch;
  168. _cbBreak -= cch;
  169. cch = 0;
  170. // Optimise the gap size:
  171. // Keep the gap small so we dont spend much time collapsing it.
  172. j = (_ibGap+_cbGap) / RSIZE - i - 1;
  173. if (j > 0)
  174. {
  175. Remove(i+1, j);
  176. _cbGap -= j * RSIZE;
  177. _cbSize -= j * RSIZE;
  178. }
  179. }
  180. else
  181. {
  182. // The deletion point is outside the gap,
  183. // Collapse the gap and go as normal.
  184. CollapseGap();
  185. }
  186. if (!cch)
  187. return VALIDATE(-cDel);
  188. LONG cit = cch / RSIZE;
  189. ITEM uh, ul; // H: high-mask after cp, L: low-mask before cp
  190. ITEM *peli, *pelj;
  191. j = (cp+cch) / RSIZE;
  192. // Get the [i] and [j]
  193. peli = Elem(i);
  194. pelj = Elem(j);
  195. // Create the high/low mask & keep the masked values
  196. ul = MASK_LOW (-1, cp % RSIZE);
  197. uh = ~MASK_LOW (-1, (cp+cch) % RSIZE);
  198. ul &= *peli;
  199. uh &= pelj ? *pelj : 0;
  200. // Remove <cch/RSIZE> items
  201. if (cit)
  202. {
  203. Remove(i, cit);
  204. cDel += (cit * RSIZE);
  205. }
  206. // Zero [i]
  207. peli = Elem(i);
  208. *peli = 0;
  209. // Reference the (new) [j]
  210. j -= cit;
  211. // Move H to [j]
  212. pelj = Elem(j);
  213. if (pelj)
  214. *pelj = uh;
  215. // Or L to [i]
  216. *peli |= ul;
  217. // Calculate gap position
  218. _ibGap = cp;
  219. _cbGap = cch % RSIZE;
  220. Assert(_cbGap < RSIZE && cDel + _cbGap == cch);
  221. _cbSize -= cDel;
  222. _cbBreak -= cch;
  223. return VALIDATE(-cDel - _cbGap);
  224. }
  225. // Determine if we can break between char[cp-1] and [cp]
  226. BOOL CBreakArray::GetBreak (LONG cp)
  227. {
  228. if (!IsValid() || cp >= _cbBreak)
  229. return FALSE;
  230. cp += cp < _ibGap ? 0 : _cbGap;
  231. if (cp / RSIZE < Count() - 1)
  232. return GetAt(cp / RSIZE) & (1<<(cp % RSIZE));
  233. return FALSE;
  234. }
  235. // Set break at cp, so it's breakable between char[cp-1] and [cp]
  236. void CBreakArray::SetBreak (LONG cp, BOOL fOn)
  237. {
  238. if (cp >= _cbBreak)
  239. return;
  240. CheckArray();
  241. cp += cp < _ibGap ? 0 : _cbGap;
  242. ITEM *pel = Elem(cp / RSIZE);
  243. *pel = fOn ? *pel | (1<<(cp % RSIZE)) : *pel & ~(1<<(cp % RSIZE));
  244. }
  245. // Clear break in range <cch> start at position <cp>
  246. void CBreakArray::ClearBreak (
  247. LONG cp,
  248. LONG cch)
  249. {
  250. if (!cch)
  251. return;
  252. Assert (cch > 0 && cp < _cbBreak);
  253. CheckArray();
  254. cp += cp < _ibGap ? 0 : _cbGap;
  255. cch += cp < _ibGap && cp + cch > _ibGap ? _cbGap : 0;
  256. LONG i = cp / RSIZE;
  257. LONG j = (cp+cch) / RSIZE;
  258. ITEM uMaskl, uMaskh;
  259. ITEM *pel;
  260. uMaskl = MASK_LOW(-1, cp % RSIZE);
  261. uMaskh = ~MASK_LOW(-1, (cp+cch) % RSIZE);
  262. if (i==j)
  263. {
  264. uMaskl |= uMaskh;
  265. uMaskh = uMaskl;
  266. }
  267. // clear first item
  268. pel = Elem(i);
  269. *pel &= uMaskl;
  270. if (uMaskh != (ITEM)-1)
  271. {
  272. // clear last item
  273. pel = Elem(j);
  274. *pel &= uMaskh;
  275. }
  276. // clear items in between
  277. i++;
  278. while (i < j)
  279. {
  280. pel = Elem(i);
  281. *pel = 0;
  282. i++;
  283. }
  284. }
  285. // Collapse the gap down to 0 using bit shifting
  286. // (using the 'bits remove with shifting' algorithm)
  287. //
  288. LONG CBreakArray::CollapseGap ()
  289. {
  290. #ifdef BITVIEW
  291. _cCollapse++;
  292. #endif
  293. if (_cbGap == 0)
  294. return 0; // No gap
  295. PUSH_STATE(0, 0, COLLAPSER);
  296. LONG cit = _cbGap / RSIZE;
  297. LONG i = _ibGap / RSIZE;
  298. LONG j = (_ibGap+_cbGap) / RSIZE;
  299. LONG cDel = 0; // number of break deleted
  300. ITEM uh, ul; // H: high-mask after cp, L: low-mask before cp
  301. ITEM *peli, *pelj;
  302. Assert (IsValid());
  303. // Get the [i] and [j]
  304. peli = Elem(i);
  305. pelj = Elem(j);
  306. // Create the high/low mask & keep the masked values
  307. ul = MASK_LOW (-1, _ibGap % RSIZE);
  308. uh = ~MASK_LOW (-1, (_ibGap+_cbGap) % RSIZE);
  309. ul &= *peli;
  310. uh &= pelj ? *pelj : 0;
  311. // Remove items
  312. if (cit)
  313. {
  314. Remove(i, cit);
  315. cDel += (cit * RSIZE);
  316. _cbSize -= cDel;
  317. if (!_cbSize)
  318. return VALIDATE(cDel);
  319. }
  320. // Zero [i]
  321. peli = Elem(i);
  322. *peli = 0;
  323. // Reference the (new) [j]
  324. j -= cit;
  325. cit = Count() - 1;
  326. // Move H to [j]
  327. pelj = Elem(j);
  328. if (pelj)
  329. *pelj = uh;
  330. // Shifting bits down <cit-i> items starting@[i]
  331. ShDn(i, cit-i, _cbGap % RSIZE);
  332. cDel += (_cbGap % RSIZE);
  333. // Or L to [i]
  334. *peli |= ul;
  335. Assert (cit > 0 && cDel == _cbGap);
  336. _cbGap = 0;
  337. if (_cbSize - _cbBreak > RSIZE)
  338. {
  339. // The last item was shifted til empty.
  340. // No need to keep it around.
  341. Remove(cit-1, 1);
  342. _cbSize -= RSIZE;
  343. }
  344. return VALIDATE(0);
  345. }
  346. // Shifting <cel> dword n bits UPWARD
  347. void CBreakArray::ShUp (LONG iel, LONG cel, LONG n)
  348. {
  349. if (n < RSIZE)
  350. {
  351. ITEM *pel;
  352. ITEM uo; // shifting overflow
  353. ITEM ua = 0; // shifting addendum
  354. ITEM uMask = MASK_HIGH(-1, n);
  355. while (cel > 0)
  356. {
  357. pel = Elem(iel);
  358. Assert (pel);
  359. uo = (*pel & uMask) >> (RSIZE-n);
  360. *pel = (*pel << n) | ua;
  361. ua = uo;
  362. iel++;
  363. cel--;
  364. }
  365. }
  366. }
  367. // Shifting <cel> dword n bits DOWNWARD
  368. void CBreakArray::ShDn (LONG iel, LONG cel, LONG n)
  369. {
  370. if (n < RSIZE)
  371. {
  372. ITEM *pel;
  373. ITEM uo; // shifting overflow
  374. ITEM ua = 0; // shifting addendum
  375. ITEM uMask = MASK_LOW(-1, n);
  376. iel += cel-1;
  377. while (cel > 0)
  378. {
  379. pel = Elem(iel);
  380. Assert (pel);
  381. uo = (*pel & uMask) << (RSIZE-n);
  382. *pel = (*pel >> n) | ua;
  383. ua = uo;
  384. iel--;
  385. cel--;
  386. }
  387. }
  388. }
  389. #ifdef BVDEBUG
  390. LONG CBreakArray::Validate (LONG cchRet)
  391. {
  392. Assert(_cbSize >= 0 && (Count() - 1)*RSIZE == _cbSize);
  393. Assert(_cbBreak - _s.cbBreak == cchRet);
  394. return cchRet;
  395. }
  396. void CBreakArray::PushState (LONG cp, LONG cch, LONG who)
  397. {
  398. _s.who = who;
  399. _s.ibGap = _ibGap;
  400. _s.cbGap = _cbGap;
  401. _s.cbSize = _cbSize;
  402. _s.cbBreak = _cbBreak;
  403. _s.cp = cp;
  404. _s.cch = cch;
  405. }
  406. #endif
  407. #ifdef BITVIEW
  408. LONG CBreakArray::SetCollapseCount ()
  409. {
  410. LONG cc = _cCollapse;
  411. _cCollapse = 0;
  412. return cc;
  413. }
  414. #endif
  415. #ifndef BITVIEW
  416. /////// CTxtBreaker class implementation
  417. //
  418. //
  419. CTxtBreaker::CTxtBreaker(
  420. CTxtEdit* ped)
  421. {
  422. // Register ourself in the notification list
  423. // so we get notified when backing store changed.
  424. CNotifyMgr *pnm = ped->GetNotifyMgr();
  425. if(pnm)
  426. pnm->Add((ITxNotify *)this);
  427. _ped = ped;
  428. }
  429. CTxtBreaker::~CTxtBreaker()
  430. {
  431. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  432. if(pnm)
  433. pnm->Remove((ITxNotify *)this);
  434. // Clear break arrays
  435. if (_pbrkWord)
  436. {
  437. _pbrkWord->Clear(AF_DELETEMEM);
  438. delete _pbrkWord;
  439. }
  440. if (_pbrkChar)
  441. {
  442. _pbrkChar->Clear(AF_DELETEMEM);
  443. delete _pbrkChar;
  444. }
  445. }
  446. // Adding the breaker
  447. // return TRUE means we plug something in.
  448. BOOL CTxtBreaker::AddBreaker(
  449. UINT brkUnit)
  450. {
  451. BOOL fr = FALSE;
  452. CUniscribe* pusp = _ped->Getusp();
  453. if (pusp && pusp->IsValid())
  454. {
  455. // Initialize proper bit mask used to test breaking bits
  456. if (!_pbrkWord && (brkUnit & BRK_WORD))
  457. {
  458. _pbrkWord = new CBreakArray();
  459. Assert(_pbrkWord);
  460. if (_pbrkWord)
  461. fr = TRUE;
  462. }
  463. if (!_pbrkChar && (brkUnit & BRK_CLUSTER))
  464. {
  465. _pbrkChar = new CBreakArray();
  466. Assert(_pbrkChar);
  467. if (_pbrkChar)
  468. fr = TRUE;
  469. }
  470. }
  471. return fr;
  472. }
  473. // <devnote:> The "cluster" break array actually contains invert logic.
  474. // This is for speed since it's likely to be a sparse array.
  475. CTxtBreaker::CanBreakCp(
  476. BREAK_UNIT brk, // kind of break
  477. LONG cp) // given cp
  478. {
  479. Assert (brk != BRK_BOTH);
  480. if (brk == BRK_WORD && _pbrkWord)
  481. return _pbrkWord->GetBreak(cp);
  482. if (brk == BRK_CLUSTER && _pbrkChar)
  483. return !_pbrkChar->GetBreak(cp);
  484. return FALSE;
  485. }
  486. void CTxtBreaker::OnPreReplaceRange (
  487. LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
  488. LONG cchDel, //@parm Count of chars after cp that are deleted
  489. LONG cchNew, //@parm Count of chars inserted after cp
  490. LONG cpFormatMin, //@parm cpMin for a formatting change
  491. LONG cpFormatMax, //@parm cpMost for a formatting change
  492. NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
  493. {
  494. /*** Not good idea to check anything in PreReplaceRange before the action is complete.
  495. #ifdef DEBUG
  496. if (_pbrkWord)
  497. Assert (_pbrkWord->GetCchBreak() == _ped->GetTextLength());
  498. if (_pbrkChar)
  499. Assert (_pbrkChar->GetCchBreak() == _ped->GetTextLength());
  500. #endif
  501. ***/
  502. }
  503. // Sync up the breaking result of each available breaker.
  504. void CTxtBreaker::Refresh()
  505. {
  506. CBreakArray* pbrk = _pbrkWord;
  507. LONG len = _ped->GetTextLength();
  508. for (int i=0; i<2; i++)
  509. {
  510. if (pbrk && pbrk->GetCchBreak())
  511. {
  512. // (temporarily) collapse the breaking result
  513. pbrk->RemoveBreak(0, len);
  514. }
  515. pbrk = _pbrkChar;
  516. }
  517. // Now announce the new coming text of the whole document.
  518. // (we recalculate both results at once here since the ScriptBreak returns
  519. // both kind of information in one call. No need to slow thing down by making 2 calls.)
  520. OnPostReplaceRange(0, 0, len, 0, 0, NULL);
  521. }
  522. // This method gets called once backing store changed.
  523. // Produce correct breaking positions for the text range effected by the change.
  524. //
  525. void CTxtBreaker::OnPostReplaceRange (
  526. LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
  527. LONG cchDel, //@parm Count of chars after cp that are deleted
  528. LONG cchNew, //@parm Count of chars inserted after cp
  529. LONG cpFormatMin, //@parm cpMin for a formatting change
  530. LONG cpFormatMax, //@parm cpMost for a formatting change
  531. NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
  532. {
  533. if (!cchDel && !cchNew)
  534. return;
  535. #ifdef DEBUG
  536. LONG cchbrkw = _pbrkWord ? _pbrkWord->GetCchBreak() : 0;
  537. LONG cchbrkc = _pbrkChar ? _pbrkChar->GetCchBreak() : 0;
  538. #endif
  539. CTxtPtr tp(_ped, cp);
  540. LONG cpBreak = cp > 0 ? cp - 1 : 0;
  541. CBreakArray* pSyncObj = NULL; // Break object to retrieve sync point
  542. LONG cBrks = 1, cBrksSave;
  543. BOOL fStop = TRUE; // default: looking for stop
  544. LONG cpStart, cpEnd;
  545. // Figure a boundary limited by whitespaces
  546. tp.FindWhiteSpaceBound(cchNew, cpStart, cpEnd);
  547. Assert (_pbrkWord || _pbrkChar);
  548. // Use wordbreak array (if available) to figure sync point,
  549. // otherwise use cluster break array
  550. if (_pbrkWord)
  551. {
  552. pSyncObj = _pbrkWord;
  553. cBrks = CWORD_TILLSYNC;
  554. }
  555. else if (_pbrkChar)
  556. {
  557. pSyncObj = _pbrkChar;
  558. cBrks = CCLUSTER_TILLSYNC;
  559. // for perf reason, we kept cluster breaks in invert logic.
  560. // Logic TRUE in the array means "NOT A CLUSTER BREAK". The array is
  561. // like a sparse metric full of 0.
  562. fStop = FALSE;
  563. }
  564. // Figure sync point so we can go from there.
  565. cBrksSave = cBrks;
  566. while (pSyncObj && cpBreak > cpStart)
  567. {
  568. if (pSyncObj->GetBreak(cpBreak) == fStop)
  569. if (!cBrks--)
  570. break;
  571. cpBreak--;
  572. }
  573. cpStart = cpBreak;
  574. tp.SetCp(cpStart);
  575. cBrks = cBrksSave;
  576. // adjust the end boundary to the state of break array.
  577. cpEnd -= cchNew - cchDel;
  578. cpBreak = cp + cchDel;
  579. while (pSyncObj && cpBreak < cpEnd)
  580. {
  581. if (pSyncObj->GetBreak(cpBreak) == fStop)
  582. if (!cBrks--)
  583. break;
  584. cpBreak++;
  585. }
  586. cpEnd = cpBreak;
  587. // adjust the end boundary back to the state of the backing store.
  588. cpEnd -= cchDel - cchNew;
  589. Assert (cpStart >= 0 && cpEnd >= 0 && cpStart <= cpEnd);
  590. if (cpStart == cpEnd)
  591. {
  592. // This is deletion process
  593. if (_pbrkWord)
  594. _pbrkWord->ReplaceBreak(cp, cchDel, 0);
  595. if (_pbrkChar)
  596. _pbrkChar->ReplaceBreak(cp, cchDel, 0);
  597. }
  598. else
  599. {
  600. CUniscribe* pusp;
  601. const SCRIPT_PROPERTIES* psp;
  602. SCRIPT_ITEM* pi;
  603. SCRIPT_LOGATTR* pl;
  604. PUSP_CLIENT pc = NULL;
  605. BYTE pbBufIn[MAX_CLIENT_BUF];
  606. WCHAR* pwchString;
  607. LONG cchString = cpEnd - cpStart;
  608. int cItems;
  609. // Now with the minimum range, we begin itemize and break the word/clusters.
  610. // :The process is per item basis.
  611. // prepare Uniscribe
  612. pusp = _ped->Getusp();
  613. if (!pusp)
  614. {
  615. // No Uniscribe instance allowed to be created.
  616. // We failed badly!
  617. Assert (FALSE);
  618. return;
  619. }
  620. // allocate temp buffer for itemization
  621. pusp->CreateClientStruc(pbBufIn, MAX_CLIENT_BUF, &pc, cchString, cli_Itemize | cli_Break);
  622. if (!pc)
  623. // nom!
  624. return;
  625. Assert (tp.GetCp() == cpStart);
  626. tp.GetText(cchString, pc->si->pwchString);
  627. if (pusp->ItemizeString (pc, 0, &cItems, pc->si->pwchString, cchString, 0) > 0)
  628. {
  629. // Prepare room in the break array(s) to put the break results
  630. if (_pbrkWord)
  631. _pbrkWord->ReplaceBreak (cp, cchDel, cchNew);
  632. if (_pbrkChar)
  633. _pbrkChar->ReplaceBreak (cp, cchDel, cchNew);
  634. // Initial working pointers
  635. pi = pc->si->psi;
  636. pwchString = pc->si->pwchString;
  637. pl = pc->sb->psla;
  638. for (int i=0; i < cItems; i++)
  639. {
  640. psp = pusp->GeteProp(pi[i].a.eScript);
  641. if (psp->fComplex &&
  642. (psp->fNeedsWordBreaking || psp->fNeedsCaretInfo))
  643. {
  644. // Break only the item needing text break
  645. if ( ScriptBreak(&pwchString[pi[i].iCharPos], pi[i+1].iCharPos - pi[i].iCharPos,
  646. &pi[i].a, pl) != S_OK )
  647. {
  648. TRACEWARNSZ ("Calling ScriptBreak FAILED!");
  649. break;
  650. }
  651. // Fill in the breaking result
  652. cp = cpStart + pi[i].iCharPos;
  653. for (int j = pi[i+1].iCharPos - pi[i].iCharPos - 1; j >= 0; j--)
  654. {
  655. if (_pbrkWord)
  656. _pbrkWord->SetBreak(cp+j, pl[j].fWordStop);
  657. if (_pbrkChar)
  658. _pbrkChar->SetBreak(cp+j, !pl[j].fCharStop);
  659. }
  660. }
  661. else
  662. {
  663. // Note: ClearBreak is faster than ZeroMemory the CArray::ArInsert()
  664. if (_pbrkWord)
  665. _pbrkWord->ClearBreak(cpStart + pi[i].iCharPos, pi[i+1].iCharPos - pi[i].iCharPos);
  666. if (_pbrkChar)
  667. _pbrkChar->ClearBreak(cpStart + pi[i].iCharPos, pi[i+1].iCharPos - pi[i].iCharPos);
  668. }
  669. }
  670. }
  671. if (pc && pbBufIn != (BYTE*)pc)
  672. delete pc;
  673. }
  674. #ifdef DEBUG
  675. if (_pbrkWord)
  676. Assert (_pbrkWord->GetCchBreak() - cchbrkw == cchNew - cchDel);
  677. if (_pbrkChar)
  678. Assert (_pbrkChar->GetCchBreak() - cchbrkc == cchNew - cchDel);
  679. #endif
  680. }
  681. #endif // !BITVIEW
  682. #endif // NOCOMPLEXSCRIPTS