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.

559 lines
14 KiB

  1. //
  2. // anchoref.cpp
  3. //
  4. // CAnchorRef
  5. //
  6. #include "private.h"
  7. #include "anchoref.h"
  8. #include "anchor.h"
  9. #include "acp2anch.h"
  10. #include "globals.h"
  11. #include "normal.h"
  12. #include "memcache.h"
  13. #include "ic.h"
  14. #include "txtcache.h"
  15. /* 9135f8f0-38e6-11d3-a745-0050040ab407 */
  16. const IID IID_PRIV_CANCHORREF = { 0x9135f8f0, 0x38e6, 0x11d3, {0xa7, 0x45, 0x00, 0x50, 0x04, 0x0a, 0xb4, 0x07} };
  17. DBG_ID_INSTANCE(CAnchorRef);
  18. MEMCACHE *CAnchorRef::_s_pMemCache = NULL;
  19. //+---------------------------------------------------------------------------
  20. //
  21. // _InitClass
  22. //
  23. //----------------------------------------------------------------------------
  24. /* static */
  25. void CAnchorRef::_InitClass()
  26. {
  27. _s_pMemCache = MemCache_New(128);
  28. }
  29. //+---------------------------------------------------------------------------
  30. //
  31. // _UninitClass
  32. //
  33. //----------------------------------------------------------------------------
  34. /* static */
  35. void CAnchorRef::_UninitClass()
  36. {
  37. if (_s_pMemCache == NULL)
  38. return;
  39. MemCache_Delete(_s_pMemCache);
  40. _s_pMemCache = NULL;
  41. }
  42. //+---------------------------------------------------------------------------
  43. //
  44. // IUnknown
  45. //
  46. //----------------------------------------------------------------------------
  47. STDAPI CAnchorRef::QueryInterface(REFIID riid, void **ppvObj)
  48. {
  49. if (&riid == &IID_PRIV_CANCHORREF ||
  50. IsEqualIID(riid, IID_PRIV_CANCHORREF))
  51. {
  52. *ppvObj = SAFECAST(this, CAnchorRef *);
  53. return S_OK; // No AddRef for IID_PRIV_CANCHORREF! this is a private IID....
  54. }
  55. *ppvObj = NULL;
  56. if (IsEqualIID(riid, IID_IUnknown) ||
  57. IsEqualIID(riid, IID_IAnchor))
  58. {
  59. *ppvObj = SAFECAST(this, IAnchor *);
  60. }
  61. if (*ppvObj)
  62. {
  63. AddRef();
  64. return S_OK;
  65. }
  66. return E_NOINTERFACE;
  67. }
  68. STDAPI_(ULONG) CAnchorRef::AddRef()
  69. {
  70. return ++_cRef;
  71. }
  72. STDAPI_(ULONG) CAnchorRef::Release()
  73. {
  74. _cRef--;
  75. Assert(_cRef >= 0);
  76. if (_cRef == 0)
  77. {
  78. delete this;
  79. return 0;
  80. }
  81. return _cRef;
  82. }
  83. //+---------------------------------------------------------------------------
  84. //
  85. // SetGravity
  86. //
  87. //----------------------------------------------------------------------------
  88. STDAPI CAnchorRef::SetGravity(TsGravity gravity)
  89. {
  90. _fForwardGravity = (gravity == TS_GR_FORWARD ? 1 : 0);
  91. return S_OK;
  92. }
  93. //+---------------------------------------------------------------------------
  94. //
  95. // GetGravity
  96. //
  97. //----------------------------------------------------------------------------
  98. STDAPI CAnchorRef::GetGravity(TsGravity *pgravity)
  99. {
  100. if (pgravity == NULL)
  101. return E_INVALIDARG;
  102. *pgravity = _fForwardGravity ? TS_GR_FORWARD : TS_GR_BACKWARD;
  103. return S_OK;
  104. }
  105. //+---------------------------------------------------------------------------
  106. //
  107. // IsEqual
  108. //
  109. //----------------------------------------------------------------------------
  110. STDAPI CAnchorRef::IsEqual(IAnchor *paWith, BOOL *pfEqual)
  111. {
  112. LONG lResult;
  113. HRESULT hr;
  114. if (pfEqual == NULL)
  115. return E_INVALIDARG;
  116. *pfEqual = FALSE;
  117. // in our implementation, Compare is no less efficient, so just use that
  118. if ((hr = Compare(paWith, &lResult)) == S_OK)
  119. {
  120. *pfEqual = (lResult == 0);
  121. }
  122. return hr;
  123. }
  124. //+---------------------------------------------------------------------------
  125. //
  126. // Compare
  127. //
  128. //----------------------------------------------------------------------------
  129. STDAPI CAnchorRef::Compare(IAnchor *paWith, LONG *plResult)
  130. {
  131. CAnchorRef *parWith;
  132. LONG acpThis;
  133. LONG acpWith;
  134. CACPWrap *paw;
  135. if (plResult == NULL)
  136. return E_INVALIDARG;
  137. //_paw->_Dbg_AssertNoAppLock(); // can't assert this because we use it legitimately while updating the span set
  138. *plResult = 0;
  139. if ((parWith = GetCAnchorRef_NA(paWith)) == NULL)
  140. return E_FAIL;
  141. // quick test for equality
  142. // we still need to check for equality again below because of normalization
  143. if (_pa == parWith->_pa)
  144. {
  145. Assert(*plResult == 0);
  146. return S_OK;
  147. }
  148. acpThis = _pa->GetIch();
  149. acpWith = parWith->_pa->GetIch();
  150. paw = _pa->_GetWrap();
  151. // we can't do a compare if either anchor is un-normalized
  152. // except when the app holds the lock (in which case we're being called from
  153. // a span set update which does not need to be normalized)
  154. if (!paw->_InOnTextChange())
  155. {
  156. // we only actually have to normalize the anchor to the left
  157. if (acpThis < acpWith)
  158. {
  159. if (!_pa->IsNormalized())
  160. {
  161. paw->_NormalizeAnchor(_pa);
  162. acpThis = _pa->GetIch();
  163. acpWith = parWith->_pa->GetIch();
  164. }
  165. }
  166. else if (acpThis > acpWith)
  167. {
  168. if (!parWith->_pa->IsNormalized())
  169. {
  170. paw->_NormalizeAnchor(parWith->_pa);
  171. acpThis = _pa->GetIch();
  172. acpWith = parWith->_pa->GetIch();
  173. }
  174. }
  175. }
  176. if (acpThis < acpWith)
  177. {
  178. *plResult = -1;
  179. }
  180. else if (acpThis > acpWith)
  181. {
  182. *plResult = +1;
  183. }
  184. else
  185. {
  186. Assert(*plResult == 0);
  187. }
  188. return S_OK;
  189. }
  190. //+---------------------------------------------------------------------------
  191. //
  192. // Shift
  193. //
  194. //----------------------------------------------------------------------------
  195. STDAPI CAnchorRef::Shift(DWORD dwFlags, LONG cchReq, LONG *pcch, IAnchor *paHaltAnchor)
  196. {
  197. CAnchorRef *parHaltAnchor;
  198. CACPWrap *paw;
  199. LONG acpHalt;
  200. LONG acpThis;
  201. LONG dacp;
  202. HRESULT hr;
  203. Perf_IncCounter(PERF_ANCHOR_SHIFT);
  204. if (dwFlags & ~(TS_SHIFT_COUNT_HIDDEN | TS_SHIFT_HALT_HIDDEN | TS_SHIFT_HALT_VISIBLE | TS_SHIFT_COUNT_ONLY))
  205. return E_INVALIDARG;
  206. if ((dwFlags & (TS_SHIFT_HALT_HIDDEN | TS_SHIFT_HALT_VISIBLE)) == (TS_SHIFT_HALT_HIDDEN | TS_SHIFT_HALT_VISIBLE))
  207. return E_INVALIDARG; // illegal to set both flags
  208. if (dwFlags & (TS_SHIFT_COUNT_HIDDEN | TS_SHIFT_HALT_HIDDEN | TS_SHIFT_HALT_VISIBLE))
  209. return E_NOTIMPL; // Issue: should support these
  210. if (pcch == NULL)
  211. return E_INVALIDARG;
  212. paw = _pa->_GetWrap();
  213. paw->_Dbg_AssertNoAppLock();
  214. if (paw->_IsDisconnected())
  215. {
  216. *pcch = 0;
  217. return TF_E_DISCONNECTED;
  218. }
  219. *pcch = cchReq; // assume success
  220. if (cchReq == 0)
  221. return S_OK;
  222. acpThis = _pa->GetIch();
  223. hr = E_FAIL;
  224. if (paHaltAnchor != NULL)
  225. {
  226. if ((parHaltAnchor = GetCAnchorRef_NA(paHaltAnchor)) == NULL)
  227. goto Exit;
  228. acpHalt = parHaltAnchor->_pa->GetIch();
  229. // return now if the halt is our base acp
  230. // (we treat acpHalt == acpThis as a nop below, anything
  231. // more ticky has problems with over/underflow)
  232. if (acpHalt == acpThis)
  233. {
  234. *pcch = 0;
  235. return S_OK;
  236. }
  237. }
  238. else
  239. {
  240. // nop the acpHalt
  241. acpHalt = acpThis;
  242. }
  243. // we can initially bound cchReq by pretending acpHalt
  244. // is plain text, an upper bound
  245. if (cchReq < 0 && acpHalt < acpThis)
  246. {
  247. cchReq = max(cchReq, acpHalt - acpThis);
  248. }
  249. else if (cchReq > 0 && acpHalt > acpThis)
  250. {
  251. cchReq = min(cchReq, acpHalt - acpThis);
  252. }
  253. // do the expensive work
  254. if (FAILED(hr = AppTextOffset(paw->_GetTSI(), acpThis, cchReq, &dacp, ATO_SKIP_HIDDEN)))
  255. goto Exit;
  256. // now we can clip percisely
  257. if (cchReq < 0 && acpHalt < acpThis)
  258. {
  259. dacp = max(dacp, acpHalt - acpThis);
  260. hr = S_FALSE;
  261. }
  262. else if (cchReq > 0 && acpHalt > acpThis)
  263. {
  264. dacp = min(dacp, acpHalt - acpThis);
  265. hr = S_FALSE;
  266. }
  267. if (hr == S_FALSE)
  268. {
  269. // nb: if we remembered whether or not we actually truncated cchReq above
  270. // before and/or after the AppTextOffset call, we could avoid always calling
  271. // PlainTextOffset when paHaltAnchor != NULL
  272. // request got clipped, need to find the plain count
  273. PlainTextOffset(paw->_GetTSI(), acpThis, dacp, pcch); // perf: we could get this info by modifying AppTextOffset
  274. }
  275. if (!(dwFlags & TS_SHIFT_COUNT_ONLY))
  276. {
  277. hr = _SetACP(acpThis + dacp) ? S_OK : E_FAIL;
  278. }
  279. else
  280. {
  281. // caller doesn't want the anchor updated, just wants a count
  282. hr = S_OK;
  283. }
  284. Exit:
  285. if (FAILED(hr))
  286. {
  287. *pcch = 0;
  288. }
  289. // return value should never exceed what the caller requested!
  290. Assert((cchReq >= 0 && *pcch <= cchReq) || (cchReq < 0 && *pcch >= cchReq));
  291. return hr;
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // ShiftTo
  296. //
  297. //----------------------------------------------------------------------------
  298. STDAPI CAnchorRef::ShiftTo(IAnchor *paSite)
  299. {
  300. CAnchorRef *parSite;
  301. LONG acpSite;
  302. if (paSite == NULL)
  303. return E_INVALIDARG;
  304. //_paw->_Dbg_AssertNoAppLock(); // can't assert this because we use it legitimately while updating the span set
  305. if ((parSite = GetCAnchorRef_NA(paSite)) == NULL)
  306. return E_FAIL;
  307. acpSite = parSite->_pa->GetIch();
  308. return _SetACP(acpSite) ? S_OK : E_FAIL;
  309. }
  310. //+---------------------------------------------------------------------------
  311. //
  312. // ShiftRegion
  313. //
  314. //----------------------------------------------------------------------------
  315. STDAPI CAnchorRef::ShiftRegion(DWORD dwFlags, TsShiftDir dir, BOOL *pfNoRegion)
  316. {
  317. LONG acp;
  318. ULONG cch;
  319. LONG i;
  320. ULONG ulRunInfoOut;
  321. LONG acpNext;
  322. ITextStoreACP *ptsi;
  323. CACPWrap *paw;
  324. WCHAR ch;
  325. DWORD dwATO;
  326. Perf_IncCounter(PERF_SHIFTREG_COUNTER);
  327. if (pfNoRegion == NULL)
  328. return E_INVALIDARG;
  329. *pfNoRegion = TRUE;
  330. if (dwFlags & ~(TS_SHIFT_COUNT_HIDDEN | TS_SHIFT_COUNT_ONLY))
  331. return E_INVALIDARG;
  332. paw = _pa->_GetWrap();
  333. if (paw->_IsDisconnected())
  334. return TF_E_DISCONNECTED;
  335. acp = _GetACP();
  336. ptsi = paw->_GetTSI();
  337. if (dir == TS_SD_BACKWARD)
  338. {
  339. // scan backwards for the preceding char
  340. dwATO = ATO_IGNORE_REGIONS | ((dwFlags & TS_SHIFT_COUNT_HIDDEN) ? 0 : ATO_SKIP_HIDDEN);
  341. if (FAILED(AppTextOffset(ptsi, acp, -1, &i, dwATO)))
  342. return E_FAIL;
  343. if (i == 0) // bod
  344. return S_OK;
  345. acp += i;
  346. }
  347. else
  348. {
  349. // normalize this guy so we can just test the next char
  350. if (!_pa->IsNormalized())
  351. {
  352. paw->_NormalizeAnchor(_pa);
  353. acp = _GetACP();
  354. }
  355. // skip past any hidden text
  356. if (!(dwFlags & TS_SHIFT_COUNT_HIDDEN))
  357. {
  358. acp = Normalize(paw->_GetTSI(), acp, NORM_SKIP_HIDDEN);
  359. }
  360. }
  361. // insure we're next to a TS_CHAR_REGION
  362. Perf_IncCounter(PERF_ANCHOR_REGION_GETTEXT);
  363. if (CProcessTextCache::GetText(ptsi, acp, -1, &ch, 1, &cch, NULL, 0, &ulRunInfoOut, &acpNext) != S_OK)
  364. return E_FAIL;
  365. if (cch == 0) // eod
  366. return S_OK;
  367. if (ch != TS_CHAR_REGION)
  368. return S_OK; // no region, so just report that in pfNoRegion
  369. if (!(dwFlags & TS_SHIFT_COUNT_ONLY)) // does caller want us to move the anchor?
  370. {
  371. if (dir == TS_SD_FORWARD)
  372. {
  373. // skip over the TS_CHAR_REGION
  374. acp += 1;
  375. }
  376. if (!_SetACP(acp))
  377. return E_FAIL;
  378. }
  379. *pfNoRegion = FALSE;
  380. return S_OK;
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // SetChangeHistoryMask
  385. //
  386. //----------------------------------------------------------------------------
  387. STDAPI CAnchorRef::SetChangeHistoryMask(DWORD dwMask)
  388. {
  389. Assert(0); // Issue: todo
  390. return E_NOTIMPL;
  391. }
  392. //+---------------------------------------------------------------------------
  393. //
  394. // GetChangeHistory
  395. //
  396. //----------------------------------------------------------------------------
  397. STDAPI CAnchorRef::GetChangeHistory(DWORD *pdwHistory)
  398. {
  399. if (pdwHistory == NULL)
  400. return E_INVALIDARG;
  401. *pdwHistory = _dwHistory;
  402. return S_OK;
  403. }
  404. //+---------------------------------------------------------------------------
  405. //
  406. // ClearChangeHistory
  407. //
  408. //----------------------------------------------------------------------------
  409. STDAPI CAnchorRef::ClearChangeHistory()
  410. {
  411. _dwHistory = 0;
  412. return S_OK;
  413. }
  414. //+---------------------------------------------------------------------------
  415. //
  416. // Clone
  417. //
  418. //----------------------------------------------------------------------------
  419. STDAPI CAnchorRef::Clone(IAnchor **ppaClone)
  420. {
  421. if (ppaClone == NULL)
  422. return E_INVALIDARG;
  423. *ppaClone = _pa->_GetWrap()->_CreateAnchorAnchor(_pa, _fForwardGravity ? TS_GR_FORWARD : TS_GR_BACKWARD);
  424. return (*ppaClone != NULL) ? S_OK : E_FAIL;
  425. }
  426. //+---------------------------------------------------------------------------
  427. //
  428. // _SetACP
  429. //
  430. //----------------------------------------------------------------------------
  431. BOOL CAnchorRef::_SetACP(LONG acp)
  432. {
  433. CACPWrap *paw;
  434. if (_pa->GetIch() == acp)
  435. return TRUE; // already positioned here
  436. paw = _pa->_GetWrap();
  437. paw->_Remove(this);
  438. if (FAILED(paw->_Insert(this, acp)))
  439. {
  440. // Issue:
  441. // we need to add a method the CACPWrap
  442. // that swaps a CAnchorRef, preserving the old
  443. // value if a new one cannot be inserted (prob.
  444. // because memory is low).
  445. Assert(0); // we have no code to handle this!
  446. return FALSE;
  447. }
  448. return TRUE;
  449. }