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.

1697 lines
45 KiB

  1. //
  2. // ic.cpp
  3. //
  4. #include "private.h"
  5. #include "ic.h"
  6. #include "range.h"
  7. #include "tim.h"
  8. #include "prop.h"
  9. #include "tsi.h"
  10. #include "rprop.h"
  11. #include "funcprv.h"
  12. #include "immxutil.h"
  13. #include "acp2anch.h"
  14. #include "dim.h"
  15. #include "rangebk.h"
  16. #include "view.h"
  17. #include "compose.h"
  18. #include "anchoref.h"
  19. #include "dam.h"
  20. #define TW_ICOWNERSINK_COOKIE 0x80000000 // high bit must be set to avoid conflict with GenericAdviseSink!
  21. #define TW_ICKBDSINK_COOKIE 0x80000001 // high bit must be set to avoid conflict with GenericAdviseSink!
  22. DBG_ID_INSTANCE(CInputContext);
  23. /* 12e53b1b-7d7f-40bd-8f88-4603ee40cf58 */
  24. extern const IID IID_PRIV_CINPUTCONTEXT = { 0x12e53b1b, 0x7d7f, 0x40bd, {0x8f, 0x88, 0x46, 0x03, 0xee, 0x40, 0xcf, 0x58} };
  25. const IID *CInputContext::_c_rgConnectionIIDs[IC_NUM_CONNECTIONPTS] =
  26. {
  27. &IID_ITfTextEditSink,
  28. &IID_ITfTextLayoutSink,
  29. &IID_ITfStatusSink,
  30. &IID_ITfStartReconversionNotifySink,
  31. &IID_ITfEditTransactionSink,
  32. };
  33. //+---------------------------------------------------------------------------
  34. //
  35. // ctor
  36. //
  37. //----------------------------------------------------------------------------
  38. CInputContext::CInputContext(TfClientId tid)
  39. : CCompartmentMgr(tid, COMPTYPE_IC)
  40. {
  41. Dbg_MemSetThisNameIDCounter(TEXT("CInputContext"), PERF_CONTEXT_COUNTER);
  42. // we sometimes use _dwLastLockReleaseID-1, which must still be > IGNORE_LAST_LOCKRELEASED
  43. // Issue: need to handle wrap-around case
  44. _dwLastLockReleaseID = (DWORD)((int)IGNORE_LAST_LOCKRELEASED + 2);
  45. }
  46. //+---------------------------------------------------------------------------
  47. //
  48. // _Init
  49. //
  50. //----------------------------------------------------------------------------
  51. HRESULT CInputContext::_Init(CThreadInputMgr *tim,
  52. CDocumentInputManager *dm, ITextStoreAnchor *ptsi,
  53. ITfContextOwnerCompositionSink *pOwnerComposeSink)
  54. {
  55. CTextStoreImpl *ptsiACP;
  56. _dm = dm; // no need to AddRef, cleared when the dm dies
  57. // scramble the _ec a bit to help debug calling EditSession on the wrong ic
  58. _ec = (TfEditCookie)((DWORD)(UINT_PTR)this<<8);
  59. if (_ec < EC_MIN) // for portability, win32 pointers can't have values this low
  60. {
  61. _ec = EC_MIN;
  62. }
  63. if (ptsi == NULL)
  64. {
  65. if ((ptsiACP = new CTextStoreImpl(this)) == NULL)
  66. return E_OUTOFMEMORY;
  67. _ptsi = new CACPWrap(ptsiACP);
  68. ptsiACP->Release();
  69. if (_ptsi == NULL)
  70. return E_OUTOFMEMORY;
  71. _fCiceroTSI = TRUE;
  72. }
  73. else
  74. {
  75. _ptsi = ptsi;
  76. _ptsi->AddRef();
  77. Assert(_fCiceroTSI == FALSE);
  78. }
  79. _pOwnerComposeSink = pOwnerComposeSink;
  80. if (_pOwnerComposeSink != NULL)
  81. {
  82. _pOwnerComposeSink->AddRef();
  83. }
  84. Assert(_pMSAAState == NULL);
  85. if (tim->_IsMSAAEnabled())
  86. {
  87. _InitMSAAHook(tim->_GetAAAdaptor());
  88. }
  89. Assert(_dwEditSessionFlags == 0);
  90. Assert(_dbg_fInOnLockGranted == FALSE);
  91. Assert(_fLayoutChanged == FALSE);
  92. Assert(_dwStatusChangedFlags == 0);
  93. Assert(_fStatusChanged == FALSE);
  94. _tidInEditSession = TF_CLIENTID_NULL;
  95. Assert(_pPropTextOwner == NULL);
  96. _dwSysFuncPrvCookie = GENERIC_ERROR_COOKIE;
  97. _gaKeyEventFilterTIP[LEFT_FILTERTIP] = TF_INVALID_GUIDATOM;
  98. _gaKeyEventFilterTIP[RIGHT_FILTERTIP] = TF_INVALID_GUIDATOM;
  99. _fInvalidKeyEventFilterTIP = TRUE;
  100. _pEditRecord = new CEditRecord(this); // perf: delay load
  101. if (!_pEditRecord)
  102. return E_OUTOFMEMORY;
  103. Assert(_pActiveView == NULL);
  104. return S_OK;
  105. }
  106. //+---------------------------------------------------------------------------
  107. //
  108. // dtor
  109. //
  110. //----------------------------------------------------------------------------
  111. CInputContext::~CInputContext()
  112. {
  113. CProperty *pProp;
  114. int i;
  115. SPAN *span;
  116. // being paranoid...these should be NULL
  117. Assert(_pICKbdSink == NULL);
  118. // nix any allocated properties
  119. while (_pPropList != NULL)
  120. {
  121. pProp = _pPropList;
  122. _pPropList = _pPropList->_pNext;
  123. delete pProp;
  124. }
  125. // nix any cached app changes
  126. for (i=0; i<_rgAppTextChanges.Count(); i++)
  127. {
  128. span = _rgAppTextChanges.GetPtr(i);
  129. span->paStart->Release();
  130. span->paEnd->Release();
  131. }
  132. Assert(_pMSAAState == NULL); // should have already cleaned up msaa hook
  133. Assert(_pOwnerComposeSink == NULL); // should cleared in _UnadviseSinks
  134. SafeRelease(_pOwnerComposeSink);
  135. Assert(_ptsi == NULL); // should be NULL, cleared in _UnadviseSinks
  136. SafeRelease(_ptsi);
  137. Assert(_pCompositionList == NULL); // all compositions should be terminated
  138. Assert(_rgLockQueue.Count() == 0); // all queue items should be freed
  139. //
  140. // all pending flag should be cleared
  141. // Otherwise psfn->_dwfLockRequestICRef could be broken..
  142. //
  143. Assert(_dwPendingLockRequest == 0);
  144. }
  145. //+---------------------------------------------------------------------------
  146. //
  147. // _AdviseSinks
  148. //
  149. // Called when this ic is pushed.
  150. //
  151. //----------------------------------------------------------------------------
  152. void CInputContext::_AdviseSinks()
  153. {
  154. if (_ptsi != NULL)
  155. {
  156. // attach our ITextStoreAnchorSink
  157. _ptsi->AdviseSink(IID_ITextStoreAnchorSink, SAFECAST(this, ITextStoreAnchorSink *), TS_AS_ALL_SINKS);
  158. }
  159. }
  160. //+---------------------------------------------------------------------------
  161. //
  162. // _UnadviseSinks
  163. //
  164. // Called when this ic is popped.
  165. // All references to the ITextStore impl should be released here.
  166. //
  167. //----------------------------------------------------------------------------
  168. void CInputContext::_UnadviseSinks(CThreadInputMgr *tim)
  169. {
  170. // kill any compositions
  171. _AbortCompositions();
  172. SafeReleaseClear(_pEditRecord);
  173. SafeReleaseClear(_pActiveView);
  174. // for now just skip any pending edit sessions
  175. // do this here in case any of the edit sessions
  176. // have a ref to this ic
  177. _AbortQueueItems();
  178. if (_ptsi != NULL)
  179. {
  180. // detach our ITextStoreAnchorSink
  181. _ptsi->UnadviseSink(SAFECAST(this, ITextStoreAnchorSink *));
  182. // if there is an ic owner sink, unadvise it now while we still can
  183. // this is to help buggy clients
  184. _UnadviseOwnerSink();
  185. // if we're msaa hooked, unhook now
  186. // must do this before Releasing _ptsi
  187. if (_pMSAAState != NULL)
  188. {
  189. Assert(tim->_GetAAAdaptor() != NULL);
  190. _UninitMSAAHook(tim->_GetAAAdaptor());
  191. }
  192. // and let the ptsi go
  193. _ptsi->Release();
  194. _ptsi = NULL;
  195. }
  196. SafeReleaseClear(_pOwnerComposeSink);
  197. // our owning doc is no longer valid
  198. _dm = NULL;
  199. }
  200. //+---------------------------------------------------------------------------
  201. //
  202. // AdviseSink
  203. //
  204. //----------------------------------------------------------------------------
  205. STDAPI CInputContext::AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie)
  206. {
  207. ITfContextOwner *pICOwnerSink;
  208. CTextStoreImpl *ptsi;
  209. IServiceProvider *psp;
  210. HRESULT hr;
  211. if (pdwCookie == NULL)
  212. return E_INVALIDARG;
  213. *pdwCookie = GENERIC_ERROR_COOKIE;
  214. if (punk == NULL)
  215. return E_INVALIDARG;
  216. if (!_IsConnected())
  217. return TF_E_DISCONNECTED;
  218. if (IsEqualIID(riid, IID_ITfContextOwner))
  219. {
  220. // there can be only one ic owner sink, so special case it
  221. if (!_IsCiceroTSI())
  222. {
  223. Assert(0); // sink should only used for def tsi
  224. return E_UNEXPECTED;
  225. }
  226. // use QueryService to get the tsi since msaa may be wrapping it
  227. if (_ptsi->QueryInterface(IID_IServiceProvider, (void **)&psp) != S_OK)
  228. {
  229. Assert(0);
  230. return E_UNEXPECTED;
  231. }
  232. hr = psp->QueryService(GUID_SERVICE_TF, IID_PRIV_CTSI, (void **)&ptsi);
  233. psp->Release();
  234. if (hr != S_OK)
  235. {
  236. Assert(0);
  237. return E_UNEXPECTED;
  238. }
  239. pICOwnerSink = NULL;
  240. if (ptsi->_HasOwner())
  241. {
  242. hr = CONNECT_E_ADVISELIMIT;
  243. goto ExitOwner;
  244. }
  245. if (FAILED(punk->QueryInterface(IID_ITfContextOwner,
  246. (void **)&pICOwnerSink)))
  247. {
  248. hr = E_UNEXPECTED;
  249. goto ExitOwner;
  250. }
  251. ptsi->_AdviseOwner(pICOwnerSink);
  252. ExitOwner:
  253. ptsi->Release();
  254. SafeRelease(pICOwnerSink);
  255. if (hr == S_OK)
  256. {
  257. *pdwCookie = TW_ICOWNERSINK_COOKIE;
  258. }
  259. return hr;
  260. }
  261. else if (IsEqualIID(riid, IID_ITfContextKeyEventSink))
  262. {
  263. // there can be only one ic kbd sink, so special case it
  264. if (_pICKbdSink != NULL)
  265. return CONNECT_E_ADVISELIMIT;
  266. if (FAILED(punk->QueryInterface(IID_ITfContextKeyEventSink,
  267. (void **)&_pICKbdSink)))
  268. return E_UNEXPECTED;
  269. *pdwCookie = TW_ICKBDSINK_COOKIE;
  270. return S_OK;
  271. }
  272. return GenericAdviseSink(riid, punk, _c_rgConnectionIIDs, _rgSinks, IC_NUM_CONNECTIONPTS, pdwCookie);
  273. }
  274. //+---------------------------------------------------------------------------
  275. //
  276. // UnadviseSink
  277. //
  278. //----------------------------------------------------------------------------
  279. STDAPI CInputContext::UnadviseSink(DWORD dwCookie)
  280. {
  281. if (dwCookie == TW_ICOWNERSINK_COOKIE)
  282. {
  283. // there can be only one ic owner sink, so special case it
  284. return _UnadviseOwnerSink();
  285. }
  286. else if (dwCookie == TW_ICKBDSINK_COOKIE)
  287. {
  288. // there can be only one ic owner sink, so special case it
  289. if (_pICKbdSink == NULL)
  290. return CONNECT_E_NOCONNECTION;
  291. SafeReleaseClear(_pICKbdSink);
  292. return S_OK;
  293. }
  294. return GenericUnadviseSink(_rgSinks, IC_NUM_CONNECTIONPTS, dwCookie);
  295. }
  296. //+---------------------------------------------------------------------------
  297. //
  298. // AdviseSingleSink
  299. //
  300. //----------------------------------------------------------------------------
  301. STDAPI CInputContext::AdviseSingleSink(TfClientId tid, REFIID riid, IUnknown *punk)
  302. {
  303. CTip *ctip;
  304. CLEANUPSINK *pCleanup;
  305. CThreadInputMgr *tim;
  306. ITfCleanupContextSink *pSink;
  307. if (punk == NULL)
  308. return E_INVALIDARG;
  309. if ((tim = CThreadInputMgr::_GetThis()) == NULL)
  310. return E_FAIL;
  311. if (!tim->_GetCTipfromGUIDATOM(tid, &ctip) && (tid != g_gaApp))
  312. return E_INVALIDARG;
  313. if (IsEqualIID(riid, IID_ITfCleanupContextSink))
  314. {
  315. if (_GetCleanupListIndex(tid) >= 0)
  316. return CONNECT_E_ADVISELIMIT;
  317. if (punk->QueryInterface(IID_ITfCleanupContextSink, (void **)&pSink) != S_OK)
  318. return E_NOINTERFACE;
  319. if ((pCleanup = _rgCleanupSinks.Append(1)) == NULL)
  320. {
  321. pSink->Release();
  322. return E_OUTOFMEMORY;
  323. }
  324. pCleanup->tid = tid;
  325. pCleanup->pSink = pSink;
  326. return S_OK;
  327. }
  328. return CONNECT_E_CANNOTCONNECT;
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. // UnadviseSingleSink
  333. //
  334. //----------------------------------------------------------------------------
  335. STDAPI CInputContext::UnadviseSingleSink(TfClientId tid, REFIID riid)
  336. {
  337. int i;
  338. if (IsEqualIID(riid, IID_ITfCleanupContextSink))
  339. {
  340. if ((i = _GetCleanupListIndex(tid)) < 0)
  341. return CONNECT_E_NOCONNECTION;
  342. _rgCleanupSinks.GetPtr(i)->pSink->Release();
  343. _rgCleanupSinks.Remove(i, 1);
  344. return S_OK;
  345. }
  346. return CONNECT_E_NOCONNECTION;
  347. }
  348. //+---------------------------------------------------------------------------
  349. //
  350. // _UnadviseOwnerSink
  351. //
  352. //----------------------------------------------------------------------------
  353. HRESULT CInputContext::_UnadviseOwnerSink()
  354. {
  355. IServiceProvider *psp;
  356. CTextStoreImpl *ptsi;
  357. HRESULT hr;
  358. if (!_IsCiceroTSI())
  359. return E_UNEXPECTED; // only our default tsi can accept an owner sink
  360. if (!_IsConnected()) // _ptsi is not safe if disconnected
  361. return TF_E_DISCONNECTED;
  362. // use QueryService to get the tsi since msaa may be wrapping it
  363. if (_ptsi->QueryInterface(IID_IServiceProvider, (void **)&psp) != S_OK)
  364. {
  365. Assert(0);
  366. return E_UNEXPECTED;
  367. }
  368. hr = psp->QueryService(GUID_SERVICE_TF, IID_PRIV_CTSI, (void **)&ptsi);
  369. psp->Release();
  370. if (hr != S_OK)
  371. {
  372. Assert(0);
  373. return E_UNEXPECTED;
  374. }
  375. if (!ptsi->_HasOwner())
  376. {
  377. hr = CONNECT_E_NOCONNECTION;
  378. goto Exit;
  379. }
  380. ptsi->_UnadviseOwner();
  381. hr = S_OK;
  382. Exit:
  383. ptsi->Release();
  384. return hr;
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // GetProperty
  389. //
  390. //----------------------------------------------------------------------------
  391. STDAPI CInputContext::GetProperty(REFGUID rguidProp, ITfProperty **ppv)
  392. {
  393. CProperty *property;
  394. HRESULT hr;
  395. if (!_IsConnected())
  396. return TF_E_DISCONNECTED;
  397. hr = _GetProperty(rguidProp, &property);
  398. *ppv = property;
  399. return hr;
  400. }
  401. //+---------------------------------------------------------------------------
  402. //
  403. // _GetProperty
  404. //
  405. //----------------------------------------------------------------------------
  406. HRESULT CInputContext::_GetProperty(REFGUID rguidProp, CProperty **ppv)
  407. {
  408. CProperty *pProp = _FindProperty(rguidProp);
  409. DWORD dwAuthority = PROPA_NONE;
  410. TFPROPERTYSTYLE propStyle;
  411. DWORD dwPropFlags;
  412. if (ppv == NULL)
  413. return E_INVALIDARG;
  414. *ppv = pProp;
  415. if (pProp != NULL)
  416. {
  417. (*ppv)->AddRef();
  418. return S_OK;
  419. }
  420. //
  421. // Overwrite propstyle for known properties.
  422. //
  423. if (IsEqualGUID(rguidProp, GUID_PROP_ATTRIBUTE))
  424. {
  425. propStyle = TFPROPSTYLE_STATIC;
  426. dwAuthority = PROPA_FOCUSRANGE | PROPA_TEXTOWNER | PROPA_WONT_SERIALZE;
  427. dwPropFlags = PROPF_VTI4TOGUIDATOM;
  428. }
  429. else if (IsEqualGUID(rguidProp, GUID_PROP_READING))
  430. {
  431. propStyle = TFPROPSTYLE_CUSTOM;
  432. dwPropFlags = 0;
  433. }
  434. else if (IsEqualGUID(rguidProp, GUID_PROP_COMPOSING))
  435. {
  436. propStyle = TFPROPSTYLE_STATICCOMPACT;
  437. dwAuthority = PROPA_READONLY | PROPA_WONT_SERIALZE;
  438. dwPropFlags = 0;
  439. }
  440. else if (IsEqualGUID(rguidProp, GUID_PROP_LANGID))
  441. {
  442. propStyle = TFPROPSTYLE_STATICCOMPACT;
  443. dwPropFlags = 0;
  444. }
  445. else if (IsEqualGUID(rguidProp, GUID_PROP_TEXTOWNER))
  446. {
  447. propStyle = TFPROPSTYLE_STATICCOMPACT;
  448. dwAuthority = PROPA_TEXTOWNER;
  449. dwPropFlags = PROPF_ACCEPTCORRECTION | PROPF_VTI4TOGUIDATOM;
  450. }
  451. else
  452. {
  453. propStyle = _GetPropStyle(rguidProp);
  454. dwPropFlags = 0;
  455. // nb: after a property is created, the PROPF_MARKUP_COLLECTION is never
  456. // again set. We make sure to call ITfDisplayAttributeCollectionProvider::GetCollection
  457. // before activating tips that use the property GUID.
  458. if (CDisplayAttributeMgr::_IsInCollection(rguidProp))
  459. {
  460. dwPropFlags = PROPF_MARKUP_COLLECTION;
  461. }
  462. }
  463. //
  464. // Allow NULL propStyle for only predefined properties.
  465. // Check the property style is correct.
  466. //
  467. if (!propStyle)
  468. {
  469. Assert(0);
  470. return E_FAIL;
  471. }
  472. pProp = new CProperty(this, rguidProp, propStyle, dwAuthority, dwPropFlags);
  473. if (pProp)
  474. {
  475. pProp->_pNext = _pPropList;
  476. _pPropList = pProp;
  477. // Update _pPropTextOner now.
  478. if (IsEqualGUID(rguidProp, GUID_PROP_TEXTOWNER))
  479. _pPropTextOwner = pProp;
  480. }
  481. if (*ppv = pProp)
  482. {
  483. (*ppv)->AddRef();
  484. return S_OK;
  485. }
  486. return E_OUTOFMEMORY;
  487. }
  488. //+---------------------------------------------------------------------------
  489. //
  490. // GetTextOwnerProperty
  491. //
  492. //----------------------------------------------------------------------------
  493. CProperty *CInputContext::GetTextOwnerProperty()
  494. {
  495. ITfProperty *prop;
  496. // GetProperty initializes _pPropTextOwner.
  497. if (!_pPropTextOwner)
  498. {
  499. GetProperty(GUID_PROP_TEXTOWNER, &prop);
  500. SafeRelease(prop);
  501. }
  502. Assert(_pPropTextOwner);
  503. return _pPropTextOwner;
  504. }
  505. //+---------------------------------------------------------------------------
  506. //
  507. // _FindProperty
  508. //
  509. //----------------------------------------------------------------------------
  510. CProperty *CInputContext::_FindProperty(TfGuidAtom gaProp)
  511. {
  512. CProperty *pProp = _pPropList;
  513. // perf: should this be faster?
  514. while (pProp)
  515. {
  516. if (pProp->GetPropGuidAtom() == gaProp)
  517. return pProp;
  518. pProp = pProp->_pNext;
  519. }
  520. return NULL;
  521. }
  522. //+---------------------------------------------------------------------------
  523. //
  524. // _PropertyTextUpdate
  525. //
  526. //----------------------------------------------------------------------------
  527. void CInputContext::_PropertyTextUpdate(DWORD dwFlags, IAnchor *paStart, IAnchor *paEnd)
  528. {
  529. CProperty *pProp = _pPropList;
  530. DWORD dwPrevESFlag = _dwEditSessionFlags;
  531. _dwEditSessionFlags |= TF_ES_INNOTIFY;
  532. while (pProp)
  533. {
  534. // clear the values over the edited text
  535. pProp->Clear(paStart, paEnd, dwFlags, TRUE /* fTextUpdate */);
  536. if (pProp->GetPropStyle() == TFPROPSTYLE_STATICCOMPACT ||
  537. pProp->GetPropStyle() == TFPROPSTYLE_CUSTOM_COMPACT)
  538. {
  539. pProp->Defrag(paStart, paEnd);
  540. }
  541. pProp = pProp->_pNext;
  542. }
  543. _dwEditSessionFlags = dwPrevESFlag;
  544. }
  545. //+---------------------------------------------------------------------------
  546. //
  547. // _GetStartOrEnd
  548. //
  549. //----------------------------------------------------------------------------
  550. HRESULT CInputContext::_GetStartOrEnd(TfEditCookie ec, BOOL fStart, ITfRange **ppStart)
  551. {
  552. CRange *range;
  553. IAnchor *paStart;
  554. IAnchor *paEnd;
  555. HRESULT hr;
  556. if (ppStart == NULL)
  557. return E_INVALIDARG;
  558. *ppStart = NULL;
  559. if (!_IsConnected())
  560. return TF_E_DISCONNECTED;
  561. if (!_IsValidEditCookie(ec, TF_ES_READ))
  562. {
  563. Assert(0);
  564. return TF_E_NOLOCK;
  565. }
  566. hr = fStart ? _ptsi->GetStart(&paStart) : _ptsi->GetEnd(&paStart);
  567. if (hr == E_NOTIMPL)
  568. return E_NOTIMPL;
  569. if (hr != S_OK)
  570. return E_FAIL;
  571. hr = E_FAIL;
  572. if (FAILED(paStart->Clone(&paEnd)))
  573. goto Exit;
  574. if ((range = new CRange) == NULL)
  575. {
  576. hr = E_OUTOFMEMORY;
  577. goto Exit;
  578. }
  579. if (!range->_InitWithDefaultGravity(this, OWN_ANCHORS, paStart, paEnd))
  580. {
  581. range->Release();
  582. goto Exit;
  583. }
  584. *ppStart = (ITfRangeAnchor *)range;
  585. hr = S_OK;
  586. Exit:
  587. if (hr != S_OK)
  588. {
  589. SafeRelease(paStart);
  590. SafeRelease(paEnd);
  591. }
  592. return hr;
  593. }
  594. //+---------------------------------------------------------------------------
  595. //
  596. // CreateRange
  597. //
  598. //----------------------------------------------------------------------------
  599. STDAPI CInputContext::CreateRange(IAnchor *paStart, IAnchor *paEnd, ITfRangeAnchor **ppRange)
  600. {
  601. CRange *range;
  602. if (ppRange == NULL)
  603. return E_INVALIDARG;
  604. *ppRange = NULL;
  605. if (paStart == NULL || paEnd == NULL)
  606. return E_INVALIDARG;
  607. if (CompareAnchors(paStart, paEnd) > 0)
  608. return E_INVALIDARG;
  609. if ((range = new CRange) == NULL)
  610. return E_OUTOFMEMORY;
  611. if (!range->_InitWithDefaultGravity(this, COPY_ANCHORS, paStart, paEnd))
  612. {
  613. range->Release();
  614. return E_FAIL;
  615. }
  616. *ppRange = range;
  617. return S_OK;
  618. }
  619. //+---------------------------------------------------------------------------
  620. //
  621. // CreateRange
  622. //
  623. //----------------------------------------------------------------------------
  624. STDAPI CInputContext::CreateRange(LONG acpStart, LONG acpEnd, ITfRangeACP **ppRange)
  625. {
  626. IServiceProvider *psp;
  627. CRange *range;
  628. CACPWrap *pACPWrap;
  629. IAnchor *paStart;
  630. IAnchor *paEnd;
  631. HRESULT hr;
  632. if (ppRange == NULL)
  633. return E_INVALIDARG;
  634. pACPWrap = NULL;
  635. *ppRange = NULL;
  636. paEnd = NULL;
  637. hr = E_FAIL;
  638. if (acpStart > acpEnd)
  639. return E_INVALIDARG;
  640. if (_ptsi->QueryInterface(IID_IServiceProvider, (void **)&psp) == S_OK)
  641. {
  642. if (psp->QueryService(GUID_SERVICE_TF, IID_PRIV_ACPWRAP, (void **)&pACPWrap) == S_OK)
  643. {
  644. // the actual impl is acp based, so this is easy
  645. if ((paStart = pACPWrap->_CreateAnchorACP(acpStart, TS_GR_BACKWARD)) == NULL)
  646. goto Exit;
  647. if ((paEnd = pACPWrap->_CreateAnchorACP(acpEnd, TS_GR_FORWARD)) == NULL)
  648. goto Exit;
  649. }
  650. else
  651. {
  652. // in case QueryService sets it on failure to garbage...
  653. pACPWrap = NULL;
  654. }
  655. psp->Release();
  656. }
  657. if (paEnd == NULL) // failure above?
  658. {
  659. Assert(0); // who's calling this?
  660. // caller should know whether or not it has an acp text store.
  661. // we don't, so we won't support this case.
  662. hr = E_FAIL;
  663. goto Exit;
  664. }
  665. if ((range = new CRange) == NULL)
  666. {
  667. hr = E_OUTOFMEMORY;
  668. goto Exit;
  669. }
  670. if (!range->_InitWithDefaultGravity(this, OWN_ANCHORS, paStart, paEnd))
  671. {
  672. range->Release();
  673. goto Exit;
  674. }
  675. *ppRange = range;
  676. hr = S_OK;
  677. Exit:
  678. SafeRelease(pACPWrap);
  679. if (hr != S_OK)
  680. {
  681. SafeRelease(paStart);
  682. SafeRelease(paEnd);
  683. }
  684. return hr;
  685. }
  686. //+---------------------------------------------------------------------------
  687. //
  688. // _Pushed
  689. //
  690. //----------------------------------------------------------------------------
  691. void CInputContext::_Pushed()
  692. {
  693. CThreadInputMgr *tim;
  694. if ((tim = CThreadInputMgr::_GetThis()) != NULL)
  695. tim->_NotifyCallbacks(TIM_INITIC, NULL, this);
  696. }
  697. //+---------------------------------------------------------------------------
  698. //
  699. // _Popped
  700. //
  701. //----------------------------------------------------------------------------
  702. void CInputContext::_Popped()
  703. {
  704. CThreadInputMgr *tim;
  705. if ((tim = CThreadInputMgr::_GetThis()) != NULL)
  706. tim->_NotifyCallbacks(TIM_UNINITIC, NULL, this);
  707. //
  708. // We release all properties and property stores.
  709. //
  710. CProperty *pProp;
  711. while (_pPropList != NULL)
  712. {
  713. pProp = _pPropList;
  714. _pPropList = _pPropList->_pNext;
  715. pProp->Release();
  716. }
  717. // we just free up the cached text property, so make sure
  718. // we don't try to use it later!
  719. _pPropTextOwner = NULL;
  720. //
  721. // We release all compartments.
  722. //
  723. CleanUp();
  724. }
  725. //+---------------------------------------------------------------------------
  726. //
  727. // _GetPropStyle
  728. //
  729. //----------------------------------------------------------------------------
  730. const GUID *CInputContext::_c_rgPropStyle[] =
  731. {
  732. &GUID_TFCAT_PROPSTYLE_CUSTOM,
  733. // {0x24af3031,0x852d,0x40a2,{0xbc,0x09,0x89,0x92,0x89,0x8c,0xe7,0x22}},
  734. &GUID_TFCAT_PROPSTYLE_STATIC,
  735. // {0x565fb8d8,0x6bd4,0x4ca1,{0xb2,0x23,0x0f,0x2c,0xcb,0x8f,0x4f,0x96}},
  736. &GUID_TFCAT_PROPSTYLE_STATICCOMPACT,
  737. // {0x85f9794b,0x4d19,0x40d8,{0x88,0x64,0x4e,0x74,0x73,0x71,0xa6,0x6d}}
  738. &GUID_TFCAT_PROPSTYLE_CUSTOM_COMPACT,
  739. };
  740. TFPROPERTYSTYLE CInputContext::_GetPropStyle(REFGUID rguidProp)
  741. {
  742. GUID guidStyle = GUID_NULL;
  743. CCategoryMgr::s_FindClosestCategory(rguidProp,
  744. &guidStyle,
  745. _c_rgPropStyle,
  746. ARRAYSIZE(_c_rgPropStyle));
  747. if (IsEqualGUID(guidStyle, GUID_TFCAT_PROPSTYLE_CUSTOM))
  748. return TFPROPSTYLE_CUSTOM;
  749. else if (IsEqualGUID(guidStyle, GUID_TFCAT_PROPSTYLE_STATIC))
  750. return TFPROPSTYLE_STATIC;
  751. else if (IsEqualGUID(guidStyle, GUID_TFCAT_PROPSTYLE_STATICCOMPACT))
  752. return TFPROPSTYLE_STATICCOMPACT;
  753. else if (IsEqualGUID(guidStyle, GUID_TFCAT_PROPSTYLE_CUSTOM_COMPACT))
  754. return TFPROPSTYLE_CUSTOM_COMPACT;
  755. return TFPROPSTYLE_NULL;
  756. }
  757. //+---------------------------------------------------------------------------
  758. //
  759. // Serialize
  760. //
  761. //----------------------------------------------------------------------------
  762. STDAPI CInputContext::Serialize(ITfProperty *pProp, ITfRange *pRange, TF_PERSISTENT_PROPERTY_HEADER_ACP *pHdr, IStream *pStream)
  763. {
  764. ITextStoreACPServices *ptss;
  765. HRESULT hr;
  766. if (pHdr == NULL)
  767. return E_INVALIDARG;
  768. memset(pHdr, 0, sizeof(*pHdr));
  769. if (!_IsCiceroTSI())
  770. return E_UNEXPECTED;
  771. if (_ptsi->QueryInterface(IID_ITextStoreACPServices, (void **)&ptss) != S_OK)
  772. return E_FAIL;
  773. hr = ptss->Serialize(pProp, pRange, pHdr, pStream);
  774. ptss->Release();
  775. return hr;
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Unserialize
  780. //
  781. //----------------------------------------------------------------------------
  782. STDAPI CInputContext::Unserialize(ITfProperty *pProp, const TF_PERSISTENT_PROPERTY_HEADER_ACP *pHdr, IStream *pStream, ITfPersistentPropertyLoaderACP *pLoader)
  783. {
  784. ITextStoreACPServices *ptss;
  785. HRESULT hr;
  786. if (!_IsCiceroTSI())
  787. return E_UNEXPECTED;
  788. if (_ptsi->QueryInterface(IID_ITextStoreACPServices, (void **)&ptss) != S_OK)
  789. return E_FAIL;
  790. hr = ptss->Unserialize(pProp, pHdr, pStream, pLoader);
  791. ptss->Release();
  792. return hr;
  793. }
  794. //+---------------------------------------------------------------------------
  795. //
  796. // GetDocumentMgr
  797. //
  798. //----------------------------------------------------------------------------
  799. STDAPI CInputContext::GetDocumentMgr(ITfDocumentMgr **ppDm)
  800. {
  801. CDocumentInputManager *dm;
  802. if (ppDm == NULL)
  803. return E_INVALIDARG;
  804. *ppDm = NULL;
  805. if ((dm = _GetDm()) == NULL)
  806. return S_FALSE; // the ic has been popped
  807. *ppDm = dm;
  808. (*ppDm)->AddRef();
  809. return S_OK;
  810. }
  811. //+---------------------------------------------------------------------------
  812. //
  813. // EnumProperties
  814. //
  815. //----------------------------------------------------------------------------
  816. STDAPI CInputContext::EnumProperties(IEnumTfProperties **ppEnum)
  817. {
  818. CEnumProperties *pEnum;
  819. if (ppEnum == NULL)
  820. return E_INVALIDARG;
  821. *ppEnum = NULL;
  822. if (!_IsConnected())
  823. return TF_E_DISCONNECTED;
  824. pEnum = new CEnumProperties;
  825. if (!pEnum)
  826. return E_OUTOFMEMORY;
  827. if (!pEnum->_Init(this))
  828. return E_FAIL;
  829. *ppEnum = pEnum;
  830. return S_OK;
  831. }
  832. //+---------------------------------------------------------------------------
  833. //
  834. // GetStart
  835. //
  836. //----------------------------------------------------------------------------
  837. STDAPI CInputContext::GetStart(TfEditCookie ec, ITfRange **ppStart)
  838. {
  839. return _GetStartOrEnd(ec, TRUE, ppStart);
  840. }
  841. //+---------------------------------------------------------------------------
  842. //
  843. // GetEnd
  844. //
  845. //----------------------------------------------------------------------------
  846. STDAPI CInputContext::GetEnd(TfEditCookie ec, ITfRange **ppEnd)
  847. {
  848. return _GetStartOrEnd(ec, FALSE, ppEnd);
  849. }
  850. //+---------------------------------------------------------------------------
  851. //
  852. // GetStatus
  853. //
  854. //----------------------------------------------------------------------------
  855. STDAPI CInputContext::GetStatus(TS_STATUS *pdcs)
  856. {
  857. if (pdcs == NULL)
  858. return E_INVALIDARG;
  859. memset(pdcs, 0, sizeof(*pdcs));
  860. if (!_IsConnected())
  861. return TF_E_DISCONNECTED;
  862. return _GetTSI()->GetStatus(pdcs);
  863. }
  864. //+---------------------------------------------------------------------------
  865. //
  866. // CreateRangeBackup
  867. //
  868. //----------------------------------------------------------------------------
  869. STDAPI CInputContext::CreateRangeBackup(TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
  870. {
  871. CRangeBackup *pRangeBackup;
  872. CRange *range;
  873. HRESULT hr;
  874. if (!ppBackup)
  875. return E_INVALIDARG;
  876. *ppBackup = NULL;
  877. if (!_IsConnected())
  878. return TF_E_DISCONNECTED;
  879. if (!_IsValidEditCookie(ec, TF_ES_READ))
  880. {
  881. Assert(0);
  882. return TF_E_NOLOCK;
  883. }
  884. if (!pRange)
  885. return E_INVALIDARG;
  886. if ((range = GetCRange_NA(pRange)) == NULL)
  887. return E_INVALIDARG;
  888. if (!VerifySameContext(this, range))
  889. return E_INVALIDARG;
  890. range->_QuickCheckCrossedAnchors();
  891. pRangeBackup = new CRangeBackup(this);
  892. if (!pRangeBackup)
  893. return E_OUTOFMEMORY;
  894. if (FAILED(hr = pRangeBackup->Init(ec, range)))
  895. {
  896. pRangeBackup->Clear();
  897. pRangeBackup->Release();
  898. return E_FAIL;
  899. }
  900. *ppBackup = pRangeBackup;
  901. return hr;
  902. }
  903. //+---------------------------------------------------------------------------
  904. //
  905. // QueryService
  906. //
  907. //----------------------------------------------------------------------------
  908. STDAPI CInputContext::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  909. {
  910. IServiceProvider *psp;
  911. HRESULT hr;
  912. if (ppv == NULL)
  913. return E_INVALIDARG;
  914. *ppv = NULL;
  915. if (IsEqualGUID(guidService, GUID_SERVICE_TEXTSTORE) &&
  916. IsEqualIID(riid, IID_IServiceProvider))
  917. {
  918. // caller wants to talk to the text store
  919. if (_ptsi == NULL)
  920. return E_FAIL;
  921. // we use an extra level of indirection, asking the IServiceProvider for an IServiceProvider
  922. // because we want to leave the app free to not expose the ITextStore object
  923. // otherwise tips could QI the IServiceProvider for ITextStore
  924. if (_ptsi->QueryInterface(IID_IServiceProvider, (void **)&psp) != S_OK || psp == NULL)
  925. return E_FAIL;
  926. hr = psp->QueryService(GUID_SERVICE_TEXTSTORE, IID_IServiceProvider, ppv);
  927. psp->Release();
  928. return hr;
  929. }
  930. if (!IsEqualGUID(guidService, GUID_SERVICE_TF) ||
  931. !IsEqualIID(riid, IID_PRIV_CINPUTCONTEXT))
  932. {
  933. // SVC_E_NOSERVICE is proper return code for wrong service....
  934. // but it's not defined anywhere. So use E_NOINTERFACE for both
  935. // cases as trident is rumored to do
  936. return E_NOINTERFACE;
  937. }
  938. *ppv = this;
  939. AddRef();
  940. return S_OK;
  941. }
  942. //+---------------------------------------------------------------------------
  943. //
  944. // AdviseMouseSink
  945. //
  946. //----------------------------------------------------------------------------
  947. STDAPI CInputContext::AdviseMouseSink(ITfRange *range, ITfMouseSink *pSink, DWORD *pdwCookie)
  948. {
  949. CRange *pCRange;
  950. CRange *pClone;
  951. ITfMouseTrackerAnchor *pTrackerAnchor;
  952. ITfMouseTrackerACP *pTrackerACP;
  953. HRESULT hr;
  954. if (pdwCookie == NULL)
  955. return E_INVALIDARG;
  956. *pdwCookie = 0;
  957. if (range == NULL || pSink == NULL)
  958. return E_INVALIDARG;
  959. if ((pCRange = GetCRange_NA(range)) == NULL)
  960. return E_INVALIDARG;
  961. if (!VerifySameContext(this, pCRange))
  962. return E_INVALIDARG;
  963. if (!_IsConnected())
  964. return TF_E_DISCONNECTED;
  965. pTrackerACP = NULL;
  966. if (_ptsi->QueryInterface(IID_ITfMouseTrackerAnchor, (void **)&pTrackerAnchor) != S_OK)
  967. {
  968. pTrackerAnchor = NULL;
  969. // we also try IID_ITfMouseTrackerACP for the benefit of wrapped implementations who
  970. // just want to forward the request off to an ACP app
  971. if (_ptsi->QueryInterface(IID_ITfMouseTrackerACP, (void **)&pTrackerACP) != S_OK)
  972. return E_NOTIMPL;
  973. }
  974. hr = E_FAIL;
  975. // need to pass on a clone, so app can hang onto range/anchors
  976. if ((pClone = pCRange->_Clone()) == NULL)
  977. goto Exit;
  978. hr = (pTrackerAnchor != NULL) ?
  979. pTrackerAnchor->AdviseMouseSink(pClone->_GetStart(), pClone->_GetEnd(), pSink, pdwCookie) :
  980. pTrackerACP->AdviseMouseSink((ITfRangeACP *)pClone, pSink, pdwCookie);
  981. pClone->Release();
  982. Exit:
  983. SafeRelease(pTrackerAnchor);
  984. SafeRelease(pTrackerACP);
  985. return hr;
  986. }
  987. //+---------------------------------------------------------------------------
  988. //
  989. // UnadviseMouseSink
  990. //
  991. //----------------------------------------------------------------------------
  992. STDAPI CInputContext::UnadviseMouseSink(DWORD dwCookie)
  993. {
  994. ITfMouseTrackerAnchor *pTrackerAnchor;
  995. ITfMouseTrackerACP *pTrackerACP;
  996. HRESULT hr;
  997. if (!_IsConnected())
  998. return TF_E_DISCONNECTED;
  999. if (_ptsi->QueryInterface(IID_ITfMouseTrackerAnchor, (void **)&pTrackerAnchor) == S_OK)
  1000. {
  1001. hr = pTrackerAnchor->UnadviseMouseSink(dwCookie);
  1002. pTrackerAnchor->Release();
  1003. }
  1004. else if (_ptsi->QueryInterface(IID_ITfMouseTrackerACP, (void **)&pTrackerACP) == S_OK)
  1005. {
  1006. // we also try IID_ITfMouseTrackerACP for the benefit of wrapped implementations who
  1007. // just want to forward the request off to an ACP app
  1008. hr = pTrackerACP->UnadviseMouseSink(dwCookie);
  1009. pTrackerACP->Release();
  1010. }
  1011. else
  1012. {
  1013. hr = E_NOTIMPL;
  1014. }
  1015. return hr;
  1016. }
  1017. //+---------------------------------------------------------------------------
  1018. //
  1019. // GetActiveView
  1020. //
  1021. //----------------------------------------------------------------------------
  1022. STDAPI CInputContext::GetActiveView(ITfContextView **ppView)
  1023. {
  1024. CContextView *pView;
  1025. TsViewCookie vcActiveView;
  1026. HRESULT hr;
  1027. if (ppView == NULL)
  1028. return E_INVALIDARG;
  1029. *ppView = NULL;
  1030. if (!_IsConnected())
  1031. return TF_E_DISCONNECTED;
  1032. hr = _ptsi->GetActiveView(&vcActiveView);
  1033. if (hr != S_OK)
  1034. {
  1035. Assert(0); // why did it fail?
  1036. if (hr != E_NOTIMPL)
  1037. return E_FAIL;
  1038. // for E_NOTIMPL, we will assume a single view and supply
  1039. // a constant value here
  1040. vcActiveView = 0;
  1041. }
  1042. // Issue: for now, just supporting an active view
  1043. // need to to handle COM identity correctly for mult views
  1044. if (_pActiveView == NULL)
  1045. {
  1046. if ((_pActiveView = new CContextView(this, vcActiveView)) == NULL)
  1047. return E_OUTOFMEMORY;
  1048. }
  1049. pView = _pActiveView;
  1050. pView->AddRef();
  1051. *ppView = pView;
  1052. return S_OK;
  1053. }
  1054. //+---------------------------------------------------------------------------
  1055. //
  1056. // EnumView
  1057. //
  1058. //----------------------------------------------------------------------------
  1059. STDAPI CInputContext::EnumViews(IEnumTfContextViews **ppEnum)
  1060. {
  1061. if (ppEnum == NULL)
  1062. return E_INVALIDARG;
  1063. *ppEnum = NULL;
  1064. if (!_IsConnected())
  1065. return TF_E_DISCONNECTED;
  1066. // Issue: support this
  1067. Assert(0);
  1068. return E_NOTIMPL;
  1069. }
  1070. //+---------------------------------------------------------------------------
  1071. //
  1072. // QueryInsertEmbedded
  1073. //
  1074. //----------------------------------------------------------------------------
  1075. STDAPI CInputContext::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
  1076. {
  1077. if (pfInsertable == NULL)
  1078. return E_INVALIDARG;
  1079. *pfInsertable = FALSE;
  1080. if (!_IsConnected())
  1081. return TF_E_DISCONNECTED;
  1082. return _ptsi->QueryInsertEmbedded(pguidService, pFormatEtc, pfInsertable);
  1083. }
  1084. //+---------------------------------------------------------------------------
  1085. //
  1086. // InsertTextAtSelection
  1087. //
  1088. //----------------------------------------------------------------------------
  1089. STDAPI CInputContext::InsertTextAtSelection(TfEditCookie ec, DWORD dwFlags,
  1090. const WCHAR *pchText, LONG cch,
  1091. ITfRange **ppRange)
  1092. {
  1093. IAS_OBJ iasobj;
  1094. iasobj.type = IAS_OBJ::IAS_TEXT;
  1095. iasobj.state.text.pchText = pchText;
  1096. iasobj.state.text.cch = cch;
  1097. return _InsertXAtSelection(ec, dwFlags, &iasobj, ppRange);
  1098. }
  1099. //+---------------------------------------------------------------------------
  1100. //
  1101. // InsertEmbeddedAtSelection
  1102. //
  1103. //----------------------------------------------------------------------------
  1104. STDAPI CInputContext::InsertEmbeddedAtSelection(TfEditCookie ec, DWORD dwFlags,
  1105. IDataObject *pDataObject,
  1106. ITfRange **ppRange)
  1107. {
  1108. IAS_OBJ iasobj;
  1109. iasobj.type = IAS_OBJ::IAS_DATAOBJ;
  1110. iasobj.state.obj.pDataObject = pDataObject;
  1111. return _InsertXAtSelection(ec, dwFlags, &iasobj, ppRange);
  1112. }
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // _InsertXAtSelection
  1116. //
  1117. //----------------------------------------------------------------------------
  1118. HRESULT CInputContext::_InsertXAtSelection(TfEditCookie ec, DWORD dwFlags,
  1119. IAS_OBJ *pObj,
  1120. ITfRange **ppRange)
  1121. {
  1122. IAnchor *paStart;
  1123. IAnchor *paEnd;
  1124. CRange *range;
  1125. CComposition *pComposition;
  1126. HRESULT hr;
  1127. BOOL fNoDefaultComposition;
  1128. if (ppRange == NULL)
  1129. return E_INVALIDARG;
  1130. *ppRange = NULL;
  1131. if (pObj->type == IAS_OBJ::IAS_TEXT)
  1132. {
  1133. if (pObj->state.text.pchText == NULL && pObj->state.text.cch != 0)
  1134. return E_INVALIDARG;
  1135. if (!(dwFlags & TS_IAS_QUERYONLY) && (pObj->state.text.pchText == NULL || pObj->state.text.cch == 0))
  1136. return E_INVALIDARG;
  1137. }
  1138. else
  1139. {
  1140. Assert(pObj->type == IAS_OBJ::IAS_DATAOBJ);
  1141. if (!(dwFlags & TS_IAS_QUERYONLY) && pObj->state.obj.pDataObject == NULL)
  1142. return E_INVALIDARG;
  1143. }
  1144. if ((dwFlags & (TS_IAS_NOQUERY | TS_IAS_QUERYONLY)) == (TS_IAS_NOQUERY | TS_IAS_QUERYONLY))
  1145. return E_INVALIDARG;
  1146. if ((dwFlags & ~(TS_IAS_NOQUERY | TS_IAS_QUERYONLY | TF_IAS_NO_DEFAULT_COMPOSITION)) != 0)
  1147. return E_INVALIDARG;
  1148. if (!_IsConnected())
  1149. return TF_E_DISCONNECTED;
  1150. if (!_IsValidEditCookie(ec, (dwFlags & TF_IAS_QUERYONLY) ? TF_ES_READ : TF_ES_READWRITE))
  1151. {
  1152. Assert(0);
  1153. return TF_E_NOLOCK;
  1154. }
  1155. // we need to clear out the TF_IAS_NO_DEFAULT_COMPOSITION bit because it is not legal
  1156. // for ITextStore methods
  1157. fNoDefaultComposition = (dwFlags & TF_IAS_NO_DEFAULT_COMPOSITION);
  1158. dwFlags &= ~TF_IAS_NO_DEFAULT_COMPOSITION;
  1159. if (pObj->type == IAS_OBJ::IAS_TEXT)
  1160. {
  1161. if (pObj->state.text.cch < 0)
  1162. {
  1163. pObj->state.text.cch = wcslen(pObj->state.text.pchText);
  1164. }
  1165. hr = _ptsi->InsertTextAtSelection(dwFlags, pObj->state.text.pchText, pObj->state.text.cch, &paStart, &paEnd);
  1166. }
  1167. else
  1168. {
  1169. Assert(pObj->type == IAS_OBJ::IAS_DATAOBJ);
  1170. hr = _ptsi->InsertEmbeddedAtSelection(dwFlags, pObj->state.obj.pDataObject, &paStart, &paEnd);
  1171. }
  1172. if (hr == S_OK)
  1173. {
  1174. if (!(dwFlags & TS_IAS_QUERYONLY))
  1175. {
  1176. CComposition::_IsRangeCovered(this, _GetClientInEditSession(ec), paStart, paEnd, &pComposition);
  1177. _DoPostTextEditNotifications(pComposition, ec, 0, 1, paStart, paEnd, NULL);
  1178. // try to start a composition
  1179. // any active compositions?
  1180. if (!fNoDefaultComposition && pComposition == NULL)
  1181. {
  1182. // not covered, need to (try to) create a composition
  1183. hr = _StartComposition(ec, paStart, paEnd, NULL, &pComposition);
  1184. if (hr == S_OK && pComposition != NULL)
  1185. {
  1186. // we just wanted to set the composing property, so end this one immediately
  1187. pComposition->EndComposition(ec);
  1188. pComposition->Release();
  1189. }
  1190. }
  1191. }
  1192. }
  1193. else
  1194. {
  1195. // the InsertAtSelection call failed in the app
  1196. switch (hr)
  1197. {
  1198. case TS_E_NOSELECTION:
  1199. case TS_E_READONLY:
  1200. return hr;
  1201. case E_NOTIMPL:
  1202. // the app hasn't implemented InsertAtSelection, so we'll fake it using GetSelection/SetText
  1203. if (!_InsertXAtSelectionAggressive(ec, dwFlags, pObj, &paStart, &paEnd))
  1204. return E_FAIL;
  1205. break;
  1206. default:
  1207. return E_FAIL;
  1208. }
  1209. }
  1210. if (!(dwFlags & TF_IAS_NOQUERY))
  1211. {
  1212. if (paStart == NULL || paEnd == NULL)
  1213. {
  1214. Assert(0); // text store returning bogus values
  1215. return E_FAIL;
  1216. }
  1217. if ((range = new CRange) == NULL)
  1218. return E_OUTOFMEMORY;
  1219. if (!range->_InitWithDefaultGravity(this, OWN_ANCHORS, paStart, paEnd))
  1220. {
  1221. range->Release();
  1222. return E_FAIL;
  1223. }
  1224. *ppRange = (ITfRangeAnchor *)range;
  1225. }
  1226. return S_OK;
  1227. }
  1228. //+---------------------------------------------------------------------------
  1229. //
  1230. // _InsertXAtSelectionAggressive
  1231. //
  1232. //----------------------------------------------------------------------------
  1233. BOOL CInputContext::_InsertXAtSelectionAggressive(TfEditCookie ec, DWORD dwFlags, IAS_OBJ *pObj, IAnchor **ppaStart, IAnchor **ppaEnd)
  1234. {
  1235. CRange *range;
  1236. TF_SELECTION sel;
  1237. ULONG pcFetched;
  1238. HRESULT hr;
  1239. // this is more expensive then using ITextStore methods directly, but by using a CRange we
  1240. // get all the composition/notification code for free
  1241. if (GetSelection(ec, TF_DEFAULT_SELECTION, 1, &sel, &pcFetched) != S_OK)
  1242. return FALSE;
  1243. hr = E_FAIL;
  1244. if (pcFetched != 1)
  1245. goto Exit;
  1246. if (dwFlags & TS_IAS_QUERYONLY)
  1247. {
  1248. hr = S_OK;
  1249. goto OutParams;
  1250. }
  1251. if (pObj->type == IAS_OBJ::IAS_TEXT)
  1252. {
  1253. hr = sel.range->SetText(ec, 0, pObj->state.text.pchText, pObj->state.text.cch);
  1254. }
  1255. else
  1256. {
  1257. Assert(pObj->type == IAS_OBJ::IAS_DATAOBJ);
  1258. hr = sel.range->InsertEmbedded(ec, 0, pObj->state.obj.pDataObject);
  1259. }
  1260. if (hr == S_OK)
  1261. {
  1262. OutParams:
  1263. range = GetCRange_NA(sel.range);
  1264. *ppaStart = range->_GetStart();
  1265. (*ppaStart)->AddRef();
  1266. *ppaEnd = range->_GetEnd();
  1267. (*ppaEnd)->AddRef();
  1268. }
  1269. Exit:
  1270. sel.range->Release();
  1271. return (hr == S_OK);
  1272. }
  1273. //+---------------------------------------------------------------------------
  1274. //
  1275. // _DoPostTextEditNotifications
  1276. //
  1277. //----------------------------------------------------------------------------
  1278. void CInputContext::_DoPostTextEditNotifications(CComposition *pComposition,
  1279. TfEditCookie ec, DWORD dwFlags,
  1280. ULONG cchInserted,
  1281. IAnchor *paStart, IAnchor *paEnd,
  1282. CRange *range)
  1283. {
  1284. CProperty *property;
  1285. VARIANT var;
  1286. if (range != NULL)
  1287. {
  1288. Assert(paStart == NULL);
  1289. Assert(paEnd == NULL);
  1290. paStart = range->_GetStart();
  1291. paEnd = range->_GetEnd();
  1292. }
  1293. if (cchInserted > 0)
  1294. {
  1295. // an insert could have crossed some anchors
  1296. _IncLastLockReleaseID(); // force a re-check for everyone!
  1297. if (range != NULL)
  1298. {
  1299. range->_QuickCheckCrossedAnchors(); // and check this guy right away
  1300. }
  1301. }
  1302. // the app won't notify us about changes we initiate, so do that now
  1303. _OnTextChangeInternal(dwFlags, paStart, paEnd, COPY_ANCHORS);
  1304. // let properties know about the update
  1305. _PropertyTextUpdate(dwFlags, paStart, paEnd);
  1306. // Set text owner property
  1307. if (cchInserted > 0
  1308. && !IsEqualAnchor(paStart, paEnd))
  1309. {
  1310. // text owner property
  1311. TfClientId tid = _GetClientInEditSession(ec);
  1312. if ((tid != g_gaApp) && (tid != g_gaSystem) &&
  1313. (property = GetTextOwnerProperty()))
  1314. {
  1315. var.vt = VT_I4;
  1316. var.lVal = tid;
  1317. Assert(var.lVal != TF_CLIENTID_NULL);
  1318. property->_SetDataInternal(ec, paStart, paEnd, &var);
  1319. }
  1320. // composition property
  1321. if (range != NULL &&
  1322. _GetProperty(GUID_PROP_COMPOSING, &property) == S_OK) // perf: consider caching property ptr
  1323. {
  1324. var.vt = VT_I4;
  1325. var.lVal = TRUE;
  1326. property->_SetDataInternal(ec, paStart, paEnd, &var);
  1327. property->Release();
  1328. }
  1329. }
  1330. // composition update
  1331. if (pComposition != NULL && _GetOwnerCompositionSink() != NULL)
  1332. {
  1333. _GetOwnerCompositionSink()->OnUpdateComposition(pComposition, NULL);
  1334. }
  1335. }