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.

586 lines
16 KiB

  1. //
  2. // ptrack.cpp
  3. //
  4. #include "private.h"
  5. #include "ic.h"
  6. #include "saa.h"
  7. #include "attr.h"
  8. #include "immxutil.h"
  9. #include "erfa.h"
  10. #include "epval.h"
  11. #include "range.h"
  12. //+---------------------------------------------------------------------------
  13. //
  14. // CalcCicPropertyTrackerAnchors
  15. //
  16. //----------------------------------------------------------------------------
  17. CSharedAnchorArray *CalcCicPropertyTrackerAnchors(CInputContext *pic, IAnchor *paStart, IAnchor *paEnd, ULONG cGUIDATOMs, const TfGuidAtom *prgGUIDATOMs)
  18. {
  19. CProperty *pProperty;
  20. CSharedAnchorArray *prgAnchors;
  21. CSharedAnchorArray **prgAnchorArrays;
  22. ULONG i;
  23. LONG iStartEdge;
  24. LONG iEndEdge;
  25. LONG iSpan;
  26. PROPERTYLIST *pPropList;
  27. IAnchor **ppa;
  28. ULONG cArrays;
  29. BOOL fExactEndMatch;
  30. ULONG cMaxElems;
  31. if ((prgAnchorArrays = (CSharedAnchorArray **)cicMemAlloc(sizeof(CSharedAnchorArray *)*(cGUIDATOMs+1))) == NULL)
  32. return NULL;
  33. cArrays = 0;
  34. //
  35. // shove in the range start and end pts
  36. //
  37. if ((prgAnchors = new CSharedAnchorArray) == NULL)
  38. goto ErrorExit;
  39. if (!prgAnchors->Insert(0, 2))
  40. goto ErrorExit;
  41. if (paStart->Clone(prgAnchors->GetPtr(0)) != S_OK)
  42. goto ErrorExit;
  43. if (IsEqualAnchor(paStart, paEnd))
  44. {
  45. // empty range, we just want a single anchor at the range pos
  46. prgAnchors->SetCount(1);
  47. goto Exit;
  48. }
  49. if (paEnd->Clone(prgAnchors->GetPtr(1)) != S_OK)
  50. goto ErrorExit;
  51. prgAnchorArrays[0] = prgAnchors;
  52. //
  53. // assemble a list of all the points between start, end
  54. //
  55. cArrays = 1; // 1 for the start, end anchors array
  56. for (i=0; i<cGUIDATOMs; i++)
  57. {
  58. if ((pProperty = pic->_FindProperty(prgGUIDATOMs[i])) == NULL)
  59. continue; // no instances of this property
  60. // find the start, end points
  61. pProperty->Find(paStart, &iStartEdge, FALSE);
  62. fExactEndMatch = (pProperty->Find(paEnd, &iEndEdge, TRUE) != NULL);
  63. if (iEndEdge < iStartEdge)
  64. continue; // start, end are in the same property span, so value is constant over range
  65. // alloc memory for all the new anchors
  66. if ((prgAnchors = new CSharedAnchorArray) == NULL)
  67. goto ErrorExit;
  68. // alloc for max anchors
  69. cMaxElems = (iEndEdge - iStartEdge + 1)*2;
  70. if ((ppa = prgAnchors->Append(cMaxElems)) == NULL)
  71. goto ErrorExit;
  72. // prep for failure
  73. memset(ppa, 0, sizeof(IAnchor *)*cMaxElems);
  74. // add all the covered anchors for this prop to the list
  75. if (iStartEdge < 0)
  76. {
  77. iSpan = 0;
  78. }
  79. else
  80. {
  81. iSpan = iStartEdge;
  82. // if paStart is to the right of the span, skip it
  83. pPropList = pProperty->GetPropList(iStartEdge);
  84. if (CompareAnchors(paStart, pPropList->_paEnd) >= 0)
  85. {
  86. // we don't cover this span at all, or we just touch the right edge
  87. // so skip it
  88. iSpan++;
  89. }
  90. }
  91. while (iSpan <= iEndEdge)
  92. {
  93. // shove in this span's anchors
  94. pPropList = pProperty->GetPropList(iSpan);
  95. if (iSpan != iStartEdge)
  96. {
  97. // filter out dups
  98. // perf: we could elim the dup check for static compact props
  99. if (ppa == prgAnchors->GetPtr(0) || !IsEqualAnchor(*(ppa-1), pPropList->_paStart))
  100. {
  101. if (pPropList->_paStart->Clone(ppa++) != S_OK)
  102. goto ErrorExit;
  103. }
  104. }
  105. Assert(!IsEqualAnchor(pPropList->_paStart, pPropList->_paEnd)); // no zero-len properties!
  106. if (iSpan != iEndEdge ||
  107. (!fExactEndMatch && (iStartEdge < iEndEdge || CompareAnchors(paStart, pPropList->_paEnd) < 0)))
  108. {
  109. if (pPropList->_paEnd->Clone(ppa++) != S_OK)
  110. goto ErrorExit;
  111. }
  112. iSpan++;
  113. }
  114. // may also want the start anchor of the next span
  115. if (!fExactEndMatch &&
  116. pProperty->GetPropNum() > iEndEdge+1)
  117. {
  118. pPropList = pProperty->GetPropList(iEndEdge+1);
  119. if (CompareAnchors(paEnd, pPropList->_paStart) > 0)
  120. {
  121. // start of this span may be same as end of prev for non-compact property, check for dup
  122. if (ppa == prgAnchors->GetPtr(0) || !IsEqualAnchor(*(ppa-1), pPropList->_paStart))
  123. {
  124. // don't need a dup check w/ paEnd because we would have set fExactEndMatch in that case
  125. if (pPropList->_paStart->Clone(ppa++) != S_OK)
  126. goto ErrorExit;
  127. }
  128. }
  129. }
  130. // need to resize the array since we may have over-alloc'd
  131. Assert((int)cMaxElems >= ppa - prgAnchors->GetPtr(0));
  132. prgAnchors->SetCount((int)(ppa - prgAnchors->GetPtr(0)));
  133. prgAnchorArrays[cArrays++] = prgAnchors;
  134. }
  135. //
  136. // sort the list
  137. //
  138. if (cArrays > 1)
  139. {
  140. // mergesort will free all the arrays in prgAnchorArrays
  141. prgAnchors = CSharedAnchorArray::_MergeSort(prgAnchorArrays, cArrays);
  142. }
  143. else
  144. {
  145. Assert(prgAnchors == prgAnchorArrays[0]);
  146. }
  147. // shrink the array down to size, it won't be modified again
  148. if (prgAnchors)
  149. prgAnchors->CompactSize();
  150. Exit:
  151. cicMemFree(prgAnchorArrays);
  152. return prgAnchors;
  153. ErrorExit:
  154. for (i=0; i<cArrays; i++)
  155. {
  156. prgAnchorArrays[i]->_Release();
  157. }
  158. prgAnchors = NULL;
  159. goto Exit;
  160. }
  161. //+---------------------------------------------------------------------------
  162. //
  163. // FillCicValueArray
  164. //
  165. //----------------------------------------------------------------------------
  166. void FillCicValueArray(CInputContext *pic, CRange *range, TF_PROPERTYVAL *rgPropVal, ULONG cGUIDATOMs, const TfGuidAtom *prgGUIDATOMs)
  167. {
  168. ULONG i;
  169. CProperty *pProperty;
  170. for (i=0; i<cGUIDATOMs; i++)
  171. {
  172. Assert(rgPropVal[i].varValue.vt == VT_EMPTY);
  173. if (MyGetGUID(prgGUIDATOMs[i], &rgPropVal[i].guidId) != S_OK)
  174. {
  175. Assert(0); // this shouldn't happen, we registered the GUID when caller created the property
  176. rgPropVal[i].guidId = GUID_NULL;
  177. continue;
  178. }
  179. if ((pProperty = pic->_FindProperty(prgGUIDATOMs[i])) != NULL)
  180. {
  181. pProperty->_GetDataInternal(range->_GetStart(), range->_GetEnd(), &rgPropVal[i].varValue);
  182. }
  183. }
  184. }
  185. //////////////////////////////////////////////////////////////////////////////
  186. //////////////////////////////////////////////////////////////////////////////
  187. //
  188. // CEnumUberRanges
  189. //
  190. //////////////////////////////////////////////////////////////////////////////
  191. //////////////////////////////////////////////////////////////////////////////
  192. class CEnumUberRanges : public CEnumRangesFromAnchorsBase
  193. {
  194. public:
  195. CEnumUberRanges()
  196. {
  197. Dbg_MemSetThisNameIDCounter(TEXT("CEnumUberRanges"), PERF_ENUMUBERPROP_COUNTER);
  198. }
  199. BOOL _Init(CInputContext *pic, ITfRange *rangeSuper, ULONG cCicGUIDs, const TfGuidAtom *prgCicGUIDATOMs, ULONG cAppGUIDs, const GUID *prgAppGUIDs);
  200. private:
  201. DBG_ID_DECLARE;
  202. };
  203. DBG_ID_INSTANCE(CEnumUberRanges);
  204. //+---------------------------------------------------------------------------
  205. //
  206. // _Init
  207. //
  208. //----------------------------------------------------------------------------
  209. BOOL CEnumUberRanges::_Init(CInputContext *pic, ITfRange *rangeSuper, ULONG cCicGUIDATOMs, const TfGuidAtom *prgCicGUIDATOMs, ULONG cAppGUIDs, const GUID *prgAppGUIDs)
  210. {
  211. CRange *range;
  212. CSharedAnchorArray *prgSrcAnchorArrays[2];
  213. Assert(_iCur == 0);
  214. Assert(_pic == NULL);
  215. Assert(_prgAnchors == NULL);
  216. // find the app property transitions
  217. prgSrcAnchorArrays[0] = CalcAppPropertyTrackerAnchors(pic->_GetTSI(), rangeSuper, cAppGUIDs, prgAppGUIDs);
  218. if (prgSrcAnchorArrays[0] == NULL)
  219. return FALSE;
  220. // find the cicero property transitions
  221. if ((range = GetCRange_NA(rangeSuper)) == NULL)
  222. goto ErrorExit;
  223. prgSrcAnchorArrays[1] = CalcCicPropertyTrackerAnchors(pic, range->_GetStart(), range->_GetEnd(), cCicGUIDATOMs, prgCicGUIDATOMs);
  224. if (prgSrcAnchorArrays[1] == NULL)
  225. goto ErrorExit;
  226. // now combine the two lists
  227. _prgAnchors = CSharedAnchorArray::_MergeSort(prgSrcAnchorArrays, 2);
  228. if (_prgAnchors == NULL)
  229. return FALSE;
  230. _pic = pic;
  231. _pic->AddRef();
  232. return TRUE;
  233. ErrorExit:
  234. prgSrcAnchorArrays[0]->_Release();
  235. return FALSE;
  236. }
  237. //////////////////////////////////////////////////////////////////////////////
  238. //////////////////////////////////////////////////////////////////////////////
  239. //
  240. // CUberProperty
  241. //
  242. //////////////////////////////////////////////////////////////////////////////
  243. //////////////////////////////////////////////////////////////////////////////
  244. class CUberProperty : public ITfReadOnlyProperty, // perf: share base clas with CAppProperty
  245. public CComObjectRootImmx
  246. {
  247. public:
  248. CUberProperty(CInputContext *pic);
  249. ~CUberProperty();
  250. BEGIN_COM_MAP_IMMX(CUberProperty)
  251. COM_INTERFACE_ENTRY(ITfReadOnlyProperty)
  252. END_COM_MAP_IMMX()
  253. IMMX_OBJECT_IUNKNOWN_FOR_ATL()
  254. BOOL _Init(ULONG cCicGUIDs, const GUID **prgCicGUIDs, ULONG cAppGUIDs, const GUID **prgAppGUIDs);
  255. // ITfReadOnlyProperty
  256. STDMETHODIMP GetType(GUID *pguid);
  257. STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange);
  258. STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue);
  259. STDMETHODIMP GetContext(ITfContext **ppContext);
  260. private:
  261. BOOL _IsValidEditCookie(TfEditCookie ec, DWORD dwFlags)
  262. {
  263. return _pic->_IsValidEditCookie(ec, dwFlags);
  264. }
  265. CInputContext *_pic;
  266. ULONG _cCicGUIDATOMs;
  267. TfGuidAtom *_prgCicGUIDATOMs;
  268. ULONG _cAppGUIDs;
  269. GUID *_prgAppGUIDs;
  270. DBG_ID_DECLARE;
  271. };
  272. DBG_ID_INSTANCE(CUberProperty);
  273. //+---------------------------------------------------------------------------
  274. //
  275. // ctor
  276. //
  277. //----------------------------------------------------------------------------
  278. CUberProperty::CUberProperty(CInputContext *pic)
  279. {
  280. Dbg_MemSetThisNameIDCounter(TEXT("CUberProperty"), PERF_UBERPROP_COUNTER);
  281. _pic = pic;
  282. _pic->AddRef();
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. // dtor
  287. //
  288. //----------------------------------------------------------------------------
  289. CUberProperty::~CUberProperty()
  290. {
  291. _pic->Release();
  292. cicMemFree(_prgCicGUIDATOMs);
  293. cicMemFree(_prgAppGUIDs);
  294. }
  295. //+---------------------------------------------------------------------------
  296. //
  297. // _Init
  298. //
  299. //----------------------------------------------------------------------------
  300. BOOL CUberProperty::_Init(ULONG cCicGUIDs, const GUID **prgCicGUIDs, ULONG cAppGUIDs, const GUID **prgAppGUIDs)
  301. {
  302. ULONG i;
  303. if ((_prgCicGUIDATOMs = (TfGuidAtom *)cicMemAlloc(cCicGUIDs*sizeof(TfGuidAtom))) == NULL)
  304. return FALSE;
  305. for (i=0; i<cCicGUIDs; i++)
  306. {
  307. if (MyRegisterGUID(*prgCicGUIDs[i], &_prgCicGUIDATOMs[i]) != S_OK)
  308. goto ExitError;
  309. }
  310. if ((_prgAppGUIDs = (GUID *)cicMemAlloc(cAppGUIDs*sizeof(GUID))) == NULL)
  311. goto ExitError;
  312. _cCicGUIDATOMs = cCicGUIDs;
  313. _cAppGUIDs = cAppGUIDs;
  314. for (i=0; i<cAppGUIDs; i++)
  315. {
  316. _prgAppGUIDs[i] = *prgAppGUIDs[i];
  317. }
  318. return TRUE;
  319. ExitError:
  320. cicMemFree(_prgCicGUIDATOMs);
  321. _prgCicGUIDATOMs = NULL; // no funny business in the dtor please
  322. return FALSE;
  323. }
  324. //+---------------------------------------------------------------------------
  325. //
  326. // EnumRanges
  327. //
  328. //----------------------------------------------------------------------------
  329. STDAPI CUberProperty::EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange)
  330. {
  331. CEnumUberRanges *pEnum;
  332. if (ppEnum == NULL)
  333. return E_INVALIDARG;
  334. *ppEnum = NULL;
  335. if (pTargetRange == NULL)
  336. return E_INVALIDARG;
  337. if (!VerifySameContext(_pic, pTargetRange))
  338. return E_INVALIDARG;
  339. if (!_IsValidEditCookie(ec, TF_ES_READ))
  340. {
  341. Assert(0);
  342. return TF_E_NOLOCK;
  343. }
  344. pEnum = new CEnumUberRanges;
  345. if (pEnum == NULL)
  346. return E_OUTOFMEMORY;
  347. if (!pEnum->_Init(_pic, pTargetRange, _cCicGUIDATOMs, _prgCicGUIDATOMs, _cAppGUIDs, _prgAppGUIDs))
  348. {
  349. pEnum->Release();
  350. return E_FAIL;
  351. }
  352. *ppEnum = pEnum;
  353. return S_OK;
  354. }
  355. //+---------------------------------------------------------------------------
  356. //
  357. // GetType
  358. //
  359. //----------------------------------------------------------------------------
  360. STDAPI CUberProperty::GetType(GUID *pguid)
  361. {
  362. if (pguid != NULL)
  363. {
  364. // tracker's don't support GetType
  365. *pguid = GUID_NULL;
  366. }
  367. return E_NOTIMPL; // by design
  368. }
  369. //+---------------------------------------------------------------------------
  370. //
  371. // GetValue
  372. //
  373. //----------------------------------------------------------------------------
  374. STDAPI CUberProperty::GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
  375. {
  376. CEnumPropertyValue *pEnumVal;
  377. CRange *range;
  378. SHARED_TFPROPERTYVAL_ARRAY *pPropVal;
  379. HRESULT hr;
  380. if (pvarValue == NULL)
  381. return E_INVALIDARG;
  382. QuickVariantInit(pvarValue);
  383. if (pRange == NULL)
  384. return E_INVALIDARG;
  385. if ((range = GetCRange_NA(pRange)) == NULL)
  386. return E_INVALIDARG;
  387. if (!VerifySameContext(_pic, range))
  388. return E_INVALIDARG;
  389. if (!_IsValidEditCookie(ec, TF_ES_READ))
  390. {
  391. Assert(0);
  392. return TF_E_NOLOCK;
  393. }
  394. hr = E_FAIL;
  395. if ((pPropVal = SAA_New(_cCicGUIDATOMs + _cAppGUIDs)) == NULL)
  396. goto Exit;
  397. // get an array of app values
  398. if (FillAppValueArray(_pic->_GetTSI(), range, pPropVal->rgAttrVals, _cAppGUIDs, _prgAppGUIDs) != S_OK)
  399. goto Exit;
  400. // get an array of cic values
  401. FillCicValueArray(_pic, range, pPropVal->rgAttrVals + _cAppGUIDs, _cCicGUIDATOMs, _prgCicGUIDATOMs);
  402. // stick them in an enum
  403. if ((pEnumVal = new CEnumPropertyValue(pPropVal)) == NULL)
  404. goto Exit;
  405. pvarValue->vt = VT_UNKNOWN;
  406. pvarValue->punkVal = pEnumVal;
  407. hr = S_OK;
  408. Exit:
  409. if (pPropVal != NULL)
  410. {
  411. SAA_Release(pPropVal);
  412. }
  413. return hr;
  414. }
  415. //+---------------------------------------------------------------------------
  416. //
  417. // GetContext
  418. //
  419. // perf: identical to CAppProperty::GetContext....move to base class?
  420. //----------------------------------------------------------------------------
  421. STDAPI CUberProperty::GetContext(ITfContext **ppContext)
  422. {
  423. if (ppContext == NULL)
  424. return E_INVALIDARG;
  425. *ppContext = _pic;
  426. (*ppContext)->AddRef();
  427. return S_OK;
  428. }
  429. //////////////////////////////////////////////////////////////////////////////
  430. //////////////////////////////////////////////////////////////////////////////
  431. //
  432. // CInputContext
  433. //
  434. //////////////////////////////////////////////////////////////////////////////
  435. //////////////////////////////////////////////////////////////////////////////
  436. //+---------------------------------------------------------------------------
  437. //
  438. // TrackProperties
  439. //
  440. //----------------------------------------------------------------------------
  441. STDAPI CInputContext::TrackProperties(const GUID **pguidProp, ULONG cProp, const GUID **pguidAppProp, ULONG cAppProp, ITfReadOnlyProperty **ppPropX)
  442. {
  443. CUberProperty *pup;
  444. if (ppPropX == NULL)
  445. return E_INVALIDARG;
  446. *ppPropX = NULL;
  447. if (pguidProp == NULL && cProp > 0)
  448. return E_INVALIDARG;
  449. if (pguidAppProp == NULL && cAppProp > 0)
  450. return E_INVALIDARG;
  451. if (!_IsConnected())
  452. return TF_E_DISCONNECTED;
  453. if ((pup = new CUberProperty(this)) == NULL)
  454. return E_OUTOFMEMORY;
  455. if (!pup->_Init(cProp, pguidProp, cAppProp, pguidAppProp))
  456. {
  457. pup->Release();
  458. return E_OUTOFMEMORY;
  459. }
  460. *ppPropX = pup;
  461. return S_OK;
  462. }