TextTreeTextNode.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextTreeTextNode.cs / 1305600 / TextTreeTextNode.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: A TextContainer node representing a run of text. 
//
// History: 
//  02/18/2004 : [....] - Created
//
//---------------------------------------------------------------------------
 
using System;
using MS.Internal; 
 
namespace System.Windows.Documents
{ 
    // Runs of text are represented internally by TextTreeTextNodes.
    //
    // Text nodes are regularly "split" -- broken in half -- when a
    // TextPointer needs to reference a character within the node's run. 
    // We track a reference counts of the number of positions referencing a
    // text node so that we can later merge it back again when no TextPositions 
    // reference it. 
    //
    // Unlike other nodes, TextTreeTextNode may only ever be referenced on a 
    // single edge by TextPositions.  This is necessary to ensure that we
    // can split a text node any time a TextPositions needs to reference a
    // character within the node.  With at most one edge referenced we are free
    // to create a new node covering the unreferenced edge without disturbing 
    // any TextPositoins referencing the original node.
    // 
    // Unlike all other nodes, text nodes may occasionally have zero symbol counts. 
    // This happens when a TextPointer wants to reference a node edge, but
    // the node's other edge is already referenced by someone else.  In this case, 
    // we split the text node, adding a zero-width node just for the
    // TextPointer's use.
    internal class TextTreeTextNode : TextTreeNode
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        // Creates a new TextTreeTextNode instance. 
        internal TextTreeTextNode()
        { 
            _symbolOffsetCache = -1; 
        }
 
        #endregion Constructors

        //------------------------------------------------------
        // 
        //  Public Methods
        // 
        //----------------------------------------------------- 

        #region Public Methods 

#if DEBUG
        // Debug-only ToString override.
        public override string ToString() 
        {
            return ("TextNode Id=" + this.DebugId + " SymbolCount=" + _symbolCount); 
        } 
#endif // DEBUG
 
        #endregion Public Methods

        //------------------------------------------------------
        // 
        //  Internal Methods
        // 
        //------------------------------------------------------ 

        #region Internal Methods 

        // Returns a shallow copy of this node.
        // Returns null if this node has a zero symbol count --
        // a clone would have no references, so there's no point 
        // in allocating one.
        internal override TextTreeNode Clone() 
        { 
            TextTreeTextNode clone;
 
            clone = null;

            if (_symbolCount > 0)
            { 
                clone = new TextTreeTextNode();
                clone._symbolCount = _symbolCount; 
            } 

            return clone; 
        }

        // Returns the TextPointerContext of the node.
        internal override TextPointerContext GetPointerContext(LogicalDirection direction) 
        {
            return TextPointerContext.Text; 
        } 

        // Increments a count of the number of TextPositions and TextNavigators 
        // referencing this node.  Called when positions are created or moved.
        // Returns the actual node referenced -- a new node will be created if
        // there are already references to this node's other edge.
        internal override TextTreeNode IncrementReferenceCount(ElementEdge edge, int delta) 
        {
            TextTreeTextNode node; 
            TextTreeTextNode mergeNode; 

            Invariant.Assert(delta >= 0); 
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge ref to TextTreeTextNode!");

            if (delta == 0)
            { 
                return this;
            } 
 
            if (_positionRefCount > 0 && edge != _referencedEdge)
            { 
                // We need to split off a node to cover the new edge.
                node = Split(edge == ElementEdge.BeforeStart ? 0 : _symbolCount, edge);

                node._referencedEdge = edge; 
                node._positionRefCount += delta;
 
                // It's possible we need to merge a neighbor node. 
                // This happens when someone calls TextContainer.GetNodeAndEdgeAtOffset,
                // which splits a text node into two non-empty nodes.  We can't merge 
                // immediately, because we don't know which of the two nodes will
                // get an additional ref.
                // If the unreferenced node of the pair gets the new reference,
                // there no possibility for a merge.  Otherwise, we have to split 
                // again on the already referenced node and end up here.
                if (edge == ElementEdge.BeforeStart) 
                { 
                    // If node B has no references it can merge with node A.
                    //  
                    mergeNode = node.GetPreviousNode() as TextTreeTextNode;
                }
                else
                { 
                    // If node A has no references it can merge with node B.
                    //  
                    mergeNode = node.GetNextNode() as TextTreeTextNode; 
                }
                if (mergeNode != null && mergeNode._positionRefCount == 0) 
                {
                    mergeNode.Merge();
                }
            } 
            else
            { 
                node = this; 
                _referencedEdge = edge;
                _positionRefCount += delta; 
            }

            return node;
        } 

        // Decrements a count of the number of TextPositions and TextNavigators 
        // referencing this node. 
        // This method attempts to merge adjacent TextTreeTextNodes when the ref count
        // transitions from 1 to 0. 
        //
        // Be careful!  This can modify the tree, removing
        // TextTreeTextNodes.
        internal override void DecrementReferenceCount(ElementEdge edge) 
        {
            Invariant.Assert(edge == _referencedEdge, "Bad edge decrement!"); 
 
            _positionRefCount--;
            Invariant.Assert(_positionRefCount >= 0, "Bogus PositionRefCount! "); 

            // If the ref count drops to zero, we may be able to merge this node with an adjacent one.
            if (_positionRefCount == 0)
            { 
                Merge();
            } 
        } 

        // Splits this node into two adjacent nodes. 
        // Returns the node which contains the original requested edge
        // (e.g., if edge == ElementEdge.BeforeStart, this method returns the
        // preceding node, if edge == ElementEdge.AfterEnd, it returns the
        // following node). 
        internal TextTreeTextNode Split(int localOffset, ElementEdge edge)
        { 
            TextTreeTextNode newNode; 
            TextTreeTextNode edgeNode;
            ElementEdge newNodeEdge; 

            Invariant.Assert(_symbolCount > 0, "Splitting a zero-width TextNode!");
            Invariant.Assert(localOffset >= 0 && localOffset <= _symbolCount, "Bad localOffset!");
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!"); 

#if DEBUG 
            if (localOffset == 0) 
            {
                TextTreeNode previousNode; 

                Invariant.Assert(edge == ElementEdge.BeforeStart, "Unexpected edge!");
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");
 
                previousNode = (TextTreeNode)GetPreviousNode();
                Invariant.Assert(previousNode == null || previousNode.SymbolCount > 0 || previousNode.AfterEndReferenceCount, 
                             "Found preceding zero-width text node inside Split!"); 
            }
            else if (localOffset == _symbolCount) 
            {
                TextTreeNode nextNode;

                Invariant.Assert(edge == ElementEdge.AfterEnd, "Unexpected edge!"); 
                Invariant.Assert(edge != _referencedEdge, "Splitting at referenced edge!");
 
                nextNode = (TextTreeNode)GetNextNode(); 
                Invariant.Assert(nextNode == null || nextNode.SymbolCount > 0 || nextNode.BeforeStartReferenceCount,
                             "Found following zero-width text node inside Split! (2)"); 
            }
#endif // DEBUG

            newNode = new TextTreeTextNode(); 
            newNode._generation = _generation;
 
            // Splay this node to the root so we don't corrupt any LeftSymbolCounts 
            // of ancestor nodes when we fixup _symbolCount below.
            Splay(); 

            if (_positionRefCount > 0 && _referencedEdge == ElementEdge.BeforeStart)
            {
                // New node is the following node. 
                newNode._symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                newNode._symbolCount = _symbolCount - localOffset; 
 
                _symbolCount = localOffset;
 
                newNodeEdge = ElementEdge.AfterEnd;

                edgeNode = (edge == ElementEdge.BeforeStart) ? this : newNode;
            } 
            else
            { 
                // New node is the preceding node. 
                newNode._symbolOffsetCache = _symbolOffsetCache;
                newNode._symbolCount = localOffset; 

                _symbolOffsetCache = (_symbolOffsetCache == -1) ? -1 : _symbolOffsetCache + localOffset;
                _symbolCount -= localOffset;
 
                newNodeEdge = ElementEdge.BeforeStart;
 
                edgeNode = (edge == ElementEdge.BeforeStart) ? newNode : this; 
            }
 
            Invariant.Assert(_symbolCount >= 0);
            Invariant.Assert(newNode._symbolCount >= 0);

            newNode.InsertAtNode(this, newNodeEdge); 

            return edgeNode; 
        } 

        #endregion Internal methods 

        //-----------------------------------------------------
        //
        //  Internal Properties 
        //
        //------------------------------------------------------ 
 
        #region Internal Properties
 
        // If this node is a local root, then ParentNode contains it.
        // Otherwise, this is the node parenting this node within its tree.
        internal override SplayTreeNode ParentNode
        { 
            get
            { 
                return _parentNode; 
            }
 
            set
            {
                _parentNode = (TextTreeNode)value;
            } 
        }
 
        // TextTreeTextNode never has contained nodes. 
        internal override SplayTreeNode ContainedNode
        { 
            get
            {
                return null;
            } 

            set 
            { 
                Invariant.Assert(false, "Can't set child on a TextTreeTextNode!");
            } 
        }

        // Count of symbols of all siblings preceding this node.
        internal override int LeftSymbolCount 
        {
            get 
            { 
                return _leftSymbolCount;
            } 

            set
            {
                _leftSymbolCount = value; 
            }
        } 
 
        // Count of chars of all siblings preceding this node.
        internal override int LeftCharCount 
        {
            get
            {
                return _leftCharCount; 
            }
 
            set 
            {
                _leftCharCount = value; 
            }
        }

        // Left child node in a sibling tree. 
        internal override SplayTreeNode LeftChildNode
        { 
            get 
            {
                return _leftChildNode; 
            }

            set
            { 
                _leftChildNode = (TextTreeNode)value;
            } 
        } 

        // Right child node in a sibling tree. 
        internal override SplayTreeNode RightChildNode
        {
            get
            { 
                return _rightChildNode;
            } 
 
            set
            { 
                _rightChildNode = (TextTreeNode)value;
            }
        }
 
        // The TextContainer's generation when SymbolOffsetCache was last updated.
        // If the current generation doesn't match TextContainer.Generation, then 
        // SymbolOffsetCache is invalid. 
        internal override uint Generation
        { 
            get
            {
                return _generation;
            } 

            set 
            { 
                _generation = value;
            } 
        }

        // Cached symbol offset.
        internal override int SymbolOffsetCache 
        {
            get 
            { 
                return _symbolOffsetCache;
            } 

            set
            {
                _symbolOffsetCache = value; 
            }
        } 
 
        // Count of symbols covered by this node.
        internal override int SymbolCount 
        {
            get
            {
                return _symbolCount; 
            }
 
            set 
            {
                _symbolCount = value; 
            }
        }

        // Count of chars covered by this node. 
        internal override int IMECharCount
        { 
            get 
            {
                return this.SymbolCount; 
            }

            set
            { 
                // Tracked redundently by _symbolCount.
            } 
        } 

        // Count of TextPositions referencing the node's BeforeStart edge. 
        internal override bool BeforeStartReferenceCount
        {
            get
            { 
                return _referencedEdge == ElementEdge.BeforeStart ? _positionRefCount > 0 : false;
            } 
 
            set
            { 
                Invariant.Assert(false, "Can't set TextTreeTextNode ref counts directly!");
            }
        }
 
        // Count of TextPositions referencing the node's AfterStart edge.
        // Since text nodes don't have an AfterStart edge, this is always zero. 
        internal override bool AfterStartReferenceCount 
        {
            get 
            {
                return false;
            }
 
            set
            { 
                Invariant.Assert(false, "Text nodes don't have an AfterStart edge!"); 
            }
        } 

        // Count of TextPositions referencing the node's BeforeEnd edge.
        // Since text nodes don't have an BeforeEnd edge, this is always zero.
        internal override bool BeforeEndReferenceCount 
        {
            get 
            { 
                return false;
            } 

            set
            {
                Invariant.Assert(false, "Text nodes don't have a BeforeEnd edge!"); 
            }
        } 
 
        // Count of TextPositions referencing the node's AfterEnd edge.
        internal override bool AfterEndReferenceCount 
        {
            get
            {
                return _referencedEdge == ElementEdge.AfterEnd ? _positionRefCount > 0 : false; 
            }
 
            set 
            {
                Invariant.Assert(false, "Can't set TextTreeTextNode ref counts directly!"); 
            }
        }

        #endregion Internal Properties 

        //----------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //-----------------------------------------------------

        #region Private Methods
 
        // Attempts to merge this node with adjacent TextTreeTextNodes.
        // Called when the position ref counts drops from 1 to 0. 
        private void Merge() 
        {
            TextTreeTextNode previousNode; 
            TextTreeTextNode nextNode;

            Invariant.Assert(_positionRefCount == 0, "Inappropriate Merge call!");
 
            // Check the previous node.
            previousNode = GetPreviousNode() as TextTreeTextNode; 
 
            if (previousNode != null &&
                (previousNode._positionRefCount == 0 || previousNode._referencedEdge == ElementEdge.BeforeStart)) 
            {
                // The previous node must take the place of this one, since previous
                // may still have references.
                Remove(); 
                // null _parentNode out so that if there's a bug and someone still references this node we'll hear about it.
                _parentNode = null; 
                previousNode.Splay(); 

                previousNode._symbolCount += _symbolCount; 
            }
            else
            {
                previousNode = this; 
            }
 
            // Check the following node. 
            nextNode = previousNode.GetNextNode() as TextTreeTextNode;
 
            if (nextNode != null)
            {
                if (previousNode._positionRefCount == 0 &&
                    (nextNode._positionRefCount == 0 || (nextNode._referencedEdge == ElementEdge.AfterEnd))) 
                {
                    // nextNode must take the place of previousNode, since nextNode 
                    // may still have references. 
                    previousNode.Remove();
                    // null _parentNode out so that if there's a bug and someone still references this node we'll hear about it. 
                    previousNode._parentNode = null;
                    nextNode.Splay();

                    if (nextNode._symbolOffsetCache != -1) 
                    {
                        nextNode._symbolOffsetCache -= previousNode._symbolCount; 
                    } 
                    nextNode._symbolCount += previousNode._symbolCount;
                } 
                else if ((previousNode._positionRefCount == 0 || previousNode._referencedEdge == ElementEdge.BeforeStart) &&
                         nextNode._positionRefCount == 0)
                {
                    // The previous node must take the place of next one, since previousNode 
                    // may still have references.
                    nextNode.Remove(); 
                    // null _parentNode out so that if there's a bug and someone still references this node we'll hear about it. 
                    nextNode._parentNode = null;
                    previousNode.Splay(); 

                    previousNode._symbolCount += nextNode._symbolCount;
                }
            } 
        }
 
        #endregion Private methods 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //------------------------------------------------------ 

        #region Private Fields 
 
        // Count of symbols of all siblings preceding this node.
        private int _leftSymbolCount; 

        // Count of chars of all siblings preceding this node.
        private int _leftCharCount;
 
        // If this node is a local root, then ParentNode contains it.
        // Otherwise, this is the node parenting this node within its tree. 
        private TextTreeNode _parentNode; 

        // Left child node in a sibling tree. 
        private TextTreeNode _leftChildNode;

        // Right child node in a sibling tree.
        private TextTreeNode _rightChildNode; // 

        // The TextContainer's generation when SymbolOffsetCache was last updated. 
        // If the current generation doesn't match TextContainer.Generation, then 
        // SymbolOffsetCache is invalid.
        private uint _generation; 

        // Cached symbol offset.
        private int _symbolOffsetCache;
 
        // Count of symbols/chars covered by this node.
        private int _symbolCount; 
 
        // The number of TextPositions referencing an edge of this node.
        // If _positionRefCount is zero, it's safe to merge with surrouding nodes. 
        //

        private int _positionRefCount;
 
        // The edge referenced by one or more TextPositions.
        // Only valid when _positionRefCount > 0. 
        private ElementEdge _referencedEdge; 

        #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