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.
 
 
 
 
 
 

639 lines
17 KiB

//
// 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;
}