/* * @doc INTERNAL * * @module _RUNPTR.H -- Text run and run pointer class defintion | * * Original Author: <nl> * Christian Fortini * * History: <nl> * 6/25/95 alexgo Commenting and Cleanup * * Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. */ #ifndef _RUNPTR_H #define _RUNPTR_H #include "_array.h" #include "_doc.h" typedef CArray<CTxtRun> CRunArray; /* * CRunPtrBase * * @class Base run pointer functionality. Keeps a position within an array * of text runs. * * @devnote Run pointers go through three different possible states : * * NULL: there is no data and no array (frequently a startup condition) <nl> * <mf CRunPtrBase::SetRunArray> will transition from this state to * the Empty state. It is typically up to the derived class to * define when that method should be called. IsValid() fails. <nl> * * <md CRunPtrBase::_pRuns> == NULL <nl> * <md CRunPtrBase::_iRun> == 0 <nl> * <md CRunPtrBase::_ich> == 0 <nl> * * Empty: an array class exists, but there is no data (can happen if all * of the elements in the array are deleted). IsValid() fails.<nl> * <md CRunPtrBase::_pRuns> != NULL <nl> * <md CRunPtrBase::_iRun> == 0 <nl> * <md CRunPtrBase::_ich> <gt>= 0 <nl> * <md CRunPtrBase::_pRuns-<gt>Count()> == 0 <nl> * * Normal: the array class exists and has data; IsValid() succeeds and * <md CRunPtrBase::_pRuns-<gt>Elem[] is defined <nl> * <md CRunPtrBase::_pRuns> != NULL <nl> * <md CRunPtrBase::_iRun> >= 0 <nl> * <md CRunPtrBase::_ich> >= 0 <nl> * <md _pRuns>-<gt>Count() > 0 <nl> * * Note that in order to support the empty and normal states, the actual * array element at <md CRunPtrBase::_iRun> must be explicitly fetched in * any method that may need it. * * Currently, there is no way to transition to the NULL state from any of * the other states. If we needed to, we could support that by explicitly * fetching the array from the document on demand. * * Note that only <md CRunPtrBase::_iRun> is kept. We could also keep * a pointer to the actual run (i.e. _pRun). Earlier versions of this * engine did in fact do this. I've opted to not do this for several * reasons: <nl> * 1. If IsValid(), _pRun is *always* available by calling Elem(_iRun). * Therefore, there is nominally no need to keep both _iRun and _pRun.<nl> * 2. Run pointers are typically used to either just move around * and then fetch data or move and fetch data every time (like during * a measuring loop). In the former case, there is no need to always * bind _pRun; you can just do it on demand. In the latter case, the * two models are equivalent. */ class CRunPtrBase { friend class CDisplayML; friend class CDisplaySL; //@access Public methods public: #ifdef DEBUG BOOL Invariant() const; //@cmember Invariant tests void ValidatePtr(void *pRun) const; //@cmember Validate <p pRun> LONG CalcTextLength() const; //@cmember Get total cch in runs #define VALIDATE_PTR(pRun) ValidatePtr(pRun) #else #define VALIDATE_PTR(pRun) #endif // DEBUG CRunPtrBase(CRunArray *pRuns); //@cmember Constructor CRunPtrBase(CRunPtrBase& rp); //@cmember Constructor // Run Control void SetRunArray(CRunArray *pRuns) //@cmember Set run array for this { // run ptr _pRuns = pRuns; } BOOL SetRun(LONG iRun, LONG ich); //@cmember Set this runptr to run // <p iRun> & char offset <p ich> BOOL NextRun(); //@cmember Advance to next run BOOL PrevRun(); //@cmember Go back to prev run BOOL ChgRun(LONG cRun) //@cmember Move <p cRun> runs { // returning TRUE if successful return SetRun(_iRun + cRun, 0); } //@cmember Count <p cRun> runs LONG CountRuns(LONG &cRun, // returning cch counted and LONG cchMax, // updating <p cRun> LONG cp, LONG cchText) const; //@cmember Find run range limits void FindRun (LONG *pcpMin, LONG *pcpMost, LONG cpMin, LONG cch, LONG cchText) const; CTxtRun * GetRun(LONG cRun) const; //@cmember Retrieve run element at // offset <p cRun> from this run LONG Count() const //@cmember Get count of runs { return _pRuns->Count(); } BOOL SameRuns(CRunPtrBase *prp) //@cmember Return TRUE iff same runs { return _pRuns == prp->_pRuns; } BOOL SameRun(CRunPtrBase *prp) { return SameRuns(prp) && _iRun == prp->_iRun; } // Character position control //@cmember Set cp for this run ptr = <p cp> LONG BindToCp(LONG cp, LONG cchText = tomForward); LONG CalculateCp() const;//@cmember Add _cch's up to _iRun, _ich LONG Move(LONG cch); //@cmember Move cp by <p cch> chars void AdjustBackward(); //@cmember If on the edge of two runs, // adjust to end of left (previous) run void AdjustForward(); //@cmember If at the edge of two runs, // adjust to start of right (next) run LONG GetIch() const //@cmember Return <md CRunPtrBase::_ich> {Assert(IsValid()); return _ich;} LONG GetIRun() const //@cmember Return <md CRunPtrBase::_iRun> {Assert(IsValid()); return _iRun;} void SetIch(LONG ich) //@cmember Set <md CRunPtrBase::_ich> {Assert(IsValid()); _ich = ich;} LONG GetCchLeft() const; //@cmember Return GetRun(0)->_cch - GetIch() inline BOOL IsValid() const //@cmember Return FALSE if run ptr is in { // empty or NULL states. TRUE otherwise return _pRuns && _pRuns->Count(); } void SetToNull(); //@cmember Clears data from run pointer //@access Protected Data protected: CRunArray * _pRuns; //@cmember Pointer to CTxtRun array LONG _iRun; //@cmember Index of current run in array LONG _ich; //@cmember Char offset inside current run }; /* * CRunPtr (template) * * @class a template over CRunPtrBase allowing for type-safe versions of * run pointers * * @tcarg class | CElem | run array class to be used * * @base public | CRunPtrBase */ template <class CElem> class CRunPtr : public CRunPtrBase { public: CRunPtr (void) //@cmember Constructor : CRunPtrBase (0) {} CRunPtr (CRunArray *pRuns) //@cmember Constructor : CRunPtrBase (pRuns) {} CRunPtr (CRunPtrBase& rp) //@cmember Constructor : CRunPtrBase (rp) {} // Array management CElem * Add (LONG cRun, LONG *pielIns) //@cmember Add <p cRun> { // elements at end of array return (CElem *)_pRuns->Add(cRun, pielIns); } CElem * Insert (LONG cRun) //@cmember Insert <p cRun> { // elements at current pos return (CElem *)_pRuns->Insert(_iRun, cRun); } void Remove (LONG cRun) //@cmember Remove <p cRun> { // elements at current pos _pRuns->Remove (_iRun, cRun); } //@cmember Replace <p cRun> elements // at current position with those // from <p parRun> BOOL Replace (LONG cRun, CArrayBase *parRun) { return _pRuns->Replace(_iRun, cRun, parRun); } CElem * Elem(LONG iRun) const //@cmember Get ptr to run <p iRun> { return (CElem *)_pRuns->Elem(iRun); } CElem * GetRun(LONG cRun) const //@cmember Get ptr <p cRun> runs { // away from current run return Elem(_iRun + cRun); } void IncPtr(CElem *&pRun) const //@cmember Increment ptr <p pRun> { VALIDATE_PTR(pRun); // Allow invalid ptr after ++ for pRun++; // for loops } CElem * GetPtr(CElem *pRun, LONG cRun) const//@cmember Get ptr <p cRun> { // runs away from ptr <p pRun> VALIDATE_PTR(pRun + cRun); return pRun + cRun; } }; #endif