// // rmcoll.cpp // // Render markup/collections. // #include "private.h" #include "dam.h" #include "saa.h" #include "strary.h" #include "ic.h" #include "attr.h" #include "range.h" #include "immxutil.h" #include "rprop.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CRenderMarkupCollection // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CRenderMarkupCollection::CRenderMarkupCollection() { // always add GUID_PROP_ATTRIBUTE at index 0 if (!_rgGUIDAtom.Append(1)) return; if (!_rgOther.Append(1)) { _rgGUIDAtom.Clear(); return; } MyRegisterGUID(GUID_PROP_ATTRIBUTE, _rgGUIDAtom.GetPtr(0)); _rgOther.GetPtr(0)->uPriority = TF_DA_PRIORITY_HIGHEST; _rgOther.GetPtr(0)->gaTip = g_gaSystem; } //+--------------------------------------------------------------------------- // // _Advise // //---------------------------------------------------------------------------- void CRenderMarkupCollection::_Advise(ITfTextInputProcessor *tip, TfGuidAtom gaTip) { ITfDisplayAttributeCollectionProvider *pProvider; ULONG uCount; TF_DA_PROPERTY rgProperty[8]; int i; int iOldCount; int iOld; int iNew; if (tip->QueryInterface(IID_ITfDisplayAttributeCollectionProvider, (void **)&pProvider) != S_OK) return; if (pProvider->GetCollection(ARRAYSIZE(rgProperty), rgProperty, &uCount) != S_OK || uCount == 0) goto Exit; iOldCount = _rgGUIDAtom.Count(); Assert(iOldCount == _rgOther.Count()); if (!_rgGUIDAtom.Append(uCount)) goto Exit; if (!_rgOther.Append(uCount)) { _rgGUIDAtom.Remove(iOldCount, uCount); goto Exit; } // merge the new guids with the old // nb: we assume rgProperty is sorted iNew = uCount-1; iOld = iOldCount-1; for (i=iNew + iOld + 1; i>=0; i--) { // nb: we put new GUIDs with same priority as existing GUIDs lower in the list // this makes sure that GUID_PROP_ATTRIBUTE is always at index 0, and keeps // existing rendering consistent (no change on screen of existing markup) if (iNew >= 0 && rgProperty[iNew].uPriority >= _rgOther.GetPtr(iOld)->uPriority) { MyRegisterGUID(rgProperty[iNew].guidProperty, _rgGUIDAtom.GetPtr(i)); _rgOther.GetPtr(i)->uPriority = rgProperty[iNew].uPriority; _rgOther.GetPtr(i)->gaTip = gaTip; iNew--; } else { *_rgGUIDAtom.GetPtr(i) = *_rgGUIDAtom.GetPtr(iOld); *_rgOther.GetPtr(i) = *_rgOther.GetPtr(iOld); iOld--; } } Exit: pProvider->Release(); } //+--------------------------------------------------------------------------- // // _Unadvise // //---------------------------------------------------------------------------- void CRenderMarkupCollection::_Unadvise(TfGuidAtom gaTip) { int iOldCount; int iNewCount; int i; int iDst; iOldCount = _rgGUIDAtom.Count(); iNewCount = 0; iDst = -1; for (i=0; igaTip == gaTip) { if (iDst == -1) { iDst = i; } } else if (iDst != -1) { *_rgGUIDAtom.GetPtr(iDst) = *_rgGUIDAtom.GetPtr(i); *_rgOther.GetPtr(iDst) = *_rgOther.GetPtr(i); iDst++; iNewCount++; } } if (iDst != -1) { _rgGUIDAtom.Remove(iDst, iOldCount - iDst); _rgOther.Remove(iDst, iOldCount - iDst); } Assert(_rgGUIDAtom.Count() == _rgOther.Count()); } //+--------------------------------------------------------------------------- // // _IsInCollection // //---------------------------------------------------------------------------- BOOL CRenderMarkupCollection::_IsInCollection(REFGUID rguidProperty) { TfGuidAtom tfGuidAtom; int i; if (_rgGUIDAtom.Count() == 0) return FALSE; MyRegisterGUID(rguidProperty, &tfGuidAtom); for (i=0; i<_rgGUIDAtom.Count(); i++) { if (*_rgGUIDAtom.GetPtr(i) == tfGuidAtom) return TRUE; } return FALSE; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CEnumRenderingMarkup // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// class CEnumRenderingMarkup : public IEnumTfRenderingMarkup, public CComObjectRootImmx { public: CEnumRenderingMarkup() { Dbg_MemSetThisNameIDCounter(TEXT("CEnumRenderingMarkup"), PERF_UBERPROP_COUNTER); } ~CEnumRenderingMarkup(); BEGIN_COM_MAP_IMMX(CEnumRenderingMarkup) COM_INTERFACE_ENTRY(IEnumTfRenderingMarkup) END_COM_MAP_IMMX() IMMX_OBJECT_IUNKNOWN_FOR_ATL() BOOL _Init(DWORD dwFlags, CRange *pRangeCover, CInputContext *pContext); // IEnumTfRenderingMarkup STDMETHODIMP Clone(IEnumTfRenderingMarkup **ppClone); STDMETHODIMP Next(ULONG ulCount, TF_RENDERINGMARKUP *rgMarkup, ULONG *pcFetched); STDMETHODIMP Reset(); STDMETHODIMP Skip(ULONG ulCount); private: int _iCur; CSharedAnchorArray *_prgAnchors; CSharedStructArray *_prgValues; CInputContext *_pContext; DBG_ID_DECLARE; }; DBG_ID_INSTANCE(CEnumRenderingMarkup); //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CEnumRenderingMarkup::~CEnumRenderingMarkup() { if (_prgAnchors != NULL) { _prgAnchors->_Release(); } if (_prgValues != NULL) { _prgValues->_Release(); } _pContext->Release(); } //+--------------------------------------------------------------------------- // // LookupProperty // //---------------------------------------------------------------------------- BOOL LookupProperty(CInputContext *pContext, ITfDisplayAttributeMgr *pDisplayAttrMgr, TfGuidAtom tfGuidAtom, IAnchor *paStart, IAnchor *paEnd, TF_DISPLAYATTRIBUTE *ptfAttrInfoNext) { CProperty *pProperty; ITfDisplayAttributeInfo *pDisplayAttrInfo; VARIANT varValue; GUID guidValue; BOOL fRet; // get the property matching the GUID if ((pProperty = pContext->_FindProperty(tfGuidAtom)) == NULL) return FALSE; // get the GUID value of the property if (pProperty->_GetDataInternal(paStart, paEnd, &varValue) != S_OK) // perf: don't really need paEnd return FALSE; Assert(varValue.vt == VT_I4); // should be a GUIDATOM if (MyGetGUID(varValue.lVal, &guidValue) != S_OK) return FALSE; // translate the GUID to a display attribute if (pDisplayAttrMgr->GetDisplayAttributeInfo(guidValue, &pDisplayAttrInfo, NULL) != S_OK) return FALSE; fRet = (pDisplayAttrInfo->GetAttributeInfo(ptfAttrInfoNext) == S_OK); pDisplayAttrInfo->Release(); return fRet; } //+--------------------------------------------------------------------------- // // _Init // //---------------------------------------------------------------------------- BOOL CEnumRenderingMarkup::_Init(DWORD dwFlags, CRange *pRangeCover, CInputContext *pContext) { CDisplayAttributeMgr *pDisplayAttrMgr; CRenderMarkupCollection *pMarkupCollection; int i; int j; TF_DISPLAYATTRIBUTE *ptfAttrInfo; TF_DISPLAYATTRIBUTE tfAttrInfoNext; BOOL fNeedLine; BOOL fNeedText; BOOL fRet; ULONG uCount; const TfGuidAtom *pAtoms; Assert(_iCur == 0); Assert(_pContext == NULL); Assert(_prgAnchors == NULL); Assert(_prgValues == NULL); pDisplayAttrMgr = CDisplayAttributeMgr::_GetThis(); if (pDisplayAttrMgr == NULL) { Assert(0); // ITfThreadMgr::Activate should ensure the singleton is initialized in tls return FALSE; } fRet = FALSE; pMarkupCollection = pDisplayAttrMgr->_GetMarkupCollection(); // find the cicero property transitions if (dwFlags & TF_GRM_INCLUDE_PROPERTY) { uCount = pMarkupCollection->_Count(); pAtoms = pMarkupCollection->_GetAtoms(); } else { // skip GUID_PROP_ATTRIBUTE at index 0 Assert(pMarkupCollection->_Count() >= 1); uCount = pMarkupCollection->_Count() - 1; pAtoms = pMarkupCollection->_GetAtoms() + 1; } _prgAnchors = CalcCicPropertyTrackerAnchors(pContext, pRangeCover->_GetStart(), pRangeCover->_GetEnd(), pMarkupCollection->_Count(), pMarkupCollection->_GetAtoms()); if (_prgAnchors == NULL) goto Exit; Assert(_prgAnchors->Count() > 0); // we should get at least the pRangeCover start anchor if ((_prgValues = new CSharedStructArray) == NULL) goto Exit; if (_prgAnchors->Count() > 1) // Append(0) will return NULL if the array is empty { // which is fine, but we don't want to return failure in that case (empty range => empty enum) if (!_prgValues->Append(_prgAnchors->Count()-1)) goto Exit; } // now calculate the TF_DISPLAYATTRIBUTE for each span for (i=0; i<_prgAnchors->Count()-1; i++) { ptfAttrInfo = _prgValues->GetPtr(i); memset(ptfAttrInfo, 0, sizeof(*ptfAttrInfo)); ptfAttrInfo->bAttr = TF_ATTR_OTHER; fNeedLine = TRUE; fNeedText = TRUE; // examine property values over the single span // index 0 is always GUID_PROP_ATTRIBUTE, only include it if the TF_GRM_INCLUDE_PROPERTY is set j = (dwFlags & TF_GRM_INCLUDE_PROPERTY) ? 0 : 1; for (; j_Count(); j++) { // get the property matching the GUID if (!LookupProperty(pContext, pDisplayAttrMgr, pMarkupCollection->_GetAtom(j), _prgAnchors->Get(i), _prgAnchors->Get(i+1), &tfAttrInfoNext)) continue; // we got one if (fNeedText && (tfAttrInfoNext.crText.type != TF_CT_NONE || tfAttrInfoNext.crBk.type != TF_CT_NONE)) { ptfAttrInfo->crText = tfAttrInfoNext.crText; ptfAttrInfo->crBk = tfAttrInfoNext.crBk; fNeedText = FALSE; } if (fNeedLine && tfAttrInfoNext.lsStyle != TF_LS_NONE) { ptfAttrInfo->lsStyle = tfAttrInfoNext.lsStyle; ptfAttrInfo->crLine = tfAttrInfoNext.crLine; ptfAttrInfo->fBoldLine = tfAttrInfoNext.fBoldLine; fNeedLine = FALSE; } // we can stop looking at this span if everything lower in the z-order is blocked if (j == 0 && (!fNeedText || !fNeedLine)) break; // GUID_PROP_ATTRIBUTE is never masked with anything else if (!fNeedText && !fNeedLine) break; // couldn't mask in any more attributes } } _pContext = pContext; _pContext->AddRef(); fRet = TRUE; Exit: return fRet; } //+--------------------------------------------------------------------------- // // Clone // //---------------------------------------------------------------------------- STDAPI CEnumRenderingMarkup::Clone(IEnumTfRenderingMarkup **ppEnum) { CEnumRenderingMarkup *pClone; if (ppEnum == NULL) return E_INVALIDARG; *ppEnum = NULL; if ((pClone = new CEnumRenderingMarkup) == NULL) return E_OUTOFMEMORY; pClone->_iCur = _iCur; pClone->_prgAnchors = _prgAnchors; pClone->_prgAnchors->_AddRef(); pClone->_prgValues = _prgValues ; pClone->_prgValues->_AddRef(); pClone->_pContext = _pContext; pClone->_pContext->AddRef(); *ppEnum = pClone; return S_OK; } //+--------------------------------------------------------------------------- // // Next // //---------------------------------------------------------------------------- STDAPI CEnumRenderingMarkup::Next(ULONG ulCount, TF_RENDERINGMARKUP *rgMarkup, ULONG *pcFetched) { ULONG cFetched; CRange *range; IAnchor *paPrev; IAnchor *pa; int iCurOld; if (pcFetched == NULL) { pcFetched = &cFetched; } *pcFetched = 0; iCurOld = _iCur; if (ulCount > 0 && rgMarkup == NULL) return E_INVALIDARG; // we should always have at least one anchor (one anchor => empty range for enum, nothing to enum) Assert(_prgAnchors->Count() >= 1); paPrev = _prgAnchors->Get(_iCur); while (_iCur < _prgAnchors->Count()-1 && *pcFetched < ulCount) { pa = _prgAnchors->Get(_iCur+1); if ((range = new CRange) == NULL) break; if (!range->_InitWithDefaultGravity(_pContext, COPY_ANCHORS, paPrev, pa)) { range->Release(); break; } // we should never be returning empty ranges, since currently this base // class is only used for property enums and property spans are never // empty. // Similarly, paPrev should always precede pa. Assert(CompareAnchors(paPrev, pa) < 0); rgMarkup->pRange = (ITfRangeAnchor *)range; rgMarkup->tfDisplayAttr = *_prgValues->GetPtr(_iCur); rgMarkup++; *pcFetched = *pcFetched + 1; _iCur++; paPrev = pa; } return *pcFetched == ulCount ? S_OK : S_FALSE; } //+--------------------------------------------------------------------------- // // Reset // //---------------------------------------------------------------------------- STDAPI CEnumRenderingMarkup::Reset() { _iCur = 0; return S_OK; } //+--------------------------------------------------------------------------- // // Skip // //---------------------------------------------------------------------------- STDAPI CEnumRenderingMarkup::Skip(ULONG ulCount) { _iCur += ulCount; return (_iCur > _prgValues->Count()) ? S_FALSE : S_OK; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CDisplayAttributeMgr // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // EnumCollections // //---------------------------------------------------------------------------- STDAPI CDisplayAttributeMgr::EnumCollections(IEnumTfCollection **ppEnum) { return E_NOTIMPL; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CInputContext // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // GetRenderingMarkup // //---------------------------------------------------------------------------- STDAPI CInputContext::GetRenderingMarkup(TfEditCookie ec, DWORD dwFlags, ITfRange *pRangeCover, IEnumTfRenderingMarkup **ppEnum) { CEnumRenderingMarkup *pEnum; CRange *range; if (ppEnum == NULL) return E_INVALIDARG; *ppEnum = NULL; if (!_IsValidEditCookie(ec, TF_ES_READ)) return TF_E_NOLOCK; if (dwFlags & ~TF_GRM_INCLUDE_PROPERTY) return E_INVALIDARG; if (pRangeCover == NULL) return E_INVALIDARG; if ((range = GetCRange_NA(pRangeCover)) == NULL) return E_INVALIDARG; if (!_IsConnected()) return TF_E_DISCONNECTED; if ((pEnum = new CEnumRenderingMarkup) == NULL) return E_OUTOFMEMORY; if (!pEnum->_Init(dwFlags, range, this)) { pEnum->Release(); return E_FAIL; } *ppEnum = pEnum; return S_OK; } //+--------------------------------------------------------------------------- // // FindNextRenderingMarkup // //---------------------------------------------------------------------------- STDAPI CInputContext::FindNextRenderingMarkup(TfEditCookie ec, DWORD dwFlags, ITfRange *pRangeQuery, TfAnchor tfAnchorQuery, ITfRange **ppRangeFound, TF_RENDERINGMARKUP *ptfRenderingMarkup) { return E_NOTIMPL; }