// // reconv.cpp // #include "private.h" #include "globals.h" #include "tim.h" #include "ic.h" #include "helpers.h" #include "fnrecon.h" #include "funcprv.h" #include "ptrary.h" #include "immxutil.h" #include "proputil.h" #include "rprop.h" #include "range.h" //+--------------------------------------------------------------------------- // // ::GrowEmptyRangeByOne // // Helper to enlarge empty ranges by shifting the end anchor + 1. // //---------------------------------------------------------------------------- HRESULT GrowEmptyRangeByOne(CInputContext *pic, ITfRange *range) { HRESULT hr = S_OK; if (pic->_DoPseudoSyncEditSession(TF_ES_READ, PSEUDO_ESCB_GROWRANGE, range, &hr) != S_OK || hr != S_OK) { Assert(0); } return hr; } HRESULT GrowEmptyRangeByOneCallback(TfEditCookie ec, ITfRange *range) { BOOL fEmpty; LONG l; HRESULT hr = S_OK; // // Check the length of the given range. // If the given range is 0 length, we try to find the owner of // the next char. // range->IsEmpty(ec, &fEmpty); if (fEmpty) { hr = range->ShiftEnd(ec, +1, &l, NULL); } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CFunction // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CFunction::CFunction(CFunctionProvider *pFuncPrv) { _pFuncPrv = pFuncPrv; _pFuncPrv->AddRef(); } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CFunction::~CFunction() { SafeRelease(_pFuncPrv); CleanUpOwnerRange(); } //+--------------------------------------------------------------------------- // // CleanUpOwnerRange // //---------------------------------------------------------------------------- void CFunction::CleanUpOwnerRange() { CRangeOwnerList *pRangeOwner; while (pRangeOwner = _listRangeOwner.GetFirst()) { _listRangeOwner.Remove(pRangeOwner); delete pRangeOwner; } } //+--------------------------------------------------------------------------- // // BuildOwnerRangeList // //---------------------------------------------------------------------------- BOOL CFunction::BuildOwnerRangeList(CInputContext *pic, ITfRange *pRange) { HRESULT hr = S_OK; BUILDOWNERRANGELISTQUEUEINFO qInfo; BOOL bRet = TRUE; qInfo.pFunc = this; qInfo.pRange = pRange; if (pic->_DoPseudoSyncEditSession(TF_ES_READ, PSEUDO_ESCB_BUILDOWNERRANGELIST, &qInfo, &hr) != S_OK || hr != S_OK) { Assert(0); bRet = FALSE; } return bRet; } //+--------------------------------------------------------------------------- // // BuildOwnerRangeListCallback // //---------------------------------------------------------------------------- HRESULT CFunction::BuildOwnerRangeListCallback(TfEditCookie ec, CInputContext *pic, ITfRange *pRange) { CProperty *pProp; IEnumTfRanges *pEnumPropRange; CRange *pRangeP = NULL; HRESULT hr = E_FAIL; if (pic->_pPropTextOwner == NULL) goto ExitOk; pProp = pic->_pPropTextOwner; CleanUpOwnerRange(); // // if pRange is NULL, we build owner list for entire dcoument. // we will enumerate all property ranges. // if (pRange) { if ((pRangeP = GetCRange_NA(pRange)) == NULL) goto Exit; } if (SUCCEEDED(pProp->EnumRanges(ec, &pEnumPropRange, pRange))) { ITfRange *pPropRange; while (pEnumPropRange->Next(1, &pPropRange, NULL) == S_OK) { TfGuidAtom guidOwner; CRangeOwnerList *pRangeOwner; ITfRange *pRangeTmp; CRange *pRangeTmpP; BOOL bKnownOwner = FALSE; pPropRange->Clone(&pRangeTmp); GetGUIDPropertyData(ec, pProp, pPropRange, &guidOwner); // // check if this guidOwner already appeared in the range. // pRangeOwner = _listRangeOwner.GetFirst(); while(pRangeOwner) { if (guidOwner == pRangeOwner->_guidOwner) { bKnownOwner = TRUE; } pRangeOwner = pRangeOwner->GetNext(); } // // get CRange. // if ((pRangeTmpP = GetCRange_NA(pRangeTmp)) == NULL) goto NoCRange; // // if pRangeP is NULL, we build owner list for entire document. // So we don't have to adjust pRangeTmp. // if (pRangeP) { if (CompareAnchors(pRangeTmpP->_GetStart(), pRangeP->_GetStart()) < 0) { // move pRangeTmp's start to match pRange pRangeTmpP->_GetStart()->ShiftTo(pRangeP->_GetStart()); // insure pRangeTmp's end is no greater than pRange's end if (CompareAnchors(pRangeTmpP->_GetEnd(), pRangeP->_GetEnd()) > 0) { pRangeTmpP->_GetEnd()->ShiftTo(pRangeP->_GetEnd()); } } else if (CompareAnchors(pRangeTmpP->_GetEnd(), pRangeP->_GetEnd()) > 0) { pRangeTmpP->_GetEnd()->ShiftTo(pRangeP->_GetEnd()); } } pRangeOwner = new CRangeOwnerList(guidOwner, pRangeTmp, bKnownOwner); _listRangeOwner.Add(pRangeOwner); NoCRange: pPropRange->Release(); pRangeTmp->Release(); } pEnumPropRange->Release(); } ExitOk: hr = S_OK; Exit: return hr; } ////////////////////////////////////////////////////////////////////////////// // // CFnReconversion // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CFnReconversion::CFnReconversion(CFunctionProvider *pFuncPrv) :CFunction(pFuncPrv) { _pReconvCache = NULL; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CFnReconversion::~CFnReconversion() { SafeRelease(_pReconvCache); } //+--------------------------------------------------------------------------- // // GetDisplayName // //---------------------------------------------------------------------------- STDAPI CFnReconversion::GetDisplayName(BSTR *pbstrName) { *pbstrName = SysAllocString(L"Reconversion"); return *pbstrName != NULL ? S_OK : E_OUTOFMEMORY; } //+--------------------------------------------------------------------------- // // CFnReconversion::GetReconversion // //---------------------------------------------------------------------------- STDAPI CFnReconversion::GetReconversion(ITfRange *pRange, ITfCandidateList **ppCandList) { if (ppCandList == NULL) return E_INVALIDARG; *ppCandList = NULL; if (pRange == NULL) return E_INVALIDARG; return Internal_GetReconversion(pRange, ppCandList, NULL, RF_GETRECONVERSION, NULL); } //+--------------------------------------------------------------------------- // // CFnReconversion::QueryRange // //---------------------------------------------------------------------------- STDAPI CFnReconversion::QueryRange(ITfRange *pRange, ITfRange **ppNewRange, BOOL *pfConvertable) { if (ppNewRange != NULL) { *ppNewRange = NULL; } if (pfConvertable != NULL) { *pfConvertable = FALSE; } if (pRange == NULL || ppNewRange == NULL || pfConvertable == NULL) { return E_INVALIDARG; } return Internal_GetReconversion(pRange, NULL, ppNewRange, RF_QUERYRECONVERT, pfConvertable); } //+--------------------------------------------------------------------------- // // CFnReconversion::Reconvert // //---------------------------------------------------------------------------- STDAPI CFnReconversion::Reconvert(ITfRange *pRange) { if (pRange == NULL) return E_INVALIDARG; return Internal_GetReconversion(pRange, NULL, NULL, RF_RECONVERT, NULL); } //+--------------------------------------------------------------------------- // // CFnReconversion::Internal_GetReconversion // //---------------------------------------------------------------------------- HRESULT CFnReconversion::Internal_GetReconversion(ITfRange *pRange, ITfCandidateList **ppCandList, ITfRange **ppNewRange, RECONVFUNC rf, BOOL *pfConvertable) { BOOL bReleaseCache = FALSE; HRESULT hr = E_FAIL; ITfRange *pRangeTmp = NULL; ITfRange *pNewRange = NULL; ITfContext *pic = NULL; if (FAILED(pRange->Clone(&pRangeTmp))) goto Exit; if (FAILED(pRangeTmp->GetContext(&pic))) goto Exit; // // when RF_QUERYRECONVERT, we alwasy create new Reconv cache. // we will keep using this chace unless another RF_QUERYRECONVERT comes. // if (rf == RF_QUERYRECONVERT) SafeReleaseClear(_pReconvCache); if (!_pReconvCache) { CInputContext *pcic = GetCInputContext(pic); if (pcic) { QueryAndGetFunction(pcic, pRangeTmp, &_pReconvCache, &pNewRange); pcic->Release(); } // // when it's not RF_QUERYRECONVERT and there was no cache, // we don't hold the reconv cache. // if (rf != RF_QUERYRECONVERT) bReleaseCache = TRUE; } if (!_pReconvCache) { hr = S_OK; goto Exit; } switch (rf) { case RF_GETRECONVERSION: if ((hr = _pReconvCache->GetReconversion(pRangeTmp, ppCandList)) != S_OK) { *ppCandList = NULL; } break; case RF_RECONVERT: hr = _pReconvCache->Reconvert(pRangeTmp); break; case RF_QUERYRECONVERT: if (!pNewRange) { if ((hr = _pReconvCache->QueryRange(pRangeTmp, ppNewRange, pfConvertable)) != S_OK) { *ppNewRange = NULL; *pfConvertable = FALSE; } } else { *ppNewRange = pNewRange; (*ppNewRange)->AddRef(); *pfConvertable = TRUE; hr = S_OK; } break; } Assert(hr == S_OK); Exit: if (bReleaseCache || FAILED(hr)) SafeReleaseClear(_pReconvCache); SafeRelease(pRangeTmp); SafeRelease(pNewRange); SafeRelease(pic); return hr; } //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- HRESULT CFnReconversion::QueryAndGetFunction(CInputContext *pic, ITfRange *pRange, ITfFnReconversion **ppFunc, ITfRange **ppRange) { IEnumTfFunctionProviders *pEnumFuncPrv; ITfFunctionProvider *pFuncPrv; CRangeOwnerList *pRangeOwner; HRESULT hr = E_FAIL; ITfRange *pRangeTmp = NULL; CThreadInputMgr *ptim; *ppFunc = NULL; if ((ptim = CThreadInputMgr::_GetThis()) == NULL) goto Exit; if (pRange) { // // To find the properr function provider, we use pRangeTmp. // if (FAILED(pRange->Clone(&pRangeTmp))) goto Exit; // // Check the length of the given range. // If the given range is 0 length, we try to find the owner of // the next char. // if (GrowEmptyRangeByOne(pic, pRangeTmp) != S_OK) goto Exit; } if (!BuildOwnerRangeList(pic, pRangeTmp)) goto Exit; pRangeOwner = _listRangeOwner.GetFirst(); if (pRangeOwner) { GUID guid; if (SUCCEEDED(MyGetGUID(pRangeOwner->_guidOwner, &guid))) { CTip *ptip; // // A way to get the TextOwner's reconversion function. // // - find a function provider of the ower. // - Do QI the text owner TIP. // - CoCreate the text onwer CLSID. // if (SUCCEEDED(ptim->GetFunctionProvider(guid, &pFuncPrv))) { hr = pFuncPrv->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown **)ppFunc); SafeReleaseClear(pFuncPrv); } else if (ptim->_GetCTipfromGUIDATOM(pRangeOwner->_guidOwner, &ptip) && ptip->_pTip) { hr = ptip->_pTip->QueryInterface(IID_ITfFnReconversion, (void **)ppFunc); } else { hr = CoCreateInstance(guid, NULL, CLSCTX_INPROC_SERVER, IID_ITfFnReconversion, (void**)ppFunc); } if (FAILED(hr)) *ppFunc = NULL; } } // // if there is no owner or the owner of the first range does not // have ITfFunction, we may find someone who has // ITfFunction. // if (!(*ppFunc) && SUCCEEDED(ptim->EnumFunctionProviders(&pEnumFuncPrv))) { while (!(*ppFunc) && pEnumFuncPrv->Next(1, &pFuncPrv, NULL) == S_OK) { GUID guid; BOOL fSkip = TRUE; if (SUCCEEDED(pFuncPrv->GetType(&guid))) { if (!IsEqualGUID(guid, GUID_SYSTEM_FUNCTIONPROVIDER)) fSkip = FALSE; } if(!fSkip) { hr = pFuncPrv->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown **)ppFunc); if ((SUCCEEDED(hr) && *ppFunc)) { BOOL fConvertable = FALSE; hr = (*ppFunc)->QueryRange(pRange, ppRange, &fConvertable); if (FAILED(hr) || !fConvertable) { (*ppFunc)->Release(); *ppFunc = NULL; } } } SafeReleaseClear(pFuncPrv); } pEnumFuncPrv->Release(); } Exit: SafeRelease(pRangeTmp); return (*ppFunc) ? S_OK : E_FAIL; } ////////////////////////////////////////////////////////////////////////////// // // CFnAbort // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CFnAbort::CFnAbort(CFunctionProvider *pFuncPrv) : CFunction(pFuncPrv) { } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CFnAbort::~CFnAbort() { } //+--------------------------------------------------------------------------- // // GetDisplayName // //---------------------------------------------------------------------------- STDAPI CFnAbort::GetDisplayName(BSTR *pbstrName) { *pbstrName = SysAllocString(L"Abort"); return *pbstrName != NULL ? S_OK : E_OUTOFMEMORY; } //+--------------------------------------------------------------------------- // // CFnAbort::Abort // //---------------------------------------------------------------------------- STDAPI CFnAbort::Abort(ITfContext *pic) { CThreadInputMgr *ptim; HRESULT hr = E_FAIL; int i; int nCnt; if (!pic) return E_INVALIDARG; if ((ptim = CThreadInputMgr::_GetThis()) == NULL) goto Exit; // // notify all tips with ITfFnAbort to abort any pending conversion. // nCnt = ptim->_GetTIPCount(); for (i = 0; i < nCnt; i++) { ITfFnAbort *pAbort; const CTip *ptip = ptim->_GetCTip(i); if (!ptip->_pFuncProvider) continue; if (SUCCEEDED(ptip->_pFuncProvider->GetFunction(GUID_NULL, IID_ITfFnAbort, (IUnknown **)&pAbort))) { pAbort->Abort(pic); pAbort->Release(); } } hr = S_OK; Exit: return hr; }