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.

2671 lines
72 KiB

  1. //
  2. // rprop.cpp
  3. //
  4. #include "private.h"
  5. #include "rprop.h"
  6. #include "rngsink.h"
  7. #include "immxutil.h"
  8. #include "varutil.h"
  9. #include "ic.h"
  10. #include "tim.h"
  11. #include "enumprop.h"
  12. #include "tfprop.h"
  13. #include "range.h"
  14. #include "anchoref.h"
  15. /* ccaefd20-38a6-11d3-a745-0050040ab407 */
  16. const IID IID_PRIV_CPROPERTY = { 0xccaefd20, 0x38a6, 0x11d3, {0xa7, 0x45, 0x00, 0x50, 0x04, 0x0a, 0xb4, 0x07} };
  17. //
  18. // By using this fake CLSID, the StaticProperty pretends
  19. // to be an TFE for persistent data.
  20. //
  21. /* b6a4bc60-0749-11d3-8def-00105a2799b5 */
  22. static const CLSID CLSID_IME_StaticProperty = {
  23. 0xb6a4bc60,
  24. 0x0749,
  25. 0x11d3,
  26. {0x8d, 0xef, 0x00, 0x10, 0x5a, 0x27, 0x99, 0xb5}
  27. };
  28. DBG_ID_INSTANCE(CProperty);
  29. inline void CheckCrossedAnchors(PROPERTYLIST *pProp)
  30. {
  31. if (CompareAnchors(pProp->_paStart, pProp->_paEnd) > 0)
  32. {
  33. // for crossed anchors, we always move the start anchor to the end pos -- ie, don't move
  34. pProp->_paStart->ShiftTo(pProp->_paEnd);
  35. }
  36. }
  37. //+---------------------------------------------------------------------------
  38. //
  39. // IsEqualPropertyValue
  40. //
  41. //----------------------------------------------------------------------------
  42. BOOL IsEqualPropertyValue(ITfPropertyStore *pStore1, ITfPropertyStore *pStore2)
  43. {
  44. BOOL fEqual;
  45. VARIANT varValue1;
  46. VARIANT varValue2;
  47. if (pStore1->GetData(&varValue1) != S_OK)
  48. return FALSE;
  49. if (pStore2->GetData(&varValue2) != S_OK)
  50. {
  51. VariantClear(&varValue1);
  52. return FALSE;
  53. }
  54. if (varValue1.vt != varValue2.vt)
  55. {
  56. Assert(0); // shouldn't happen for property of same type
  57. VariantClear(&varValue1);
  58. VariantClear(&varValue2);
  59. return FALSE;
  60. }
  61. switch (varValue1.vt)
  62. {
  63. case VT_I4:
  64. fEqual = varValue1.lVal == varValue2.lVal;
  65. break;
  66. case VT_UNKNOWN:
  67. fEqual = IdentityCompare(varValue1.punkVal, varValue2.punkVal);
  68. varValue1.punkVal->Release();
  69. varValue2.punkVal->Release();
  70. break;
  71. case VT_BSTR:
  72. fEqual = (wcscmp(varValue1.bstrVal, varValue2.bstrVal) == 0);
  73. SysFreeString(varValue1.bstrVal);
  74. SysFreeString(varValue2.bstrVal);
  75. break;
  76. case VT_EMPTY:
  77. fEqual = TRUE;
  78. break;
  79. default:
  80. Assert(0); // invalid type
  81. fEqual = FALSE;
  82. VariantClear(&varValue1);
  83. VariantClear(&varValue2);
  84. break;
  85. }
  86. return fEqual;
  87. }
  88. //////////////////////////////////////////////////////////////////////////////
  89. //
  90. // CProperty
  91. //
  92. //////////////////////////////////////////////////////////////////////////////
  93. //+---------------------------------------------------------------------------
  94. //
  95. // ctor
  96. //
  97. //----------------------------------------------------------------------------
  98. CProperty::CProperty(CInputContext *pic, REFGUID guidProp, TFPROPERTYSTYLE propStyle, DWORD dwAuthority, DWORD dwPropFlags)
  99. {
  100. Dbg_MemSetThisNameIDCounter(TEXT("CProperty"), PERF_PROP_COUNTER);
  101. _dwAuthority = dwAuthority;
  102. _propStyle = propStyle;
  103. _pic = pic; // don't need to AddRef because we are contained in the ic
  104. // CPropertySub, otoh, must AddRef the owner ic
  105. MyRegisterGUID(guidProp, &_guidatom);
  106. _dwPropFlags = dwPropFlags;
  107. _dwCookie = 0;
  108. Assert(_pss == NULL);
  109. #ifdef DEBUG
  110. _dbg_guid = guidProp;
  111. #endif // DEBUG
  112. }
  113. //+---------------------------------------------------------------------------
  114. //
  115. // dtor
  116. //
  117. //----------------------------------------------------------------------------
  118. CProperty::~CProperty()
  119. {
  120. int nCnt = GetPropNum();
  121. int i;
  122. for (i = 0; i < nCnt; i++)
  123. {
  124. PROPERTYLIST *pProp = GetPropList(i);
  125. Assert(pProp);
  126. _FreePropertyList(pProp);
  127. }
  128. _rgProp.Clear();
  129. if (_pss != NULL)
  130. {
  131. delete _pss;
  132. }
  133. Assert(!GetPropNum());
  134. }
  135. //+---------------------------------------------------------------------------
  136. //
  137. // _FreePropertyList
  138. //
  139. //----------------------------------------------------------------------------
  140. void CProperty::_FreePropertyList(PROPERTYLIST *pProp)
  141. {
  142. SafeRelease(pProp->_pPropStore);
  143. if (pProp->_pPropLoad)
  144. {
  145. delete pProp->_pPropLoad;
  146. }
  147. SafeRelease(pProp->_paStart);
  148. SafeRelease(pProp->_paEnd);
  149. cicMemFree(pProp);
  150. }
  151. //+---------------------------------------------------------------------------
  152. //
  153. // GetType
  154. //
  155. //----------------------------------------------------------------------------
  156. HRESULT CProperty::GetType(GUID *pguid)
  157. {
  158. return MyGetGUID(_guidatom, pguid);
  159. }
  160. //+---------------------------------------------------------------------------
  161. //
  162. // _FindComplex
  163. //
  164. // If piOut != NULL then it is set to the index where ich was found, or the
  165. // index of the next lower ich if ich isn't in the array.
  166. // If there is no element in the array with a lower ich, returns offset -1.
  167. //
  168. // If fTextUpdate == TRUE, the expectation is that this method is being called
  169. // from _PropertyTextUpdate and we have to worry about empty or crossed spans.
  170. //----------------------------------------------------------------------------
  171. PROPERTYLIST *CProperty::_FindComplex(IAnchor *pa, LONG *piOut, BOOL fEnd, BOOL fTextUpdate)
  172. {
  173. PROPERTYLIST *pProp;
  174. PROPERTYLIST *pPropMatch;
  175. int iMin;
  176. int iMax;
  177. int iMid;
  178. LONG l;
  179. pPropMatch = NULL;
  180. iMid = -1;
  181. iMin = 0;
  182. iMax = _rgProp.Count();
  183. while (iMin < iMax)
  184. {
  185. iMid = (iMin + iMax) / 2;
  186. pProp = _rgProp.Get(iMid);
  187. Assert(pProp != NULL);
  188. if (fTextUpdate)
  189. {
  190. // after an edit, the anchors may be crossed
  191. CheckCrossedAnchors(pProp);
  192. }
  193. l = CompareAnchors(pa, fEnd ? pProp->_paEnd : pProp->_paStart);
  194. if (l < 0)
  195. {
  196. iMax = iMid;
  197. }
  198. else if (l > 0)
  199. {
  200. iMin = iMid + 1;
  201. }
  202. else // pa == paPropStart
  203. {
  204. pPropMatch = pProp;
  205. break;
  206. }
  207. }
  208. if (fTextUpdate &&
  209. pPropMatch != NULL &&
  210. iMid != -1)
  211. {
  212. // we have to account for empty spans during a textupdate
  213. pPropMatch = _FindUpdateTouchup(pa, &iMid, fEnd);
  214. }
  215. if (piOut != NULL)
  216. {
  217. if (pPropMatch == NULL && iMid >= 0)
  218. {
  219. PROPERTYLIST *pPropTmp = _rgProp.Get(iMid);
  220. // couldn't find a match, return the next lowest ich
  221. // this assert won't work because the previous property list might have crossed anchors (which is ok)
  222. //Assert(iMid == 0 || CompareAnchors(fEnd ? GetPropList(iMid - 1)->_paEnd : GetPropList(iMid - 1)->_paStart, pa) < 0);
  223. if (CompareAnchors(fEnd ? pProp->_paEnd : pPropTmp->_paStart, pa) > 0)
  224. {
  225. iMid--;
  226. }
  227. }
  228. *piOut = iMid;
  229. }
  230. return pPropMatch;
  231. }
  232. //+---------------------------------------------------------------------------
  233. //
  234. // _FindUpdateTouchup
  235. //
  236. //----------------------------------------------------------------------------
  237. PROPERTYLIST *CProperty::_FindUpdateTouchup(IAnchor *pa, int *piMid, BOOL fEnd)
  238. {
  239. PROPERTYLIST *pPropertyList;
  240. int iTmp;
  241. // we may have empty spans after a text update, because of a text delete.
  242. // in this case, return the last empty span.
  243. // We'll do a O(n) scan instead of anything tricky, because in this case
  244. // we'll soon touch every empty span again just so we can delete it.
  245. // if we testing vs. the span end, we want the first empty span, otherwise we want the last one
  246. for (iTmp = fEnd ? *piMid-1 : *piMid+1; iTmp >= 0 && iTmp < _rgProp.Count(); iTmp += fEnd ? -1 : +1)
  247. {
  248. pPropertyList = _rgProp.Get(iTmp);
  249. if (CompareAnchors(pPropertyList->_paStart, pPropertyList->_paEnd) < 0) // use Compare instead of IsEqual to handle crossed anchors
  250. break;
  251. *piMid = iTmp;
  252. }
  253. // was the next/prev span truncated? we want it if it matches the original search criteria
  254. if (fEnd)
  255. {
  256. if (iTmp >= 0 && IsEqualAnchor(pa, pPropertyList->_paEnd))
  257. {
  258. *piMid = iTmp;
  259. }
  260. }
  261. else
  262. {
  263. if (iTmp < _rgProp.Count() && IsEqualAnchor(pa, pPropertyList->_paStart))
  264. {
  265. *piMid = iTmp;
  266. }
  267. }
  268. return _rgProp.Get(*piMid);
  269. }
  270. //+---------------------------------------------------------------------------
  271. //
  272. // Set
  273. //
  274. //----------------------------------------------------------------------------
  275. HRESULT CProperty::Set(IAnchor *paStart, IAnchor *paEnd, ITfPropertyStore *pPropStore)
  276. {
  277. BOOL bRet;
  278. Assert(pPropStore != NULL);
  279. bRet = _InsertPropList(paStart, paEnd, pPropStore, NULL);
  280. if (bRet)
  281. PropertyUpdated(paStart, paEnd);
  282. _Dbg_AssertProp();
  283. return bRet ? S_OK : E_FAIL;
  284. }
  285. //+---------------------------------------------------------------------------
  286. //
  287. // SetLoader
  288. //
  289. //----------------------------------------------------------------------------
  290. HRESULT CProperty::SetLoader(IAnchor *paStart, IAnchor *paEnd, CPropertyLoad *pPropLoad)
  291. {
  292. BOOL bRet;
  293. bRet = _InsertPropList(paStart, paEnd, NULL, pPropLoad);
  294. if (bRet)
  295. PropertyUpdated(paStart, paEnd);
  296. return bRet ? S_OK : E_FAIL;
  297. }
  298. //+---------------------------------------------------------------------------
  299. //
  300. // ForceLoad
  301. //
  302. //----------------------------------------------------------------------------
  303. HRESULT CProperty::ForceLoad()
  304. {
  305. int nCnt = GetPropNum();
  306. int i;
  307. for (i = 0; i < nCnt; i++)
  308. {
  309. PROPERTYLIST *pProp = GetPropList(i);
  310. if (!pProp->_pPropStore)
  311. {
  312. HRESULT hr;
  313. if (FAILED(hr = LoadData(pProp)))
  314. return hr;
  315. }
  316. }
  317. return S_OK;
  318. }
  319. //+---------------------------------------------------------------------------
  320. //
  321. // Clear
  322. //
  323. // Removes property spans from paStart to paEnd.
  324. //----------------------------------------------------------------------------
  325. void CProperty::Clear(IAnchor *paStart, IAnchor *paEnd, DWORD dwFlags, BOOL fTextUpdate)
  326. {
  327. PROPERTYLIST *pPropertyList;
  328. LONG iEnd;
  329. LONG iStart;
  330. LONG iRunSrc;
  331. LONG iRunDst;
  332. LONG iBogus;
  333. LONG lResult;
  334. BOOL fStartMatchesSpanEnd;
  335. BOOL fEndMatchesSpanStart;
  336. BOOL fSkipNextOnTextUpdate;
  337. if (_rgProp.Count() == 0)
  338. return; // no props
  339. fEndMatchesSpanStart = (_FindComplex(paEnd, &iEnd, FALSE /* fFindEndEdge */, fTextUpdate) != NULL);
  340. if (iEnd < 0)
  341. return; // no props covered -- delta preceeds all spans
  342. fStartMatchesSpanEnd = (_FindComplex(paStart, &iStart, TRUE /* fFindEndEdge */, fTextUpdate) != NULL);
  343. if (!fStartMatchesSpanEnd)
  344. {
  345. // we can skip this span, it's end edge is to the left of paStart
  346. iStart++;
  347. }
  348. if (iEnd < iStart)
  349. return; // no props covered -- delta is between two spans
  350. //
  351. // first span is special, since it may be partially covered
  352. //
  353. // just one span?
  354. if (iStart == iEnd)
  355. {
  356. _ClearOneSpan(paStart, paEnd, iStart, fStartMatchesSpanEnd, fEndMatchesSpanStart, dwFlags, fTextUpdate);
  357. return;
  358. }
  359. // first span may be truncated
  360. pPropertyList = _rgProp.Get(iStart);
  361. if (!_ClearFirstLastSpan(TRUE /* fFirst */, fStartMatchesSpanEnd, paStart, paEnd, pPropertyList, dwFlags, fTextUpdate, &fSkipNextOnTextUpdate))
  362. {
  363. // we're not going clear the first span, so skip past it
  364. iStart++;
  365. }
  366. //
  367. // handle all the totally covered spans
  368. //
  369. iBogus = iStart-1; // a sentinel
  370. iRunSrc = iBogus;
  371. iRunDst = iBogus;
  372. if (!fTextUpdate)
  373. {
  374. // we don't need a loop for non-text updates
  375. // everything will be deleted, and we don't have
  376. // to worry about crossed anchors or change histories
  377. // we just need to some extra checking on the last span
  378. if (iStart < iEnd)
  379. {
  380. iRunDst = iStart;
  381. }
  382. iStart = iEnd;
  383. }
  384. for (; iStart <= iEnd; iStart++)
  385. {
  386. pPropertyList = _rgProp.Get(iStart);
  387. if (iStart == iEnd)
  388. {
  389. // last span is special, since it may be partially covered
  390. if (_ClearFirstLastSpan(FALSE /* fFirst */, fEndMatchesSpanStart, paStart, paEnd,
  391. pPropertyList, dwFlags, fTextUpdate, &fSkipNextOnTextUpdate))
  392. {
  393. goto ClearSpan;
  394. }
  395. else
  396. {
  397. goto SaveSpan;
  398. }
  399. }
  400. // make sure we handle any crossed anchors
  401. lResult = CompareAnchors(pPropertyList->_paStart, pPropertyList->_paEnd);
  402. if (lResult >= 0)
  403. {
  404. if (lResult > 0)
  405. {
  406. // for crossed anchors, we always move the start anchor to the end pos -- ie, don't move
  407. pPropertyList->_paStart->ShiftTo(pPropertyList->_paEnd);
  408. }
  409. // don't do OnTextUpdated for empty spans!
  410. fSkipNextOnTextUpdate = TRUE;
  411. }
  412. // give the property owner a chance to ignore text updates
  413. if (fSkipNextOnTextUpdate ||
  414. !_OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  415. {
  416. ClearSpan:
  417. // this span is going to die
  418. fSkipNextOnTextUpdate = FALSE;
  419. if (iRunDst == iBogus)
  420. {
  421. iRunDst = iStart;
  422. }
  423. else if (iRunSrc > iRunDst)
  424. {
  425. // time to move this run
  426. _MovePropertySpans(iRunDst, iRunSrc, iStart - iRunSrc);
  427. // and update the pointers
  428. iRunDst += iStart - iRunSrc;
  429. iRunSrc = iBogus;
  430. }
  431. }
  432. else
  433. {
  434. // make sure we clear the history for this span
  435. pPropertyList->_paStart->ClearChangeHistory();
  436. pPropertyList->_paEnd->ClearChangeHistory();
  437. SaveSpan:
  438. // this span will live
  439. if (iRunSrc == iBogus && iRunDst != iBogus)
  440. {
  441. iRunSrc = iStart;
  442. }
  443. }
  444. }
  445. // handle the final run
  446. if (iRunDst > iBogus)
  447. {
  448. // if iRunSrc == iBogus, then we want to delete every span we saw
  449. if (iRunSrc == iBogus)
  450. {
  451. _MovePropertySpans(iRunDst, iStart, _rgProp.Count()-iStart);
  452. }
  453. else
  454. {
  455. _MovePropertySpans(iRunDst, iRunSrc, _rgProp.Count()-iRunSrc);
  456. }
  457. }
  458. _Dbg_AssertProp();
  459. }
  460. //+---------------------------------------------------------------------------
  461. //
  462. // _ClearOneSpan
  463. //
  464. // Handle a clear that intersects just one span.
  465. //----------------------------------------------------------------------------
  466. void CProperty::_ClearOneSpan(IAnchor *paStart, IAnchor *paEnd, int iIndex,
  467. BOOL fStartMatchesSpanEnd, BOOL fEndMatchesSpanStart, DWORD dwFlags, BOOL fTextUpdate)
  468. {
  469. PROPERTYLIST *pPropertyList;
  470. ITfPropertyStore *pPropertyStore;
  471. IAnchor *paTmp;
  472. LONG lResult;
  473. DWORD dwStartHistory;
  474. DWORD dwEndHistory;
  475. LONG lStartDeltaToStartSpan;
  476. LONG lEndDeltaToEndSpan;
  477. HRESULT hr;
  478. pPropertyList = _rgProp.Get(iIndex);
  479. lResult = 0;
  480. // empty or crossed span?
  481. if (fTextUpdate)
  482. {
  483. if ((lResult = CompareAnchors(pPropertyList->_paStart, pPropertyList->_paEnd)) >= 0)
  484. goto ClearSpan; // we shouldn't call OnTextUpdated for empty/crossed spans
  485. }
  486. else
  487. {
  488. // we should never see an empty span outside a text update
  489. Assert(!IsEqualAnchor(pPropertyList->_paStart, pPropertyList->_paEnd));
  490. }
  491. if (fTextUpdate)
  492. {
  493. // make sure we clear the history for this span in case it isn't cleared
  494. _ClearChangeHistory(pPropertyList, &dwStartHistory, &dwEndHistory);
  495. }
  496. // handle edge case first, if the clear range just touches an edge of the property span
  497. if (fStartMatchesSpanEnd || fEndMatchesSpanStart)
  498. {
  499. // if this is not a text update, then the ranges don't intersect
  500. if (!fTextUpdate)
  501. return;
  502. // some of the text at either end of the span might have been deleted
  503. if (fStartMatchesSpanEnd)
  504. {
  505. if (!(dwEndHistory & TS_CH_PRECEDING_DEL))
  506. return;
  507. if (_OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  508. return;
  509. goto ShrinkLeft; // we can avoid the CompareAnchors calls below
  510. }
  511. else
  512. {
  513. Assert(fEndMatchesSpanStart);
  514. if (!(dwStartHistory & TS_CH_FOLLOWING_DEL))
  515. return;
  516. if (_OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  517. return;
  518. goto ShrinkRight; // we can avoid the CompareAnchors calls below
  519. }
  520. }
  521. if (fTextUpdate &&
  522. _OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  523. {
  524. // property owner is ok with the clear
  525. return;
  526. }
  527. lStartDeltaToStartSpan = CompareAnchors(paStart, pPropertyList->_paStart);
  528. lEndDeltaToEndSpan = CompareAnchors(paEnd, pPropertyList->_paEnd);
  529. if (lStartDeltaToStartSpan > 0)
  530. {
  531. if (lEndDeltaToEndSpan < 0)
  532. {
  533. //
  534. // divide, we're clearing in the middle of the span
  535. //
  536. if (pPropertyList->_paEnd->Clone(&paTmp) != S_OK)
  537. goto ClearSpan; // give up
  538. hr = _Divide(pPropertyList, paStart, paEnd, &pPropertyStore);
  539. if (hr == S_OK)
  540. {
  541. _CreateNewProp(paEnd, paTmp, pPropertyStore, NULL);
  542. pPropertyStore->Release();
  543. PropertyUpdated(paStart, paEnd);
  544. }
  545. paTmp->Release();
  546. if (hr != S_OK)
  547. goto ClearSpan;
  548. }
  549. else
  550. {
  551. //
  552. // shrink to the left, we're clearing the right edge of this span
  553. //
  554. ShrinkLeft:
  555. if (pPropertyList->_paEnd->Clone(&paTmp) != S_OK)
  556. goto ClearSpan;
  557. hr = _SetNewExtent(pPropertyList, pPropertyList->_paStart, paStart, FALSE);
  558. PropertyUpdated(paStart, paTmp);
  559. paTmp->Release();
  560. if (hr != S_OK)
  561. goto ClearSpan;
  562. }
  563. }
  564. else if (lEndDeltaToEndSpan < 0)
  565. {
  566. //
  567. // shrink to the right, we're clearing the left edge of this span
  568. //
  569. ShrinkRight:
  570. if (pPropertyList->_paStart->Clone(&paTmp) != S_OK)
  571. goto ClearSpan;
  572. hr = _SetNewExtent(pPropertyList, paEnd, pPropertyList->_paEnd, FALSE);
  573. PropertyUpdated(paTmp, paEnd);
  574. paTmp->Release();
  575. if (hr != S_OK)
  576. goto ClearSpan;
  577. }
  578. else
  579. {
  580. // we're wiping the whole span
  581. ClearSpan:
  582. if (lResult <= 0)
  583. {
  584. PropertyUpdated(pPropertyList->_paStart, pPropertyList->_paEnd);
  585. }
  586. else
  587. {
  588. // we found a crossed span above, report as if empty
  589. PropertyUpdated(pPropertyList->_paEnd, pPropertyList->_paEnd);
  590. }
  591. _FreePropertyList(pPropertyList);
  592. _rgProp.Remove(iIndex, 1);
  593. }
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // _OnTextUpdate
  598. //
  599. // Make a ITfPropertyStore::OnTextUpdate callback.
  600. // Returns FALSE if the property should be freed.
  601. //----------------------------------------------------------------------------
  602. BOOL CProperty::_OnTextUpdate(DWORD dwFlags, PROPERTYLIST *pPropertyList, IAnchor *paStart, IAnchor *paEnd)
  603. {
  604. CRange *pRange;
  605. BOOL fRet;
  606. BOOL fAccept;
  607. if (pPropertyList->_pPropStore == NULL)
  608. {
  609. // need to load data to make a change notification
  610. if (LoadData(pPropertyList) != S_OK)
  611. return FALSE;
  612. Assert(pPropertyList->_pPropStore != NULL);
  613. }
  614. // perf: can we cache the range for the notification?
  615. if ((pRange = new CRange) == NULL)
  616. return FALSE; // out of memory, give up
  617. fRet = FALSE;
  618. if (!pRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, paStart, paEnd))
  619. goto Exit;
  620. if (pPropertyList->_pPropStore->OnTextUpdated(dwFlags, (ITfRangeAnchor *)pRange, &fAccept) != S_OK)
  621. goto Exit;
  622. fRet = fAccept;
  623. Exit:
  624. pRange->Release();
  625. return fRet;
  626. }
  627. //+---------------------------------------------------------------------------
  628. //
  629. // _MovePropertySpans
  630. //
  631. // Shift PROPERTYLISTs from iSrc to iDst, and shrink the array if we move
  632. // anything that touches the very end.
  633. //----------------------------------------------------------------------------
  634. void CProperty::_MovePropertySpans(int iDst, int iSrc, int iCount)
  635. {
  636. PROPERTYLIST *pPropertyList;
  637. PROPERTYLIST **pSrc;
  638. PROPERTYLIST **pDst;
  639. LONG i;
  640. LONG iHalt;
  641. int cb;
  642. BOOL fLastRun;
  643. Assert(iCount >= 0);
  644. Assert(iDst < iSrc);
  645. Assert(iDst >= 0);
  646. Assert(iSrc + iCount <= _rgProp.Count());
  647. fLastRun = (iSrc + iCount == _rgProp.Count());
  648. if (!fLastRun)
  649. {
  650. // free all the spans that are going to be clobbered
  651. iHalt = min(iSrc, iDst + iCount);
  652. }
  653. else
  654. {
  655. // on the last call, cleanup everything that never got clobbered
  656. iHalt = iSrc;
  657. }
  658. for (i=iDst; i<iHalt; i++)
  659. {
  660. pPropertyList = _rgProp.Get(i);
  661. if (pPropertyList == NULL)
  662. continue; // already freed this guy
  663. if (CompareAnchors(pPropertyList->_paStart, pPropertyList->_paEnd) <= 0)
  664. {
  665. PropertyUpdated(pPropertyList->_paStart, pPropertyList->_paEnd);
  666. }
  667. else
  668. {
  669. // crossed anchors
  670. PropertyUpdated(pPropertyList->_paEnd, pPropertyList->_paEnd);
  671. }
  672. *_rgProp.GetPtr(i) = NULL; // NULL before the callbacks in _FreePropertyList
  673. _FreePropertyList(pPropertyList);
  674. }
  675. // shift the moving spans down
  676. pSrc = _rgProp.GetPtr(iSrc);
  677. pDst = _rgProp.GetPtr(iDst);
  678. memmove(pDst, pSrc, iCount*sizeof(PROPERTYLIST *));
  679. // this method is called from Clear as we shift through an array of spans
  680. // to remove. On the last call only, we want to re-size the array.
  681. if (fLastRun)
  682. {
  683. // free any unused memory at the end of the array
  684. _rgProp.Remove(iDst + iCount, _rgProp.Count() - (iDst + iCount));
  685. }
  686. else
  687. {
  688. // mark vacated spans so we don't try to free them a second time
  689. // nb: we don't do this on the last call, which can be a big win since
  690. // in the case of delete there is only one single call
  691. pDst = _rgProp.GetPtr(max(iSrc, iDst + iCount));
  692. cb = sizeof(PROPERTYLIST *)*(iSrc+iCount - max(iSrc, iDst + iCount));
  693. memset(pDst, 0, cb);
  694. }
  695. }
  696. //+---------------------------------------------------------------------------
  697. //
  698. // _ClearFirstLastSpan
  699. //
  700. // Returns TRUE if the span should be cleared.
  701. //----------------------------------------------------------------------------
  702. BOOL CProperty::_ClearFirstLastSpan(BOOL fFirst, BOOL fMatchesSpanEdge,
  703. IAnchor *paStart, IAnchor *paEnd, PROPERTYLIST *pPropertyList,
  704. DWORD dwFlags, BOOL fTextUpdate, BOOL *pfSkipNextOnTextUpdate)
  705. {
  706. DWORD dwStartHistory;
  707. DWORD dwEndHistory;
  708. BOOL fCovered;
  709. LONG lResult;
  710. *pfSkipNextOnTextUpdate = FALSE;
  711. if (fTextUpdate)
  712. {
  713. lResult = CompareAnchors(pPropertyList->_paStart, pPropertyList->_paEnd);
  714. if (lResult == 0)
  715. {
  716. // empty span, nix it
  717. goto Exit;
  718. }
  719. // make sure we clear the history for this span in case it isn't cleared
  720. _ClearChangeHistory(pPropertyList, &dwStartHistory, &dwEndHistory);
  721. // make sure we handle any crossed anchors
  722. if (lResult > 0)
  723. {
  724. // for crossed anchors, we always move the start anchor to the end pos -- ie, don't move
  725. pPropertyList->_paStart->ShiftTo(pPropertyList->_paEnd);
  726. }
  727. }
  728. // completely covered?
  729. if (fFirst)
  730. {
  731. fCovered = (CompareAnchors(pPropertyList->_paStart, paStart) >= 0);
  732. }
  733. else
  734. {
  735. fCovered = (CompareAnchors(pPropertyList->_paEnd, paEnd) <= 0);
  736. }
  737. if (fCovered)
  738. {
  739. // this span is covered, so we're going to clear it unless it's a text update
  740. // and the store is cool with it
  741. if (!fTextUpdate)
  742. return TRUE;
  743. if (_OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  744. return FALSE;
  745. goto Exit; // return TRUE, and make sure we don't call OnTextUpdate again
  746. }
  747. // start of span matches end of clear range? (or vice-versa)
  748. if (fMatchesSpanEdge)
  749. {
  750. // if no text was deleted, then there really is no overlap
  751. if (!fTextUpdate)
  752. return FALSE;
  753. // otherwise, we may have just deleted text at the edge of the property span
  754. if (fFirst)
  755. {
  756. if (!(dwEndHistory & TS_CH_PRECEDING_DEL))
  757. return FALSE;
  758. }
  759. else
  760. {
  761. if (!(dwStartHistory & TS_CH_FOLLOWING_DEL))
  762. return FALSE;
  763. }
  764. }
  765. // if we made it here we're going to clear some of the property span
  766. if (fTextUpdate)
  767. {
  768. if (_OnTextUpdate(dwFlags, pPropertyList, paStart, paEnd))
  769. {
  770. // property owner is ok with the text edit
  771. return FALSE;
  772. }
  773. }
  774. if (fFirst)
  775. {
  776. if (_SetNewExtent(pPropertyList, pPropertyList->_paStart, paStart, FALSE) == S_OK)
  777. return FALSE;
  778. }
  779. else
  780. {
  781. if (_SetNewExtent(pPropertyList, paEnd, pPropertyList->_paEnd, FALSE) == S_OK)
  782. return FALSE;
  783. }
  784. Exit:
  785. // property owner is not ok with the shink, kill this span
  786. *pfSkipNextOnTextUpdate = TRUE;
  787. return TRUE;
  788. }
  789. //+---------------------------------------------------------------------------
  790. //
  791. // CreateNewProp
  792. //
  793. //----------------------------------------------------------------------------
  794. PROPERTYLIST *CProperty::_CreateNewProp(IAnchor *paStart, IAnchor *paEnd, ITfPropertyStore *pPropStore, CPropertyLoad *pPropLoad)
  795. {
  796. PROPERTYLIST *pProp;
  797. LONG iProp;
  798. Assert(!IsEqualAnchor(paStart, paEnd));
  799. if (Find(paStart, &iProp, FALSE))
  800. {
  801. Assert(0);
  802. }
  803. iProp++;
  804. pProp = (PROPERTYLIST *)cicMemAllocClear(sizeof(PROPERTYLIST));
  805. if (pProp == NULL)
  806. return NULL;
  807. Dbg_MemSetNameIDCounter(pProp, TEXT("PROPERTYLIST"), (DWORD)-1, PERF_PROPERTYLIST_COUNTER);
  808. if (!_rgProp.Insert(iProp, 1))
  809. {
  810. cicMemFree(pProp);
  811. return NULL;
  812. }
  813. _rgProp.Set(iProp, pProp);
  814. pProp->_pPropStore = pPropStore;
  815. pProp->_pPropLoad = pPropLoad;
  816. if (pPropStore)
  817. pPropStore->AddRef();
  818. Assert(pProp->_paStart == NULL);
  819. Assert(pProp->_paEnd == NULL);
  820. Assert(pProp->_pPropStore || pProp->_pPropLoad);
  821. _SetNewExtent(pProp, paStart, paEnd, TRUE);
  822. pProp->_paStart->SetGravity(TS_GR_FORWARD);
  823. pProp->_paEnd->SetGravity(TS_GR_BACKWARD); // End must be LEFT, too. Because we don't want to stratch this property.
  824. if (GetPropStyle() == TFPROPSTYLE_STATICCOMPACT ||
  825. GetPropStyle() == TFPROPSTYLE_CUSTOM_COMPACT)
  826. {
  827. _DefragAfterThis(iProp);
  828. }
  829. return pProp;
  830. }
  831. //+---------------------------------------------------------------------------
  832. //
  833. // _SetNewExtent
  834. //
  835. // return S_FALSE, if tip wants to free the property.
  836. //
  837. //----------------------------------------------------------------------------
  838. HRESULT CProperty::_SetNewExtent(PROPERTYLIST *pProp, IAnchor *paStart, IAnchor *paEnd, BOOL fNew)
  839. {
  840. HRESULT hr;
  841. BOOL fFree;
  842. CRange *pRange = NULL;
  843. Assert(!IsEqualAnchor(paStart, paEnd));
  844. ShiftToOrClone(&pProp->_paStart, paStart);
  845. ShiftToOrClone(&pProp->_paEnd, paEnd);
  846. // we don't load actual data or send a resize event for new data
  847. if (fNew)
  848. return S_OK;
  849. Assert(pProp);
  850. if (!pProp->_pPropStore)
  851. {
  852. //
  853. // need to load data to make a change notification.
  854. //
  855. // perf: we may skip and delete Loader if this property is not
  856. // custom property.
  857. //
  858. if (FAILED(LoadData(pProp)))
  859. return E_FAIL;
  860. }
  861. hr = E_FAIL;
  862. if ((pRange = new CRange) != NULL)
  863. {
  864. if (pRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pProp->_paStart, pProp->_paEnd))
  865. {
  866. hr = pProp->_pPropStore->Shrink((ITfRangeAnchor *)pRange, &fFree);
  867. if (hr != S_OK || fFree)
  868. {
  869. SafeReleaseClear(pProp->_pPropStore); // caller will free this property when it see S_FALSE return
  870. hr = S_FALSE;
  871. }
  872. }
  873. pRange->Release();
  874. }
  875. return hr;
  876. }
  877. //+---------------------------------------------------------------------------
  878. //
  879. // _Divide
  880. //
  881. // return S_FALSE, if tip wants to free the property.
  882. //
  883. //----------------------------------------------------------------------------
  884. HRESULT CProperty::_Divide(PROPERTYLIST *pProp, IAnchor *paBreakPtStart, IAnchor *paBreakPtEnd, ITfPropertyStore **ppStore)
  885. {
  886. HRESULT hr = E_FAIL;
  887. CRange *pRangeThis = NULL;
  888. CRange *pRangeNew = NULL;
  889. Assert(CompareAnchors(pProp->_paStart, paBreakPtStart) <= 0);
  890. Assert(CompareAnchors(paBreakPtStart, paBreakPtEnd) <= 0);
  891. Assert(CompareAnchors(paBreakPtEnd, pProp->_paEnd) <= 0);
  892. if ((pRangeThis = new CRange) == NULL)
  893. goto Exit;
  894. if (!pRangeThis->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pProp->_paStart, paBreakPtStart))
  895. goto Exit;
  896. if ((pRangeNew = new CRange) == NULL)
  897. goto Exit;
  898. if (!pRangeNew->_InitWithDefaultGravity(_pic, COPY_ANCHORS, paBreakPtEnd, pProp->_paEnd))
  899. goto Exit;
  900. if (!pProp->_pPropStore)
  901. {
  902. //
  903. // we need to load data to make a change notification.
  904. //
  905. // perf: we may skip and delete Loader if this property is not
  906. // custom property.
  907. //
  908. if (FAILED(LoadData(pProp)))
  909. goto Exit;
  910. }
  911. hr = pProp->_pPropStore->Divide((ITfRangeAnchor *)pRangeThis, (ITfRangeAnchor *)pRangeNew, ppStore);
  912. if ((hr == S_OK) && *ppStore)
  913. {
  914. ShiftToOrClone(&pProp->_paEnd, paBreakPtStart);
  915. }
  916. else
  917. {
  918. *ppStore = NULL;
  919. hr = S_FALSE;
  920. }
  921. Exit:
  922. SafeRelease(pRangeThis);
  923. SafeRelease(pRangeNew);
  924. return hr;
  925. }
  926. //+---------------------------------------------------------------------------
  927. //
  928. // DestroyProp
  929. //
  930. //----------------------------------------------------------------------------
  931. void CProperty::_RemoveProp(LONG iIndex, PROPERTYLIST *pProp)
  932. {
  933. #ifdef DEBUG
  934. LONG iProp;
  935. Assert(Find(pProp->_paStart, &iProp, FALSE) == pProp);
  936. Assert(iProp == iIndex);
  937. #endif // DEBUG
  938. _rgProp.Remove(iIndex, 1);
  939. _FreePropertyList(pProp);
  940. }
  941. //+---------------------------------------------------------------------------
  942. //
  943. // _InsertPropList
  944. //
  945. //----------------------------------------------------------------------------
  946. BOOL CProperty::_InsertPropList(IAnchor *paStart, IAnchor *paEnd, ITfPropertyStore *pPropStore, CPropertyLoad *pPropLoad)
  947. {
  948. PROPERTYLIST *pProp;
  949. IAnchor *paTmpEnd = NULL;
  950. LONG nCnt = GetPropNum();
  951. LONG nCur;
  952. Assert(!IsEqualAnchor(paStart, paEnd));
  953. if (!nCnt)
  954. {
  955. //
  956. // we create the first PropList.
  957. //
  958. _CreateNewProp(paStart, paEnd, pPropStore, pPropLoad);
  959. goto End;
  960. }
  961. nCur = 0;
  962. Find(paStart, &nCur, FALSE);
  963. if (nCur <= 0)
  964. nCur = 0;
  965. pProp = QuickGetPropList(nCur);
  966. while (nCur < nCnt)
  967. {
  968. Assert(pProp);
  969. SafeReleaseClear(paTmpEnd);
  970. pProp->_paEnd->Clone(&paTmpEnd);
  971. if (CompareAnchors(paStart, paTmpEnd) >= 0)
  972. goto Next;
  973. if (CompareAnchors(paEnd, pProp->_paStart) <= 0)
  974. {
  975. //
  976. // we insert new PropList just before pProp.
  977. //
  978. if (!_AddIntoProp(nCur - 1, paStart, paEnd, pPropStore))
  979. _CreateNewProp(paStart, paEnd, pPropStore, pPropLoad);
  980. goto End;
  981. }
  982. if (CompareAnchors(paStart, pProp->_paStart) > 0)
  983. {
  984. //
  985. // Now need to split pProp to insert new Prop.
  986. //
  987. Assert(pProp->_pPropStore);
  988. if (CompareAnchors(paTmpEnd, paEnd) > 0)
  989. {
  990. ITfPropertyStore *pNewPropStore = NULL;
  991. if (S_OK != _Divide(pProp, paStart, paEnd, &pNewPropStore))
  992. {
  993. _RemoveProp(nCur, pProp);
  994. nCnt--;
  995. goto DoAgain;
  996. }
  997. else if (pNewPropStore)
  998. {
  999. _CreateNewProp(paEnd, paTmpEnd, pNewPropStore, pPropLoad);
  1000. pNewPropStore->Release();
  1001. pProp = GetPropList(nCur);
  1002. nCnt++;
  1003. }
  1004. }
  1005. else
  1006. {
  1007. if (S_OK != _SetNewExtent(pProp, pProp->_paStart, paStart, FALSE))
  1008. {
  1009. _RemoveProp(nCur, pProp);
  1010. nCnt--;
  1011. goto DoAgain;
  1012. }
  1013. }
  1014. //
  1015. // next time, new Prop will be inserted.
  1016. //
  1017. goto Next;
  1018. }
  1019. Assert(CompareAnchors(paStart, pProp->_paStart) <= 0);
  1020. if (CompareAnchors(pProp->_paStart, paEnd) < 0)
  1021. {
  1022. if (CompareAnchors(paTmpEnd, paEnd) <= 0)
  1023. {
  1024. //
  1025. // pProp is completely overlapped by new Prop.
  1026. // so we delete this pProp.
  1027. //
  1028. _RemoveProp(nCur, pProp);
  1029. nCnt--;
  1030. }
  1031. else
  1032. {
  1033. //
  1034. // A part of pProp is overlapped by new Prop.
  1035. //
  1036. if (S_OK != _SetNewExtent(pProp, paEnd, paTmpEnd, FALSE))
  1037. {
  1038. _RemoveProp(nCur, pProp);
  1039. nCnt--;
  1040. }
  1041. }
  1042. goto DoAgain;
  1043. }
  1044. Assert(0);
  1045. Next:
  1046. nCur++;
  1047. DoAgain:
  1048. pProp = SafeGetPropList(nCur);
  1049. }
  1050. if (!_AddIntoProp(nCur - 1, paStart, paEnd, pPropStore))
  1051. _CreateNewProp(paStart, paEnd, pPropStore, pPropLoad);
  1052. End:
  1053. _Dbg_AssertProp();
  1054. SafeRelease(paTmpEnd);
  1055. return TRUE;
  1056. }
  1057. //+---------------------------------------------------------------------------
  1058. //
  1059. // Defrag
  1060. //
  1061. // paStart, paEnd == NULL will defrag everything.
  1062. //----------------------------------------------------------------------------
  1063. BOOL CProperty::Defrag(IAnchor *paStart, IAnchor *paEnd)
  1064. {
  1065. PROPERTYLIST *pProp;
  1066. LONG nCnt = GetPropNum();
  1067. LONG nCur;
  1068. BOOL fSamePropIndex;
  1069. BOOL fDone = FALSE;
  1070. if (GetPropStyle() != TFPROPSTYLE_STATICCOMPACT &&
  1071. GetPropStyle() != TFPROPSTYLE_CUSTOM_COMPACT)
  1072. {
  1073. return fDone;
  1074. }
  1075. if (!nCnt)
  1076. return fDone;
  1077. pProp = GetFirstPropList();
  1078. nCur = 0;
  1079. if (paStart != NULL)
  1080. {
  1081. if (Find(paStart, &nCur, FALSE))
  1082. nCur--;
  1083. if (nCur <= 0)
  1084. nCur = 0;
  1085. }
  1086. pProp = GetPropList(nCur);
  1087. while (nCur < nCnt - 1) // Issue: shouldn't this terminate at paEnd?
  1088. {
  1089. PROPERTYLIST *pPropNext = GetPropList(nCur + 1);
  1090. if (paEnd != NULL && CompareAnchors(pProp->_paStart, paEnd) > 0)
  1091. break;
  1092. fSamePropIndex = FALSE;
  1093. if (CompareAnchors(pProp->_paEnd, pPropNext->_paStart) == 0)
  1094. {
  1095. if (!pProp->_pPropStore)
  1096. {
  1097. if (FAILED(LoadData(pProp)))
  1098. return FALSE;
  1099. }
  1100. if (!pPropNext->_pPropStore)
  1101. {
  1102. if (FAILED(LoadData(pPropNext)))
  1103. return FALSE;
  1104. }
  1105. // compare the value of each property instance
  1106. if (IsEqualPropertyValue(pProp->_pPropStore, pPropNext->_pPropStore))
  1107. {
  1108. //
  1109. // pPropNext is next to pProp and has same data.
  1110. // So we merge them.
  1111. // We should never fail this.
  1112. //
  1113. _SetNewExtent(pProp, pProp->_paStart, pPropNext->_paEnd, FALSE);
  1114. Assert(pProp->_pPropStore);
  1115. _RemoveProp(nCur+1, pPropNext);
  1116. nCnt = GetPropNum();
  1117. pProp = GetPropList(nCur);
  1118. fDone = TRUE;
  1119. //
  1120. // Do same pProp again because _pNext was changed.
  1121. //
  1122. fSamePropIndex = TRUE;
  1123. }
  1124. }
  1125. if (!fSamePropIndex)
  1126. {
  1127. nCur++;
  1128. }
  1129. pProp = GetPropList(nCur);
  1130. }
  1131. _Dbg_AssertProp();
  1132. return fDone;
  1133. }
  1134. //+---------------------------------------------------------------------------
  1135. //
  1136. // _AddIntoProp
  1137. //
  1138. //----------------------------------------------------------------------------
  1139. BOOL CProperty::_AddIntoProp(int nCur, IAnchor *paStart, IAnchor *paEnd, ITfPropertyStore *pPropStore)
  1140. {
  1141. PROPERTYLIST *pProp;
  1142. BOOL bRet = FALSE;
  1143. Assert(!IsEqualAnchor(paStart, paEnd));
  1144. if (GetPropStyle() != TFPROPSTYLE_STATICCOMPACT &&
  1145. GetPropStyle() != TFPROPSTYLE_CUSTOM_COMPACT)
  1146. {
  1147. return FALSE;
  1148. }
  1149. if (!pPropStore)
  1150. return FALSE;
  1151. if (nCur < 0)
  1152. return FALSE;
  1153. if (!(pProp = GetPropList(nCur)))
  1154. return FALSE;
  1155. if (CompareAnchors(pProp->_paStart, paStart) <= 0 && // Issue: why do we need 2 compares? isn't CompareAnchors(pProp->_paEnd, paStart) >= 0 enough?
  1156. CompareAnchors(pProp->_paEnd, paStart) >= 0)
  1157. {
  1158. if (CompareAnchors(paEnd, pProp->_paEnd) > 0)
  1159. {
  1160. if (!pProp->_pPropStore)
  1161. {
  1162. if (FAILED(LoadData(pProp)))
  1163. return FALSE;
  1164. }
  1165. if (IsEqualPropertyValue(pProp->_pPropStore, pPropStore))
  1166. {
  1167. HRESULT hr;
  1168. hr = _SetNewExtent(pProp, pProp->_paStart, paEnd, FALSE);
  1169. //
  1170. // Our static property store should never fail.
  1171. //
  1172. Assert(hr == S_OK);
  1173. Assert(pProp->_pPropStore);
  1174. bRet = TRUE;
  1175. }
  1176. }
  1177. }
  1178. if (bRet)
  1179. _DefragAfterThis(nCur);
  1180. _Dbg_AssertProp();
  1181. return bRet;
  1182. }
  1183. //+---------------------------------------------------------------------------
  1184. //
  1185. // DefragThis
  1186. //
  1187. //----------------------------------------------------------------------------
  1188. void CProperty::_DefragAfterThis(int nCur)
  1189. {
  1190. nCur++;
  1191. while (1)
  1192. {
  1193. IAnchor *paTmpStart = NULL;
  1194. IAnchor *paTmpEnd = NULL;
  1195. PROPERTYLIST *pProp;
  1196. int nCnt = GetPropNum();
  1197. BOOL bRet;
  1198. if (nCur >= nCnt)
  1199. goto Exit;
  1200. if (!(pProp = GetPropList(nCur)))
  1201. goto Exit;
  1202. pProp->_paStart->Clone(&paTmpStart);
  1203. pProp->_paEnd->Clone(&paTmpEnd);
  1204. bRet = Defrag(paTmpStart, paTmpEnd);
  1205. SafeRelease(paTmpStart);
  1206. SafeRelease(paTmpEnd);
  1207. if (!bRet)
  1208. goto Exit;
  1209. }
  1210. Exit:
  1211. return;
  1212. }
  1213. //+---------------------------------------------------------------------------
  1214. //
  1215. // FindPropertyListByPos
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. PROPERTYLIST *CProperty::FindPropertyListByPos(IAnchor *paPos, BOOL fEnd)
  1219. {
  1220. PROPERTYLIST *pPropList = NULL;
  1221. BOOL fFound = FALSE;
  1222. LONG nCnt;
  1223. Find(paPos, &nCnt, fEnd);
  1224. if (nCnt >= 0)
  1225. pPropList = GetPropList(nCnt);
  1226. if (pPropList)
  1227. {
  1228. if (!fEnd)
  1229. {
  1230. if (CompareAnchors(pPropList->_paStart, paPos) <= 0 &&
  1231. CompareAnchors(paPos, pPropList->_paEnd) < 0)
  1232. {
  1233. fFound = TRUE;
  1234. }
  1235. }
  1236. else
  1237. {
  1238. if (CompareAnchors(pPropList->_paStart, paPos) < 0 &&
  1239. CompareAnchors(paPos, pPropList->_paEnd) <= 0)
  1240. {
  1241. fFound = TRUE;
  1242. }
  1243. }
  1244. }
  1245. return fFound ? pPropList : NULL;
  1246. }
  1247. //+---------------------------------------------------------------------------
  1248. //
  1249. // LoadData
  1250. //
  1251. //----------------------------------------------------------------------------
  1252. HRESULT CProperty::LoadData(PROPERTYLIST *pPropList)
  1253. {
  1254. HRESULT hr = E_FAIL;
  1255. ITfPropertyStore *pStore;
  1256. TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *ph;
  1257. IStream *pStream = NULL;
  1258. CRange *pRange = NULL;
  1259. Assert(!pPropList->_pPropStore);
  1260. Assert(pPropList->_pPropLoad);
  1261. //
  1262. // Update ichAnchor and cch of TF_PERSISTENT_PROPERTY_HEADER_ACP.
  1263. // As text may be updated, the original value is
  1264. // obsolete.
  1265. //
  1266. ph = &pPropList->_pPropLoad->_hdr;
  1267. ShiftToOrClone(&ph->paStart, pPropList->_paStart);
  1268. ShiftToOrClone(&ph->paEnd, pPropList->_paEnd);
  1269. if (FAILED(pPropList->_pPropLoad->_pLoader->LoadProperty(ph, &pStream)))
  1270. goto Exit;
  1271. if ((pRange = new CRange) == NULL)
  1272. {
  1273. hr = E_OUTOFMEMORY;
  1274. goto Exit;
  1275. }
  1276. if (!pRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, ph->paStart, ph->paEnd))
  1277. {
  1278. hr = E_FAIL;
  1279. goto Exit;
  1280. }
  1281. if (FAILED(_GetPropStoreFromStream(ph, pStream, pRange, &pStore)))
  1282. goto Exit;
  1283. pPropList->_pPropStore = pStore;
  1284. delete pPropList->_pPropLoad;
  1285. pPropList->_pPropLoad = NULL;
  1286. hr = S_OK;
  1287. Exit:
  1288. SafeRelease(pStream);
  1289. SafeRelease(pRange);
  1290. return hr;
  1291. }
  1292. //+---------------------------------------------------------------------------
  1293. //
  1294. // _Dbg_AssertProp
  1295. //
  1296. //----------------------------------------------------------------------------
  1297. #ifdef DEBUG
  1298. void CProperty::_Dbg_AssertProp()
  1299. {
  1300. LONG nCnt = GetPropNum();
  1301. LONG n;
  1302. IAnchor *paEndLast = NULL;
  1303. for (n = 0; n < nCnt; n++)
  1304. {
  1305. PROPERTYLIST *pProp = GetPropList(n);
  1306. Assert(paEndLast == NULL || CompareAnchors(paEndLast, pProp->_paStart) <= 0);
  1307. Assert(CompareAnchors(pProp->_paStart, pProp->_paEnd) < 0);
  1308. Assert(pProp->_pPropStore || pProp->_pPropLoad);
  1309. paEndLast = pProp->_paEnd;
  1310. }
  1311. }
  1312. #endif
  1313. //+---------------------------------------------------------------------------
  1314. //
  1315. // PropertyUpdated
  1316. //
  1317. //----------------------------------------------------------------------------
  1318. void CProperty::PropertyUpdated(IAnchor *paStart, IAnchor *paEnd)
  1319. {
  1320. CSpanSet *pss;
  1321. CProperty *pDisplayAttrProperty;
  1322. if (pss = _CreateSpanSet())
  1323. {
  1324. pss->Add(0, paStart, paEnd, COPY_ANCHORS);
  1325. }
  1326. if (_dwPropFlags & PROPF_MARKUP_COLLECTION)
  1327. {
  1328. // we also need to update the display attribute property
  1329. if (_pic->_GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttrProperty) == S_OK)
  1330. {
  1331. Assert(!(pDisplayAttrProperty->_dwPropFlags & PROPF_MARKUP_COLLECTION)); // don't allow infinite recursion!
  1332. pDisplayAttrProperty->PropertyUpdated(paStart, paEnd);
  1333. pDisplayAttrProperty->Release();
  1334. }
  1335. }
  1336. }
  1337. //+---------------------------------------------------------------------------
  1338. //
  1339. // GetPropStoreFromStream
  1340. //
  1341. //----------------------------------------------------------------------------
  1342. HRESULT CProperty::_GetPropStoreFromStream(const TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr, IStream *pStream, CRange *pRange, ITfPropertyStore **ppStore)
  1343. {
  1344. ITfTextInputProcessor *pIME = NULL;
  1345. CTip *ptip = NULL;
  1346. ITfCreatePropertyStore *pCreateStore = NULL;
  1347. ITfPropertyStore *pPropStore = NULL;
  1348. CRange *pRangeTmp = NULL;
  1349. GUID guidProp;
  1350. CThreadInputMgr *ptim = CThreadInputMgr::_GetThis();
  1351. HRESULT hr = E_FAIL;
  1352. LARGE_INTEGER li;
  1353. TfGuidAtom guidatom;
  1354. Assert(!IsEqualAnchor(pHdr->paStart, pHdr->paEnd));
  1355. GetCurrentPos(pStream, &li);
  1356. if (!ptim)
  1357. goto Exit;
  1358. if (FAILED(GetType(&guidProp)))
  1359. goto Exit;
  1360. if (!IsEqualGUID(guidProp, pHdr->guidType))
  1361. goto Exit;
  1362. //
  1363. // Try QI.
  1364. //
  1365. if (FAILED(MyRegisterGUID(pHdr->clsidTIP, &guidatom)))
  1366. goto Exit;
  1367. if (ptim->_GetCTipfromGUIDATOM(guidatom, &ptip))
  1368. pIME = ptip->_pTip;
  1369. if (pIME && ptip->_fActivated)
  1370. {
  1371. if (FAILED(hr = pIME->QueryInterface(IID_ITfCreatePropertyStore,
  1372. (void **)&pCreateStore)))
  1373. goto Exit;
  1374. if ((pRangeTmp = new CRange) == NULL)
  1375. {
  1376. hr = E_OUTOFMEMORY;
  1377. goto Exit;
  1378. }
  1379. if (!pRangeTmp->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pHdr->paStart, pHdr->paEnd))
  1380. {
  1381. hr = E_FAIL;
  1382. goto Exit;
  1383. }
  1384. if (FAILED(hr = pCreateStore->CreatePropertyStore(guidProp,
  1385. (ITfRangeAnchor *)pRangeTmp,
  1386. pHdr->cb,
  1387. pStream,
  1388. &pPropStore)))
  1389. goto Exit;
  1390. }
  1391. else
  1392. {
  1393. if (IsEqualCLSID(pHdr->clsidTIP, CLSID_IME_StaticProperty))
  1394. {
  1395. //
  1396. // Unserialize Static properties.
  1397. //
  1398. CGeneralPropStore *pStore;
  1399. // GUID_PROP_READING is TFPROPSTYLE_CUSTOM ==> uses a general prop store
  1400. if (_propStyle == TFPROPSTYLE_CUSTOM)
  1401. {
  1402. // general prop stores are thrown away if their text is edited
  1403. pStore = new CGeneralPropStore;
  1404. }
  1405. else
  1406. {
  1407. // static prop stores are per char, and simply clone themselves in response to any edit
  1408. pStore = new CStaticPropStore;
  1409. }
  1410. if (!pStore)
  1411. goto Exit;
  1412. if (!pStore->_Init(GetPropGuidAtom(),
  1413. pHdr->cb,
  1414. (TfPropertyType)pHdr->dwPrivate,
  1415. pStream,
  1416. _dwPropFlags))
  1417. {
  1418. goto Exit;
  1419. }
  1420. pPropStore = pStore;
  1421. hr = S_OK;
  1422. }
  1423. else
  1424. {
  1425. //
  1426. // There is no TFE installed in this system. So we use
  1427. // PropStoreProxy to hold the data.
  1428. // Temporarily we use ITfIME_APP. But original TFE that owns this
  1429. // data is kept in CPropStoreProxy.
  1430. //
  1431. CPropStoreProxy *pStoreProxy = new CPropStoreProxy;
  1432. if (!pStoreProxy)
  1433. goto Exit;
  1434. if (!pStoreProxy->_Init(&pHdr->clsidTIP,
  1435. GetPropGuidAtom(),
  1436. pHdr->cb,
  1437. pStream,
  1438. _dwPropFlags))
  1439. {
  1440. goto Exit;
  1441. }
  1442. pPropStore = pStoreProxy;
  1443. hr = S_OK;
  1444. }
  1445. }
  1446. Exit:
  1447. // make sure the stream seek ptr is in a consistent state -- don't count
  1448. // on any tip to do it right!
  1449. if (SUCCEEDED(hr))
  1450. {
  1451. li.QuadPart += pHdr->cb;
  1452. }
  1453. pStream->Seek(li, STREAM_SEEK_SET, NULL);
  1454. *ppStore = pPropStore;
  1455. SafeRelease(pRangeTmp);
  1456. SafeRelease(pCreateStore);
  1457. return hr;
  1458. }
  1459. //+---------------------------------------------------------------------------
  1460. //
  1461. // GetContext
  1462. //
  1463. //----------------------------------------------------------------------------
  1464. STDAPI CProperty::GetContext(ITfContext **ppContext)
  1465. {
  1466. if (ppContext == NULL)
  1467. return E_INVALIDARG;
  1468. *ppContext = _pic;
  1469. if (*ppContext)
  1470. {
  1471. (*ppContext)->AddRef();
  1472. return S_OK;
  1473. }
  1474. return E_FAIL;
  1475. }
  1476. //+---------------------------------------------------------------------------
  1477. //
  1478. // Clear
  1479. //
  1480. //----------------------------------------------------------------------------
  1481. STDAPI CProperty::Clear(TfEditCookie ec, ITfRange *pRange)
  1482. {
  1483. CRange *pCRange = NULL;
  1484. IAnchor *paStart = NULL;
  1485. IAnchor *paEnd = NULL;
  1486. HRESULT hr;
  1487. if (!_IsValidEditCookie(ec, TF_ES_READ_PROPERTY_WRITE))
  1488. {
  1489. Assert(0);
  1490. return TF_E_NOLOCK;
  1491. }
  1492. paStart = NULL;
  1493. paEnd = NULL;
  1494. if (pRange != NULL)
  1495. {
  1496. pCRange = GetCRange_NA(pRange);
  1497. if (!pCRange)
  1498. return E_INVALIDARG;
  1499. if (!VerifySameContext(_pic, pCRange))
  1500. return E_INVALIDARG;
  1501. pCRange->_QuickCheckCrossedAnchors();
  1502. paStart = pCRange->_GetStart();
  1503. paEnd = pCRange->_GetEnd();
  1504. }
  1505. if ((hr = _CheckValidation(ec, pCRange)) != S_OK)
  1506. return hr;
  1507. return _ClearInternal(ec, paStart, paEnd);
  1508. }
  1509. //+---------------------------------------------------------------------------
  1510. //
  1511. // _CheckValidation
  1512. //
  1513. //----------------------------------------------------------------------------
  1514. HRESULT CProperty::_CheckValidation(TfEditCookie ec, CRange *range)
  1515. {
  1516. CProperty *prop;
  1517. BOOL fExactEndMatch;
  1518. LONG iStartEdge;
  1519. LONG iEndEdge;
  1520. LONG iSpan;
  1521. PROPERTYLIST *pPropList;
  1522. TfClientId tid;
  1523. IAnchor *paStart;
  1524. //
  1525. // There is no validation. Return TRUE;
  1526. //
  1527. if (_dwAuthority == PROPA_NONE)
  1528. return S_OK;
  1529. if (_dwAuthority & PROPA_READONLY)
  1530. return TF_E_READONLY;
  1531. tid = _pic->_GetClientInEditSession(ec);
  1532. if (range == NULL)
  1533. return (tid == _pic->_GetTIPOwner()) ? S_OK : TF_E_NOTOWNEDRANGE;
  1534. if (!(_dwAuthority & PROPA_FOCUSRANGE))
  1535. {
  1536. Assert(_dwAuthority & PROPA_TEXTOWNER);
  1537. return _CheckOwner(tid, range->_GetStart(), range->_GetEnd());
  1538. }
  1539. //
  1540. // If the validation is PROPA_FOCUSTEXTOWNER, we check the focus range
  1541. // first. If the range is not focus range, we allow tip to
  1542. // update the property.
  1543. //
  1544. if ((prop = _pic->_FindProperty(GUID_PROP_COMPOSING)) == NULL)
  1545. return S_OK; // no focus spans, so must be valid
  1546. // for each focus span covered by the range, we need to make sure
  1547. // this tip is the owner
  1548. prop->Find(range->_GetStart(), &iStartEdge, FALSE);
  1549. fExactEndMatch = (prop->Find(range->_GetEnd(), &iEndEdge, TRUE) != NULL);
  1550. for (iSpan = max(iStartEdge, 0); iSpan <= iEndEdge; iSpan++)
  1551. {
  1552. pPropList = prop->GetPropList(iSpan);
  1553. if (iSpan == iStartEdge)
  1554. {
  1555. // this span may not be covered, need to check
  1556. // only relivent case: are we entirely to the right of the span?
  1557. if (CompareAnchors(range->_GetStart(), pPropList->_paEnd) >= 0)
  1558. continue;
  1559. paStart = range->_GetStart();
  1560. }
  1561. else
  1562. {
  1563. paStart = pPropList->_paStart;
  1564. }
  1565. if (_CheckOwner(tid, paStart, pPropList->_paEnd) == TF_E_NOTOWNEDRANGE)
  1566. return TF_E_NOTOWNEDRANGE;
  1567. }
  1568. // might also need to check the next span, since we rounded down
  1569. if (!fExactEndMatch && prop->GetPropNum() > iEndEdge+1)
  1570. {
  1571. pPropList = prop->GetPropList(iEndEdge+1);
  1572. IAnchor *paMaxStart;
  1573. if (CompareAnchors(range->_GetStart(), pPropList->_paStart) >= 0)
  1574. paMaxStart = range->_GetStart();
  1575. else
  1576. paMaxStart = pPropList->_paStart;
  1577. if (CompareAnchors(range->_GetEnd(), pPropList->_paStart) > 0)
  1578. {
  1579. return _CheckOwner(tid, paMaxStart, range->_GetEnd());
  1580. }
  1581. }
  1582. return S_OK;
  1583. }
  1584. //+---------------------------------------------------------------------------
  1585. //
  1586. // _CheckOwner
  1587. //
  1588. //----------------------------------------------------------------------------
  1589. HRESULT CProperty::_CheckOwner(TfClientId tid, IAnchor *paStart, IAnchor *paEnd)
  1590. {
  1591. CProperty *prop;
  1592. BOOL fExactEndMatch;
  1593. LONG iStartEdge;
  1594. LONG iEndEdge;
  1595. LONG iSpan;
  1596. PROPERTYLIST *pPropList;
  1597. VARIANT var;
  1598. if ((prop = _pic->GetTextOwnerProperty()) == NULL)
  1599. return S_OK; // no owned spans, so must be valid
  1600. // for each owner span covered by the range, we need to make sure
  1601. // this tip is the owner
  1602. prop->Find(paStart, &iStartEdge, FALSE);
  1603. fExactEndMatch = (prop->Find(paEnd, &iEndEdge, TRUE) != NULL);
  1604. for (iSpan = max(iStartEdge, 0); iSpan <= iEndEdge; iSpan++)
  1605. {
  1606. pPropList = prop->QuickGetAndLoadPropList(iSpan);
  1607. if (pPropList == NULL)
  1608. {
  1609. // this probably means we couldn't unserialize the data
  1610. // just skip it
  1611. continue;
  1612. }
  1613. if (iSpan == iStartEdge)
  1614. {
  1615. // this span may not be covered, need to check
  1616. // only relivent case: are we entirely to the right of the span?
  1617. if (CompareAnchors(paStart, pPropList->_paEnd) >= 0)
  1618. continue;
  1619. }
  1620. if (pPropList->_pPropStore->GetData(&var) == S_OK)
  1621. {
  1622. Assert(var.vt == VT_I4); // this is the text owner property!
  1623. if ((TfClientId)var.lVal != tid)
  1624. {
  1625. return TF_E_NOTOWNEDRANGE;
  1626. }
  1627. }
  1628. }
  1629. // might also need to check the next span, since we rounded down
  1630. if (!fExactEndMatch && prop->GetPropNum() > iEndEdge+1)
  1631. {
  1632. pPropList = prop->QuickGetAndLoadPropList(iEndEdge+1);
  1633. if (pPropList == NULL)
  1634. {
  1635. // this probably means we couldn't unserialize the data
  1636. goto Exit;
  1637. }
  1638. if (CompareAnchors(paEnd, pPropList->_paStart) > 0)
  1639. {
  1640. if (pPropList->_pPropStore->GetData(&var) == S_OK)
  1641. {
  1642. Assert(var.vt == VT_I4); // this is the text owner property!
  1643. if ((TfClientId)var.lVal != tid)
  1644. {
  1645. return TF_E_NOTOWNEDRANGE;
  1646. }
  1647. }
  1648. }
  1649. }
  1650. Exit:
  1651. return S_OK;
  1652. }
  1653. //+---------------------------------------------------------------------------
  1654. //
  1655. // CheckTextOwner
  1656. //
  1657. //----------------------------------------------------------------------------
  1658. BOOL CProperty::_IsValidEditCookie(TfEditCookie ec, DWORD dwFlags)
  1659. {
  1660. return _pic->_IsValidEditCookie(ec, dwFlags);
  1661. }
  1662. //+---------------------------------------------------------------------------
  1663. //
  1664. // SetValue
  1665. //
  1666. //----------------------------------------------------------------------------
  1667. STDAPI CProperty::SetValue(TfEditCookie ec, ITfRange *pRange, const VARIANT *pvarValue)
  1668. {
  1669. CRange *pCRange;
  1670. HRESULT hr;
  1671. if (pRange == NULL)
  1672. return E_INVALIDARG;
  1673. if (pvarValue == NULL)
  1674. return E_INVALIDARG;
  1675. if (!IsValidCiceroVarType(pvarValue->vt))
  1676. return E_INVALIDARG;
  1677. if (!_IsValidEditCookie(ec, TF_ES_READ_PROPERTY_WRITE))
  1678. {
  1679. Assert(0);
  1680. return TF_E_NOLOCK;
  1681. }
  1682. pCRange = GetCRange_NA(pRange);
  1683. if (!pCRange)
  1684. return E_INVALIDARG;
  1685. if (!VerifySameContext(_pic, pCRange))
  1686. return E_INVALIDARG;
  1687. pCRange->_QuickCheckCrossedAnchors();
  1688. if ((hr = _CheckValidation(ec, pCRange)) != S_OK)
  1689. return hr;
  1690. if (IsEqualAnchor(pCRange->_GetStart(), pCRange->_GetEnd()))
  1691. return E_INVALIDARG;
  1692. return _SetDataInternal(ec, pCRange->_GetStart(), pCRange->_GetEnd(), pvarValue);
  1693. }
  1694. //+---------------------------------------------------------------------------
  1695. //
  1696. // GetValue
  1697. //
  1698. //----------------------------------------------------------------------------
  1699. STDAPI CProperty::GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
  1700. {
  1701. CRange *pCRange;
  1702. if (pvarValue == NULL)
  1703. return E_INVALIDARG;
  1704. QuickVariantInit(pvarValue);
  1705. if (pRange == NULL)
  1706. return E_INVALIDARG;
  1707. if ((pCRange = GetCRange_NA(pRange)) == NULL)
  1708. return E_INVALIDARG;
  1709. if (!VerifySameContext(_pic, pCRange))
  1710. return E_INVALIDARG;
  1711. if (!_IsValidEditCookie(ec, TF_ES_READ))
  1712. {
  1713. Assert(0);
  1714. return TF_E_NOLOCK;
  1715. }
  1716. pCRange->_QuickCheckCrossedAnchors();
  1717. return _GetDataInternal(pCRange->_GetStart(), pCRange->_GetEnd(), pvarValue);
  1718. }
  1719. //+---------------------------------------------------------------------------
  1720. //
  1721. // SetValueStore
  1722. //
  1723. //----------------------------------------------------------------------------
  1724. STDAPI CProperty::SetValueStore(TfEditCookie ec, ITfRange *pRange, ITfPropertyStore *pPropStore)
  1725. {
  1726. CRange *pCRange;
  1727. if (pRange == NULL || pPropStore == NULL)
  1728. return E_INVALIDARG;
  1729. if (!_IsValidEditCookie(ec, TF_ES_READ_PROPERTY_WRITE))
  1730. {
  1731. Assert(0);
  1732. return TF_E_NOLOCK;
  1733. }
  1734. pCRange = GetCRange_NA(pRange);
  1735. if (!pCRange)
  1736. return E_INVALIDARG;
  1737. if (!VerifySameContext(_pic, pCRange))
  1738. return E_INVALIDARG;
  1739. pCRange->_QuickCheckCrossedAnchors();
  1740. return _SetStoreInternal(ec, pCRange, pPropStore, FALSE);
  1741. }
  1742. //+---------------------------------------------------------------------------
  1743. //
  1744. // FindRange
  1745. //
  1746. //----------------------------------------------------------------------------
  1747. STDAPI CProperty::FindRange(TfEditCookie ec, ITfRange *pRange, ITfRange **ppv, TfAnchor aPos)
  1748. {
  1749. CRange *pCRange;
  1750. CRange *range;
  1751. HRESULT hr;
  1752. if (!ppv)
  1753. return E_INVALIDARG;
  1754. *ppv = NULL;
  1755. if (pRange == NULL)
  1756. return E_INVALIDARG;
  1757. if ((range = GetCRange_NA(pRange)) == NULL)
  1758. return E_INVALIDARG;
  1759. if (!VerifySameContext(_pic, range))
  1760. return E_INVALIDARG;
  1761. if (!_IsValidEditCookie(ec, TF_ES_READ))
  1762. {
  1763. Assert(0);
  1764. return TF_E_NOLOCK;
  1765. }
  1766. range->_QuickCheckCrossedAnchors();
  1767. if (SUCCEEDED(hr = _InternalFindRange(range, &pCRange, aPos, FALSE)))
  1768. {
  1769. *ppv = (ITfRangeAnchor *)pCRange;
  1770. }
  1771. return hr;
  1772. }
  1773. //+---------------------------------------------------------------------------
  1774. //
  1775. // FindRange
  1776. //
  1777. //----------------------------------------------------------------------------
  1778. HRESULT CProperty::_InternalFindRange(CRange *pRange, CRange **ppv, TfAnchor aPos, BOOL fEnd)
  1779. {
  1780. PROPERTYLIST *pPropList;
  1781. CRange *pCRange;
  1782. //
  1783. // Issue: need to defrag for STATICCOMPACT property.
  1784. //
  1785. if (pRange)
  1786. {
  1787. pPropList = FindPropertyListByPos((aPos == TF_ANCHOR_START) ? pRange->_GetStart() : pRange->_GetEnd(), fEnd);
  1788. }
  1789. else
  1790. {
  1791. // if pRange is NULL, we returns the first or last property.
  1792. if (aPos == TF_ANCHOR_START)
  1793. pPropList = GetFirstPropList();
  1794. else
  1795. pPropList = GetLastPropList();
  1796. }
  1797. *ppv = NULL;
  1798. if (!pPropList)
  1799. return S_FALSE;
  1800. if ((pCRange = new CRange) == NULL)
  1801. return E_OUTOFMEMORY;
  1802. if (!pCRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pPropList->_paStart, pPropList->_paEnd))
  1803. {
  1804. pCRange->Release();
  1805. return E_FAIL;
  1806. }
  1807. *ppv = pCRange;
  1808. return S_OK;
  1809. }
  1810. //+---------------------------------------------------------------------------
  1811. //
  1812. // EnumRanges
  1813. //
  1814. //----------------------------------------------------------------------------
  1815. STDAPI CProperty::EnumRanges(TfEditCookie ec, IEnumTfRanges **ppv, ITfRange *pTargetRange)
  1816. {
  1817. CRange *range;
  1818. CEnumPropertyRanges *pEnum;
  1819. if (ppv == NULL)
  1820. return E_INVALIDARG;
  1821. *ppv = NULL;
  1822. if (!_IsValidEditCookie(ec, TF_ES_READ))
  1823. {
  1824. Assert(0);
  1825. return TF_E_NOLOCK;
  1826. }
  1827. range = NULL;
  1828. if (pTargetRange != NULL)
  1829. {
  1830. if ((range = GetCRange_NA(pTargetRange)) == NULL)
  1831. return E_INVALIDARG;
  1832. if (!VerifySameContext(_pic, range))
  1833. return E_INVALIDARG;
  1834. range->_QuickCheckCrossedAnchors();
  1835. }
  1836. if ((pEnum = new CEnumPropertyRanges) == NULL)
  1837. return E_OUTOFMEMORY;
  1838. if (!pEnum->_Init(_pic, range ? range->_GetStart() : NULL, range ? range->_GetEnd() : NULL, this))
  1839. {
  1840. pEnum->Release();
  1841. return E_FAIL;
  1842. }
  1843. *ppv = pEnum;
  1844. return S_OK;
  1845. }
  1846. //+---------------------------------------------------------------------------
  1847. //
  1848. // _Serialize
  1849. //
  1850. //----------------------------------------------------------------------------
  1851. HRESULT CProperty::_Serialize(CRange *pRange, TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr, IStream *pStream)
  1852. {
  1853. HRESULT hr = E_FAIL;
  1854. CLSID clsidTIP;
  1855. LARGE_INTEGER li;
  1856. GUID guidProp;
  1857. PROPERTYLIST *pPropList;
  1858. memset(pHdr, 0, sizeof(*pHdr));
  1859. if (_dwAuthority & PROPA_WONT_SERIALZE)
  1860. return S_FALSE;
  1861. // nb: this call ignores any property spans following the leftmost span covered by pRange
  1862. // callers are expected to call for each span (which is goofy, but that's the way it is)
  1863. pPropList = _FindPropListAndDivide(pRange->_GetStart(), pRange->_GetEnd());
  1864. if (pPropList == NULL)
  1865. {
  1866. //
  1867. // There is no actual property data.
  1868. //
  1869. hr = S_FALSE;
  1870. goto Exit;
  1871. }
  1872. //
  1873. // perf: we have to tell the application that the data is not
  1874. // unserialized yet. maybe we don't have to load it.
  1875. //
  1876. if (!pPropList->_pPropStore)
  1877. {
  1878. if (FAILED(THR(LoadData(pPropList))))
  1879. return E_FAIL;
  1880. }
  1881. Assert(pPropList->_pPropStore);
  1882. if (FAILED(GetType(&guidProp)))
  1883. goto Exit;
  1884. //
  1885. // If the request range does not match the PROPERTYLIST,
  1886. // we can not serialize STATIC and CUSTOM correctly.
  1887. //
  1888. // STATICCOMPACT property does not care about boundary, so
  1889. // let it serialize.
  1890. //
  1891. if (CompareAnchors(pRange->_GetStart(), pPropList->_paStart) != 0 ||
  1892. CompareAnchors(pRange->_GetEnd(), pPropList->_paEnd) != 0)
  1893. {
  1894. if (_propStyle != TFPROPSTYLE_STATICCOMPACT &&
  1895. _propStyle != TFPROPSTYLE_CUSTOM_COMPACT)
  1896. {
  1897. hr = S_FALSE;
  1898. goto Exit;
  1899. }
  1900. pRange->_GetStart()->Clone(&pHdr->paStart);
  1901. pRange->_GetEnd()->Clone(&pHdr->paEnd);
  1902. }
  1903. else
  1904. {
  1905. pPropList->_paStart->Clone(&pHdr->paStart);
  1906. pPropList->_paEnd->Clone(&pHdr->paEnd);
  1907. }
  1908. hr = pPropList->_pPropStore->GetPropertyRangeCreator(&clsidTIP);
  1909. if (FAILED(hr))
  1910. {
  1911. hr = E_FAIL;
  1912. goto Exit;
  1913. }
  1914. if (hr == S_OK)
  1915. {
  1916. if (IsEqualGUID(clsidTIP, GUID_NULL)) // NULL owner means "I don't want to be serialized"
  1917. {
  1918. hr = S_FALSE;
  1919. goto Exit;
  1920. }
  1921. //
  1922. // Check if clsid has ITfCreatePropertyStore interface.
  1923. //
  1924. CThreadInputMgr *ptim = CThreadInputMgr::_GetThis();
  1925. ITfTextInputProcessor *pIME;
  1926. ITfCreatePropertyStore *pCreateStore;
  1927. TfGuidAtom guidatom;
  1928. hr = E_FAIL;
  1929. if (FAILED(MyRegisterGUID(clsidTIP, &guidatom)))
  1930. goto Exit;
  1931. if (!ptim->_GetITfIMEfromGUIDATOM(guidatom, &pIME))
  1932. goto Exit;
  1933. if (FAILED(pIME->QueryInterface(IID_ITfCreatePropertyStore,
  1934. (void **)&pCreateStore)))
  1935. {
  1936. hr = S_FALSE;
  1937. goto Exit;
  1938. }
  1939. BOOL fSerializable = FALSE;
  1940. Assert(pRange != NULL);
  1941. if (FAILED(pCreateStore->IsStoreSerializable(guidProp,
  1942. (ITfRangeAnchor *)pRange,
  1943. pPropList->_pPropStore,
  1944. &fSerializable)))
  1945. {
  1946. fSerializable = FALSE;
  1947. }
  1948. pCreateStore->Release();
  1949. if (!fSerializable)
  1950. {
  1951. hr = S_FALSE;
  1952. goto Exit;
  1953. }
  1954. pHdr->clsidTIP = clsidTIP;
  1955. }
  1956. else if (hr == TF_S_PROPSTOREPROXY)
  1957. {
  1958. //
  1959. // the data is held by our PropertyStoreProxy.
  1960. // we don't have to check this.
  1961. //
  1962. pHdr->clsidTIP = clsidTIP;
  1963. }
  1964. else if (hr == TF_S_GENERALPROPSTORE)
  1965. {
  1966. //
  1967. // the data is held by our GeneralPropertyStore.
  1968. // we don't have to check this.
  1969. //
  1970. pHdr->clsidTIP = CLSID_IME_StaticProperty;
  1971. }
  1972. else
  1973. {
  1974. Assert(0);
  1975. hr = E_FAIL;
  1976. goto Exit;
  1977. }
  1978. pHdr->guidType = guidProp;
  1979. if (FAILED(hr = THR(pPropList->_pPropStore->GetDataType(&pHdr->dwPrivate))))
  1980. {
  1981. goto Exit;
  1982. }
  1983. GetCurrentPos(pStream, &li);
  1984. hr = THR(pPropList->_pPropStore->Serialize(pStream, &pHdr->cb));
  1985. // make sure the stream seek ptr is in a consistent state -- don't count
  1986. // on any tip to do it right!
  1987. if (hr == S_OK)
  1988. {
  1989. li.QuadPart += pHdr->cb;
  1990. }
  1991. pStream->Seek(li, STREAM_SEEK_SET, NULL);
  1992. Exit:
  1993. if (hr != S_OK)
  1994. {
  1995. SafeRelease(pHdr->paStart);
  1996. SafeRelease(pHdr->paEnd);
  1997. memset(pHdr, 0, sizeof(*pHdr));
  1998. }
  1999. _Dbg_AssertProp();
  2000. return hr;
  2001. }
  2002. //+---------------------------------------------------------------------------
  2003. //
  2004. // Unserialize
  2005. //
  2006. //----------------------------------------------------------------------------
  2007. HRESULT CProperty::_Unserialize(const TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *pHdr, IStream *pStream, ITfPersistentPropertyLoaderAnchor *pLoader)
  2008. {
  2009. HRESULT hr = E_FAIL;
  2010. CRange *pRange;
  2011. if (pStream)
  2012. {
  2013. if (pRange = new CRange)
  2014. {
  2015. if (pRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pHdr->paStart, pHdr->paEnd))
  2016. {
  2017. ITfPropertyStore *pPropStore;
  2018. if (SUCCEEDED(hr = _GetPropStoreFromStream(pHdr, pStream, pRange, &pPropStore)))
  2019. {
  2020. hr = _SetStoreInternal(BACKDOOR_EDIT_COOKIE, pRange, pPropStore, TRUE);
  2021. pPropStore->Release();
  2022. }
  2023. }
  2024. pRange->Release();
  2025. }
  2026. }
  2027. else if (pLoader)
  2028. {
  2029. if (pRange = new CRange)
  2030. {
  2031. if (pRange->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pHdr->paStart, pHdr->paEnd))
  2032. {
  2033. CPropertyLoad *pPropLoad = new CPropertyLoad;
  2034. if (pPropLoad != NULL)
  2035. {
  2036. hr = E_FAIL;
  2037. if (pPropLoad->_Init(pHdr, pLoader))
  2038. {
  2039. hr = _SetPropertyLoaderInternal(BACKDOOR_EDIT_COOKIE, pRange, pPropLoad);
  2040. }
  2041. if (FAILED(hr))
  2042. {
  2043. delete pPropLoad;
  2044. }
  2045. }
  2046. }
  2047. pRange->Release();
  2048. }
  2049. }
  2050. _Dbg_AssertProp();
  2051. return hr;
  2052. }
  2053. //+---------------------------------------------------------------------------
  2054. //
  2055. // _ClearChangeHistory
  2056. //
  2057. //----------------------------------------------------------------------------
  2058. void CProperty::_ClearChangeHistory(PROPERTYLIST *prop, DWORD *pdwStartHistory, DWORD *pdwEndHistory)
  2059. {
  2060. if (prop->_paStart->GetChangeHistory(pdwStartHistory) != S_OK)
  2061. {
  2062. *pdwStartHistory = 0;
  2063. }
  2064. if (prop->_paEnd->GetChangeHistory(pdwEndHistory) != S_OK)
  2065. {
  2066. *pdwEndHistory = 0;
  2067. }
  2068. // need to clear the history so we don't deal with the after-effects
  2069. // of a SetText more than once
  2070. if (*pdwStartHistory != 0)
  2071. {
  2072. prop->_paStart->ClearChangeHistory();
  2073. }
  2074. if (*pdwEndHistory != 0)
  2075. {
  2076. prop->_paEnd->ClearChangeHistory();
  2077. }
  2078. }
  2079. //+---------------------------------------------------------------------------
  2080. //
  2081. // _ClearChangeHistory
  2082. //
  2083. //----------------------------------------------------------------------------
  2084. #ifdef DEBUG
  2085. void CProperty::_Dbg_AssertNoChangeHistory()
  2086. {
  2087. int i;
  2088. PROPERTYLIST *prop;
  2089. DWORD dwHistory;
  2090. // all the history bits should have been cleared immediately following the text change notification
  2091. for (i=0; i<_rgProp.Count(); i++)
  2092. {
  2093. prop = _rgProp.Get(i);
  2094. prop->_paStart->GetChangeHistory(&dwHistory);
  2095. Assert(dwHistory == 0);
  2096. prop->_paEnd->GetChangeHistory(&dwHistory);
  2097. Assert(dwHistory == 0);
  2098. }
  2099. }
  2100. #endif // DEBUG
  2101. //+---------------------------------------------------------------------------
  2102. //
  2103. // FindNextValue
  2104. //
  2105. //----------------------------------------------------------------------------
  2106. STDAPI CProperty::FindNextValue(TfEditCookie ec, ITfRange *pRangeQueryIn, TfAnchor tfAnchorQuery,
  2107. DWORD dwFlags, BOOL *pfContained, ITfRange **ppRangeNextValue)
  2108. {
  2109. CRange *pRangeQuery;
  2110. CRange *pRangeNextValue;
  2111. IAnchor *paQuery;
  2112. PROPERTYLIST *pPropertyList;
  2113. LONG iIndex;
  2114. BOOL fSearchForward;
  2115. BOOL fContained;
  2116. BOOL fExactMatch;
  2117. if (pfContained != NULL)
  2118. {
  2119. *pfContained = FALSE;
  2120. }
  2121. if (ppRangeNextValue != NULL)
  2122. {
  2123. *ppRangeNextValue = NULL;
  2124. }
  2125. if (pfContained == NULL || ppRangeNextValue == NULL)
  2126. return E_INVALIDARG;
  2127. if (pRangeQueryIn == NULL)
  2128. return E_INVALIDARG;
  2129. if (dwFlags & ~(TF_FNV_BACKWARD | TF_FNV_NO_CONTAINED))
  2130. return E_INVALIDARG;
  2131. if (!_IsValidEditCookie(ec, TF_ES_READ))
  2132. return TF_E_NOLOCK;
  2133. if ((pRangeQuery = GetCRange_NA(pRangeQueryIn)) == NULL)
  2134. return E_INVALIDARG;
  2135. if (!VerifySameContext(_pic, pRangeQuery))
  2136. return E_INVALIDARG;
  2137. fSearchForward = !(dwFlags & TF_FNV_BACKWARD);
  2138. pRangeQuery->_QuickCheckCrossedAnchors();
  2139. paQuery = (tfAnchorQuery == TF_ANCHOR_START) ? pRangeQuery->_GetStart() : pRangeQuery->_GetEnd();
  2140. fExactMatch = (Find(paQuery, &iIndex, fSearchForward) != NULL);
  2141. if (fSearchForward)
  2142. {
  2143. if (++iIndex >= _rgProp.Count())
  2144. return S_OK; // no next value
  2145. }
  2146. else
  2147. {
  2148. if (fExactMatch)
  2149. {
  2150. --iIndex;
  2151. }
  2152. if (iIndex < 0)
  2153. return S_OK; // no prev value
  2154. }
  2155. pPropertyList = _rgProp.Get(iIndex);
  2156. Assert(pPropertyList != NULL);
  2157. fContained = (CompareAnchors(pPropertyList->_paStart, paQuery) <= 0) &&
  2158. (CompareAnchors(pPropertyList->_paEnd, paQuery) >= 0);
  2159. if (fContained && (dwFlags & TF_FNV_NO_CONTAINED))
  2160. {
  2161. // caller wants to skip any contained value span
  2162. if (fSearchForward)
  2163. {
  2164. if (++iIndex >= _rgProp.Count())
  2165. return S_OK; // no next value
  2166. }
  2167. else
  2168. {
  2169. if (--iIndex == -1)
  2170. return S_OK; // no prev value
  2171. }
  2172. pPropertyList = _rgProp.Get(iIndex);
  2173. Assert(pPropertyList != NULL);
  2174. fContained = FALSE;
  2175. }
  2176. if ((pRangeNextValue = new CRange) == NULL)
  2177. return E_OUTOFMEMORY;
  2178. if (!pRangeNextValue->_InitWithDefaultGravity(_pic, COPY_ANCHORS, pPropertyList->_paStart, pPropertyList->_paEnd))
  2179. {
  2180. pRangeNextValue->Release();
  2181. return E_FAIL;
  2182. }
  2183. *pfContained = fContained;
  2184. *ppRangeNextValue = (ITfRangeAnchor *)pRangeNextValue;
  2185. return S_OK;
  2186. }