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.

332 lines
8.2 KiB

  1. //
  2. // spans.cpp
  3. //
  4. // CSpanSet
  5. //
  6. #include "private.h"
  7. #include "spans.h"
  8. #include "immxutil.h"
  9. DBG_ID_INSTANCE(CSpanSet);
  10. //+---------------------------------------------------------------------------
  11. //
  12. // _InsertNewSpan
  13. //
  14. //----------------------------------------------------------------------------
  15. SPAN *CSpanSet::_InsertNewSpan(int iIndex)
  16. {
  17. if (!_rgSpans.Insert(iIndex, 1))
  18. return NULL;
  19. return _rgSpans.GetPtr(iIndex);
  20. }
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Add
  24. //
  25. //----------------------------------------------------------------------------
  26. void CSpanSet::Add(DWORD dwFlags, IAnchor *paStart, IAnchor *paEnd, AnchorOwnership ao)
  27. {
  28. int iStart;
  29. int iEnd;
  30. SPAN *psStart;
  31. SPAN *psEnd;
  32. IAnchor *paLowerBound;
  33. IAnchor *paUpperBound;
  34. IAnchor *paClone;
  35. BOOL fReleaseStart;
  36. BOOL fReleaseEnd;
  37. fReleaseStart = fReleaseEnd = (ao == OWN_ANCHORS);
  38. if (_AllSpansCovered())
  39. {
  40. // if we already cover the entire doc, nothing to do
  41. goto ExitRelease;
  42. }
  43. if (paStart == NULL)
  44. {
  45. Assert(paEnd == NULL);
  46. // NULL, NULL means "the whole doc"
  47. // so this new span automatically eats all pre-existing ones
  48. dwFlags = 0; // don't accept corrections for the entire doc
  49. iStart = 0;
  50. iEnd = _rgSpans.Count();
  51. if (iEnd == 0)
  52. {
  53. if ((psStart = _InsertNewSpan(0)) == NULL)
  54. return; // out-of-memory!
  55. memset(psStart, 0, sizeof(*psStart));
  56. }
  57. else
  58. {
  59. // need to free the anchors in the first span
  60. psStart = _rgSpans.GetPtr(0);
  61. SafeReleaseClear(psStart->paStart);
  62. SafeReleaseClear(psStart->paEnd);
  63. psStart->dwFlags = 0;
  64. }
  65. goto Exit;
  66. }
  67. Assert(CompareAnchors(paStart, paEnd) <= 0);
  68. psStart = _Find(paStart, &iStart);
  69. psEnd = _Find(paEnd, &iEnd);
  70. if (iStart == iEnd)
  71. {
  72. if (psStart == NULL)
  73. {
  74. // this span doesn't overlap with anything else
  75. iStart++;
  76. if ((psStart = _InsertNewSpan(iStart)) == NULL)
  77. goto ExitRelease; // out-of-memory!
  78. if (ao == OWN_ANCHORS)
  79. {
  80. psStart->paStart = paStart;
  81. fReleaseStart = FALSE;
  82. psStart->paEnd = paEnd;
  83. fReleaseEnd = FALSE;
  84. }
  85. else
  86. {
  87. if (paStart->Clone(&psStart->paStart) != S_OK)
  88. {
  89. _rgSpans.Remove(iStart, 1);
  90. goto ExitRelease;
  91. }
  92. if (paEnd->Clone(&psStart->paEnd) != S_OK)
  93. {
  94. psStart->paStart->Release();
  95. _rgSpans.Remove(iStart, 1);
  96. goto ExitRelease;
  97. }
  98. }
  99. psStart->dwFlags = dwFlags;
  100. }
  101. else if (psEnd != NULL)
  102. {
  103. Assert(psStart == psEnd);
  104. // the new span is a subset of an existing span
  105. psStart->dwFlags &= dwFlags;
  106. }
  107. else
  108. {
  109. // this spans overlaps with an existing one, but extends further to the right
  110. // just swap out the end anchor, since we know (iStart == iEnd) that we only
  111. // cover just this one span
  112. if (ao == OWN_ANCHORS)
  113. {
  114. psStart->paEnd->Release();
  115. psStart->paEnd = paEnd;
  116. fReleaseEnd = FALSE;
  117. }
  118. else
  119. {
  120. if (paEnd->Clone(&paClone) != S_OK || paClone == NULL)
  121. goto ExitRelease;
  122. psStart->paEnd->Release();
  123. psStart->paEnd = paClone;
  124. }
  125. }
  126. goto ExitRelease;
  127. }
  128. // delete all but one of the covered spans
  129. if (psStart == NULL)
  130. {
  131. iStart++;
  132. psStart = _rgSpans.GetPtr(iStart);
  133. Assert(psStart != NULL);
  134. if (ao == OWN_ANCHORS)
  135. {
  136. paLowerBound = paStart;
  137. fReleaseStart = FALSE;
  138. }
  139. else
  140. {
  141. if (FAILED(paStart->Clone(&paLowerBound)))
  142. goto ExitRelease;
  143. }
  144. }
  145. else
  146. {
  147. paLowerBound = psStart->paStart;
  148. paLowerBound->AddRef();
  149. }
  150. if (psEnd == NULL)
  151. {
  152. if (ao == OWN_ANCHORS)
  153. {
  154. paUpperBound = paEnd;
  155. fReleaseEnd = FALSE;
  156. }
  157. else
  158. {
  159. if (FAILED(paEnd->Clone(&paUpperBound)))
  160. goto ExitRelease;
  161. }
  162. }
  163. else
  164. {
  165. paUpperBound = psEnd->paEnd;
  166. paUpperBound->AddRef();
  167. }
  168. // psStart grows to cover the entire span
  169. psStart->paStart->Release();
  170. psStart->paEnd->Release();
  171. psStart->paStart = paLowerBound;
  172. psStart->paEnd = paUpperBound;
  173. Exit:
  174. // then delete the covered spans
  175. for (int i=iStart + 1; i <= iEnd; i++)
  176. {
  177. SPAN *ps = _rgSpans.GetPtr(i);
  178. dwFlags &= ps->dwFlags;
  179. ps->paStart->Release();
  180. ps->paEnd->Release();
  181. }
  182. psStart->dwFlags &= dwFlags; // only set correction bit if all spans were corrections
  183. //Remove all spans we just cleared out
  184. if (iEnd - iStart > 0)
  185. {
  186. _rgSpans.Remove(iStart+1, iEnd - iStart);
  187. }
  188. ExitRelease:
  189. if (fReleaseStart)
  190. {
  191. SafeRelease(paStart);
  192. }
  193. if (fReleaseEnd)
  194. {
  195. SafeRelease(paEnd);
  196. }
  197. }
  198. //+---------------------------------------------------------------------------
  199. //
  200. // _Find
  201. //
  202. //----------------------------------------------------------------------------
  203. SPAN *CSpanSet::_Find(IAnchor *pa, int *piOut)
  204. {
  205. SPAN *ps;
  206. SPAN *psMatch;
  207. int iMin;
  208. int iMax;
  209. int iMid;
  210. psMatch = NULL;
  211. iMid = -1;
  212. iMin = 0;
  213. iMax = _rgSpans.Count();
  214. while (iMin < iMax)
  215. {
  216. iMid = (iMin + iMax) / 2;
  217. ps = _rgSpans.GetPtr(iMid);
  218. Assert(ps != NULL);
  219. if (CompareAnchors(pa, ps->paStart) < 0)
  220. {
  221. iMax = iMid;
  222. }
  223. else if (CompareAnchors(pa, ps->paEnd) > 0)
  224. {
  225. iMin = iMid + 1;
  226. }
  227. else // anchor is in the span
  228. {
  229. psMatch = ps;
  230. break;
  231. }
  232. }
  233. if (piOut != NULL)
  234. {
  235. if (psMatch == NULL && iMid >= 0)
  236. {
  237. // couldn't find a match, return the next lowest span
  238. Assert(iMid == 0 || CompareAnchors(_rgSpans.GetPtr(iMid-1)->paEnd, pa) < 0);
  239. if (CompareAnchors(_rgSpans.GetPtr(iMid)->paStart, pa) > 0)
  240. {
  241. iMid--;
  242. }
  243. }
  244. *piOut = iMid;
  245. }
  246. return psMatch;
  247. }
  248. //+---------------------------------------------------------------------------
  249. //
  250. // AnchorsAway
  251. //
  252. // Note we don't zero-out the IAnchors pointers! Be careful.
  253. //----------------------------------------------------------------------------
  254. void CSpanSet::_AnchorsAway()
  255. {
  256. SPAN *span;
  257. int i;
  258. for (i=0; i<_rgSpans.Count(); i++)
  259. {
  260. span = _rgSpans.GetPtr(i);
  261. SafeRelease(span->paStart);
  262. SafeRelease(span->paEnd);
  263. }
  264. }
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Normalize
  268. //
  269. // Replaces (NULL, NULL) spans with actual anchor values for start, end of doc
  270. //----------------------------------------------------------------------------
  271. BOOL CSpanSet::Normalize(ITextStoreAnchor *ptsi)
  272. {
  273. SPAN *span;
  274. if (!_AllSpansCovered())
  275. return TRUE;
  276. // if we get here, we have a single span with NULL/NULL anchors
  277. span = _rgSpans.GetPtr(0);
  278. if (ptsi->GetStart(&span->paStart) != S_OK || span->paStart == NULL)
  279. return FALSE;
  280. // Issue: need a GetEnd wrapper that handle unimplemented case! DON'T USE GetEnd!
  281. if (ptsi->GetEnd(&span->paEnd) != S_OK || span->paEnd == NULL)
  282. {
  283. SafeReleaseClear(span->paStart);
  284. return FALSE;
  285. }
  286. return TRUE;
  287. }