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.

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