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.

792 lines
20 KiB

  1. //
  2. // anchor.cpp
  3. //
  4. // CACPWrap
  5. //
  6. #include "private.h"
  7. #include "anchor.h"
  8. #include "globals.h"
  9. #include "normal.h"
  10. #include "anchoref.h"
  11. #include "txtcache.h"
  12. DBG_ID_INSTANCE(CAnchor);
  13. //+---------------------------------------------------------------------------
  14. //
  15. // _NormalizeAnchor
  16. //
  17. //----------------------------------------------------------------------------
  18. void CACPWrap::_NormalizeAnchor(CAnchor *pa)
  19. {
  20. int iNew;
  21. int iCurrent;
  22. LONG acpNew;
  23. CAnchor *paInto;
  24. AssertPrivate(!pa->_fNormalized); // perf: we shouldn't normalize more than once
  25. Perf_IncCounter(PERF_LAZY_NORM);
  26. acpNew = Normalize(_ptsi, pa->GetIch());
  27. pa->_fNormalized = TRUE;
  28. if (acpNew == pa->GetIch())
  29. return;
  30. _Find(pa->GetIch(), &iCurrent);
  31. paInto = _Find(acpNew, &iNew);
  32. _Update(pa, acpNew, iCurrent, paInto, iNew);
  33. if (paInto == NULL)
  34. {
  35. // the target anchor didn't get merged, pretend it did
  36. paInto = pa;
  37. }
  38. else
  39. {
  40. // the target anchor got merged
  41. // need to set the norm bit for the anchor it got merged into
  42. paInto->_fNormalized = TRUE;
  43. }
  44. // we may have just skipped over anchors to the right of this one
  45. // handle those guys now
  46. while ((pa = _rgAnchors.Get(iCurrent)) != paInto)
  47. {
  48. Assert(pa->GetIch() < acpNew);
  49. _Merge(paInto, pa);
  50. }
  51. _Dbg_AssertAnchors();
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // _DragAnchors
  56. //
  57. //----------------------------------------------------------------------------
  58. void CACPWrap::_DragAnchors(LONG acpFrom, LONG acpTo)
  59. {
  60. CAnchor *paFrom;
  61. CAnchor *paTo;
  62. int iFrom;
  63. int iTo;
  64. int i;
  65. Assert(acpFrom > acpTo); // this method only handles dragging to the left
  66. _Find(acpFrom, &iFrom);
  67. if (iFrom < 0)
  68. return; // nothing to drag
  69. if (!_Find(acpTo, &iTo))
  70. {
  71. // if acpTo isn't occupied, drag to the next highest anchor
  72. iTo++;
  73. }
  74. if (iTo > iFrom)
  75. return; // nothing to drag, iTo and iFrom ref anchors to the left of acpTo
  76. // merge all the anchors into the left most
  77. paTo = _rgAnchors.Get(iTo);
  78. for (i=iFrom; i>iTo; i--)
  79. {
  80. paFrom = _rgAnchors.Get(i);
  81. Assert(paFrom->GetIch() > paTo->GetIch());
  82. _Merge(paTo, paFrom);
  83. }
  84. // if the left most anchor isn't already positioned, do that now
  85. paTo->SetACP(acpTo);
  86. _Dbg_AssertAnchors();
  87. }
  88. //+---------------------------------------------------------------------------
  89. //
  90. // _Insert
  91. //
  92. //----------------------------------------------------------------------------
  93. HRESULT CACPWrap::_Insert(CAnchorRef *par, LONG ich)
  94. {
  95. int i;
  96. CAnchor *pa;
  97. if ((pa = _Find(ich, &i)) == NULL)
  98. {
  99. // this ich isn't in the array, allocate a new anchor
  100. if ((pa = new CAnchor) == NULL)
  101. return E_OUTOFMEMORY;
  102. // and insert it into the array
  103. if (!_rgAnchors.Insert(i+1, 1))
  104. {
  105. delete pa;
  106. return E_FAIL;
  107. }
  108. // update _lPendingDeltaIndex
  109. if (i+1 <= _lPendingDeltaIndex)
  110. {
  111. _lPendingDeltaIndex++;
  112. }
  113. else
  114. {
  115. // new anchor is covered by a pending delta, so account for it
  116. ich -= _lPendingDelta;
  117. }
  118. pa->_paw = this;
  119. pa->_ich = ich;
  120. _rgAnchors.Set(i+1, pa);
  121. }
  122. return _Insert(par, pa);
  123. }
  124. //+---------------------------------------------------------------------------
  125. //
  126. // _Insert
  127. //
  128. //----------------------------------------------------------------------------
  129. HRESULT CACPWrap::_Insert(CAnchorRef *par, CAnchor *pa)
  130. {
  131. par->_pa = pa;
  132. par->_prev = NULL;
  133. par->_next = pa->_parFirst;
  134. if (pa->_parFirst)
  135. {
  136. Assert(pa->_parFirst->_prev == NULL);
  137. pa->_parFirst->_prev = par;
  138. }
  139. pa->_parFirst = par;
  140. return S_OK;
  141. }
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Remove
  145. //
  146. //----------------------------------------------------------------------------
  147. void CACPWrap::_Remove(CAnchorRef *parIn)
  148. {
  149. CAnchor *pa = parIn->_pa;
  150. if (parIn->_prev != NULL)
  151. {
  152. // make the previous guy point past parIn
  153. parIn->_prev->_next = parIn->_next;
  154. }
  155. else
  156. {
  157. // this par is at the head of the list
  158. pa->_parFirst = parIn->_next;
  159. }
  160. if (parIn->_next != NULL)
  161. {
  162. parIn->_next->_prev = parIn->_prev;
  163. }
  164. if (pa->_parFirst == NULL)
  165. {
  166. // no more refs, delete the anchor
  167. _Delete(pa);
  168. }
  169. }
  170. //+---------------------------------------------------------------------------
  171. //
  172. // Remove
  173. //
  174. //----------------------------------------------------------------------------
  175. void CACPWrap::_Delete(CAnchor *pa)
  176. {
  177. int i;
  178. if (_Find(pa->GetIch(), &i) == pa)
  179. {
  180. _rgAnchors.Remove(i, 1);
  181. // update _lPendingDeltaIndex
  182. if (i < _lPendingDeltaIndex)
  183. {
  184. _lPendingDeltaIndex--;
  185. }
  186. }
  187. delete pa;
  188. }
  189. //+---------------------------------------------------------------------------
  190. //
  191. // Update
  192. //
  193. // Normalization is handled by the caller who needs to use Renormalize after
  194. // calling this method.
  195. //----------------------------------------------------------------------------
  196. void CACPWrap::_Update(const TS_TEXTCHANGE *pdctc)
  197. {
  198. int iStart;
  199. int ichEndOrg;
  200. int iEndOrg;
  201. int iEndNew;
  202. CAnchorRef *par;
  203. CAnchorRef **ppar;
  204. CAnchor *paStart;
  205. CAnchor *paEnd;
  206. CAnchor *paInto;
  207. BOOL fExactEndMatch;
  208. int dSize;
  209. int iDeltaStart;
  210. int ichStart = pdctc->acpStart;
  211. int ichEndOld = pdctc->acpOldEnd;
  212. int ichEndNew = pdctc->acpNewEnd;
  213. // always invalidate our text cache
  214. CProcessTextCache::Invalidate(_ptsi);
  215. Assert(ichStart >= 0);
  216. Assert(ichEndOld >= ichStart);
  217. Assert(ichEndNew >= ichStart);
  218. if (_rgAnchors.Count() == 0) // any anchors?
  219. return;
  220. dSize = ichEndNew - ichEndOld;
  221. if (dSize == 0)
  222. return;
  223. paStart = _Find(ichStart, &iStart);
  224. if (paStart == NULL)
  225. {
  226. iStart++; // return value was anchor closest to but less than ichStart
  227. if (iStart >= _rgAnchors.Count())
  228. {
  229. // there aren't any anchors >= iStart, so bail, nothing to do
  230. return;
  231. }
  232. paStart = _rgAnchors.Get(iStart);
  233. if (iStart == 0 && paStart->GetIch() > ichEndOld)
  234. {
  235. // the delta is to the left of all the ranges
  236. _AdjustIchs(0, dSize);
  237. _Dbg_AssertAnchors();
  238. return;
  239. }
  240. }
  241. paEnd = _Find(ichEndOld, &iEndOrg);
  242. if (paEnd == NULL)
  243. {
  244. Assert(iEndOrg >= 0); // there should be at least one anchor <= ichEndOld
  245. // if we made it this far
  246. fExactEndMatch = FALSE;
  247. paEnd = _rgAnchors.Get(iEndOrg);
  248. }
  249. else
  250. {
  251. fExactEndMatch = TRUE;
  252. }
  253. if (dSize < 0)
  254. {
  255. // if dSize < 0, then gotta merge all the anchors between old, new pos
  256. if (paEnd->GetIch() > ichEndNew) // are there any anchors between old, new pos?
  257. {
  258. // track change history
  259. // drag the paEnd to its new position
  260. ichEndOrg = paEnd->GetIch();
  261. paInto = _Find(ichEndNew, &iEndNew);
  262. _TrackDelHistory(iEndOrg, fExactEndMatch, iEndNew, paInto != NULL);
  263. iEndNew = _Update(paEnd, ichEndNew, iEndOrg, paInto, iEndNew);
  264. _Find(ichEndOrg, &iEndOrg); // might be a prev anchor if paEnd got deleted in Update!
  265. while (iEndOrg > iEndNew)
  266. {
  267. // don't try to cache pointers, _rgAnchors might get realloc'd
  268. // during the _Merge!
  269. _Merge(_rgAnchors.Get(iEndNew), _rgAnchors.Get(iEndOrg));
  270. iEndOrg--;
  271. }
  272. iEndOrg = iEndNew; // for below
  273. }
  274. // iEndOrg was updated so let's start from next.
  275. iDeltaStart = iEndOrg + 1;
  276. }
  277. else // dSize > 0
  278. {
  279. // iEndOrg will be < iStart when the delta fits entirely between two existing anchors
  280. Assert(iEndOrg >= iStart || (iEndOrg == iStart - 1));
  281. iDeltaStart = (iEndOrg <= iStart) ? iEndOrg + 1 : iEndOrg;
  282. }
  283. // update all the following anchors
  284. _AdjustIchs(iDeltaStart, dSize);
  285. if (dSize > 0 && paStart == paEnd)
  286. {
  287. // Need to account for gravity in the case of an insert to a single anchor pos.
  288. // In practice, this means that we have to handle the anchor refs at the insertion
  289. // anchor individually -- some will want to shift left, others right.
  290. ppar = &paStart->_parFirst;
  291. while (par = *ppar)
  292. {
  293. if (par->_fForwardGravity)
  294. {
  295. // remove the ref from this anchor
  296. *ppar = par->_next;
  297. if (par->_next != NULL)
  298. {
  299. par->_next->_prev = par->_prev;
  300. }
  301. // shove the ref over, it needs to be moved. Insert adds to the head of the list
  302. // so this call is fast and in constant time.
  303. _Insert(par, paStart->GetIch() + dSize);
  304. }
  305. else
  306. {
  307. ppar = &par->_next;
  308. }
  309. }
  310. if (paStart->_parFirst == NULL)
  311. {
  312. // we cleaned this guy out!
  313. Assert(_rgAnchors.Get(iEndOrg) == paStart);
  314. _rgAnchors.Remove(iEndOrg, 1);
  315. delete paStart;
  316. // update _lPendingDeltaIndex
  317. if (iEndOrg < _lPendingDeltaIndex)
  318. {
  319. _lPendingDeltaIndex--;
  320. }
  321. }
  322. }
  323. _Dbg_AssertAnchors();
  324. }
  325. //+---------------------------------------------------------------------------
  326. //
  327. // _TrackDelHistory
  328. //
  329. //----------------------------------------------------------------------------
  330. void CACPWrap::_TrackDelHistory(int iEndOrg, BOOL fExactEndOrgMatch, int iEndNew, BOOL fExactEndNewMatch)
  331. {
  332. CAnchorRef *par;
  333. int i;
  334. Assert(iEndOrg >= iEndNew);
  335. if (fExactEndOrgMatch)
  336. {
  337. // all the anchoref's at iEndOrg get a preceding del
  338. for (par = _rgAnchors.Get(iEndOrg)->_parFirst; par != NULL; par = par->_next)
  339. {
  340. par->_dwHistory |= TS_CH_PRECEDING_DEL;
  341. }
  342. // if iEndOrg == iEndNew on entry, that's everything
  343. if (iEndOrg == iEndNew)
  344. return;
  345. iEndOrg--; // exclude this anchor from loop below
  346. }
  347. if (fExactEndNewMatch)
  348. {
  349. // all the anchoref's at iEndNew get a following del
  350. for (par = _rgAnchors.Get(iEndNew)->_parFirst; par != NULL; par = par->_next)
  351. {
  352. par->_dwHistory |= TS_CH_FOLLOWING_DEL;
  353. }
  354. }
  355. // exclude leftmost anchor from loop below
  356. // either we just handled it in the loop above or !fExactEndNewMatch
  357. // in which case it lies to the left of the affected anchors
  358. iEndNew++;
  359. // the the anchoref's in between get both dels
  360. for (i=iEndNew; i<=iEndOrg; i++)
  361. {
  362. for (par = _rgAnchors.Get(i)->_parFirst; par != NULL; par = par->_next)
  363. {
  364. par->_dwHistory = (TS_CH_PRECEDING_DEL | TS_CH_FOLLOWING_DEL);
  365. }
  366. }
  367. }
  368. //+---------------------------------------------------------------------------
  369. //
  370. // _Update
  371. //
  372. // piInto gets loaded with the index of the anchor after the update. If the
  373. // index changed, pa is now bogus and a new pointer should be grabbed using
  374. // the index.
  375. //----------------------------------------------------------------------------
  376. int CACPWrap::_Update(CAnchor *pa, int ichNew, int iOrg, CAnchor *paInto, int iInto)
  377. {
  378. int i;
  379. Assert(pa->GetIch() != ichNew); // we are so hosed if this happens
  380. i = iInto;
  381. if (paInto != NULL)
  382. {
  383. // gotta do a merge
  384. _Merge(paInto, pa);
  385. }
  386. else
  387. {
  388. if (iInto != iOrg)
  389. {
  390. // move the entry in the array to the new position
  391. i = _rgAnchors.Move(iInto+1, iOrg);
  392. }
  393. // did we cross _lPendingDeltaIndex?
  394. if (i > _lPendingDeltaIndex)
  395. {
  396. // new position is in the pending range, adjust ich
  397. ichNew -= _lPendingDelta;
  398. }
  399. else if (iOrg >= _lPendingDeltaIndex && i <= _lPendingDeltaIndex) // shifting an anchor out of the pending range
  400. {
  401. // one less anchor in the pending range
  402. _lPendingDeltaIndex++;
  403. }
  404. // change the ich
  405. _rgAnchors.Get(i)->_ich = ichNew;
  406. }
  407. _Dbg_AssertAnchors();
  408. return i;
  409. }
  410. //+---------------------------------------------------------------------------
  411. //
  412. // Renormalize
  413. //
  414. //----------------------------------------------------------------------------
  415. void CACPWrap::_Renormalize(int ichStart, int ichEnd)
  416. {
  417. CAnchor *pa;
  418. int iCurrent;
  419. int iEnd;
  420. BOOL fExactEndMatch;
  421. Perf_IncCounter(PERF_RENORMALIZE_COUNTER);
  422. if (_rgAnchors.Count() == 0)
  423. return;
  424. fExactEndMatch = (_Find(ichEnd, &iEnd) != NULL);
  425. if (iEnd < 0)
  426. return;
  427. if (ichStart == ichEnd)
  428. {
  429. if (!fExactEndMatch)
  430. return;
  431. // this can happen on deletions
  432. iCurrent = iEnd;
  433. }
  434. else if (_Find(ichStart, &iCurrent) == NULL)
  435. {
  436. iCurrent++; // we don't care about anchors < ichStart
  437. }
  438. Assert(iCurrent >= 0);
  439. for (;iCurrent <= iEnd; iCurrent++)
  440. {
  441. pa = _rgAnchors.Get(iCurrent);
  442. Assert(pa->GetIch() >= 0);
  443. Assert(pa->GetIch() >= ichStart);
  444. Assert(pa->GetIch() <= ichEnd);
  445. // we'll do the real work only when we have too...
  446. pa->_fNormalized = FALSE;
  447. }
  448. _Dbg_AssertAnchors();
  449. }
  450. //+---------------------------------------------------------------------------
  451. //
  452. // _Find
  453. //
  454. // If piOut != NULL then it is set to the index where ich was found, or the
  455. // index of the next lower ich if ich isn't in the array.
  456. // If there is no element in the array with a lower ich, returns offset -1.
  457. //----------------------------------------------------------------------------
  458. CAnchor *CACPWrap::_Find(int ich, int *piOut)
  459. {
  460. CAnchor *paMatch;
  461. int iMin;
  462. int iMax;
  463. int iMid;
  464. LONG lPendingDeltaIch;
  465. iMin = 0;
  466. iMax = _rgAnchors.Count();
  467. // adjust search for pending delta range
  468. // values aren't consistent across the range boundary
  469. if (_lPendingDelta != 0 && _lPendingDeltaIndex < _rgAnchors.Count())
  470. {
  471. lPendingDeltaIch = _rgAnchors.Get(_lPendingDeltaIndex)->_ich;
  472. if (ich < lPendingDeltaIch + _lPendingDelta)
  473. {
  474. iMax = _lPendingDeltaIndex;
  475. }
  476. else if (ich > lPendingDeltaIch + _lPendingDelta)
  477. {
  478. iMin = _lPendingDeltaIndex+1;
  479. ich -= _lPendingDelta; // make the search below work
  480. }
  481. else
  482. {
  483. iMid = _lPendingDeltaIndex;
  484. paMatch = _rgAnchors.Get(_lPendingDeltaIndex);
  485. goto Exit;
  486. }
  487. }
  488. paMatch = _FindInnerLoop(ich, iMin, iMax, &iMid);
  489. Exit:
  490. if (piOut != NULL)
  491. {
  492. if (paMatch == NULL && iMid >= 0)
  493. {
  494. // couldn't find a match, return the next lowest ich
  495. Assert(iMid == 0 || iMid == _lPendingDeltaIndex || _rgAnchors.Get(iMid-1)->_ich < ich);
  496. if (_rgAnchors.Get(iMid)->_ich > ich)
  497. {
  498. iMid--;
  499. }
  500. }
  501. *piOut = iMid;
  502. }
  503. return paMatch;
  504. }
  505. //+---------------------------------------------------------------------------
  506. //
  507. // _FindInnerLoop
  508. //
  509. //----------------------------------------------------------------------------
  510. CAnchor *CACPWrap::_FindInnerLoop(LONG acp, int iMin, int iMax, int *piIndex)
  511. {
  512. CAnchor *pa;
  513. CAnchor *paMatch;
  514. int iMid;
  515. paMatch = NULL;
  516. iMid = iMin - 1;
  517. while (iMin < iMax)
  518. {
  519. iMid = (iMin + iMax) / 2;
  520. pa = _rgAnchors.Get(iMid);
  521. Assert(pa != NULL);
  522. if (acp < pa->_ich)
  523. {
  524. iMax = iMid;
  525. }
  526. else if (acp > pa->_ich)
  527. {
  528. iMin = iMid + 1;
  529. }
  530. else // acp == pa->_ich
  531. {
  532. paMatch = pa;
  533. break;
  534. }
  535. }
  536. *piIndex = iMid;
  537. return paMatch;
  538. }
  539. //+---------------------------------------------------------------------------
  540. //
  541. // _Merge
  542. //
  543. //----------------------------------------------------------------------------
  544. void CACPWrap::_Merge(CAnchor *paInto, CAnchor *paFrom)
  545. {
  546. CAnchorRef *par;
  547. Assert(paInto != paFrom); // very bad!
  548. Assert(paInto->_parFirst != NULL); // should never have an anchor w/o any refs
  549. if (par = paFrom->_parFirst)
  550. {
  551. // update the anchor for the paFrom refs
  552. while (TRUE)
  553. {
  554. par->_pa = paInto;
  555. if (par->_next == NULL)
  556. break;
  557. par = par->_next;
  558. }
  559. // now par is the last ref in paFrom
  560. // shove all the refs in paFrom into paInto
  561. if (par != NULL)
  562. {
  563. Assert(par->_next == NULL);
  564. par->_next = paInto->_parFirst;
  565. Assert(paInto->_parFirst->_prev == NULL);
  566. paInto->_parFirst->_prev = par;
  567. paInto->_parFirst = paFrom->_parFirst;
  568. }
  569. }
  570. // and free the parFrom
  571. _Delete(paFrom);
  572. }
  573. //+---------------------------------------------------------------------------
  574. //
  575. // _Dbg_AssertAnchors
  576. //
  577. //----------------------------------------------------------------------------
  578. #ifdef DEBUG
  579. void CACPWrap::_Dbg_AssertAnchors()
  580. {
  581. int i;
  582. int ichLast;
  583. CAnchor *pa;
  584. ichLast = -1;
  585. // assert that the anchor array has ascending ich's
  586. for (i=0; i<_rgAnchors.Count(); i++)
  587. {
  588. pa = _rgAnchors.Get(i);
  589. Assert(ichLast < pa->GetIch());
  590. ichLast = pa->GetIch();
  591. }
  592. }
  593. #endif // DEBUG
  594. //+---------------------------------------------------------------------------
  595. //
  596. // _AdjustIchs
  597. //
  598. //----------------------------------------------------------------------------
  599. void CACPWrap::_AdjustIchs(int iFirst, int dSize)
  600. {
  601. CAnchor **ppaFirst;
  602. CAnchor **ppaLast;
  603. LONG dSizeAdjust;
  604. int iLastAnchor;
  605. Assert(dSize != 0);
  606. iLastAnchor = _rgAnchors.Count()-1;
  607. if (iFirst > iLastAnchor)
  608. return;
  609. if (_lPendingDelta == 0 || // no delta pending
  610. _lPendingDeltaIndex > iLastAnchor) // old pending anchors got deleted before update
  611. {
  612. // no pending delta, start a new one
  613. _lPendingDeltaIndex = iFirst;
  614. _lPendingDelta = dSize;
  615. return;
  616. }
  617. if (max(iFirst, _lPendingDeltaIndex) - min(iFirst, _lPendingDeltaIndex)
  618. > iLastAnchor / 2)
  619. {
  620. // adjust points are far apart, update the tail of the range
  621. if (iFirst > _lPendingDeltaIndex)
  622. {
  623. ppaFirst = _rgAnchors.GetPtr(iFirst);
  624. dSizeAdjust = dSize;
  625. }
  626. else
  627. {
  628. ppaFirst = _rgAnchors.GetPtr(_lPendingDeltaIndex);
  629. _lPendingDeltaIndex = iFirst;
  630. dSizeAdjust = _lPendingDelta;
  631. _lPendingDelta = dSize;
  632. }
  633. ppaLast = _rgAnchors.GetPtr(iLastAnchor);
  634. }
  635. else
  636. {
  637. // adjust points are close, update the head of the range
  638. if (iFirst > _lPendingDeltaIndex)
  639. {
  640. ppaFirst = _rgAnchors.GetPtr(_lPendingDeltaIndex);
  641. _lPendingDeltaIndex = iFirst;
  642. ppaLast = _rgAnchors.GetPtr(iFirst - 1);
  643. dSizeAdjust = _lPendingDelta;
  644. }
  645. else
  646. {
  647. ppaFirst = _rgAnchors.GetPtr(iFirst);
  648. ppaLast = _rgAnchors.GetPtr(_lPendingDeltaIndex-1);
  649. dSizeAdjust = dSize;
  650. }
  651. _lPendingDelta += dSize;
  652. }
  653. // do the real work
  654. while (ppaFirst <= ppaLast)
  655. {
  656. (*ppaFirst++)->_ich += dSizeAdjust;
  657. }
  658. }