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.
 
 
 
 
 
 

586 lines
16 KiB

//
// ptrack.cpp
//
#include "private.h"
#include "ic.h"
#include "saa.h"
#include "attr.h"
#include "immxutil.h"
#include "erfa.h"
#include "epval.h"
#include "range.h"
//+---------------------------------------------------------------------------
//
// CalcCicPropertyTrackerAnchors
//
//----------------------------------------------------------------------------
CSharedAnchorArray *CalcCicPropertyTrackerAnchors(CInputContext *pic, IAnchor *paStart, IAnchor *paEnd, ULONG cGUIDATOMs, const TfGuidAtom *prgGUIDATOMs)
{
CProperty *pProperty;
CSharedAnchorArray *prgAnchors;
CSharedAnchorArray **prgAnchorArrays;
ULONG i;
LONG iStartEdge;
LONG iEndEdge;
LONG iSpan;
PROPERTYLIST *pPropList;
IAnchor **ppa;
ULONG cArrays;
BOOL fExactEndMatch;
ULONG cMaxElems;
if ((prgAnchorArrays = (CSharedAnchorArray **)cicMemAlloc(sizeof(CSharedAnchorArray *)*(cGUIDATOMs+1))) == NULL)
return NULL;
cArrays = 0;
//
// shove in the range start and end pts
//
if ((prgAnchors = new CSharedAnchorArray) == NULL)
goto ErrorExit;
if (!prgAnchors->Insert(0, 2))
goto ErrorExit;
if (paStart->Clone(prgAnchors->GetPtr(0)) != S_OK)
goto ErrorExit;
if (IsEqualAnchor(paStart, paEnd))
{
// empty range, we just want a single anchor at the range pos
prgAnchors->SetCount(1);
goto Exit;
}
if (paEnd->Clone(prgAnchors->GetPtr(1)) != S_OK)
goto ErrorExit;
prgAnchorArrays[0] = prgAnchors;
//
// assemble a list of all the points between start, end
//
cArrays = 1; // 1 for the start, end anchors array
for (i=0; i<cGUIDATOMs; i++)
{
if ((pProperty = pic->_FindProperty(prgGUIDATOMs[i])) == NULL)
continue; // no instances of this property
// find the start, end points
pProperty->Find(paStart, &iStartEdge, FALSE);
fExactEndMatch = (pProperty->Find(paEnd, &iEndEdge, TRUE) != NULL);
if (iEndEdge < iStartEdge)
continue; // start, end are in the same property span, so value is constant over range
// alloc memory for all the new anchors
if ((prgAnchors = new CSharedAnchorArray) == NULL)
goto ErrorExit;
// alloc for max anchors
cMaxElems = (iEndEdge - iStartEdge + 1)*2;
if ((ppa = prgAnchors->Append(cMaxElems)) == NULL)
goto ErrorExit;
// prep for failure
memset(ppa, 0, sizeof(IAnchor *)*cMaxElems);
// add all the covered anchors for this prop to the list
if (iStartEdge < 0)
{
iSpan = 0;
}
else
{
iSpan = iStartEdge;
// if paStart is to the right of the span, skip it
pPropList = pProperty->GetPropList(iStartEdge);
if (CompareAnchors(paStart, pPropList->_paEnd) >= 0)
{
// we don't cover this span at all, or we just touch the right edge
// so skip it
iSpan++;
}
}
while (iSpan <= iEndEdge)
{
// shove in this span's anchors
pPropList = pProperty->GetPropList(iSpan);
if (iSpan != iStartEdge)
{
// filter out dups
// perf: we could elim the dup check for static compact props
if (ppa == prgAnchors->GetPtr(0) || !IsEqualAnchor(*(ppa-1), pPropList->_paStart))
{
if (pPropList->_paStart->Clone(ppa++) != S_OK)
goto ErrorExit;
}
}
Assert(!IsEqualAnchor(pPropList->_paStart, pPropList->_paEnd)); // no zero-len properties!
if (iSpan != iEndEdge ||
(!fExactEndMatch && (iStartEdge < iEndEdge || CompareAnchors(paStart, pPropList->_paEnd) < 0)))
{
if (pPropList->_paEnd->Clone(ppa++) != S_OK)
goto ErrorExit;
}
iSpan++;
}
// may also want the start anchor of the next span
if (!fExactEndMatch &&
pProperty->GetPropNum() > iEndEdge+1)
{
pPropList = pProperty->GetPropList(iEndEdge+1);
if (CompareAnchors(paEnd, pPropList->_paStart) > 0)
{
// start of this span may be same as end of prev for non-compact property, check for dup
if (ppa == prgAnchors->GetPtr(0) || !IsEqualAnchor(*(ppa-1), pPropList->_paStart))
{
// don't need a dup check w/ paEnd because we would have set fExactEndMatch in that case
if (pPropList->_paStart->Clone(ppa++) != S_OK)
goto ErrorExit;
}
}
}
// need to resize the array since we may have over-alloc'd
Assert((int)cMaxElems >= ppa - prgAnchors->GetPtr(0));
prgAnchors->SetCount((int)(ppa - prgAnchors->GetPtr(0)));
prgAnchorArrays[cArrays++] = prgAnchors;
}
//
// sort the list
//
if (cArrays > 1)
{
// mergesort will free all the arrays in prgAnchorArrays
prgAnchors = CSharedAnchorArray::_MergeSort(prgAnchorArrays, cArrays);
}
else
{
Assert(prgAnchors == prgAnchorArrays[0]);
}
// shrink the array down to size, it won't be modified again
if (prgAnchors)
prgAnchors->CompactSize();
Exit:
cicMemFree(prgAnchorArrays);
return prgAnchors;
ErrorExit:
for (i=0; i<cArrays; i++)
{
prgAnchorArrays[i]->_Release();
}
prgAnchors = NULL;
goto Exit;
}
//+---------------------------------------------------------------------------
//
// FillCicValueArray
//
//----------------------------------------------------------------------------
void FillCicValueArray(CInputContext *pic, CRange *range, TF_PROPERTYVAL *rgPropVal, ULONG cGUIDATOMs, const TfGuidAtom *prgGUIDATOMs)
{
ULONG i;
CProperty *pProperty;
for (i=0; i<cGUIDATOMs; i++)
{
Assert(rgPropVal[i].varValue.vt == VT_EMPTY);
if (MyGetGUID(prgGUIDATOMs[i], &rgPropVal[i].guidId) != S_OK)
{
Assert(0); // this shouldn't happen, we registered the GUID when caller created the property
rgPropVal[i].guidId = GUID_NULL;
continue;
}
if ((pProperty = pic->_FindProperty(prgGUIDATOMs[i])) != NULL)
{
pProperty->_GetDataInternal(range->_GetStart(), range->_GetEnd(), &rgPropVal[i].varValue);
}
}
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CEnumUberRanges
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class CEnumUberRanges : public CEnumRangesFromAnchorsBase
{
public:
CEnumUberRanges()
{
Dbg_MemSetThisNameIDCounter(TEXT("CEnumUberRanges"), PERF_ENUMUBERPROP_COUNTER);
}
BOOL _Init(CInputContext *pic, ITfRange *rangeSuper, ULONG cCicGUIDs, const TfGuidAtom *prgCicGUIDATOMs, ULONG cAppGUIDs, const GUID *prgAppGUIDs);
private:
DBG_ID_DECLARE;
};
DBG_ID_INSTANCE(CEnumUberRanges);
//+---------------------------------------------------------------------------
//
// _Init
//
//----------------------------------------------------------------------------
BOOL CEnumUberRanges::_Init(CInputContext *pic, ITfRange *rangeSuper, ULONG cCicGUIDATOMs, const TfGuidAtom *prgCicGUIDATOMs, ULONG cAppGUIDs, const GUID *prgAppGUIDs)
{
CRange *range;
CSharedAnchorArray *prgSrcAnchorArrays[2];
Assert(_iCur == 0);
Assert(_pic == NULL);
Assert(_prgAnchors == NULL);
// find the app property transitions
prgSrcAnchorArrays[0] = CalcAppPropertyTrackerAnchors(pic->_GetTSI(), rangeSuper, cAppGUIDs, prgAppGUIDs);
if (prgSrcAnchorArrays[0] == NULL)
return FALSE;
// find the cicero property transitions
if ((range = GetCRange_NA(rangeSuper)) == NULL)
goto ErrorExit;
prgSrcAnchorArrays[1] = CalcCicPropertyTrackerAnchors(pic, range->_GetStart(), range->_GetEnd(), cCicGUIDATOMs, prgCicGUIDATOMs);
if (prgSrcAnchorArrays[1] == NULL)
goto ErrorExit;
// now combine the two lists
_prgAnchors = CSharedAnchorArray::_MergeSort(prgSrcAnchorArrays, 2);
if (_prgAnchors == NULL)
return FALSE;
_pic = pic;
_pic->AddRef();
return TRUE;
ErrorExit:
prgSrcAnchorArrays[0]->_Release();
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CUberProperty
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class CUberProperty : public ITfReadOnlyProperty, // perf: share base clas with CAppProperty
public CComObjectRootImmx
{
public:
CUberProperty(CInputContext *pic);
~CUberProperty();
BEGIN_COM_MAP_IMMX(CUberProperty)
COM_INTERFACE_ENTRY(ITfReadOnlyProperty)
END_COM_MAP_IMMX()
IMMX_OBJECT_IUNKNOWN_FOR_ATL()
BOOL _Init(ULONG cCicGUIDs, const GUID **prgCicGUIDs, ULONG cAppGUIDs, const GUID **prgAppGUIDs);
// ITfReadOnlyProperty
STDMETHODIMP GetType(GUID *pguid);
STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange);
STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue);
STDMETHODIMP GetContext(ITfContext **ppContext);
private:
BOOL _IsValidEditCookie(TfEditCookie ec, DWORD dwFlags)
{
return _pic->_IsValidEditCookie(ec, dwFlags);
}
CInputContext *_pic;
ULONG _cCicGUIDATOMs;
TfGuidAtom *_prgCicGUIDATOMs;
ULONG _cAppGUIDs;
GUID *_prgAppGUIDs;
DBG_ID_DECLARE;
};
DBG_ID_INSTANCE(CUberProperty);
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CUberProperty::CUberProperty(CInputContext *pic)
{
Dbg_MemSetThisNameIDCounter(TEXT("CUberProperty"), PERF_UBERPROP_COUNTER);
_pic = pic;
_pic->AddRef();
}
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CUberProperty::~CUberProperty()
{
_pic->Release();
cicMemFree(_prgCicGUIDATOMs);
cicMemFree(_prgAppGUIDs);
}
//+---------------------------------------------------------------------------
//
// _Init
//
//----------------------------------------------------------------------------
BOOL CUberProperty::_Init(ULONG cCicGUIDs, const GUID **prgCicGUIDs, ULONG cAppGUIDs, const GUID **prgAppGUIDs)
{
ULONG i;
if ((_prgCicGUIDATOMs = (TfGuidAtom *)cicMemAlloc(cCicGUIDs*sizeof(TfGuidAtom))) == NULL)
return FALSE;
for (i=0; i<cCicGUIDs; i++)
{
if (MyRegisterGUID(*prgCicGUIDs[i], &_prgCicGUIDATOMs[i]) != S_OK)
goto ExitError;
}
if ((_prgAppGUIDs = (GUID *)cicMemAlloc(cAppGUIDs*sizeof(GUID))) == NULL)
goto ExitError;
_cCicGUIDATOMs = cCicGUIDs;
_cAppGUIDs = cAppGUIDs;
for (i=0; i<cAppGUIDs; i++)
{
_prgAppGUIDs[i] = *prgAppGUIDs[i];
}
return TRUE;
ExitError:
cicMemFree(_prgCicGUIDATOMs);
_prgCicGUIDATOMs = NULL; // no funny business in the dtor please
return FALSE;
}
//+---------------------------------------------------------------------------
//
// EnumRanges
//
//----------------------------------------------------------------------------
STDAPI CUberProperty::EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange)
{
CEnumUberRanges *pEnum;
if (ppEnum == NULL)
return E_INVALIDARG;
*ppEnum = NULL;
if (pTargetRange == NULL)
return E_INVALIDARG;
if (!VerifySameContext(_pic, pTargetRange))
return E_INVALIDARG;
if (!_IsValidEditCookie(ec, TF_ES_READ))
{
Assert(0);
return TF_E_NOLOCK;
}
pEnum = new CEnumUberRanges;
if (pEnum == NULL)
return E_OUTOFMEMORY;
if (!pEnum->_Init(_pic, pTargetRange, _cCicGUIDATOMs, _prgCicGUIDATOMs, _cAppGUIDs, _prgAppGUIDs))
{
pEnum->Release();
return E_FAIL;
}
*ppEnum = pEnum;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// GetType
//
//----------------------------------------------------------------------------
STDAPI CUberProperty::GetType(GUID *pguid)
{
if (pguid != NULL)
{
// tracker's don't support GetType
*pguid = GUID_NULL;
}
return E_NOTIMPL; // by design
}
//+---------------------------------------------------------------------------
//
// GetValue
//
//----------------------------------------------------------------------------
STDAPI CUberProperty::GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
{
CEnumPropertyValue *pEnumVal;
CRange *range;
SHARED_TFPROPERTYVAL_ARRAY *pPropVal;
HRESULT hr;
if (pvarValue == NULL)
return E_INVALIDARG;
QuickVariantInit(pvarValue);
if (pRange == NULL)
return E_INVALIDARG;
if ((range = GetCRange_NA(pRange)) == NULL)
return E_INVALIDARG;
if (!VerifySameContext(_pic, range))
return E_INVALIDARG;
if (!_IsValidEditCookie(ec, TF_ES_READ))
{
Assert(0);
return TF_E_NOLOCK;
}
hr = E_FAIL;
if ((pPropVal = SAA_New(_cCicGUIDATOMs + _cAppGUIDs)) == NULL)
goto Exit;
// get an array of app values
if (FillAppValueArray(_pic->_GetTSI(), range, pPropVal->rgAttrVals, _cAppGUIDs, _prgAppGUIDs) != S_OK)
goto Exit;
// get an array of cic values
FillCicValueArray(_pic, range, pPropVal->rgAttrVals + _cAppGUIDs, _cCicGUIDATOMs, _prgCicGUIDATOMs);
// stick them in an enum
if ((pEnumVal = new CEnumPropertyValue(pPropVal)) == NULL)
goto Exit;
pvarValue->vt = VT_UNKNOWN;
pvarValue->punkVal = pEnumVal;
hr = S_OK;
Exit:
if (pPropVal != NULL)
{
SAA_Release(pPropVal);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// GetContext
//
// perf: identical to CAppProperty::GetContext....move to base class?
//----------------------------------------------------------------------------
STDAPI CUberProperty::GetContext(ITfContext **ppContext)
{
if (ppContext == NULL)
return E_INVALIDARG;
*ppContext = _pic;
(*ppContext)->AddRef();
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CInputContext
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// TrackProperties
//
//----------------------------------------------------------------------------
STDAPI CInputContext::TrackProperties(const GUID **pguidProp, ULONG cProp, const GUID **pguidAppProp, ULONG cAppProp, ITfReadOnlyProperty **ppPropX)
{
CUberProperty *pup;
if (ppPropX == NULL)
return E_INVALIDARG;
*ppPropX = NULL;
if (pguidProp == NULL && cProp > 0)
return E_INVALIDARG;
if (pguidAppProp == NULL && cAppProp > 0)
return E_INVALIDARG;
if (!_IsConnected())
return TF_E_DISCONNECTED;
if ((pup = new CUberProperty(this)) == NULL)
return E_OUTOFMEMORY;
if (!pup->_Init(cProp, pguidProp, cAppProp, pguidAppProp))
{
pup->Release();
return E_OUTOFMEMORY;
}
*ppPropX = pup;
return S_OK;
}