documentsequencetextpointer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Documents / documentsequencetextpointer.cs / 1 / documentsequencetextpointer.cs

                            //---------------------------------------------------------------------------- 
// 
//      Copyright (C) 2004 by Microsoft Corporation.  All rights reserved.
// 
// 
// Description:
//      DocumentSequenceTextPointer is an implementation of ITextPointer/ITextPointer 
//      for FixedDocumentSequence. It is the base class for DocumentSequenceTextPointer and 
//      DocumentSequenceTextPointer.
// 
// History:
//      07/12/2004 - Zhenbin Xu (ZhenbinX) - Created.
//
//--------------------------------------------------------------------------- 

#pragma warning disable 1634, 1691 // To enable presharp warning disables (#pragma suppress) below. 
 
namespace System.Windows.Documents
{ 
    using MS.Internal.Documents;
    using MS.Utility;
    using MS.Internal;
    using System.Windows; 
    using System;
    using System.Diagnostics; 
 

    ///  
    /// DocumentSequenceTextPointer is an implementation of ITextPointer for FixedDocumentSequence
    /// 
    internal sealed class DocumentSequenceTextPointer : ContentPosition, ITextPointer
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 
        #region Constructors
        // Ctor always set mutable flag to false
        internal DocumentSequenceTextPointer(ChildDocumentBlock childBlock, ITextPointer childPosition)
        { 
            Debug.Assert(childBlock != null);
            Debug.Assert(childPosition != null); 
            _childBlock = childBlock; 
            _childTp = childPosition;
        } 
        #endregion Constructors

        //------------------------------------------------------
        // 
        //  Public Methods
        // 
        //----------------------------------------------------- 
        #region TextPointer Methods
 
        /// 
        /// 
        /// 
        void ITextPointer.SetLogicalDirection(LogicalDirection direction) 
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 
            _childTp.SetLogicalDirection(direction); 
        }
 
        /// 
        /// 
        /// 
        int ITextPointer.CompareTo(ITextPointer position) 
        {
            return DocumentSequenceTextPointer.CompareTo(this, position); 
        } 

        int ITextPointer.CompareTo(StaticTextPointer position) 
        {
            return ((ITextPointer)this).CompareTo((ITextPointer)position.Handle0);
        }
 
        /// 
        ///  
        ///  
        int ITextPointer.GetOffsetToPosition(ITextPointer position)
        { 
            return DocumentSequenceTextPointer.GetOffsetToPosition(this, position);
        }

        ///  
        /// 
        ///  
        TextPointerContext ITextPointer.GetPointerContext(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetPointerContext(this, direction); 
        }

        /// 
        ///  
        /// 
        /// Return 0 if non-text run 
        int ITextPointer.GetTextRunLength(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetTextRunLength(this, direction); 
        }

        // 
        string ITextPointer.GetTextInRun(LogicalDirection direction) 
        {
            return TextPointerBase.GetTextInRun(this, direction); 
        } 

        ///  
        /// 
        /// 
        /// Only reutrn uninterrupted runs of text
        int ITextPointer.GetTextInRun(LogicalDirection direction, char[] textBuffer, int startIndex, int count) 
        {
            return DocumentSequenceTextPointer.GetTextInRun(this, direction, textBuffer, startIndex, count); 
        } 

        ///  
        /// 
        /// 
        /// Return null if the embedded object does not exist
        object ITextPointer.GetAdjacentElement(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetAdjacentElement(this, direction); 
        } 

        ///  
        /// 
        /// 
        /// Return null if no TextElement in the direction
        Type ITextPointer.GetElementType(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetElementType(this, direction); 
        } 

        ///  
        /// 
        /// 
        bool ITextPointer.HasEqualScope(ITextPointer position)
        { 
            return DocumentSequenceTextPointer.HasEqualScope(this, position);
        } 
 

        ///  
        /// 
        /// 
        /// return property values even if there is no scoping element
        object ITextPointer.GetValue(DependencyProperty property) 
        {
            return DocumentSequenceTextPointer.GetValue(this, property); 
        } 

        ///  
        /// 
        /// 
        /// Throws InvalidOperationException if there is no scoping element
        object ITextPointer.ReadLocalValue(DependencyProperty property) 
        {
            return DocumentSequenceTextPointer.ReadLocalValue(this, property); 
        } 

        ///  
        /// 
        /// 
        /// Returns an empty enumerator if there is no scoping element
        LocalValueEnumerator ITextPointer.GetLocalValueEnumerator() 
        {
            return DocumentSequenceTextPointer.GetLocalValueEnumerator(this); 
        } 

        ITextPointer ITextPointer.CreatePointer() 
        {
            return DocumentSequenceTextPointer.CreatePointer(this);
        }
 
        // Unoptimized CreateStaticPointer implementation.
        // Creates a simple wrapper for an ITextPointer instance. 
        StaticTextPointer ITextPointer.CreateStaticPointer() 
        {
            return new StaticTextPointer(((ITextPointer)this).TextContainer, ((ITextPointer)this).CreatePointer()); 
        }

        ITextPointer ITextPointer.CreatePointer(int distance)
        { 
            return DocumentSequenceTextPointer.CreatePointer(this, distance);
        } 
 
        ITextPointer ITextPointer.CreatePointer(LogicalDirection gravity)
        { 
            return DocumentSequenceTextPointer.CreatePointer(this, gravity);
        }

        ///  
        /// 
        ///  
        ITextPointer ITextPointer.CreatePointer(int distance, LogicalDirection gravity) 
        {
            return DocumentSequenceTextPointer.CreatePointer(this, distance, gravity); 
        }

        // 
        void ITextPointer.Freeze() 
        {
            _isFrozen = true; 
        } 

        ///  
        /// 
        /// 
        ITextPointer ITextPointer.GetFrozenPointer(LogicalDirection logicalDirection)
        { 
            return TextPointerBase.GetFrozenPointer(this, logicalDirection);
        } 
 
        /// 
        /// Inserts text at a specified position. 
        /// 
        /// 
        /// Text to insert.
        ///  
        void ITextPointer.InsertTextInRun(string textData)
        { 
            throw new InvalidOperationException(SR.Get(SRID.DocumentReadOnly)); 
        }
 
        /// 
        /// Removes content covered by a pair of positions.
        /// 
        ///  
        /// Position following the last symbol to delete.  endPosition must be
        /// scoped by the same text element as startPosition. 
        ///  
        void ITextPointer.DeleteContentToPosition(ITextPointer limit)
        { 
            throw new InvalidOperationException(SR.Get(SRID.DocumentReadOnly));
        }

        // Candidate for replacing MoveToNextContextPosition for immutable TextPointer model 
        ITextPointer ITextPointer.GetNextContextPosition(LogicalDirection direction)
        { 
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            if (pointer.MoveToNextContextPosition(direction))
            { 
                pointer.Freeze();
            }
            else
            { 
                pointer = null;
            } 
            return pointer; 
        }
 
        // Candidate for replacing MoveToInsertionPosition for immutable TextPointer model
        ITextPointer ITextPointer.GetInsertionPosition(LogicalDirection direction)
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            pointer.MoveToInsertionPosition(direction);
            pointer.Freeze(); 
            return pointer; 
        }
 
        // Returns the closest insertion position, treating all unicode code points
        // as valid insertion positions.  A useful performance win over
        // GetNextInsertionPosition when only formatting scopes are important.
        ITextPointer ITextPointer.GetFormatNormalizedPosition(LogicalDirection direction) 
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            TextPointerBase.MoveToFormatNormalizedPosition(pointer, direction); 
            pointer.Freeze();
            return pointer; 
        }

        // Candidate for replacing MoveToNextInsertionPosition for immutable TextPointer model
        ITextPointer ITextPointer.GetNextInsertionPosition(LogicalDirection direction) 
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            if (pointer.MoveToNextInsertionPosition(direction)) 
            {
                pointer.Freeze(); 
            }
            else
            {
                pointer = null; 
            }
            return pointer; 
        } 

        ///  
        bool ITextPointer.ValidateLayout()
        {
            return TextPointerBase.ValidateLayout(this, ((ITextPointer)this).TextContainer.TextView);
        } 

        #endregion TextPointer Methods 
 
        #region Public Methods
#if DEBUG 
        /// 
        /// Debug only ToString override.
        /// 
        public override string ToString() 
        {
            return DocumentSequenceTextPointer.ToString(this); 
        } 
#endif // DEBUG
        #endregion Public Methods 



        //------------------------------------------------------ 
        //
        //  Public Properties 
        // 
        //------------------------------------------------------
 
        #region TextPointer Properties

        // 
        Type ITextPointer.ParentType 
        {
            get 
            { 
                return DocumentSequenceTextPointer.GetElementType(this);
            } 
        }

        /// 
        ///  
        /// 
        ITextContainer ITextPointer.TextContainer 
        { 
            get { return this.AggregatedContainer; }
        } 

        // 
        bool ITextPointer.HasValidLayout
        { 
            get
            { 
                return (((ITextPointer)this).TextContainer.TextView != null && 
                        ((ITextPointer)this).TextContainer.TextView.IsValid &&
                        ((ITextPointer)this).TextContainer.TextView.Contains(this)); 
            }
        }

        //  
        bool ITextPointer.IsAtCaretUnitBoundary
        { 
            get 
            {
                Invariant.Assert(((ITextPointer)this).HasValidLayout); 
                ITextView textView = ((ITextPointer)this).TextContainer.TextView;
                bool isAtCaretUnitBoundary = textView.IsAtCaretUnitBoundary(this);

                if (!isAtCaretUnitBoundary && ((ITextPointer)this).LogicalDirection == LogicalDirection.Backward) 
                {
                    // In MIL Text and TextView worlds, a position at trailing edge of a newline (with backward gravity) 
                    // is not an allowed caret stop. 
                    // However, in TextPointer world we must allow such a position to be a valid insertion position,
                    // since it breaks textrange normalization for empty ranges. 
                    // Hence, we need to check for TextView.IsAtCaretUnitBoundary in reverse direction below.

                    ITextPointer positionForwardGravity = ((ITextPointer)this).CreatePointer(LogicalDirection.Forward);
                    isAtCaretUnitBoundary = textView.IsAtCaretUnitBoundary(positionForwardGravity); 
                }
                return isAtCaretUnitBoundary; 
            } 
        }
 
        /// 
        /// 
        /// 
        LogicalDirection ITextPointer.LogicalDirection 
        {
            get 
            { 
                return _childTp.LogicalDirection;
            } 
        }

        bool ITextPointer.IsAtInsertionPosition
        { 
            get { return TextPointerBase.IsAtInsertionPosition(this); }
        } 
 
        // 
        bool ITextPointer.IsFrozen 
        {
            get
            {
                return _isFrozen; 
            }
        } 
 
        // 
        int ITextPointer.Offset 
        {
            get
            {
                return TextPointerBase.GetOffset(this); 
            }
        } 
 
        // Not implemented.
        int ITextPointer.CharOffset 
        {
            get
            {
                #pragma warning suppress 56503 
                throw new NotImplementedException();
            } 
        } 

        #endregion TextPointer Properties 

        //-----------------------------------------------------
        //
        //  Public Events 
        //
        //------------------------------------------------------ 
 
        //-----------------------------------------------------
        // 
        //  Internal Properties
        //
        //-----------------------------------------------------
 
        //-----------------------------------------------------
        // 
        //  Public Methods 
        //
        //------------------------------------------------------ 

        #region TextNavigator Methods

        ///  
        /// 
        ///  
        bool ITextPointer.MoveToNextContextPosition(LogicalDirection direction) 
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 
            return DocumentSequenceTextPointer.iScan(this, direction);
        }

 
        /// 
        ///  
        ///  
        int ITextPointer.MoveByOffset(int offset)
        { 
            if (_isFrozen) throw new InvalidOperationException(SR.Get(SRID.TextPositionIsFrozen));

            if (DocumentSequenceTextPointer.iScan(this, offset))
            { 
                return offset;
            } 
            else 
            {
                return 0; 
            }
        }

        ///  
        /// 
        ///  
        void ITextPointer.MoveToPosition(ITextPointer position) 
        {
            DocumentSequenceTextPointer tp = this.AggregatedContainer.VerifyPosition(position); 

            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            LogicalDirection gravity = this.ChildPointer.LogicalDirection; 
            this.ChildBlock = tp.ChildBlock;
            if (this.ChildPointer.TextContainer == tp.ChildPointer.TextContainer) 
            { 
                this.ChildPointer.MoveToPosition(tp.ChildPointer);
            } 
            else
            {
                this.ChildPointer = tp.ChildPointer.CreatePointer();
                this.ChildPointer.SetLogicalDirection(gravity); 
            }
        } 
 
        /// 
        ///  
        /// 
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 

            this.ChildPointer.MoveToElementEdge(edge); 
        } 

        //  
        int ITextPointer.MoveToLineBoundary(int count)
        {
            return TextPointerBase.MoveToLineBoundary(this, ((ITextPointer)this).TextContainer.TextView, count, true);
        } 

        //  
        Rect ITextPointer.GetCharacterRect(LogicalDirection direction) 
        {
            return TextPointerBase.GetCharacterRect(this, direction); 
        }

        bool ITextPointer.MoveToInsertionPosition(LogicalDirection direction)
        { 
            return TextPointerBase.MoveToInsertionPosition(this, direction);
        } 
 
        bool ITextPointer.MoveToNextInsertionPosition(LogicalDirection direction)
        { 
            return TextPointerBase.MoveToNextInsertionPosition(this, direction);
        }

        #endregion TextNavigator Methods 

        //----------------------------------------------------- 
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------

        #region Internal Properties
        internal DocumentSequenceTextContainer AggregatedContainer 
        {
            get { return _childBlock.AggregatedContainer; } 
        } 

 
        // Accessor to base class ChildBlock.
        internal ChildDocumentBlock ChildBlock
        {
            get 
            {
                return _childBlock; 
            } 
            set
            { 
                _childBlock = value;
            }
        }
 
        // Helper exposing base classes ChildPointer as an ITextPointer,
        // which is guaranteed safe, since we set its value in the ctor 
        // for this class. 
        internal ITextPointer ChildPointer
        { 
            get
            {
                return _childTp;
            } 
            set
            { 
                _childTp = value; 
                Debug.Assert(_childTp != null);
            } 
        }

#if DEBUG
        // Debug-only identifier. 
        private uint DebugId
        { 
            get 
            {
                return _debugId; 
            }
        }
#endif // DEBUG
 
        #endregion Internal Properties
 
        // ====================================================== 
        // Static part of a class
 
        // 
        // DocumentSequenceTextPointer is a static  class that is provided all the
        // common functions of ITextPointer/ITextNavigaor for DocumentSequence.
        // Since we don't have multiple inheritance, this is a way to share code between 
        // DocumentSequenceTextPointer and DocumentSequenceTextPointer.
        //  
 
        //-----------------------------------------------------
        // 
        //  Public Methods
         //
        //------------------------------------------------------
        #region TextPointer Methods 
        /// 
        ///  
        ///  
        public static int CompareTo(DocumentSequenceTextPointer thisTp, ITextPointer position)
        { 
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position);

            // Now do compare
            return xGapAwareCompareTo(thisTp, tp); 
        }
 
 
        /// 
        ///  
        /// 
        public static int GetOffsetToPosition(DocumentSequenceTextPointer thisTp, ITextPointer position)
        {
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); 

            int comp = xGapAwareCompareTo(thisTp, tp); 
            if (comp == 0) 
            {
                return 0; 
            }
            else if (comp <= 0)
            {
                return xGapAwareGetDistance(thisTp, tp); 
            }
            else 
            { 
                return -1 * xGapAwareGetDistance(tp, thisTp);
            } 
        }

        /// 
        ///  
        /// 
        public static TextPointerContext GetPointerContext(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyDirection(direction, "direction");
 
            return xGapAwareGetSymbolType(thisTp, direction);
        }

        ///  
        /// 
        ///  
        /// Return 0 if non-text run 
        public static int GetTextRunLength(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            ValidationHelper.VerifyDirection(direction, "direction");

            return thisTp.ChildPointer.GetTextRunLength(direction);
        } 

        ///  
        ///  
        /// 
        /// Only reutrn uninterrupted runs of text 
        public static int GetTextInRun(DocumentSequenceTextPointer thisTp, LogicalDirection direction, char[] textBuffer, int startIndex, int count)
        {
            ValidationHelper.VerifyDirection(direction, "direction");
 
            if (textBuffer == null)
            { 
                throw new ArgumentNullException("textBuffer"); 
            }
            if (startIndex < 0) 
            {
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "startIndex"));
            }
            if (startIndex > textBuffer.Length) 
            {
                throw new ArgumentException(SR.Get(SRID.StartIndexExceedsBufferSize, startIndex, textBuffer.Length)); 
            } 
            if (count < 0)
            { 
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "count"));
            }
            if (count > textBuffer.Length - startIndex)
            { 
                throw new ArgumentException(SR.Get(SRID.MaxLengthExceedsBufferSize, count, textBuffer.Length, startIndex));
            } 
 
            return thisTp.ChildPointer.GetTextInRun(direction, textBuffer, startIndex, count);
        } 

        /// 
        /// 
        ///  
        /// Return null if the embedded object does not exist
        public static object GetAdjacentElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyDirection(direction, "direction");
 
            return xGapAwareGetEmbeddedElement(thisTp, direction);
        }

        ///  
        /// 
        ///  
        /// Return null if no TextElement in the direction 
        public static Type GetElementType(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            ValidationHelper.VerifyDirection(direction, "direction");

            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction);
 
            return tp.ChildPointer.GetElementType(direction);
        } 
 
        /// 
        ///  
        /// 
        public static Type GetElementType(DocumentSequenceTextPointer thisTp)
        {
            return thisTp.ChildPointer.ParentType; 
        }
 
        ///  
        /// 
        ///  
        public static bool HasEqualScope(DocumentSequenceTextPointer thisTp, ITextPointer position)
        {
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position);
 
            if (thisTp.ChildPointer.TextContainer == tp.ChildPointer.TextContainer)
            { 
                return thisTp.ChildPointer.HasEqualScope(tp.ChildPointer); 
            }
            // The TextOM speced behavior is if both scopes are null, return true. 
            return thisTp.ChildPointer.ParentType == typeof(FixedDocument) && tp.ChildPointer.ParentType == typeof(FixedDocument);
        }

        ///  
        /// 
        ///  
        /// return property values even if there is no scoping element 
        public static object GetValue(DocumentSequenceTextPointer thisTp, DependencyProperty property)
        { 
            if (property == null)
            {
                throw new ArgumentNullException("property");
            } 

            return thisTp.ChildPointer.GetValue(property); 
        } 

        ///  
        /// 
        /// 
        /// Throws InvalidOperationException if there is no scoping element
        public static object ReadLocalValue(DocumentSequenceTextPointer thisTp, DependencyProperty property) 
        {
            if (property == null) 
            { 
                throw new ArgumentNullException("property");
            } 

            return thisTp.ChildPointer.ReadLocalValue(property);
        }
 
        /// 
        ///  
        ///  
        /// Returns an empty enumerator if there is no scoping element
        public static LocalValueEnumerator GetLocalValueEnumerator(DocumentSequenceTextPointer thisTp) 
        {
            return thisTp.ChildPointer.GetLocalValueEnumerator();
        }
 
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp)
        { 
            return CreatePointer(thisTp, 0, thisTp.ChildPointer.LogicalDirection); 
        }
 
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance)
        {
            return CreatePointer(thisTp, distance, thisTp.ChildPointer.LogicalDirection);
        } 

        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, LogicalDirection gravity) 
        { 
            return CreatePointer(thisTp, 0, gravity);
        } 

        /// 
        /// 
        ///  
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance, LogicalDirection gravity)
        { 
            ValidationHelper.VerifyDirection(gravity, "gravity"); 

            // Special case for common case of distance == 0 
            // to avoid calculating child container size, which
            // could be expansive especially in case where child
            // container requires virtualization.
            DocumentSequenceTextPointer newTp = new DocumentSequenceTextPointer(thisTp.ChildBlock, thisTp.ChildPointer.CreatePointer(gravity)); 
            if (distance != 0)
            { 
                if (!xGapAwareScan(newTp, distance)) 
                {
                    throw new ArgumentException(SR.Get(SRID.BadDistance), "distance"); 
                }
            }
            return newTp;
        } 

        #endregion TextPointer Methods 
 
        //-----------------------------------------------------
        // 
        //  Public Properties
        //
        //-----------------------------------------------------
 

        //----------------------------------------------------- 
        // 
        //  Public Events
        // 
        //------------------------------------------------------


        //----------------------------------------------------- 
        //
        //  Internal Methods 
        // 
        //------------------------------------------------------
 
        #region Internal Methods


        // Internal Method, input parameter contains TP that is not synced to generation 
        internal static bool iScan(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            bool moved = thisTp.ChildPointer.MoveToNextContextPosition(direction); 
            if (!moved)
            { 
                moved = xGapAwareScan(thisTp, (direction == LogicalDirection.Forward ? 1 : -1));
            }
            return moved;
        } 

 
        // Internal Method, input parameter contains TP that is not synced to generation 
        internal static bool iScan(DocumentSequenceTextPointer thisTp, int distance)
        { 
            return xGapAwareScan(thisTp, distance);
        }

#if DEBUG 
        // Allocate a unique debug-only ID as identifier.
        internal static uint GetDebugId() 
        { 
            return _debugIdCounter++;
        } 

        internal static string ToString(DocumentSequenceTextPointer thisTp)
        {
            return  (thisTp is DocumentSequenceTextPointer ? "DSTP" : "DSTN") 
                    + " Id=" + thisTp.DebugId
                    + " B=" + thisTp.ChildBlock.DebugId 
                    + " G=" + thisTp.ChildPointer.LogicalDirection 
                    ;
        } 
#endif
        #endregion Internal Methods

 
        //------------------------------------------------------
        // 
        //  Internal Property 
        //
        //----------------------------------------------------- 

        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
 
        #region Private Methods
        private static DocumentSequenceTextPointer xGetClingDSTP(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        {
            TextPointerContext context = thisTp.ChildPointer.GetPointerContext(direction);

            if (context != TextPointerContext.None) 
            {
                return thisTp; 
            } 

            ChildDocumentBlock block = thisTp.ChildBlock; 
            ITextPointer pointer = thisTp.ChildPointer;

            if (direction == LogicalDirection.Forward)
            { 
                while (context == TextPointerContext.None && !block.IsTail)
                { 
                    // get next block 
                    block = block.NextBlock;
                    // get start 
                    pointer = block.ChildContainer.Start;
                    context = pointer.GetPointerContext(direction);
                }
            } 
            else
            { 
                Debug.Assert(direction == LogicalDirection.Backward); 
                while (context == TextPointerContext.None && !block.IsHead)
                { 
                    // get next block
                    block = block.PreviousBlock;
                    // get start
                    pointer = block.ChildContainer.End; 
                    context = pointer.GetPointerContext(direction);
                } 
            } 

            return new DocumentSequenceTextPointer(block, pointer); 
        }


        //----------------------------------------------------------------------- 
        // Trusted Methods -- all positions are in valid blocks
        // 
        // Each ChildDocumentBlock pair is separated by a gap (DocumentBreak), 
        // which is surfaced as an embedded object. Besides the Head and Tail block,
        // each block is enclosed by two gap objects, one at each end of the 
        // TextContainer (Before TextContainer.Start and After TextContainer.End)
        //-----------------------------------------------------------------------

 
        private static TextPointerContext xGapAwareGetSymbolType(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction); 
            return tp.ChildPointer.GetPointerContext(direction);
        } 


        private static object xGapAwareGetEmbeddedElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction);
            return tp.ChildPointer.GetAdjacentElement(direction); 
        } 

 
        //  Intelligent compare routine that understands block gap
        //  Since there it is assumed that there is an invisible Gap
        //  object between adjancent two blocks, there is no position
        //  overlap. 
        private static int xGapAwareCompareTo(DocumentSequenceTextPointer thisTp, DocumentSequenceTextPointer tp)
        { 
            Debug.Assert(tp != null); 
            if ((object)thisTp == (object)tp)
            { 
                return 0;
            }

            ChildDocumentBlock thisBlock = thisTp.ChildBlock; 
            ChildDocumentBlock tpBlock = tp.ChildBlock;
 
            int comp = thisTp.AggregatedContainer.GetChildBlockDistance(thisBlock, tpBlock); 
            if (comp == 0)
            { 
                Debug.Assert(thisTp.ChildBlock.ChildContainer == tp.ChildBlock.ChildContainer);
                return thisTp.ChildPointer.CompareTo(tp.ChildPointer);
            }
            else if (comp < 0) 
            {
                // thisBlock is after tpBlock 
                return xUnseparated(tp, thisTp) ? 0 : 1; 
            }
            else 
            {
                // thisBlock is before tpBlock
                return xUnseparated(thisTp, tp) ? 0 : -1;
            } 
        }
 
        private static bool xUnseparated(DocumentSequenceTextPointer tp1, DocumentSequenceTextPointer tp2) 
        {
            // tp1 is before tp2, check both are at edge of documents 
            //check nothing of any length between them
            if (tp1.ChildPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None ||
                tp2.ChildPointer.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.None)
            { 
                return false;
            } 
 
            ChildDocumentBlock block = tp1.ChildBlock.NextBlock;
 
            while (block != tp2.ChildBlock)
            {
                if (block.ChildContainer.Start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None)
                { 
                    return false;
                } 
 
                block = block.NextBlock;
            } 

            return true;
        }
        // Get the count of symbols between two TP. 
        // Gap aware
        // TP1 <= TP2 
        private static int xGapAwareGetDistance(DocumentSequenceTextPointer tp1, DocumentSequenceTextPointer tp2) 
        {
            Debug.Assert(xGapAwareCompareTo(tp1, tp2) <= 0); 
            if (tp1 == tp2)
            {
                return 0;
            } 

            int count = 0; 
            DocumentSequenceTextPointer tpScan = new DocumentSequenceTextPointer(tp1.ChildBlock, tp1.ChildPointer); 
            while (tpScan.ChildBlock != tp2.ChildBlock)
            { 
                // Skip the entire block to the end
                count += tpScan.ChildPointer.GetOffsetToPosition(tpScan.ChildPointer.TextContainer.End);

                // Move on to next block 
                ChildDocumentBlock nextBlock = tpScan.ChildBlock.NextBlock;
                tpScan.ChildBlock       = nextBlock; 
                tpScan.ChildPointer    = nextBlock.ChildContainer.Start; 
            }
            count += tpScan.ChildPointer.GetOffsetToPosition(tp2.ChildPointer); 
            return count;
        }

        // Move this TP by distance, and respect virtualization of child TextContainer 
        // Return true if distance is within boundary of the aggregated container, false otherwise
        private static bool xGapAwareScan(DocumentSequenceTextPointer thisTp, int distance) 
        { 
            //
            // Note: To calculate distance between thisTp.ChildPointer to 
            // it container Start/End position would have been devastating
            // for those who implemented vitualization.
            // Ideally we would need a new API on ITextPointer
            //      ITextPointer.IsDistanceOutOfRange 
            ChildDocumentBlock cdb = thisTp.ChildBlock;
            bool isNavigator = true; 
            ITextPointer childTn = thisTp.ChildPointer; 
            if (childTn == null)
            { 
                isNavigator = false;
                childTn = thisTp.ChildPointer.CreatePointer();
            }
            LogicalDirection scanDir = (distance > 0 ? LogicalDirection.Forward : LogicalDirection.Backward); 
            distance = Math.Abs(distance);
            while (distance > 0) 
            { 
                TextPointerContext tst = childTn.GetPointerContext(scanDir);
                switch (tst) 
                {
                    case TextPointerContext.ElementStart:
                        childTn.MoveToNextContextPosition(scanDir);
                        distance--; 
                        break;
 
                    case TextPointerContext.ElementEnd: 
                        childTn.MoveToNextContextPosition(scanDir);
                        distance--; 
                        break;

                    case TextPointerContext.EmbeddedElement:
                        childTn.MoveToNextContextPosition(scanDir); 
                        distance--;
                        break; 
 
                    case TextPointerContext.Text:
                        int runLength  = childTn.GetTextRunLength(scanDir); 
                        int moveLength = runLength < distance ? runLength : distance;
                        distance -= moveLength;
                        //agurcan: Fix for 1098225
                        //We need to propagate direction info to MoveByOffset 
                        if (scanDir == LogicalDirection.Backward)
                        { 
                            moveLength *= -1; 
                        }
                        childTn.MoveByOffset(moveLength); 
                        break;

                    case TextPointerContext.None:
                        if (!((cdb.IsHead && scanDir == LogicalDirection.Backward) 
                              || (cdb.IsTail && scanDir == LogicalDirection.Forward)
                              ) 
                            ) 
                        {
                            cdb = (scanDir == LogicalDirection.Forward ? cdb.NextBlock : cdb.PreviousBlock); 
                            childTn = (scanDir == LogicalDirection.Forward ?
                                      cdb.ChildContainer.Start.CreatePointer(childTn.LogicalDirection)
                                    : cdb.ChildContainer.End.CreatePointer(childTn.LogicalDirection)
                                  ); 
                        }
                        else 
                        { 
                            return false;
                        } 
                        break;

                    default:
                        Debug.Assert(false, "invalid TextPointerContext"); 
                        break;
                } 
            } 

            // Re-position thisTp to the new location. 
            thisTp.ChildBlock = cdb;
            if (isNavigator)
            {
                thisTp.ChildPointer = childTn; 
            }
            else 
            { 
                thisTp.ChildPointer = childTn.CreatePointer();
            } 
            return true;
        }

        #endregion Private Methods 

 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------
        #region Private Fields
 
        private ChildDocumentBlock _childBlock;
        private ITextPointer _childTp; 
 
        // True if Freeze has been called, in which case
        // this TextPointer is immutable and may not be repositioned. 
        private bool _isFrozen;

#if DEBUG
        private uint _debugId = GetDebugId(); 
        private static uint _debugIdCounter = 0;
#endif 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
// 
//      Copyright (C) 2004 by Microsoft Corporation.  All rights reserved.
// 
// 
// Description:
//      DocumentSequenceTextPointer is an implementation of ITextPointer/ITextPointer 
//      for FixedDocumentSequence. It is the base class for DocumentSequenceTextPointer and 
//      DocumentSequenceTextPointer.
// 
// History:
//      07/12/2004 - Zhenbin Xu (ZhenbinX) - Created.
//
//--------------------------------------------------------------------------- 

#pragma warning disable 1634, 1691 // To enable presharp warning disables (#pragma suppress) below. 
 
namespace System.Windows.Documents
{ 
    using MS.Internal.Documents;
    using MS.Utility;
    using MS.Internal;
    using System.Windows; 
    using System;
    using System.Diagnostics; 
 

    ///  
    /// DocumentSequenceTextPointer is an implementation of ITextPointer for FixedDocumentSequence
    /// 
    internal sealed class DocumentSequenceTextPointer : ContentPosition, ITextPointer
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 
        #region Constructors
        // Ctor always set mutable flag to false
        internal DocumentSequenceTextPointer(ChildDocumentBlock childBlock, ITextPointer childPosition)
        { 
            Debug.Assert(childBlock != null);
            Debug.Assert(childPosition != null); 
            _childBlock = childBlock; 
            _childTp = childPosition;
        } 
        #endregion Constructors

        //------------------------------------------------------
        // 
        //  Public Methods
        // 
        //----------------------------------------------------- 
        #region TextPointer Methods
 
        /// 
        /// 
        /// 
        void ITextPointer.SetLogicalDirection(LogicalDirection direction) 
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 
            _childTp.SetLogicalDirection(direction); 
        }
 
        /// 
        /// 
        /// 
        int ITextPointer.CompareTo(ITextPointer position) 
        {
            return DocumentSequenceTextPointer.CompareTo(this, position); 
        } 

        int ITextPointer.CompareTo(StaticTextPointer position) 
        {
            return ((ITextPointer)this).CompareTo((ITextPointer)position.Handle0);
        }
 
        /// 
        ///  
        ///  
        int ITextPointer.GetOffsetToPosition(ITextPointer position)
        { 
            return DocumentSequenceTextPointer.GetOffsetToPosition(this, position);
        }

        ///  
        /// 
        ///  
        TextPointerContext ITextPointer.GetPointerContext(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetPointerContext(this, direction); 
        }

        /// 
        ///  
        /// 
        /// Return 0 if non-text run 
        int ITextPointer.GetTextRunLength(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetTextRunLength(this, direction); 
        }

        // 
        string ITextPointer.GetTextInRun(LogicalDirection direction) 
        {
            return TextPointerBase.GetTextInRun(this, direction); 
        } 

        ///  
        /// 
        /// 
        /// Only reutrn uninterrupted runs of text
        int ITextPointer.GetTextInRun(LogicalDirection direction, char[] textBuffer, int startIndex, int count) 
        {
            return DocumentSequenceTextPointer.GetTextInRun(this, direction, textBuffer, startIndex, count); 
        } 

        ///  
        /// 
        /// 
        /// Return null if the embedded object does not exist
        object ITextPointer.GetAdjacentElement(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetAdjacentElement(this, direction); 
        } 

        ///  
        /// 
        /// 
        /// Return null if no TextElement in the direction
        Type ITextPointer.GetElementType(LogicalDirection direction) 
        {
            return DocumentSequenceTextPointer.GetElementType(this, direction); 
        } 

        ///  
        /// 
        /// 
        bool ITextPointer.HasEqualScope(ITextPointer position)
        { 
            return DocumentSequenceTextPointer.HasEqualScope(this, position);
        } 
 

        ///  
        /// 
        /// 
        /// return property values even if there is no scoping element
        object ITextPointer.GetValue(DependencyProperty property) 
        {
            return DocumentSequenceTextPointer.GetValue(this, property); 
        } 

        ///  
        /// 
        /// 
        /// Throws InvalidOperationException if there is no scoping element
        object ITextPointer.ReadLocalValue(DependencyProperty property) 
        {
            return DocumentSequenceTextPointer.ReadLocalValue(this, property); 
        } 

        ///  
        /// 
        /// 
        /// Returns an empty enumerator if there is no scoping element
        LocalValueEnumerator ITextPointer.GetLocalValueEnumerator() 
        {
            return DocumentSequenceTextPointer.GetLocalValueEnumerator(this); 
        } 

        ITextPointer ITextPointer.CreatePointer() 
        {
            return DocumentSequenceTextPointer.CreatePointer(this);
        }
 
        // Unoptimized CreateStaticPointer implementation.
        // Creates a simple wrapper for an ITextPointer instance. 
        StaticTextPointer ITextPointer.CreateStaticPointer() 
        {
            return new StaticTextPointer(((ITextPointer)this).TextContainer, ((ITextPointer)this).CreatePointer()); 
        }

        ITextPointer ITextPointer.CreatePointer(int distance)
        { 
            return DocumentSequenceTextPointer.CreatePointer(this, distance);
        } 
 
        ITextPointer ITextPointer.CreatePointer(LogicalDirection gravity)
        { 
            return DocumentSequenceTextPointer.CreatePointer(this, gravity);
        }

        ///  
        /// 
        ///  
        ITextPointer ITextPointer.CreatePointer(int distance, LogicalDirection gravity) 
        {
            return DocumentSequenceTextPointer.CreatePointer(this, distance, gravity); 
        }

        // 
        void ITextPointer.Freeze() 
        {
            _isFrozen = true; 
        } 

        ///  
        /// 
        /// 
        ITextPointer ITextPointer.GetFrozenPointer(LogicalDirection logicalDirection)
        { 
            return TextPointerBase.GetFrozenPointer(this, logicalDirection);
        } 
 
        /// 
        /// Inserts text at a specified position. 
        /// 
        /// 
        /// Text to insert.
        ///  
        void ITextPointer.InsertTextInRun(string textData)
        { 
            throw new InvalidOperationException(SR.Get(SRID.DocumentReadOnly)); 
        }
 
        /// 
        /// Removes content covered by a pair of positions.
        /// 
        ///  
        /// Position following the last symbol to delete.  endPosition must be
        /// scoped by the same text element as startPosition. 
        ///  
        void ITextPointer.DeleteContentToPosition(ITextPointer limit)
        { 
            throw new InvalidOperationException(SR.Get(SRID.DocumentReadOnly));
        }

        // Candidate for replacing MoveToNextContextPosition for immutable TextPointer model 
        ITextPointer ITextPointer.GetNextContextPosition(LogicalDirection direction)
        { 
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            if (pointer.MoveToNextContextPosition(direction))
            { 
                pointer.Freeze();
            }
            else
            { 
                pointer = null;
            } 
            return pointer; 
        }
 
        // Candidate for replacing MoveToInsertionPosition for immutable TextPointer model
        ITextPointer ITextPointer.GetInsertionPosition(LogicalDirection direction)
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            pointer.MoveToInsertionPosition(direction);
            pointer.Freeze(); 
            return pointer; 
        }
 
        // Returns the closest insertion position, treating all unicode code points
        // as valid insertion positions.  A useful performance win over
        // GetNextInsertionPosition when only formatting scopes are important.
        ITextPointer ITextPointer.GetFormatNormalizedPosition(LogicalDirection direction) 
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            TextPointerBase.MoveToFormatNormalizedPosition(pointer, direction); 
            pointer.Freeze();
            return pointer; 
        }

        // Candidate for replacing MoveToNextInsertionPosition for immutable TextPointer model
        ITextPointer ITextPointer.GetNextInsertionPosition(LogicalDirection direction) 
        {
            ITextPointer pointer = ((ITextPointer)this).CreatePointer(); 
            if (pointer.MoveToNextInsertionPosition(direction)) 
            {
                pointer.Freeze(); 
            }
            else
            {
                pointer = null; 
            }
            return pointer; 
        } 

        ///  
        bool ITextPointer.ValidateLayout()
        {
            return TextPointerBase.ValidateLayout(this, ((ITextPointer)this).TextContainer.TextView);
        } 

        #endregion TextPointer Methods 
 
        #region Public Methods
#if DEBUG 
        /// 
        /// Debug only ToString override.
        /// 
        public override string ToString() 
        {
            return DocumentSequenceTextPointer.ToString(this); 
        } 
#endif // DEBUG
        #endregion Public Methods 



        //------------------------------------------------------ 
        //
        //  Public Properties 
        // 
        //------------------------------------------------------
 
        #region TextPointer Properties

        // 
        Type ITextPointer.ParentType 
        {
            get 
            { 
                return DocumentSequenceTextPointer.GetElementType(this);
            } 
        }

        /// 
        ///  
        /// 
        ITextContainer ITextPointer.TextContainer 
        { 
            get { return this.AggregatedContainer; }
        } 

        // 
        bool ITextPointer.HasValidLayout
        { 
            get
            { 
                return (((ITextPointer)this).TextContainer.TextView != null && 
                        ((ITextPointer)this).TextContainer.TextView.IsValid &&
                        ((ITextPointer)this).TextContainer.TextView.Contains(this)); 
            }
        }

        //  
        bool ITextPointer.IsAtCaretUnitBoundary
        { 
            get 
            {
                Invariant.Assert(((ITextPointer)this).HasValidLayout); 
                ITextView textView = ((ITextPointer)this).TextContainer.TextView;
                bool isAtCaretUnitBoundary = textView.IsAtCaretUnitBoundary(this);

                if (!isAtCaretUnitBoundary && ((ITextPointer)this).LogicalDirection == LogicalDirection.Backward) 
                {
                    // In MIL Text and TextView worlds, a position at trailing edge of a newline (with backward gravity) 
                    // is not an allowed caret stop. 
                    // However, in TextPointer world we must allow such a position to be a valid insertion position,
                    // since it breaks textrange normalization for empty ranges. 
                    // Hence, we need to check for TextView.IsAtCaretUnitBoundary in reverse direction below.

                    ITextPointer positionForwardGravity = ((ITextPointer)this).CreatePointer(LogicalDirection.Forward);
                    isAtCaretUnitBoundary = textView.IsAtCaretUnitBoundary(positionForwardGravity); 
                }
                return isAtCaretUnitBoundary; 
            } 
        }
 
        /// 
        /// 
        /// 
        LogicalDirection ITextPointer.LogicalDirection 
        {
            get 
            { 
                return _childTp.LogicalDirection;
            } 
        }

        bool ITextPointer.IsAtInsertionPosition
        { 
            get { return TextPointerBase.IsAtInsertionPosition(this); }
        } 
 
        // 
        bool ITextPointer.IsFrozen 
        {
            get
            {
                return _isFrozen; 
            }
        } 
 
        // 
        int ITextPointer.Offset 
        {
            get
            {
                return TextPointerBase.GetOffset(this); 
            }
        } 
 
        // Not implemented.
        int ITextPointer.CharOffset 
        {
            get
            {
                #pragma warning suppress 56503 
                throw new NotImplementedException();
            } 
        } 

        #endregion TextPointer Properties 

        //-----------------------------------------------------
        //
        //  Public Events 
        //
        //------------------------------------------------------ 
 
        //-----------------------------------------------------
        // 
        //  Internal Properties
        //
        //-----------------------------------------------------
 
        //-----------------------------------------------------
        // 
        //  Public Methods 
        //
        //------------------------------------------------------ 

        #region TextNavigator Methods

        ///  
        /// 
        ///  
        bool ITextPointer.MoveToNextContextPosition(LogicalDirection direction) 
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 
            return DocumentSequenceTextPointer.iScan(this, direction);
        }

 
        /// 
        ///  
        ///  
        int ITextPointer.MoveByOffset(int offset)
        { 
            if (_isFrozen) throw new InvalidOperationException(SR.Get(SRID.TextPositionIsFrozen));

            if (DocumentSequenceTextPointer.iScan(this, offset))
            { 
                return offset;
            } 
            else 
            {
                return 0; 
            }
        }

        ///  
        /// 
        ///  
        void ITextPointer.MoveToPosition(ITextPointer position) 
        {
            DocumentSequenceTextPointer tp = this.AggregatedContainer.VerifyPosition(position); 

            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!");

            LogicalDirection gravity = this.ChildPointer.LogicalDirection; 
            this.ChildBlock = tp.ChildBlock;
            if (this.ChildPointer.TextContainer == tp.ChildPointer.TextContainer) 
            { 
                this.ChildPointer.MoveToPosition(tp.ChildPointer);
            } 
            else
            {
                this.ChildPointer = tp.ChildPointer.CreatePointer();
                this.ChildPointer.SetLogicalDirection(gravity); 
            }
        } 
 
        /// 
        ///  
        /// 
        void ITextPointer.MoveToElementEdge(ElementEdge edge)
        {
            Debug.Assert(!_isFrozen, "Can't reposition a frozen pointer!"); 

            this.ChildPointer.MoveToElementEdge(edge); 
        } 

        //  
        int ITextPointer.MoveToLineBoundary(int count)
        {
            return TextPointerBase.MoveToLineBoundary(this, ((ITextPointer)this).TextContainer.TextView, count, true);
        } 

        //  
        Rect ITextPointer.GetCharacterRect(LogicalDirection direction) 
        {
            return TextPointerBase.GetCharacterRect(this, direction); 
        }

        bool ITextPointer.MoveToInsertionPosition(LogicalDirection direction)
        { 
            return TextPointerBase.MoveToInsertionPosition(this, direction);
        } 
 
        bool ITextPointer.MoveToNextInsertionPosition(LogicalDirection direction)
        { 
            return TextPointerBase.MoveToNextInsertionPosition(this, direction);
        }

        #endregion TextNavigator Methods 

        //----------------------------------------------------- 
        // 
        //  Internal Properties
        // 
        //------------------------------------------------------

        #region Internal Properties
        internal DocumentSequenceTextContainer AggregatedContainer 
        {
            get { return _childBlock.AggregatedContainer; } 
        } 

 
        // Accessor to base class ChildBlock.
        internal ChildDocumentBlock ChildBlock
        {
            get 
            {
                return _childBlock; 
            } 
            set
            { 
                _childBlock = value;
            }
        }
 
        // Helper exposing base classes ChildPointer as an ITextPointer,
        // which is guaranteed safe, since we set its value in the ctor 
        // for this class. 
        internal ITextPointer ChildPointer
        { 
            get
            {
                return _childTp;
            } 
            set
            { 
                _childTp = value; 
                Debug.Assert(_childTp != null);
            } 
        }

#if DEBUG
        // Debug-only identifier. 
        private uint DebugId
        { 
            get 
            {
                return _debugId; 
            }
        }
#endif // DEBUG
 
        #endregion Internal Properties
 
        // ====================================================== 
        // Static part of a class
 
        // 
        // DocumentSequenceTextPointer is a static  class that is provided all the
        // common functions of ITextPointer/ITextNavigaor for DocumentSequence.
        // Since we don't have multiple inheritance, this is a way to share code between 
        // DocumentSequenceTextPointer and DocumentSequenceTextPointer.
        //  
 
        //-----------------------------------------------------
        // 
        //  Public Methods
         //
        //------------------------------------------------------
        #region TextPointer Methods 
        /// 
        ///  
        ///  
        public static int CompareTo(DocumentSequenceTextPointer thisTp, ITextPointer position)
        { 
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position);

            // Now do compare
            return xGapAwareCompareTo(thisTp, tp); 
        }
 
 
        /// 
        ///  
        /// 
        public static int GetOffsetToPosition(DocumentSequenceTextPointer thisTp, ITextPointer position)
        {
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position); 

            int comp = xGapAwareCompareTo(thisTp, tp); 
            if (comp == 0) 
            {
                return 0; 
            }
            else if (comp <= 0)
            {
                return xGapAwareGetDistance(thisTp, tp); 
            }
            else 
            { 
                return -1 * xGapAwareGetDistance(tp, thisTp);
            } 
        }

        /// 
        ///  
        /// 
        public static TextPointerContext GetPointerContext(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyDirection(direction, "direction");
 
            return xGapAwareGetSymbolType(thisTp, direction);
        }

        ///  
        /// 
        ///  
        /// Return 0 if non-text run 
        public static int GetTextRunLength(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            ValidationHelper.VerifyDirection(direction, "direction");

            return thisTp.ChildPointer.GetTextRunLength(direction);
        } 

        ///  
        ///  
        /// 
        /// Only reutrn uninterrupted runs of text 
        public static int GetTextInRun(DocumentSequenceTextPointer thisTp, LogicalDirection direction, char[] textBuffer, int startIndex, int count)
        {
            ValidationHelper.VerifyDirection(direction, "direction");
 
            if (textBuffer == null)
            { 
                throw new ArgumentNullException("textBuffer"); 
            }
            if (startIndex < 0) 
            {
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "startIndex"));
            }
            if (startIndex > textBuffer.Length) 
            {
                throw new ArgumentException(SR.Get(SRID.StartIndexExceedsBufferSize, startIndex, textBuffer.Length)); 
            } 
            if (count < 0)
            { 
                throw new ArgumentException(SR.Get(SRID.NegativeValue, "count"));
            }
            if (count > textBuffer.Length - startIndex)
            { 
                throw new ArgumentException(SR.Get(SRID.MaxLengthExceedsBufferSize, count, textBuffer.Length, startIndex));
            } 
 
            return thisTp.ChildPointer.GetTextInRun(direction, textBuffer, startIndex, count);
        } 

        /// 
        /// 
        ///  
        /// Return null if the embedded object does not exist
        public static object GetAdjacentElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        { 
            ValidationHelper.VerifyDirection(direction, "direction");
 
            return xGapAwareGetEmbeddedElement(thisTp, direction);
        }

        ///  
        /// 
        ///  
        /// Return null if no TextElement in the direction 
        public static Type GetElementType(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            ValidationHelper.VerifyDirection(direction, "direction");

            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction);
 
            return tp.ChildPointer.GetElementType(direction);
        } 
 
        /// 
        ///  
        /// 
        public static Type GetElementType(DocumentSequenceTextPointer thisTp)
        {
            return thisTp.ChildPointer.ParentType; 
        }
 
        ///  
        /// 
        ///  
        public static bool HasEqualScope(DocumentSequenceTextPointer thisTp, ITextPointer position)
        {
            DocumentSequenceTextPointer tp = thisTp.AggregatedContainer.VerifyPosition(position);
 
            if (thisTp.ChildPointer.TextContainer == tp.ChildPointer.TextContainer)
            { 
                return thisTp.ChildPointer.HasEqualScope(tp.ChildPointer); 
            }
            // The TextOM speced behavior is if both scopes are null, return true. 
            return thisTp.ChildPointer.ParentType == typeof(FixedDocument) && tp.ChildPointer.ParentType == typeof(FixedDocument);
        }

        ///  
        /// 
        ///  
        /// return property values even if there is no scoping element 
        public static object GetValue(DocumentSequenceTextPointer thisTp, DependencyProperty property)
        { 
            if (property == null)
            {
                throw new ArgumentNullException("property");
            } 

            return thisTp.ChildPointer.GetValue(property); 
        } 

        ///  
        /// 
        /// 
        /// Throws InvalidOperationException if there is no scoping element
        public static object ReadLocalValue(DocumentSequenceTextPointer thisTp, DependencyProperty property) 
        {
            if (property == null) 
            { 
                throw new ArgumentNullException("property");
            } 

            return thisTp.ChildPointer.ReadLocalValue(property);
        }
 
        /// 
        ///  
        ///  
        /// Returns an empty enumerator if there is no scoping element
        public static LocalValueEnumerator GetLocalValueEnumerator(DocumentSequenceTextPointer thisTp) 
        {
            return thisTp.ChildPointer.GetLocalValueEnumerator();
        }
 
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp)
        { 
            return CreatePointer(thisTp, 0, thisTp.ChildPointer.LogicalDirection); 
        }
 
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance)
        {
            return CreatePointer(thisTp, distance, thisTp.ChildPointer.LogicalDirection);
        } 

        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, LogicalDirection gravity) 
        { 
            return CreatePointer(thisTp, 0, gravity);
        } 

        /// 
        /// 
        ///  
        public static ITextPointer CreatePointer(DocumentSequenceTextPointer thisTp, int distance, LogicalDirection gravity)
        { 
            ValidationHelper.VerifyDirection(gravity, "gravity"); 

            // Special case for common case of distance == 0 
            // to avoid calculating child container size, which
            // could be expansive especially in case where child
            // container requires virtualization.
            DocumentSequenceTextPointer newTp = new DocumentSequenceTextPointer(thisTp.ChildBlock, thisTp.ChildPointer.CreatePointer(gravity)); 
            if (distance != 0)
            { 
                if (!xGapAwareScan(newTp, distance)) 
                {
                    throw new ArgumentException(SR.Get(SRID.BadDistance), "distance"); 
                }
            }
            return newTp;
        } 

        #endregion TextPointer Methods 
 
        //-----------------------------------------------------
        // 
        //  Public Properties
        //
        //-----------------------------------------------------
 

        //----------------------------------------------------- 
        // 
        //  Public Events
        // 
        //------------------------------------------------------


        //----------------------------------------------------- 
        //
        //  Internal Methods 
        // 
        //------------------------------------------------------
 
        #region Internal Methods


        // Internal Method, input parameter contains TP that is not synced to generation 
        internal static bool iScan(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            bool moved = thisTp.ChildPointer.MoveToNextContextPosition(direction); 
            if (!moved)
            { 
                moved = xGapAwareScan(thisTp, (direction == LogicalDirection.Forward ? 1 : -1));
            }
            return moved;
        } 

 
        // Internal Method, input parameter contains TP that is not synced to generation 
        internal static bool iScan(DocumentSequenceTextPointer thisTp, int distance)
        { 
            return xGapAwareScan(thisTp, distance);
        }

#if DEBUG 
        // Allocate a unique debug-only ID as identifier.
        internal static uint GetDebugId() 
        { 
            return _debugIdCounter++;
        } 

        internal static string ToString(DocumentSequenceTextPointer thisTp)
        {
            return  (thisTp is DocumentSequenceTextPointer ? "DSTP" : "DSTN") 
                    + " Id=" + thisTp.DebugId
                    + " B=" + thisTp.ChildBlock.DebugId 
                    + " G=" + thisTp.ChildPointer.LogicalDirection 
                    ;
        } 
#endif
        #endregion Internal Methods

 
        //------------------------------------------------------
        // 
        //  Internal Property 
        //
        //----------------------------------------------------- 

        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
 
        #region Private Methods
        private static DocumentSequenceTextPointer xGetClingDSTP(DocumentSequenceTextPointer thisTp, LogicalDirection direction) 
        {
            TextPointerContext context = thisTp.ChildPointer.GetPointerContext(direction);

            if (context != TextPointerContext.None) 
            {
                return thisTp; 
            } 

            ChildDocumentBlock block = thisTp.ChildBlock; 
            ITextPointer pointer = thisTp.ChildPointer;

            if (direction == LogicalDirection.Forward)
            { 
                while (context == TextPointerContext.None && !block.IsTail)
                { 
                    // get next block 
                    block = block.NextBlock;
                    // get start 
                    pointer = block.ChildContainer.Start;
                    context = pointer.GetPointerContext(direction);
                }
            } 
            else
            { 
                Debug.Assert(direction == LogicalDirection.Backward); 
                while (context == TextPointerContext.None && !block.IsHead)
                { 
                    // get next block
                    block = block.PreviousBlock;
                    // get start
                    pointer = block.ChildContainer.End; 
                    context = pointer.GetPointerContext(direction);
                } 
            } 

            return new DocumentSequenceTextPointer(block, pointer); 
        }


        //----------------------------------------------------------------------- 
        // Trusted Methods -- all positions are in valid blocks
        // 
        // Each ChildDocumentBlock pair is separated by a gap (DocumentBreak), 
        // which is surfaced as an embedded object. Besides the Head and Tail block,
        // each block is enclosed by two gap objects, one at each end of the 
        // TextContainer (Before TextContainer.Start and After TextContainer.End)
        //-----------------------------------------------------------------------

 
        private static TextPointerContext xGapAwareGetSymbolType(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction); 
            return tp.ChildPointer.GetPointerContext(direction);
        } 


        private static object xGapAwareGetEmbeddedElement(DocumentSequenceTextPointer thisTp, LogicalDirection direction)
        { 
            DocumentSequenceTextPointer tp = xGetClingDSTP(thisTp, direction);
            return tp.ChildPointer.GetAdjacentElement(direction); 
        } 

 
        //  Intelligent compare routine that understands block gap
        //  Since there it is assumed that there is an invisible Gap
        //  object between adjancent two blocks, there is no position
        //  overlap. 
        private static int xGapAwareCompareTo(DocumentSequenceTextPointer thisTp, DocumentSequenceTextPointer tp)
        { 
            Debug.Assert(tp != null); 
            if ((object)thisTp == (object)tp)
            { 
                return 0;
            }

            ChildDocumentBlock thisBlock = thisTp.ChildBlock; 
            ChildDocumentBlock tpBlock = tp.ChildBlock;
 
            int comp = thisTp.AggregatedContainer.GetChildBlockDistance(thisBlock, tpBlock); 
            if (comp == 0)
            { 
                Debug.Assert(thisTp.ChildBlock.ChildContainer == tp.ChildBlock.ChildContainer);
                return thisTp.ChildPointer.CompareTo(tp.ChildPointer);
            }
            else if (comp < 0) 
            {
                // thisBlock is after tpBlock 
                return xUnseparated(tp, thisTp) ? 0 : 1; 
            }
            else 
            {
                // thisBlock is before tpBlock
                return xUnseparated(thisTp, tp) ? 0 : -1;
            } 
        }
 
        private static bool xUnseparated(DocumentSequenceTextPointer tp1, DocumentSequenceTextPointer tp2) 
        {
            // tp1 is before tp2, check both are at edge of documents 
            //check nothing of any length between them
            if (tp1.ChildPointer.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None ||
                tp2.ChildPointer.GetPointerContext(LogicalDirection.Backward) != TextPointerContext.None)
            { 
                return false;
            } 
 
            ChildDocumentBlock block = tp1.ChildBlock.NextBlock;
 
            while (block != tp2.ChildBlock)
            {
                if (block.ChildContainer.Start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.None)
                { 
                    return false;
                } 
 
                block = block.NextBlock;
            } 

            return true;
        }
        // Get the count of symbols between two TP. 
        // Gap aware
        // TP1 <= TP2 
        private static int xGapAwareGetDistance(DocumentSequenceTextPointer tp1, DocumentSequenceTextPointer tp2) 
        {
            Debug.Assert(xGapAwareCompareTo(tp1, tp2) <= 0); 
            if (tp1 == tp2)
            {
                return 0;
            } 

            int count = 0; 
            DocumentSequenceTextPointer tpScan = new DocumentSequenceTextPointer(tp1.ChildBlock, tp1.ChildPointer); 
            while (tpScan.ChildBlock != tp2.ChildBlock)
            { 
                // Skip the entire block to the end
                count += tpScan.ChildPointer.GetOffsetToPosition(tpScan.ChildPointer.TextContainer.End);

                // Move on to next block 
                ChildDocumentBlock nextBlock = tpScan.ChildBlock.NextBlock;
                tpScan.ChildBlock       = nextBlock; 
                tpScan.ChildPointer    = nextBlock.ChildContainer.Start; 
            }
            count += tpScan.ChildPointer.GetOffsetToPosition(tp2.ChildPointer); 
            return count;
        }

        // Move this TP by distance, and respect virtualization of child TextContainer 
        // Return true if distance is within boundary of the aggregated container, false otherwise
        private static bool xGapAwareScan(DocumentSequenceTextPointer thisTp, int distance) 
        { 
            //
            // Note: To calculate distance between thisTp.ChildPointer to 
            // it container Start/End position would have been devastating
            // for those who implemented vitualization.
            // Ideally we would need a new API on ITextPointer
            //      ITextPointer.IsDistanceOutOfRange 
            ChildDocumentBlock cdb = thisTp.ChildBlock;
            bool isNavigator = true; 
            ITextPointer childTn = thisTp.ChildPointer; 
            if (childTn == null)
            { 
                isNavigator = false;
                childTn = thisTp.ChildPointer.CreatePointer();
            }
            LogicalDirection scanDir = (distance > 0 ? LogicalDirection.Forward : LogicalDirection.Backward); 
            distance = Math.Abs(distance);
            while (distance > 0) 
            { 
                TextPointerContext tst = childTn.GetPointerContext(scanDir);
                switch (tst) 
                {
                    case TextPointerContext.ElementStart:
                        childTn.MoveToNextContextPosition(scanDir);
                        distance--; 
                        break;
 
                    case TextPointerContext.ElementEnd: 
                        childTn.MoveToNextContextPosition(scanDir);
                        distance--; 
                        break;

                    case TextPointerContext.EmbeddedElement:
                        childTn.MoveToNextContextPosition(scanDir); 
                        distance--;
                        break; 
 
                    case TextPointerContext.Text:
                        int runLength  = childTn.GetTextRunLength(scanDir); 
                        int moveLength = runLength < distance ? runLength : distance;
                        distance -= moveLength;
                        //agurcan: Fix for 1098225
                        //We need to propagate direction info to MoveByOffset 
                        if (scanDir == LogicalDirection.Backward)
                        { 
                            moveLength *= -1; 
                        }
                        childTn.MoveByOffset(moveLength); 
                        break;

                    case TextPointerContext.None:
                        if (!((cdb.IsHead && scanDir == LogicalDirection.Backward) 
                              || (cdb.IsTail && scanDir == LogicalDirection.Forward)
                              ) 
                            ) 
                        {
                            cdb = (scanDir == LogicalDirection.Forward ? cdb.NextBlock : cdb.PreviousBlock); 
                            childTn = (scanDir == LogicalDirection.Forward ?
                                      cdb.ChildContainer.Start.CreatePointer(childTn.LogicalDirection)
                                    : cdb.ChildContainer.End.CreatePointer(childTn.LogicalDirection)
                                  ); 
                        }
                        else 
                        { 
                            return false;
                        } 
                        break;

                    default:
                        Debug.Assert(false, "invalid TextPointerContext"); 
                        break;
                } 
            } 

            // Re-position thisTp to the new location. 
            thisTp.ChildBlock = cdb;
            if (isNavigator)
            {
                thisTp.ChildPointer = childTn; 
            }
            else 
            { 
                thisTp.ChildPointer = childTn.CreatePointer();
            } 
            return true;
        }

        #endregion Private Methods 

 
        //------------------------------------------------------ 
        //
        //  Private Fields 
        //
        //-----------------------------------------------------
        #region Private Fields
 
        private ChildDocumentBlock _childBlock;
        private ITextPointer _childTp; 
 
        // True if Freeze has been called, in which case
        // this TextPointer is immutable and may not be repositioned. 
        private bool _isFrozen;

#if DEBUG
        private uint _debugId = GetDebugId(); 
        private static uint _debugIdCounter = 0;
#endif 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK