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.

619 lines
16 KiB

  1. //
  2. // attr.cpp
  3. //
  4. #include "private.h"
  5. #include "attr.h"
  6. #include "ic.h"
  7. #include "saa.h"
  8. #include "erfa.h"
  9. #include "epval.h"
  10. #include "immxutil.h"
  11. #include "range.h"
  12. //+---------------------------------------------------------------------------
  13. //
  14. // CalcAppPropertyTrackerAnchors
  15. //
  16. // NB: an empty range will result in a single anchor at the range pos.
  17. //----------------------------------------------------------------------------
  18. CSharedAnchorArray *CalcAppPropertyTrackerAnchors(ITextStoreAnchor *ptsi, ITfRange *rangeSuper, ULONG cGUIDs, const GUID *prgGUIDs)
  19. {
  20. CSharedAnchorArray *prgAnchors;
  21. CRange *rangeScan;
  22. IAnchor *paPrevTrans;
  23. IAnchor **ppa;
  24. BOOL fRet;
  25. BOOL fFound;
  26. LONG lFoundOffset;
  27. HRESULT hr;
  28. if ((rangeScan = GetCRange_NA(rangeSuper)) == NULL)
  29. return NULL;
  30. if ((prgAnchors = new CSharedAnchorArray) == NULL)
  31. return NULL;
  32. fRet = FALSE;
  33. if (rangeScan->_GetStart()->Clone(&paPrevTrans) != S_OK)
  34. {
  35. paPrevTrans = NULL;
  36. goto Exit;
  37. }
  38. // now scan down the length of the range, building up a list
  39. while (TRUE)
  40. {
  41. // we've just found the end point of this run
  42. if (!prgAnchors->Append(1))
  43. goto Exit;
  44. ppa = prgAnchors->GetPtr(prgAnchors->Count()-1);
  45. if (paPrevTrans->Clone(ppa) != S_OK)
  46. goto Exit;
  47. if (cGUIDs == 0) // no transition for zero GUIDs, just do the end anchor Clone outside the loop
  48. break;
  49. hr = ptsi->FindNextAttrTransition(paPrevTrans, rangeScan->_GetEnd(), cGUIDs, prgGUIDs, TS_ATTR_FIND_UPDATESTART, &fFound, &lFoundOffset);
  50. if (hr != S_OK)
  51. goto Exit;
  52. // no more property spans?
  53. if (!fFound)
  54. break;
  55. // stop when we hit the end of the range
  56. if (IsEqualAnchor(paPrevTrans, rangeScan->_GetEnd()))
  57. break;
  58. }
  59. if (!IsEqualAnchor(rangeScan->_GetStart(), rangeScan->_GetEnd()))
  60. {
  61. // add a final anchor at the end of the range
  62. if (!prgAnchors->Append(1))
  63. goto Exit;
  64. ppa = prgAnchors->GetPtr(prgAnchors->Count()-1);
  65. if (rangeScan->_GetEnd()->Clone(ppa) != S_OK)
  66. goto Exit;
  67. }
  68. // shrink the array down to size, it won't be modified again
  69. prgAnchors->CompactSize();
  70. fRet = TRUE;
  71. Exit:
  72. if (!fRet)
  73. {
  74. prgAnchors->_Release();
  75. prgAnchors = NULL;
  76. }
  77. else
  78. {
  79. Assert(prgAnchors != NULL);
  80. }
  81. SafeRelease(paPrevTrans);
  82. return prgAnchors;
  83. }
  84. //+---------------------------------------------------------------------------
  85. //
  86. // GetDefaultValue
  87. //
  88. //----------------------------------------------------------------------------
  89. HRESULT GetDefaultValue(ITextStoreAnchor *ptsi, REFGUID guidType, VARIANT *pvarValue)
  90. {
  91. TS_ATTRVAL av;
  92. ULONG cFetched;
  93. HRESULT hr;
  94. Assert(pvarValue != NULL);
  95. // VT_EMPTY for unsupported attrib/error
  96. QuickVariantInit(pvarValue);
  97. hr = ptsi->RequestSupportedAttrs(TS_ATTR_FIND_WANT_VALUE, 1, &guidType);
  98. if (hr != S_OK)
  99. {
  100. return (hr == E_NOTIMPL) ? E_NOTIMPL : E_FAIL;
  101. }
  102. if (ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) == S_OK &&
  103. cFetched == 1)
  104. {
  105. Assert(IsEqualGUID(av.idAttr, guidType));
  106. *pvarValue = av.varValue; // caller owns it now
  107. }
  108. else
  109. {
  110. // the aimm layer will sometimes stop supporting an attribute
  111. // it has two sink callback points, the one for reconversion doesn't
  112. // handle attributes.
  113. // we'll just return VT_EMPTY
  114. Assert(pvarValue->vt == VT_EMPTY);
  115. }
  116. return S_OK;
  117. }
  118. //+---------------------------------------------------------------------------
  119. //
  120. // FillAppValueArray
  121. //
  122. //----------------------------------------------------------------------------
  123. HRESULT FillAppValueArray(ITextStoreAnchor *ptsi, CRange *range, TF_PROPERTYVAL *rgPropVal, ULONG cGUIDs, const GUID *prgGUIDs)
  124. {
  125. ULONG i;
  126. ULONG j;
  127. ULONG iNext;
  128. ULONG cMissing;
  129. TS_ATTRVAL *prgVals;
  130. ULONG cFetched;
  131. HRESULT hr;
  132. if (cGUIDs == 0)
  133. return S_OK;
  134. if ((prgVals = (TS_ATTRVAL *)cicMemAlloc(cGUIDs*sizeof(TS_ATTRVAL))) == NULL)
  135. return E_OUTOFMEMORY;
  136. hr = ptsi->RequestAttrsAtPosition(range->_GetStart(), cGUIDs, prgGUIDs, 0);
  137. if (hr != S_OK)
  138. goto Exit;
  139. hr = ptsi->RetrieveRequestedAttrs(cGUIDs, prgVals, &cFetched);
  140. if (hr != S_OK)
  141. goto Exit;
  142. // copy over the values in prgVals
  143. for (i=0; i<cFetched; i++)
  144. {
  145. rgPropVal[i].guidId = prgVals[i].idAttr;
  146. rgPropVal[i].varValue = prgVals[i].varValue; // we take ownership, no VariantCopy
  147. }
  148. // figure out what was missing
  149. cMissing = cGUIDs - cFetched;
  150. if (cMissing == 0)
  151. goto Exit;
  152. iNext = cFetched; // index of first missing guid
  153. // perf: this is O(n^2), we could do a sort or something...
  154. for (i=0; i<cGUIDs; i++)
  155. {
  156. for (j=0; j<cFetched; j++)
  157. {
  158. if (IsEqualGUID(prgVals[j].idAttr, prgGUIDs[i]))
  159. break;
  160. }
  161. if (j < cFetched)
  162. continue;
  163. // found a missing GUID, need to get the default value
  164. hr = GetDefaultValue(ptsi, prgGUIDs[i], &rgPropVal[iNext].varValue);
  165. if (hr != S_OK)
  166. {
  167. Assert(0); // why did we fail?
  168. QuickVariantInit(&rgPropVal[iNext].varValue);
  169. }
  170. rgPropVal[iNext].guidId = prgGUIDs[i];
  171. if (--cMissing == 0) // anything left to look for?
  172. break;
  173. iNext++;
  174. }
  175. Exit:
  176. cicMemFree(prgVals);
  177. return hr;
  178. }
  179. //////////////////////////////////////////////////////////////////////////////
  180. //////////////////////////////////////////////////////////////////////////////
  181. //
  182. // CEnumAppPropRanges
  183. //
  184. //////////////////////////////////////////////////////////////////////////////
  185. //////////////////////////////////////////////////////////////////////////////
  186. class CEnumAppPropRanges : public CEnumRangesFromAnchorsBase
  187. {
  188. public:
  189. CEnumAppPropRanges()
  190. {
  191. Dbg_MemSetThisNameIDCounter(TEXT("CEnumAppPropRanges"), PERF_ENUMAPPPROP_COUNTER);
  192. }
  193. BOOL _Init(CInputContext *pic, ITfRange *rangeSuper, REFGUID rguid);
  194. private:
  195. DBG_ID_DECLARE;
  196. };
  197. DBG_ID_INSTANCE(CEnumAppPropRanges);
  198. //+---------------------------------------------------------------------------
  199. //
  200. // _Init
  201. //
  202. // Scan the superset range and build up a list of covered ranges.
  203. //
  204. //----------------------------------------------------------------------------
  205. BOOL CEnumAppPropRanges::_Init(CInputContext *pic, ITfRange *rangeSuper, REFGUID rguid)
  206. {
  207. Assert(_iCur == 0);
  208. Assert(_pic == NULL);
  209. Assert(_prgAnchors == NULL);
  210. _prgAnchors = CalcAppPropertyTrackerAnchors(pic->_GetTSI(), rangeSuper, 1, &rguid);
  211. if (_prgAnchors == NULL)
  212. return FALSE;
  213. _pic = pic;
  214. _pic->AddRef();
  215. return TRUE;
  216. }
  217. //////////////////////////////////////////////////////////////////////////////
  218. //////////////////////////////////////////////////////////////////////////////
  219. //
  220. // CAppProperty
  221. //
  222. //////////////////////////////////////////////////////////////////////////////
  223. //////////////////////////////////////////////////////////////////////////////
  224. class CAppProperty : public ITfReadOnlyProperty,
  225. public CComObjectRootImmx
  226. {
  227. public:
  228. CAppProperty(CInputContext *pic, REFGUID guid);
  229. ~CAppProperty();
  230. BEGIN_COM_MAP_IMMX(CAppProperty)
  231. COM_INTERFACE_ENTRY(ITfReadOnlyProperty)
  232. END_COM_MAP_IMMX()
  233. IMMX_OBJECT_IUNKNOWN_FOR_ATL()
  234. // ITfReadOnlyProperty
  235. STDMETHODIMP GetType(GUID *pguid);
  236. STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange);
  237. STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue);
  238. STDMETHODIMP GetContext(ITfContext **ppContext);
  239. private:
  240. BOOL _IsValidEditCookie(TfEditCookie ec, DWORD dwFlags)
  241. {
  242. return _pic->_IsValidEditCookie(ec, dwFlags);
  243. }
  244. CInputContext *_pic;
  245. GUID _guid;
  246. DBG_ID_DECLARE;
  247. };
  248. DBG_ID_INSTANCE(CAppProperty);
  249. //+---------------------------------------------------------------------------
  250. //
  251. // ctor
  252. //
  253. //----------------------------------------------------------------------------
  254. CAppProperty::CAppProperty(CInputContext *pic, REFGUID guid)
  255. {
  256. Dbg_MemSetThisNameIDCounter(TEXT("CAppProperty"), PERF_APPPROP_COUNTER);
  257. _pic = pic;
  258. _pic->AddRef();
  259. _guid = guid;
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // dtor
  264. //
  265. //----------------------------------------------------------------------------
  266. CAppProperty::~CAppProperty()
  267. {
  268. _pic->Release();
  269. }
  270. //+---------------------------------------------------------------------------
  271. //
  272. // GetType
  273. //
  274. //----------------------------------------------------------------------------
  275. STDAPI CAppProperty::GetType(GUID *pguid)
  276. {
  277. if (pguid == NULL)
  278. return E_INVALIDARG;
  279. *pguid = _guid;
  280. return S_OK;
  281. }
  282. //+---------------------------------------------------------------------------
  283. //
  284. // EnumRanges
  285. //
  286. //----------------------------------------------------------------------------
  287. STDAPI CAppProperty::EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange)
  288. {
  289. CEnumAppPropRanges *pEnum;
  290. if (ppEnum == NULL)
  291. return E_INVALIDARG;
  292. *ppEnum = NULL;
  293. if (!_IsValidEditCookie(ec, TF_ES_READ))
  294. {
  295. Assert(0);
  296. return TF_E_NOLOCK;
  297. }
  298. // nb: unlike ITfProperty, ITfReadOnlyProperty does not accept pTargetRange == NULL!
  299. if (pTargetRange == NULL)
  300. return E_INVALIDARG;
  301. // make sure ic, range are in the same context
  302. if (!VerifySameContext(_pic, pTargetRange))
  303. return E_INVALIDARG;
  304. pEnum = new CEnumAppPropRanges;
  305. if (pEnum == NULL)
  306. return E_OUTOFMEMORY;
  307. if (!pEnum->_Init(_pic, pTargetRange, _guid))
  308. {
  309. pEnum->Release();
  310. return E_FAIL;
  311. }
  312. *ppEnum = pEnum;
  313. return S_OK;
  314. }
  315. //+---------------------------------------------------------------------------
  316. //
  317. // GetValue
  318. //
  319. //----------------------------------------------------------------------------
  320. STDAPI CAppProperty::GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
  321. {
  322. TS_ATTRVAL av;
  323. HRESULT hr;
  324. CRange *range;
  325. ULONG cFetched;
  326. ITextStoreAnchor *ptsi;
  327. if (pvarValue == NULL)
  328. return E_INVALIDARG;
  329. QuickVariantInit(pvarValue);
  330. if (!_IsValidEditCookie(ec, TF_ES_READ))
  331. {
  332. Assert(0);
  333. return TF_E_NOLOCK;
  334. }
  335. if (pRange == NULL)
  336. return E_INVALIDARG; // supporting "whole doc" behavior too expensive!
  337. if ((range = GetCRange_NA(pRange)) == NULL)
  338. return E_INVALIDARG;
  339. if (!VerifySameContext(_pic, range))
  340. return E_INVALIDARG;
  341. ptsi = _pic->_GetTSI();
  342. // we always return the value at the start anchor
  343. hr = ptsi->RequestAttrsAtPosition(range->_GetStart(), 1, &_guid, 0);
  344. if (hr != S_OK)
  345. return E_FAIL;
  346. QuickVariantInit(&av.varValue);
  347. // just return the single VARIANT value directly
  348. if (ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) != S_OK)
  349. return E_FAIL;
  350. if (cFetched == 0)
  351. {
  352. // default value
  353. return GetDefaultValue(_pic->_GetTSI(), _guid, pvarValue);
  354. }
  355. *pvarValue = av.varValue; // caller takes ownership
  356. return S_OK;
  357. }
  358. //+---------------------------------------------------------------------------
  359. //
  360. // GetContext
  361. //
  362. //----------------------------------------------------------------------------
  363. STDAPI CAppProperty::GetContext(ITfContext **ppContext)
  364. {
  365. if (ppContext == NULL)
  366. return E_INVALIDARG;
  367. *ppContext = _pic;
  368. (*ppContext)->AddRef();
  369. return S_OK;
  370. }
  371. //////////////////////////////////////////////////////////////////////////////
  372. //////////////////////////////////////////////////////////////////////////////
  373. //
  374. // CInputContext
  375. //
  376. //////////////////////////////////////////////////////////////////////////////
  377. //////////////////////////////////////////////////////////////////////////////
  378. //+---------------------------------------------------------------------------
  379. //
  380. // GetAppProperty
  381. //
  382. //----------------------------------------------------------------------------
  383. STDAPI CInputContext::GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp)
  384. {
  385. CAppProperty *prop;
  386. TS_ATTRVAL av;
  387. ULONG cFetched;
  388. BOOL fUnsupported;
  389. HRESULT hr;
  390. if (ppProp == NULL)
  391. return E_INVALIDARG;
  392. *ppProp = NULL;
  393. if (!_IsConnected())
  394. return TF_E_DISCONNECTED;
  395. //
  396. // if we have a mapping property, it will be returned.
  397. //
  398. APPPROPMAP *pMap = FindMapAppProperty(guidProp);
  399. if (pMap)
  400. {
  401. CProperty *pProp;
  402. if (SUCCEEDED(_GetProperty(pMap->guidProp, &pProp)))
  403. {
  404. *ppProp = (ITfReadOnlyProperty *)pProp;
  405. return S_OK;
  406. }
  407. }
  408. // does the app support this property?
  409. fUnsupported = TRUE;
  410. if ((hr = _ptsi->RequestSupportedAttrs(0, 1, &guidProp)) != S_OK)
  411. {
  412. return (hr == E_NOTIMPL) ? E_NOTIMPL : E_FAIL;
  413. }
  414. QuickVariantInit(&av.varValue);
  415. if (_ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) == S_OK &&
  416. cFetched == 1)
  417. {
  418. if (IsEqualGUID(av.idAttr, guidProp)) // paranoia
  419. {
  420. fUnsupported = FALSE;
  421. }
  422. else
  423. {
  424. Assert(0); // bad out param!
  425. }
  426. }
  427. if (fUnsupported)
  428. {
  429. return S_FALSE;
  430. }
  431. if ((prop = new CAppProperty(this, guidProp)) == NULL)
  432. return E_OUTOFMEMORY;
  433. *ppProp = prop;
  434. return S_OK;
  435. }
  436. //+---------------------------------------------------------------------------
  437. //
  438. // MapAppProperty
  439. //
  440. //----------------------------------------------------------------------------
  441. STDAPI CInputContext::MapAppProperty(REFGUID guidAppProp, REFGUID guidProp)
  442. {
  443. APPPROPMAP *pMap;
  444. //
  445. // overwrite the mapping guidProp.
  446. //
  447. if (pMap = FindMapAppProperty(guidAppProp))
  448. {
  449. pMap->guidProp = guidProp;
  450. return S_OK;
  451. }
  452. pMap = _rgAppPropMap.Append(1);
  453. if (!pMap)
  454. return E_OUTOFMEMORY;
  455. pMap->guidAppProp = guidAppProp;
  456. pMap->guidProp = guidProp;
  457. return S_OK;
  458. }
  459. //+---------------------------------------------------------------------------
  460. //
  461. // FindMapProp
  462. //
  463. //----------------------------------------------------------------------------
  464. CInputContext::APPPROPMAP *CInputContext::FindMapAppProperty(REFGUID guidAppProp)
  465. {
  466. int i;
  467. for (i = 0; i < _rgAppPropMap.Count(); i++)
  468. {
  469. APPPROPMAP *pMap = _rgAppPropMap.GetPtr(i);
  470. if (IsEqualGUID(pMap->guidAppProp, guidAppProp))
  471. return pMap;
  472. }
  473. return NULL;
  474. }
  475. //+---------------------------------------------------------------------------
  476. //
  477. // GetMappedAppProperty
  478. //
  479. //----------------------------------------------------------------------------
  480. HRESULT CInputContext::GetMappedAppProperty(REFGUID guidProp, CProperty **ppProp)
  481. {
  482. if (!_IsConnected())
  483. return TF_E_DISCONNECTED;
  484. //
  485. // if we have a mapping property, it will be returned.
  486. //
  487. APPPROPMAP *pMap = FindMapAppProperty(guidProp);
  488. if (pMap)
  489. {
  490. if (SUCCEEDED(_GetProperty(pMap->guidProp, ppProp)))
  491. {
  492. return S_OK;
  493. }
  494. }
  495. return E_FAIL;
  496. }