// Copies a run of text into a ContentContainer.
        // Returns the next node to examine.
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out ContentContainer container)
        {
            SplayTreeNode node;

            char[] text;
            int    count;
            int    symbolOffset;

            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");

            symbolOffset = textNode.GetSymbolOffset(this.TextContainer.Generation);

            // Get a count of all the characters we're about to copy.
            count = 0;
            node  = textNode;

            do
            {
                count += textNode.SymbolCount;

                node     = textNode.GetNextNode();
                textNode = node as TextTreeTextNode;
            }while (textNode != null && textNode != haltNode);

            // Allocate storage.
            text = new char[count];

            // Copy the text.
            TextTreeText.ReadText(this.TextContainer.RootTextBlock, symbolOffset, count, text, 0 /*startIndex*/);

            container = new TextContentContainer(text);

            return((TextTreeNode)node);
        }
Example #2
0
        // Token: 0x06003E0B RID: 15883 RVA: 0x0011D230 File Offset: 0x0011B430
        internal TextTreeTextNode Split(int localOffset, ElementEdge edge)
        {
            Invariant.Assert(this._symbolCount > 0, "Splitting a zero-width TextNode!");
            Invariant.Assert(localOffset >= 0 && localOffset <= this._symbolCount, "Bad localOffset!");
            Invariant.Assert(edge == ElementEdge.BeforeStart || edge == ElementEdge.AfterEnd, "Bad edge parameter!");
            TextTreeTextNode textTreeTextNode = new TextTreeTextNode();

            textTreeTextNode._generation = this._generation;
            base.Splay();
            ElementEdge      edge2;
            TextTreeTextNode result;

            if (this._positionRefCount > 0 && this._referencedEdge == ElementEdge.BeforeStart)
            {
                textTreeTextNode._symbolOffsetCache = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset));
                textTreeTextNode._symbolCount       = this._symbolCount - localOffset;
                this._symbolCount = localOffset;
                edge2             = ElementEdge.AfterEnd;
                result            = ((edge == ElementEdge.BeforeStart) ? this : textTreeTextNode);
            }
            else
            {
                textTreeTextNode._symbolOffsetCache = this._symbolOffsetCache;
                textTreeTextNode._symbolCount       = localOffset;
                this._symbolOffsetCache             = ((this._symbolOffsetCache == -1) ? -1 : (this._symbolOffsetCache + localOffset));
                this._symbolCount -= localOffset;
                edge2              = ElementEdge.BeforeStart;
                result             = ((edge == ElementEdge.BeforeStart) ? textTreeTextNode : this);
            }
            Invariant.Assert(this._symbolCount >= 0);
            Invariant.Assert(textTreeTextNode._symbolCount >= 0);
            textTreeTextNode.InsertAtNode(this, edge2);
            return(result);
        }
Example #3
0
        // Token: 0x06003E07 RID: 15879 RVA: 0x0011D0F8 File Offset: 0x0011B2F8
        internal override TextTreeNode Clone()
        {
            TextTreeTextNode textTreeTextNode = null;

            if (this._symbolCount > 0)
            {
                textTreeTextNode = new TextTreeTextNode();
                textTreeTextNode._symbolCount = this._symbolCount;
            }
            return(textTreeTextNode);
        }
Example #4
0
        //------------------------------------------------------
        //
        //  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);
        }
        // Token: 0x06003D13 RID: 15635 RVA: 0x0011BAC8 File Offset: 0x00119CC8
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out TextTreeDeleteContentUndoUnit.ContentContainer container)
        {
            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");
            int           symbolOffset = textNode.GetSymbolOffset(base.TextContainer.Generation);
            int           num          = 0;
            SplayTreeNode nextNode;

            do
            {
                num     += textNode.SymbolCount;
                nextNode = textNode.GetNextNode();
                textNode = (nextNode as TextTreeTextNode);
            }while (textNode != null && textNode != haltNode);
            char[] array = new char[num];
            TextTreeText.ReadText(base.TextContainer.RootTextBlock, symbolOffset, num, array, 0);
            container = new TextTreeDeleteContentUndoUnit.TextContentContainer(array);
            return((TextTreeNode)nextNode);
        }
Example #6
0
        // Token: 0x06003E28 RID: 15912 RVA: 0x0011D458 File Offset: 0x0011B658
        private void Merge()
        {
            Invariant.Assert(this._positionRefCount == 0, "Inappropriate Merge call!");
            TextTreeTextNode textTreeTextNode = base.GetPreviousNode() as TextTreeTextNode;

            if (textTreeTextNode != null && (textTreeTextNode._positionRefCount == 0 || textTreeTextNode._referencedEdge == ElementEdge.BeforeStart))
            {
                base.Remove();
                this._parentNode = null;
                textTreeTextNode.Splay();
                textTreeTextNode._symbolCount += this._symbolCount;
            }
            else
            {
                textTreeTextNode = this;
            }
            TextTreeTextNode textTreeTextNode2 = textTreeTextNode.GetNextNode() as TextTreeTextNode;

            if (textTreeTextNode2 != null)
            {
                if (textTreeTextNode._positionRefCount == 0 && (textTreeTextNode2._positionRefCount == 0 || textTreeTextNode2._referencedEdge == ElementEdge.AfterEnd))
                {
                    textTreeTextNode.Remove();
                    textTreeTextNode._parentNode = null;
                    textTreeTextNode2.Splay();
                    if (textTreeTextNode2._symbolOffsetCache != -1)
                    {
                        textTreeTextNode2._symbolOffsetCache -= textTreeTextNode._symbolCount;
                    }
                    textTreeTextNode2._symbolCount += textTreeTextNode._symbolCount;
                    return;
                }
                if ((textTreeTextNode._positionRefCount == 0 || textTreeTextNode._referencedEdge == ElementEdge.BeforeStart) && textTreeTextNode2._positionRefCount == 0)
                {
                    textTreeTextNode2.Remove();
                    textTreeTextNode2._parentNode = null;
                    textTreeTextNode.Splay();
                    textTreeTextNode._symbolCount += textTreeTextNode2._symbolCount;
                }
            }
        }
 // Token: 0x06003D12 RID: 15634 RVA: 0x0011BA44 File Offset: 0x00119C44
 private TextTreeDeleteContentUndoUnit.ContentContainer CopyContent(TextTreeNode node, TextTreeNode haltNode)
 {
     TextTreeDeleteContentUndoUnit.ContentContainer result           = null;
     TextTreeDeleteContentUndoUnit.ContentContainer contentContainer = null;
     while (node != haltNode && node != null)
     {
         TextTreeTextNode textTreeTextNode = node as TextTreeTextNode;
         TextTreeDeleteContentUndoUnit.ContentContainer contentContainer2;
         if (textTreeTextNode != null)
         {
             node = this.CopyTextNode(textTreeTextNode, haltNode, out contentContainer2);
         }
         else
         {
             TextTreeObjectNode textTreeObjectNode = node as TextTreeObjectNode;
             if (textTreeObjectNode != null)
             {
                 node = this.CopyObjectNode(textTreeObjectNode, out contentContainer2);
             }
             else
             {
                 Invariant.Assert(node is TextTreeTextElementNode, "Unexpected TextTreeNode type!");
                 TextTreeTextElementNode elementNode = (TextTreeTextElementNode)node;
                 node = this.CopyElementNode(elementNode, out contentContainer2);
             }
         }
         if (contentContainer == null)
         {
             result = contentContainer2;
         }
         else
         {
             contentContainer.NextContainer = contentContainer2;
         }
         contentContainer = contentContainer2;
     }
     return(result);
 }
        // Copies a run of text into a ContentContainer.
        // Returns the next node to examine.
        private TextTreeNode CopyTextNode(TextTreeTextNode textNode, TextTreeNode haltNode, out ContentContainer container)
        {
            SplayTreeNode node;
            char[] text;
            int count;
            int symbolOffset;

            Invariant.Assert(textNode != haltNode, "Expect at least one node to copy!");

            symbolOffset = textNode.GetSymbolOffset(this.TextContainer.Generation);

            // Get a count of all the characters we're about to copy.
            count = 0;
            node = textNode;

            do
            {
                count += textNode.SymbolCount;

                node = textNode.GetNextNode();
                textNode = node as TextTreeTextNode;
            }
            while (textNode != null && textNode != haltNode);

            // Allocate storage.
            text = new char[count];

            // Copy the text.
            TextTreeText.ReadText(this.TextContainer.RootTextBlock, symbolOffset, count, text, 0 /*startIndex*/);

            container = new TextContentContainer(text);

            return (TextTreeNode)node;
        }
Example #9
0
        // 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);
        }
Example #10
0
        //------------------------------------------------------
        // 
        //  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; 
        }
Example #11
0
        // 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; 
        } 
Example #12
0
        // The InsertText worker.  Adds text to the tree at a specified position. 
        // text is either a string or char[] to insert. 
        internal void InsertTextInternal(TextPointer position, object text)
        { 
            TextTreeTextNode textNode;
            SplayTreeNode containingNode;
            TextPointer originalPosition;
            int symbolOffset; 
            int textLength;
            LogicalDirection direction; 
 
            Invariant.Assert(text is string || text is char[], "Unexpected type for 'text' parameter!");
 
            textLength = GetTextLength(text);

            if (textLength == 0)
                return; 

            DemandCreateText(); 
 
            position.SyncToTreeGeneration();
 
            if (Invariant.Strict)
            {
                if (position.Node.SymbolCount == 0)
                { 
                    // We expect only TextTreeTextNodes ever have zero symbol counts.
                    // This can happen in two cases: 
                    // 
                    // <TextNode referencedEdge=BeforeStart symbolCount=1+/> <TextNode referencedEdge=AfterEnd symbolCount=0/>
                    // or 
                    // <TextNode referencedEdge=BeforeStart symbolCount=0/> <TextNode referencedEdge=AfterEnd symbolCount=1+/>
                    //
                    Invariant.Assert(position.Node is TextTreeTextNode);
                    Invariant.Assert((position.Edge == ElementEdge.AfterEnd && position.Node.GetPreviousNode() is TextTreeTextNode && position.Node.GetPreviousNode().SymbolCount > 0) || 
                                 (position.Edge == ElementEdge.BeforeStart && position.Node.GetNextNode() is TextTreeTextNode && position.Node.GetNextNode().SymbolCount > 0));
                } 
            } 

            BeforeAddChange(); 

            // During document load we won't have listeners and we can save
            // an allocation on every insert.  This can easily save 1000's of allocations during boot.
            originalPosition = this.HasListeners ? new TextPointer(position, LogicalDirection.Backward) : null; 

            // Find a bordering TextTreeTextNode, if any. 
 
            // We know position already points to the current TextNode, if there is one, so
            // we can't append text to that node (it would disrespect position's gravity to do so). 
            // So we either have to find a neighboring text node with no position references, or
            // create a new node.

            // Look for a bordering text node. 
            if (position.Edge == ElementEdge.BeforeStart || position.Edge == ElementEdge.BeforeEnd)
            { 
                direction = LogicalDirection.Backward; 
            }
            else 
            {
                direction = LogicalDirection.Forward;
            }
            textNode = position.GetAdjacentTextNodeSibling(direction); 

            if (textNode != null) 
            { 
                // We can't use a text node that is already referred to by text positions.
                // Doing so could displace the positions, since they expect to remain at 
                // the node edge no matter what happens.
                if ((direction == LogicalDirection.Backward && textNode.AfterEndReferenceCount) ||
                    (direction == LogicalDirection.Forward && textNode.BeforeStartReferenceCount))
                { 
                    textNode = null;
                } 
            } 

            if (textNode == null) 
            {
                // No text node available.  Create and insert one.
                textNode = new TextTreeTextNode();
                textNode.InsertAtPosition(position); 
                containingNode = textNode.GetContainingNode();
            } 
            else 
            {
                // We didn't insert a new node, so splay textNode to the root so 
                // we don't invalidate any LeftSymbolCounts of ancestor nodes.
                textNode.Splay();
                containingNode = textNode.ParentNode;
            } 

            // Update the symbol counts. 
            textNode.SymbolCount += textLength; // This simultaneously updates textNode.IMECharCount. 
            UpdateContainerSymbolCount(containingNode, /* symbolCount */ textLength, /* charCount */ textLength);
 
            // Insert the raw text.
            symbolOffset = textNode.GetSymbolOffset(this.Generation);
            TextTreeText.InsertText(_rootNode.RootTextBlock, symbolOffset, text);
 
            // Handle undo.
            TextTreeUndo.CreateInsertUndoUnit(this, symbolOffset, textLength); 
 
            // Announce the change.
            NextGeneration(false /* deletedContent */); 

            AddChange(originalPosition, /* symbolCount */ textLength, /* charCount */ textLength, PrecursorTextChangeType.ContentAdded);

            // Notify the TextElement of a content change. 
            TextElement textElement = position.Parent as TextElement;
            if (textElement != null) 
            { 
                textElement.OnTextUpdated();
            } 
        }
Example #13
0
        internal static int GetTextInRun(TextContainer textContainer, int symbolOffset, TextTreeTextNode textNode, int nodeOffset, LogicalDirection direction, char[] textBuffer, int startIndex, int count)
        {
            int skipCount;
            int finalCount;

            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));
            }
            Invariant.Assert(textNode != null, "textNode is expected to be non-null");

            textContainer.EmptyDeadPositionList();

            if (nodeOffset < 0)
            {
                skipCount = 0;
            }
            else
            {
                skipCount = (direction == LogicalDirection.Forward) ? nodeOffset : textNode.SymbolCount - nodeOffset;
                symbolOffset += nodeOffset;
            }
            finalCount = 0;

            // Loop and combine adjacent text nodes into a single run.
            // This isn't just a perf optimization.  Because text positions
            // split text nodes, if we just returned a single node's text
            // callers would see strange side effects where position.GetTextLength() !=
            // position.GetText() if another position is moved between the calls.
            while (textNode != null)
            {
                // Never return more textBuffer than the text following this position in the current text node.
                finalCount += Math.Min(count - finalCount, textNode.SymbolCount - skipCount);
                skipCount = 0;
                if (finalCount == count)
                    break;
                textNode = ((direction == LogicalDirection.Forward) ? textNode.GetNextNode() : textNode.GetPreviousNode()) as TextTreeTextNode;
            }

            // If we're reading backwards, need to fixup symbolOffset to point into the node.
            if (direction == LogicalDirection.Backward)
            {
                symbolOffset -= finalCount;
            }

            if (finalCount > 0) // We may not have allocated textContainer.RootTextBlock if no text was ever inserted.
            {
                TextTreeText.ReadText(textContainer.RootTextBlock, symbolOffset, finalCount, textBuffer, startIndex);
            }

            return finalCount;
        }